diff options
Diffstat (limited to 'src')
311 files changed, 18220 insertions, 13162 deletions
diff --git a/src/bindings/interface/ScriptMgr.cpp b/src/bindings/interface/ScriptMgr.cpp index 2a6a9861829..154d612678d 100644 --- a/src/bindings/interface/ScriptMgr.cpp +++ b/src/bindings/interface/ScriptMgr.cpp @@ -288,6 +288,15 @@ bool ItemUse( Player *player, Item* _Item, SpellCastTargets const& targets) } TRINITY_DLL_EXPORT +bool ItemExpire( Player *player, ItemPrototype const *_ItemProto) +{ + Script *tmpscript = m_scripts[_ItemProto->ScriptId]; + if (!tmpscript || !tmpscript->pItemExpire) return true; + + return tmpscript->pItemExpire(player,_ItemProto); +} + +TRINITY_DLL_EXPORT bool EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget ) { Script *tmpscript = m_scripts[crTarget->GetScriptId()]; diff --git a/src/bindings/interface/ScriptMgr.h b/src/bindings/interface/ScriptMgr.h index 04d3a6df14f..9b3c59d17ca 100644 --- a/src/bindings/interface/ScriptMgr.h +++ b/src/bindings/interface/ScriptMgr.h @@ -42,7 +42,7 @@ struct Script pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL), pGOSelect(NULL), pGOSelectWithCode(NULL), pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), pChooseReward(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), pGOQuestAccept(NULL), - pGOChooseReward(NULL), pItemUse(NULL), pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), + pGOChooseReward(NULL), pItemUse(NULL), pItemExpire(NULL), pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), pEffectDummyItem(NULL), GetAI(NULL), GetInstanceData(NULL) {} @@ -67,6 +67,7 @@ struct Script bool (*pGOQuestAccept )(Player*, GameObject*, Quest const* ); bool (*pGOChooseReward )(Player*, GameObject*, Quest const*, uint32 ); bool (*pItemUse )(Player*, Item*, SpellCastTargets const& ); + bool (*pItemExpire )(Player*, ItemPrototype const*); bool (*pEffectDummyCreature )(Unit*, uint32, uint32, Creature* ); bool (*pEffectDummyGameObj )(Unit*, uint32, uint32, GameObject* ); bool (*pEffectDummyItem )(Unit*, uint32, uint32, Item* ); diff --git a/src/bindings/scripts/CMakeLists.txt b/src/bindings/scripts/CMakeLists.txt index 3f86535f5e3..b67d7cfe4aa 100644 --- a/src/bindings/scripts/CMakeLists.txt +++ b/src/bindings/scripts/CMakeLists.txt @@ -208,6 +208,7 @@ SET(trinityscript_LIB_SRCS scripts/zone/magisters_terrace/boss_vexallus.cpp scripts/zone/magisters_terrace/def_magisters_terrace.h scripts/zone/magisters_terrace/instance_magisters_terrace.cpp + scripts/zone/magisters_terrace/magisters_terrace.cpp scripts/zone/maraudon/boss_celebras_the_cursed.cpp scripts/zone/maraudon/boss_landslide.cpp scripts/zone/maraudon/boss_noxxion.cpp @@ -293,6 +294,7 @@ SET(trinityscript_LIB_SRCS scripts/zone/shadowmoon_valley/boss_doomwalker.cpp scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp scripts/zone/shattrath/shattrath_city.cpp + scripts/zone/sholazar_basin/sholazar_basin.cpp scripts/zone/silithus/silithus.cpp scripts/zone/silvermoon/silvermoon_city.cpp scripts/zone/silverpine_forest/silverpine_forest.cpp @@ -380,6 +382,7 @@ SET(trinityscript_LIB_SRCS scripts/zone/zulaman/def_zulaman.h scripts/zone/zulaman/instance_zulaman.cpp scripts/zone/zulaman/zulaman.cpp + scripts/zone/zuldrak/zuldrak.cpp scripts/zone/zulfarrak/zulfarrak.cpp scripts/zone/zulgurub/boss_arlokk.cpp scripts/zone/zulgurub/boss_gahzranka.cpp @@ -481,6 +484,7 @@ SET(trinityscript_LIB_SRCS scripts/zone/obsidian_sanctum/def_obsidian_sanctum.h scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp scripts/zone/vault_of_archavon/boss_archavon.cpp + scripts/zone/vault_of_archavon/boss_emalon.cpp scripts/zone/vault_of_archavon/def_vault_of_archavon.h scripts/zone/wintergrasp/wintergrasp.cpp scripts/zone/ulduar/ulduar/boss_algalon.cpp diff --git a/src/bindings/scripts/ScriptMgr.cpp b/src/bindings/scripts/ScriptMgr.cpp index 217752b340e..7a67acef149 100644 --- a/src/bindings/scripts/ScriptMgr.cpp +++ b/src/bindings/scripts/ScriptMgr.cpp @@ -356,6 +356,7 @@ extern void AddSC_boss_selin_fireheart(); extern void AddSC_boss_vexallus(); extern void AddSC_boss_priestess_delrissa(); extern void AddSC_instance_magisters_terrace(); +extern void AddSC_magisters_terrace(); //Maraudon extern void AddSC_boss_celebras_the_cursed(); @@ -414,6 +415,9 @@ extern void AddSC_boss_ormorok(); extern void AddSC_boss_keristrasza(); extern void AddSC_instance_nexus(); +//Obsidian Sanctum +extern void AddSC_instance_obsidian_sanctum(); + //Onyxia's Lair extern void AddSC_boss_onyxia(); @@ -472,6 +476,9 @@ extern void AddSC_shadowmoon_valley(); //Shattrath extern void AddSC_shattrath_city(); +//Sholazar Basin +extern void AddSC_sholazar_basin(); + //Silithus extern void AddSC_silithus(); @@ -636,10 +643,19 @@ extern void AddSC_boss_zuljin(); extern void AddSC_instance_zulaman(); extern void AddSC_zulaman(); +//Zul'Drak +extern void AddSC_zuldrak(); + //Northrend //Dungeon //Vault of Archavon extern void AddSC_boss_archavon(); +extern void AddSC_boss_emalon(); +extern void AddSC_instance_archavon(); + +//Ulduar +extern void AddSC_boss_flame_leviathan(); +extern void AddSC_boss_razorscale(); //Region extern void AddSC_wintergrasp(); @@ -1254,6 +1270,7 @@ void ScriptsInit(char const* cfg_file = "trinitycore.conf") AddSC_boss_vexallus(); AddSC_boss_priestess_delrissa(); AddSC_instance_magisters_terrace(); + AddSC_magisters_terrace(); //Maraudon AddSC_boss_celebras_the_cursed(); @@ -1312,6 +1329,9 @@ void ScriptsInit(char const* cfg_file = "trinitycore.conf") AddSC_boss_keristrasza(); AddSC_instance_nexus(); + //Obsidian Sanctum + AddSC_instance_obsidian_sanctum(); + //Onyxia's Lair AddSC_boss_onyxia(); @@ -1370,6 +1390,9 @@ void ScriptsInit(char const* cfg_file = "trinitycore.conf") //Shattrath AddSC_shattrath_city(); + //Sholazar Basin + AddSC_sholazar_basin(); + //Silithus AddSC_silithus(); @@ -1534,10 +1557,19 @@ void ScriptsInit(char const* cfg_file = "trinitycore.conf") AddSC_instance_zulaman(); AddSC_zulaman(); + //Zul'Drak + AddSC_zuldrak(); + //Northrend //Dungeon //Vault of Archavon AddSC_boss_archavon(); + AddSC_boss_emalon(); + AddSC_instance_archavon(); + + //Ulduar + AddSC_boss_flame_leviathan(); + AddSC_boss_razorscale(); //Region AddSC_wintergrasp(); @@ -1857,6 +1889,15 @@ bool ItemUse( Player *player, Item* _Item, SpellCastTargets const& targets) } TRINITY_DLL_EXPORT +bool ItemExpire( Player *player, ItemPrototype const * _ItemProto) +{ + Script *tmpscript = m_scripts[_ItemProto->ScriptId]; + if (!tmpscript || !tmpscript->pItemExpire) return true; + + return tmpscript->pItemExpire(player,_ItemProto); +} + +TRINITY_DLL_EXPORT bool EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget ) { Script *tmpscript = m_scripts[crTarget->GetScriptId()]; diff --git a/src/bindings/scripts/ScriptMgr.h b/src/bindings/scripts/ScriptMgr.h index 719cf7932e9..06830532c9b 100644 --- a/src/bindings/scripts/ScriptMgr.h +++ b/src/bindings/scripts/ScriptMgr.h @@ -23,6 +23,7 @@ class SpellCastTargets; class Map; class Unit; class WorldObject; +struct ItemPrototype; #define MAX_SCRIPTS 5000 //72 bytes each (approx 351kb) #define VISIBLE_RANGE (166.0f) //MAX visible range (size of grid) @@ -34,7 +35,7 @@ struct Script pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL), pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), pChooseReward(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), - pGOQuestAccept(NULL), pGOChooseReward(NULL),pItemUse(NULL), + pGOQuestAccept(NULL), pGOChooseReward(NULL),pItemUse(NULL), pItemExpire(NULL), pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), pEffectDummyItem(NULL), GetAI(NULL), GetInstanceData(NULL) {} @@ -60,6 +61,7 @@ struct Script bool (*pGOQuestAccept )(Player*, GameObject*, Quest const* ); bool (*pGOChooseReward )(Player*, GameObject*, Quest const*, uint32 ); bool (*pItemUse )(Player*, Item*, SpellCastTargets const& ); + bool (*pItemExpire )(Player*, ItemPrototype const *); bool (*pEffectDummyCreature )(Unit*, uint32, uint32, Creature* ); bool (*pEffectDummyGameObj )(Unit*, uint32, uint32, GameObject* ); bool (*pEffectDummyItem )(Unit*, uint32, uint32, Item* ); diff --git a/src/bindings/scripts/VC71/71ScriptDev2.vcproj b/src/bindings/scripts/VC71/71ScriptDev2.vcproj deleted file mode 100644 index d5fe63852ba..00000000000 --- a/src/bindings/scripts/VC71/71ScriptDev2.vcproj +++ /dev/null @@ -1,2290 +0,0 @@ -<?xml version="1.0" encoding="windows-1251"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="7,10" - Name="TrinityScript" - ProjectGUID="{4295C8A9-79B7-4354-8064-F05FB9CA0C96}" - RootNamespace="ScriptDev2" - Keyword="Win32Proj" - TargetFrameworkVersion="131072" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="..\..\..\..\bin\$(PlatformName)_$(ConfigurationName)" - IntermediateDirectory=".\ScriptDev2__$(PlatformName)_$(ConfigurationName)" - ConfigurationType="2" - InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\..\..\..\dep\ACE_wrappers" - PreprocessorDefinitions="WIN32;_DEBUG;MANGOS_DEBUG;_WINDOWS;_USRDLL;SCRIPT" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="3" - UsePrecompiledHeader="2" - PrecompiledHeaderThrough="precompiled.h" - WarningLevel="3" - Detect64BitPortabilityProblems="true" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="trinitycore.lib zthread.lib" - OutputFile="$(OutDir)/TrinityScript.dll" - LinkIncremental="2" - AdditionalLibraryDirectories="..\..\..\..\win\VC71\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC71\trinitycore__$(PlatformName)_$(ConfigurationName)" - GenerateDebugInformation="true" - ProgramDatabaseFile="$(OutDir)/MaNGOSScript.pdb" - SubSystem="2" - RandomizedBaseAddress="1" - DataExecutionPrevention="0" - ImportLibrary="$(OutDir)/TrinityScript.lib" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="..\..\..\..\bin\$(PlatformName)_$(ConfigurationName)" - IntermediateDirectory=".\ScriptDev2__$(PlatformName)_$(ConfigurationName)" - ConfigurationType="2" - InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - AdditionalIncludeDirectories="..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\..\..\..\dep\ACE_wrappers" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT" - RuntimeLibrary="2" - EnableEnhancedInstructionSet="1" - UsePrecompiledHeader="2" - PrecompiledHeaderThrough="precompiled.h" - WarningLevel="3" - Detect64BitPortabilityProblems="true" - DebugInformationFormat="3" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="trinitycore.lib zthread.lib" - OutputFile="$(OutDir)/TrinityScript.dll" - LinkIncremental="1" - AdditionalLibraryDirectories="..\..\..\..\win\VC71\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC71\trinitycore__$(PlatformName)_$(ConfigurationName)" - GenerateDebugInformation="false" - SubSystem="2" - OptimizeReferences="2" - EnableCOMDATFolding="2" - RandomizedBaseAddress="1" - DataExecutionPrevention="0" - ImportLibrary="$(OutDir)/TrinityScript.lib" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <Filter - Name="Scripts" - > - <Filter - Name="boss" - > - <File - RelativePath="..\scripts\boss\boss_emeriss.cpp" - > - </File> - <File - RelativePath="..\scripts\boss\boss_lethon.cpp" - > - </File> - <File - RelativePath="..\scripts\boss\boss_taerar.cpp" - > - </File> - <File - RelativePath="..\scripts\boss\boss_ysondre.cpp" - > - </File> - </Filter> - <Filter - Name="creature" - > - <File - RelativePath="..\scripts\creature\mob_event_ai.cpp" - > - </File> - <File - RelativePath="..\scripts\creature\mob_event_ai.h" - > - </File> - <File - RelativePath="..\scripts\creature\mob_generic_creature.cpp" - > - </File> - <File - RelativePath="..\scripts\creature\simple_ai.cpp" - > - </File> - <File - RelativePath="..\scripts\creature\simple_ai.h" - > - </File> - </Filter> - <Filter - Name="guard" - > - <File - RelativePath="..\scripts\guard\guard_ai.cpp" - > - </File> - <File - RelativePath="..\scripts\guard\guard_ai.h" - > - </File> - <File - RelativePath="..\scripts\guard\guards.cpp" - > - </File> - </Filter> - <Filter - Name="honor" - > - </Filter> - <Filter - Name="npc" - > - <File - RelativePath="..\scripts\npc\npc_escortAI.cpp" - > - </File> - <File - RelativePath="..\scripts\npc\npc_escortAI.h" - > - </File> - <File - RelativePath="..\scripts\npc\npc_innkeeper.cpp" - > - </File> - <File - RelativePath="..\scripts\npc\npc_professions.cpp" - > - </File> - <File - RelativePath="..\scripts\npc\npcs_special.cpp" - > - </File> - </Filter> - <Filter - Name="servers" - > - </Filter> - <Filter - Name="custom" - > - <File - RelativePath="..\scripts\custom\custom_example.cpp" - > - </File> - <File - RelativePath="..\scripts\custom\custom_gossip_codebox.cpp" - > - </File> - <File - RelativePath="..\scripts\custom\test.cpp" - > - </File> - </Filter> - <Filter - Name="areatrigger" - > - <File - RelativePath="..\scripts\areatrigger\areatrigger_scripts.cpp" - > - </File> - </Filter> - <Filter - Name="go" - > - <File - RelativePath="..\scripts\go\go_scripts.cpp" - > - </File> - </Filter> - <Filter - Name="item" - > - <File - RelativePath="..\scripts\item\item_scripts.cpp" - > - </File> - <File - RelativePath="..\scripts\item\item_test.cpp" - > - </File> - </Filter> - <Filter - Name="zone" - > - <Filter - Name="Alterac Mountains" - > - <File - RelativePath="..\scripts\zone\alterac_mountains\alterac_mountains.cpp" - > - </File> - </Filter> - <Filter - Name="Ashenvale Forest" - > - <File - RelativePath="..\scripts\zone\ashenvale_forest\ashenvale.cpp" - > - </File> - </Filter> - <Filter - Name="Azshara" - > - <File - RelativePath="..\scripts\zone\azshara\azshara.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\azshara\boss_azuregos.cpp" - > - </File> - </Filter> - <Filter - Name="Badlands" - > - </Filter> - <Filter - Name="Barrens" - > - <File - RelativePath="..\scripts\zone\barrens\the_barrens.cpp" - > - </File> - </Filter> - <Filter - Name="Blackfathom Depths" - > - <File - RelativePath="..\scripts\zone\blackfathom_depths\instance_blackfathom_deeps.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackfathom_depths\def_blackfathom_deeps.h" - > - </File> - </Filter> - <Filter - Name="Arathi Highlands" - > - <File - RelativePath="..\scripts\zone\arathi_highlands\arathi_highlands.cpp" - > - </File> - </Filter> - <Filter - Name="Deadmines" - > - <File - RelativePath="..\scripts\zone\deadmines\deadmines.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\deadmines\def_deadmines.h" - > - </File> - </Filter> - <Filter - Name="Deadwind Pass" - > - </Filter> - <Filter - Name="Desolace" - > - </Filter> - <Filter - Name="Dire Maul" - > - </Filter> - <Filter - Name="Dun Morogh" - > - <File - RelativePath="..\scripts\zone\dun_morogh\dun_morogh.cpp" - > - </File> - </Filter> - <Filter - Name="Durotar" - > - </Filter> - <Filter - Name="Duskwood" - > - </Filter> - <Filter - Name="Dustwallow Marsh" - > - <File - RelativePath="..\scripts\zone\dustwallow_marsh\dustwallow_marsh.cpp" - > - </File> - </Filter> - <Filter - Name="Blackwing Lair" - > - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_broodlord_lashlayer.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_chromaggus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_ebonroc.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_firemaw.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_flamegor.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_nefarian.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_razorgore.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_vaelastrasz.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\boss_victor_nefarius.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackwing_lair\instance_blackwing_lair.cpp" - > - </File> - </Filter> - <Filter - Name="Bloodmyst Isle" - > - <File - RelativePath="..\scripts\zone\bloodmyst_isle\bloodmyst_isle.cpp" - > - </File> - </Filter> - <Filter - Name="Gruul's Lair" - > - <File - RelativePath="..\scripts\zone\gruuls_lair\boss_gruul.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\gruuls_lair\boss_high_king_maulgar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\gruuls_lair\def_gruuls_lair.h" - > - </File> - <File - RelativePath="..\scripts\zone\gruuls_lair\instance_gruuls_lair.cpp" - > - </File> - </Filter> - <Filter - Name="Burning Steppes" - > - <File - RelativePath="..\scripts\zone\burning_steppes\burning_steppes.cpp" - > - </File> - </Filter> - <Filter - Name="Darkshore" - > - <File - RelativePath="..\scripts\zone\darkshore\darkshore.cpp" - > - </File> - </Filter> - <Filter - Name="Eastern Plaguelands" - > - <File - RelativePath="..\scripts\zone\eastern_plaguelands\eastern_plaguelands.cpp" - > - </File> - </Filter> - <Filter - Name="Moonglade" - > - <File - RelativePath="..\scripts\zone\moonglade\moonglade.cpp" - > - </File> - </Filter> - <Filter - Name="Razorfen Kraul" - > - <File - RelativePath="..\scripts\zone\razorfen_kraul\razorfen_kraul.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\razorfen_kraul\instance_razorfen_kraul.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\razorfen_kraul\def_razorfen_kraul.h" - > - </File> - </Filter> - <Filter - Name="Redridge Mountains" - > - </Filter> - <Filter - Name="Ruins of Ahn'Qiraj" - > - <File - RelativePath="..\scripts\zone\ruins_of_ahnqiraj\boss_ayamiss.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\ruins_of_ahnqiraj\boss_buru.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\ruins_of_ahnqiraj\boss_kurinnaxx.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\ruins_of_ahnqiraj\boss_moam.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\ruins_of_ahnqiraj\boss_ossirian.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\ruins_of_ahnqiraj\boss_rajaxx.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\ruins_of_ahnqiraj\instance_ruins_of_ahnqiraj.cpp" - > - </File> - </Filter> - <Filter - Name="Swamp of Sorrows" - > - </Filter> - <Filter - Name="Scarlet Monastery" - > - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_arcanist_doan.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_azshir_the_sleepless.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_bloodmage_thalnos.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_headless_horseman.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_herod.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_high_inquisitor_fairbanks.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_houndmaster_loksey.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_interrogator_vishas.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_mograine_and_whitemane.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\boss_scorn.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\def_scarlet_monastery.h" - > - </File> - <File - RelativePath="..\scripts\zone\scarlet_monastery\instance_scarlet_monastery.cpp" - > - </File> - </Filter> - <Filter - Name="Scholomance" - > - <File - RelativePath="..\scripts\zone\scholomance\boss_darkmaster_gandling.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_death_knight_darkreaver.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_doctor_theolen_krastinov.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_illucia_barov.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_instructor_malicia.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_jandice_barov.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_kormok.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_lord_alexei_barov.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_lorekeeper_polkelt.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_ras_frostwhisper.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_the_ravenian.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\boss_vectus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\def_scholomance.h" - > - </File> - <File - RelativePath="..\scripts\zone\scholomance\instance_scholomance.cpp" - > - </File> - </Filter> - <Filter - Name="Searing Gorge" - > - <File - RelativePath="..\scripts\zone\searing_gorge\searing_gorge.cpp" - > - </File> - </Filter> - <Filter - Name="Elwynn Forest" - > - <File - RelativePath="..\scripts\zone\elwynn_forest\elwynn_forest.cpp" - > - </File> - </Filter> - <Filter - Name="Felwood" - > - <File - RelativePath="..\scripts\zone\felwood\felwood.cpp" - > - </File> - </Filter> - <Filter - Name="Feralas" - > - <File - RelativePath="..\scripts\zone\feralas\feralas.cpp" - > - </File> - </Filter> - <Filter - Name="Gnomeregan" - > - </Filter> - <Filter - Name="Hillsbrad Foothills" - > - </Filter> - <Filter - Name="Hinterlands" - > - </Filter> - <Filter - Name="Maraudon" - > - <File - RelativePath="..\scripts\zone\maraudon\boss_celebras_the_cursed.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\maraudon\boss_landslide.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\maraudon\boss_noxxion.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\maraudon\boss_princess_theradras.cpp" - > - </File> - </Filter> - <Filter - Name="Molten Core" - > - <File - RelativePath="..\scripts\zone\molten_core\boss_baron_geddon.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_garr.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_gehennas.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_golemagg.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_lucifron.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_magmadar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_majordomo_executus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_ragnaros.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_shazzrah.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\boss_sulfuron_harbinger.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\def_molten_core.h" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\instance_molten_core.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\molten_core\molten_core.cpp" - > - </File> - </Filter> - <Filter - Name="Mulgore" - > - <File - RelativePath="..\scripts\zone\mulgore\mulgore.cpp" - > - </File> - </Filter> - <Filter - Name="Naxxramas" - > - <File - RelativePath="..\scripts\zone\naxxramas\boss_anubrekhan.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_faerlina.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_four_horsemen.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_gluth.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_gothik.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_grobbulus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_heigan.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_highlord_mograine.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_kelthuzad.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_loatheb.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_maexxna.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_noth.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_patchwerk.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_razuvious.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_sapphiron.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\boss_thaddius.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\naxxramas\instance_naxxramas.cpp" - > - </File> - </Filter> - <Filter - Name="Onyxia's Lair" - > - <File - RelativePath="..\scripts\zone\onyxias_lair\boss_onyxia.cpp" - > - </File> - </Filter> - <Filter - Name="Ragefire Chasm" - > - </Filter> - <Filter - Name="Razorfen Downs" - > - <File - RelativePath="..\scripts\zone\razorfen_downs\boss_amnennar_the_coldbringer.cpp" - > - </File> - </Filter> - <Filter - Name="Shadowfang Keep" - > - <File - RelativePath="..\scripts\zone\shadowfang_keep\def_shadowfang_keep.h" - > - </File> - <File - RelativePath="..\scripts\zone\shadowfang_keep\instance_shadowfang_keep.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\shadowfang_keep\shadowfang_keep.cpp" - > - </File> - </Filter> - <Filter - Name="Stonetalon Mountains" - > - <File - RelativePath="..\scripts\zone\stonetalon_mountains\stonetalon_mountains.cpp" - > - </File> - </Filter> - <Filter - Name="Stranglethorn Vale" - > - <File - RelativePath="..\scripts\zone\stranglethorn_vale\stranglethorn_vale.cpp" - > - </File> - </Filter> - <Filter - Name="Stratholme" - > - <File - RelativePath="..\scripts\zone\stratholme\boss_baron_rivendare.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_baroness_anastari.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_cannon_master_willey.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_dathrohan_balnazzar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_magistrate_barthilas.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_maleki_the_pallid.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_nerubenkan.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_order_of_silver_hand.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_postmaster_malown.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_ramstein_the_gorger.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\boss_timmy_the_cruel.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\def_stratholme.h" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\instance_stratholme.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\stratholme\stratholme.cpp" - > - </File> - </Filter> - <Filter - Name="Sunken Temple" - > - </Filter> - <Filter - Name="Tanaris" - > - <File - RelativePath="..\scripts\zone\tanaris\tanaris.cpp" - > - </File> - </Filter> - <Filter - Name="Teldrassil" - > - </Filter> - <Filter - Name="Temple of Ahn'Qiraj" - > - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_bug_trio.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_cthun.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_fankriss.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_huhuran.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_ouro.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_sartura.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_skeram.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_twinemperors.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\boss_viscidus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\def_temple_of_ahnqiraj.h" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\instance_temple_of_ahnqiraj.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\temple_of_ahnqiraj\mob_anubisath_sentinel.cpp" - > - </File> - </Filter> - <Filter - Name="Thousand Needles" - > - <File - RelativePath="..\scripts\zone\thousand_needles\thousand_needles.cpp" - > - </File> - </Filter> - <Filter - Name="Silithus" - > - <File - RelativePath="..\scripts\zone\silithus\silithus.cpp" - > - </File> - </Filter> - <Filter - Name="Silverpine Forest" - > - <File - RelativePath="..\scripts\zone\silverpine_forest\silverpine_forest.cpp" - > - </File> - </Filter> - <Filter - Name="Stockade" - > - </Filter> - <Filter - Name="Tirisfal Glades" - > - <File - RelativePath="..\scripts\zone\tirisfal_glades\tirisfal_glades.cpp" - > - </File> - </Filter> - <Filter - Name="Wailing Caverns" - > - <File - RelativePath="..\scripts\zone\wailing_caverns\instance_wailing_caverns.cpp" - > - </File> - </Filter> - <Filter - Name="Western Plaguelands" - > - <File - RelativePath="..\scripts\zone\western_plaguelands\western_plaguelands.cpp" - > - </File> - </Filter> - <Filter - Name="Westfall" - > - <File - RelativePath="..\scripts\zone\westfall\westfall.cpp" - > - </File> - </Filter> - <Filter - Name="Wetlands" - > - </Filter> - <Filter - Name="Winterspring" - > - <File - RelativePath="..\scripts\zone\winterspring\winterspring.cpp" - > - </File> - </Filter> - <Filter - Name="Zul'Farrak" - > - <File - RelativePath="..\scripts\zone\zulfarrak\zulfarrak.cpp" - > - </File> - </Filter> - <Filter - Name="Zul'Gurub" - > - <File - RelativePath="..\scripts\zone\zulgurub\boss_arlokk.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_gahzranka.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_grilek.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_hakkar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_hazzarah.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_jeklik.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_jindo.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_mandokir.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_marli.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_renataki.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_thekal.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_venoxis.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\boss_wushoolay.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\def_zulgurub.h" - > - </File> - <File - RelativePath="..\scripts\zone\zulgurub\instance_zulgurub.cpp" - > - </File> - </Filter> - <Filter - Name="Uldaman" - > - <File - RelativePath="..\scripts\zone\uldaman\boss_archaedas.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\uldaman\boss_ironaya.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\uldaman\instance_uldaman.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\uldaman\uldaman.cpp" - > - </File> - </Filter> - <Filter - Name="Un'Goro Crater" - > - <File - RelativePath="..\scripts\zone\ungoro_crater\ungoro_crater.cpp" - > - </File> - </Filter> - <Filter - Name="Aunchindoun" - > - <Filter - Name="Auchenai Crypts" - > - <File - RelativePath="..\scripts\zone\aunchindoun\auchenai_crypts\boss_exarch_maladaar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\auchenai_crypts\boss_shirrak_the_dead_watcher.cpp" - > - </File> - </Filter> - <Filter - Name="Mana Tombs" - > - <File - RelativePath="..\scripts\zone\aunchindoun\mana_tombs\boss_nexusprince_shaffar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\mana_tombs\boss_pandemonius.cpp" - > - </File> - </Filter> - <Filter - Name="Sethekk Halls" - > - <File - RelativePath="..\scripts\zone\aunchindoun\sethekk_halls\boss_darkweaver_syth.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\sethekk_halls\boss_tailonking_ikiss.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\sethekk_halls\def_sethekk_halls.h" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\sethekk_halls\instance_sethekk_halls.cpp" - > - </File> - </Filter> - <Filter - Name="Shadow Labyrinth" - > - <File - RelativePath="..\scripts\zone\aunchindoun\shadow_labyrinth\boss_ambassador_hellmaw.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\shadow_labyrinth\boss_blackheart_the_inciter.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\shadow_labyrinth\boss_grandmaster_vorpil.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\shadow_labyrinth\boss_murmur.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\shadow_labyrinth\def_shadow_labyrinth.h" - > - </File> - <File - RelativePath="..\scripts\zone\aunchindoun\shadow_labyrinth\instance_shadow_labyrinth.cpp" - > - </File> - </Filter> - </Filter> - <Filter - Name="Azuremyst Isle" - > - <File - RelativePath="..\scripts\zone\azuremyst_isle\azuremyst_isle.cpp" - > - </File> - </Filter> - <Filter - Name="Black Temple" - > - <File - RelativePath="..\scripts\zone\black_temple\black_temple.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_bloodboil.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_illidan.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_mother_shahraz.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_reliquary_of_souls.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_shade_of_akama.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_supremus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_teron_gorefiend.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\boss_warlord_najentus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\def_black_temple.h" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\illidari_council.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\black_temple\instance_black_temple.cpp" - > - </File> - </Filter> - <Filter - Name="Eversong Woods" - > - <File - RelativePath="..\scripts\zone\eversong_woods\eversong_woods.cpp" - > - </File> - </Filter> - <Filter - Name="Ghostlands" - > - <File - RelativePath="..\scripts\zone\ghostlands\ghostlands.cpp" - > - </File> - </Filter> - <Filter - Name="Blade's Edge Mountains" - > - <File - RelativePath="..\scripts\zone\blades_edge_mountains\blades_edge_mountains.cpp" - > - </File> - </Filter> - <Filter - Name="Blasted Lands" - > - <File - RelativePath="..\scripts\zone\blasted_lands\blasted_lands.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blasted_lands\boss_kruul.cpp" - > - </File> - </Filter> - <Filter - Name="Hellfire Citadel" - > - <Filter - Name="Blood Furnace" - > - <File - RelativePath="..\scripts\zone\hellfire_citadel\blood_furnace\boss_broggok.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\blood_furnace\boss_kelidan_the_breaker.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\blood_furnace\boss_the_maker.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\blood_furnace\def_blood_furnace.h" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\blood_furnace\instance_blood_furnace.cpp" - > - </File> - </Filter> - <Filter - Name="Magtheridon's lair" - > - <File - RelativePath="..\scripts\zone\hellfire_citadel\magtheridons_lair\boss_magtheridon.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\magtheridons_lair\def_magtheridons_lair.h" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\magtheridons_lair\instance_magtheridons_lair.cpp" - > - </File> - </Filter> - <Filter - Name="Hellfire Ramparts" - > - <File - RelativePath="..\scripts\zone\hellfire_citadel\hellfire_ramparts\boss_omor_the_unscarred.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\hellfire_ramparts\boss_watchkeeper_gargolmar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\hellfire_ramparts\boss_vazruden_the_herald.cpp" - > - </File> - </Filter> - <Filter - Name="Shattered Halls" - > - <File - RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\boss_nethekurse.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\boss_warbringer_omrogg.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\boss_warchief_kargath_bladefist.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\def_shattered_halls.h" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\instance_shattered_halls.cpp" - > - </File> - </Filter> - </Filter> - <Filter - Name="Hellfire Peninsula" - > - <File - RelativePath="..\scripts\zone\hellfire_peninsula\boss_doomlord_kazzak.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\hellfire_peninsula\hellfire_peninsula.cpp" - > - </File> - </Filter> - <Filter - Name="Karazhan" - > - <File - RelativePath="..\scripts\zone\karazhan\boss_curator.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_maiden_of_virtue.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_midnight.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_moroes.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_netherspite.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_nightbane.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_prince_malchezaar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_shade_of_aran.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\boss_terestian_illhoof.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\bosses_opera.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\def_karazhan.h" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\instance_karazhan.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\karazhan\karazhan.cpp" - > - </File> - </Filter> - <Filter - Name="Nagrand" - > - <File - RelativePath="..\scripts\zone\nagrand\nagrand.cpp" - > - </File> - </Filter> - <Filter - Name="Netherstorm" - > - <File - RelativePath="..\scripts\zone\netherstorm\netherstorm.cpp" - > - </File> - </Filter> - <Filter - Name="Shadowmoon Valley" - > - <File - RelativePath="..\scripts\zone\shadowmoon_valley\boss_doomwalker.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\shadowmoon_valley\shadowmoon_valley.cpp" - > - </File> - </Filter> - <Filter - Name="Tempest Keep" - > - <Filter - Name="Arcatraz" - > - <File - RelativePath="..\scripts\zone\tempest_keep\arcatraz\arcatraz.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\arcatraz\boss_harbinger_skyriss.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\arcatraz\def_arcatraz.h" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\arcatraz\instance_arcatraz.cpp" - > - </File> - </Filter> - <Filter - Name="Botanica" - > - <File - RelativePath="..\scripts\zone\tempest_keep\botanica\boss_high_botanist_freywinn.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\botanica\boss_laj.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\botanica\boss_warp_splinter.cpp" - > - </File> - </Filter> - <Filter - Name="The Eye" - > - <File - RelativePath="..\scripts\zone\tempest_keep\the_eye\boss_alar.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_eye\boss_astromancer.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_eye\boss_kaelthas.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_eye\boss_void_reaver.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_eye\def_the_eye.h" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_eye\instance_the_eye.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_eye\the_eye.cpp" - > - </File> - </Filter> - <Filter - Name="The Mechanar" - > - <File - RelativePath="..\scripts\zone\tempest_keep\the_mechanar\boss_gatewatcher_gyrokill.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_mechanar\boss_gatewatcher_ironhand.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_mechanar\boss_nethermancer_sepethrea.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_mechanar\boss_pathaleon_the_calculator.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_mechanar\def_mechanar.h" - > - </File> - <File - RelativePath="..\scripts\zone\tempest_keep\the_mechanar\instance_mechanar.cpp" - > - </File> - </Filter> - </Filter> - <Filter - Name="Terokkar Forest" - > - <File - RelativePath="..\scripts\zone\terokkar_forest\terokkar_forest.cpp" - > - </File> - </Filter> - <Filter - Name="Zangarmarsh" - > - <File - RelativePath="..\scripts\zone\zangarmarsh\zangarmarsh.cpp" - > - </File> - </Filter> - <Filter - Name="Blackrock Spire" - > - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_drakkisath.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_gyth.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_halycon.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_highlord_omokk.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_mother_smolderweb.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_overlord_wyrmthalak.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_pyroguard_emberseer.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_quartermaster_zigris.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_rend_blackhand.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_shadow_hunter_voshgajin.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_the_beast.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_spire\boss_warmaster_voone.cpp" - > - </File> - </Filter> - <Filter - Name="Stormwind City" - > - <File - RelativePath="..\scripts\zone\stormwind\stormwind_city.cpp" - > - </File> - </Filter> - <Filter - Name="Coilfang Resevoir" - > - <Filter - Name="Serpent Shrine Cavern" - > - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\boss_fathomlord_karathress.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\boss_hydross_the_unstable.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\boss_lady_vashj.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\boss_leotheras_the_blind.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\boss_lurker_below.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\boss_morogrim_tidewalker.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\def_serpent_shrine.h" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\serpent_shrine\instance_serpent_shrine.cpp" - > - </File> - </Filter> - <Filter - Name="Slave Pens" - > - </Filter> - <Filter - Name="Steam Vault" - > - <File - RelativePath="..\scripts\zone\coilfang_resevoir\steam_vault\boss_hydromancer_thespia.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\steam_vault\boss_mekgineer_steamrigger.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\steam_vault\boss_warlord_kalithresh.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\steam_vault\def_steam_vault.h" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\steam_vault\instance_steam_vault.cpp" - > - </File> - </Filter> - <Filter - Name="Underbog" - > - <File - RelativePath="..\scripts\zone\coilfang_resevoir\underbog\boss_hungarfen.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\coilfang_resevoir\underbog\boss_the_black_stalker.cpp" - > - </File> - </Filter> - </Filter> - <Filter - Name="Caverns of Time" - > - <Filter - Name="The Dark Portal" - > - <File - RelativePath="..\scripts\zone\caverns_of_time\dark_portal\boss_aeonus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\dark_portal\boss_chrono_lord_deja.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\dark_portal\boss_temporus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\dark_portal\dark_portal.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\dark_portal\def_dark_portal.h" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\dark_portal\instance_dark_portal.cpp" - > - </File> - </Filter> - <Filter - Name="Battle for Mt. Hyjal" - > - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\boss_anetheron.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\boss_archimonde.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\boss_azgalor.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\boss_kazrogal.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\boss_rage_winterchill.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\def_hyjal.h" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\hyjal.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\hyjal_trash.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\hyjal_trash.h" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\hyjalAI.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\hyjalAI.h" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\hyjal\instance_hyjal.cpp" - > - </File> - </Filter> - - <Filter - Name="Old Hillsbrad" - > - <File - RelativePath="..\scripts\zone\caverns_of_time\old_hillsbrad\boss_captain_skarloc.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\old_hillsbrad\boss_epoch_hunter.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\old_hillsbrad\boss_leutenant_drake.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\old_hillsbrad\def_old_hillsbrad.h" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\old_hillsbrad\instance_old_hillsbrad.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\caverns_of_time\old_hillsbrad\old_hillsbrad.cpp" - > - </File> - </Filter> - </Filter> - <Filter - Name="Silvermoon City" - > - <File - RelativePath="..\scripts\zone\silvermoon\silvermoon_city.cpp" - > - </File> - </Filter> - <Filter - Name="Darnassus" - > - </Filter> - <Filter - Name="Exodar" - > - </Filter> - <Filter - Name="Iron Forge" - > - <File - RelativePath="..\scripts\zone\ironforge\ironforge.cpp" - > - </File> - </Filter> - <Filter - Name="Orgrimmar" - > - <File - RelativePath="..\scripts\zone\orgrimmar\orgrimmar.cpp" - > - </File> - </Filter> - <Filter - Name="Shattrath City" - > - <File - RelativePath="..\scripts\zone\shattrath\shattrath_city.cpp" - > - </File> - </Filter> - <Filter - Name="Thunder Bluff" - > - <File - RelativePath="..\scripts\zone\thunder_bluff\thunder_bluff.cpp" - > - </File> - </Filter> - <Filter - Name="Undercity" - > - <File - RelativePath="..\scripts\zone\undercity\undercity.cpp" - > - </File> - </Filter> - <Filter - Name="Zul'Aman" - > - <File - RelativePath="..\scripts\zone\zulaman\boss_akilzon.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\boss_halazzi.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\boss_hexlord.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\boss_janalai.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\boss_nalorakk.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\boss_zuljin.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\def_zulaman.h" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\instance_zulaman.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\zulaman\zulaman.cpp" - > - </File> - </Filter> - <Filter - Name="Isle of Quel'Danas" - > - <File - RelativePath="..\scripts\zone\isle_of_queldanas\isle_of_queldanas.cpp" - > - </File> - </Filter> - <Filter - Name="Magister's Terrace" - > - <File - RelativePath="..\scripts\zone\magisters_terrace\boss_felblood_kaelthas.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\magisters_terrace\boss_priestess_delrissa.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\magisters_terrace\boss_selin_fireheart.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\magisters_terrace\boss_vexallus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\magisters_terrace\def_magisters_terrace.h" - > - </File> - <File - RelativePath="..\scripts\zone\magisters_terrace\instance_magisters_terrace.cpp" - > - </File> - </Filter> - <Filter - Name="Sunwell Plateau" - > - <File - RelativePath="..\scripts\zone\sunwell_plateau\boss_brutallus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\boss_eredar_twins.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\boss_felmyst.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\boss_kalecgos.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\boss_muru.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\boss_kiljaeden.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\sunwell_plateau.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\def_sunwell_plateau.h" - > - </File> - <File - RelativePath="..\scripts\zone\sunwell_plateau\instance_sunwell_plateau.cpp" - > - </File> - </Filter> - <Filter - Name="Blackrock Depths" - > - <File - RelativePath="..\scripts\zone\blackrock_depths\blackrock_depths.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\def_blackrock_depths.h" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\instance_blackrock_depths.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_ambassador_flamelash.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_anubshiah.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_emperor_dagran_thaurissan.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_general_angerforge.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_gorosh_the_dervish.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_grizzle.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_high_interrogator_gerstahn.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_magmus.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_moira_bronzebeard.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackrock_depths\boss_tomb_of_seven.cpp" - > - </File> - </Filter> - <Filter - Name="Loch Modan" - > - <File - RelativePath="..\scripts\zone\loch_modan\loch_modan.cpp" - > - </File> - </Filter> - </Filter> - </Filter> - <Filter - Name="Include" - > - <File - RelativePath="..\include\precompiled.cpp" - > - <FileConfiguration - Name="Debug|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="1" - /> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="1" - /> - </FileConfiguration> - </File> - <File - RelativePath="..\include\precompiled.h" - > - </File> - <File - RelativePath="..\include\sc_creature.cpp" - > - </File> - <File - RelativePath="..\include\sc_creature.h" - > - </File> - <File - RelativePath="..\include\sc_gossip.h" - > - </File> - <File - RelativePath="..\include\sc_instance.h" - > - </File> - <File - RelativePath="..\include\sc_item.h" - > - </File> - </Filter> - <File - RelativePath="..\config.h" - > - </File> - <File - RelativePath="..\ScriptMgr.cpp" - > - </File> - <File - RelativePath="..\ScriptMgr.h" - > - </File> - <File - RelativePath="..\svn_revision.h" - > - </File> - <File - RelativePath="..\system.cpp" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> diff --git a/src/bindings/scripts/VC80/80ScriptDev2.vcproj b/src/bindings/scripts/VC80/80ScriptDev2.vcproj index 76167df9ae1..e5eeda086ff 100644 --- a/src/bindings/scripts/VC80/80ScriptDev2.vcproj +++ b/src/bindings/scripts/VC80/80ScriptDev2.vcproj @@ -130,7 +130,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" AdditionalIncludeDirectories="..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\..\..\..\dep\ACE_wrappers" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0" RuntimeLibrary="2" EnableEnhancedInstructionSet="1" FloatingPointModel="2" @@ -300,7 +300,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" AdditionalIncludeDirectories="..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\..\..\..\dep\ACE_wrappers" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0" RuntimeLibrary="2" FloatingPointModel="2" UsePrecompiledHeader="2" @@ -1102,6 +1102,10 @@ RelativePath="..\scripts\zone\magisters_terrace\instance_magisters_terrace.cpp" > </File> + <File + RelativePath="..\scripts\zone\magisters_terrace\magisters_terrace.cpp" + > + </File> </Filter> <Filter Name="Loch Modan" @@ -1835,6 +1839,14 @@ > </File> </Filter> + <Filter + Name="Zul'Drak" + > + <File + RelativePath="..\scripts\zone\zuldrak\zuldrak.cpp" + > + </File> + </Filter> <Filter Name="Wetlands" > @@ -2445,6 +2457,10 @@ <Filter Name="Sholazar Basin" > + <File + RelativePath="..\scripts\zone\sholazar_basin\sholazar_basin.cpp" + > + </File> </Filter> <Filter Name="Dalaran" @@ -2818,6 +2834,10 @@ > </File> <File + RelativePath="..\scripts\zone\vault_of_archavon\boss_emalon.cpp" + > + </File> + <File RelativePath="..\scripts\zone\vault_of_archavon\def_vault_of_archavon.h" > </File> diff --git a/src/bindings/scripts/VC90/90ScriptDev2.vcproj b/src/bindings/scripts/VC90/90ScriptDev2.vcproj index d3f7fc71e79..7fe459734ed 100644 --- a/src/bindings/scripts/VC90/90ScriptDev2.vcproj +++ b/src/bindings/scripts/VC90/90ScriptDev2.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" - Version="9.00" + Version="9,00" Name="TrinityScript" ProjectGUID="{4295C8A9-79B7-4354-8064-F05FB9CA0C96}" RootNamespace="ScriptDev2" @@ -130,7 +130,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" AdditionalIncludeDirectories="..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\..\..\..\dep\ACE_wrappers" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0" MinimalRebuild="false" RuntimeLibrary="2" EnableEnhancedInstructionSet="1" @@ -300,7 +300,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" AdditionalIncludeDirectories="..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\..\..\..\dep\ACE_wrappers" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0" MinimalRebuild="false" RuntimeLibrary="2" UsePrecompiledHeader="2" @@ -555,14 +555,14 @@ <Filter Name="Blackfathom Depths" > - <File - RelativePath="..\scripts\zone\blackfathom_depths\instance_blackfathom_deeps.cpp" - > - </File> - <File - RelativePath="..\scripts\zone\blackfathom_depths\def_blackfathom_deeps.h" - > - </File> + <File + RelativePath="..\scripts\zone\blackfathom_depths\def_blackfathom_deeps.h" + > + </File> + <File + RelativePath="..\scripts\zone\blackfathom_depths\instance_blackfathom_deeps.cpp" + > + </File> </Filter> <Filter Name="Bloodmyst Isle" @@ -725,10 +725,12 @@ > </Filter> <Filter - Name="Desolace"> - <File - RelativePath="..\scripts\zone\desolace\desolace.cpp"> - </File> + Name="Desolace" + > + <File + RelativePath="..\scripts\zone\desolace\desolace.cpp" + > + </File> </Filter> <Filter Name="Dire Maul" @@ -838,7 +840,7 @@ Name="Razorfen Kraul" > <File - RelativePath="..\scripts\zone\razorfen_kraul\razorfen_kraul.cpp" + RelativePath="..\scripts\zone\razorfen_kraul\def_razorfen_kraul.h" > </File> <File @@ -846,7 +848,7 @@ > </File> <File - RelativePath="..\scripts\zone\razorfen_kraul\def_razorfen_kraul.h" + RelativePath="..\scripts\zone\razorfen_kraul\razorfen_kraul.cpp" > </File> </Filter> @@ -1101,6 +1103,10 @@ RelativePath="..\scripts\zone\magisters_terrace\instance_magisters_terrace.cpp" > </File> + <File + RelativePath="..\scripts\zone\magisters_terrace\magisters_terrace.cpp" + > + </File> </Filter> <Filter Name="Loch Modan" @@ -1834,6 +1840,14 @@ > </File> </Filter> + <Filter + Name="Zul'Drak" + > + <File + RelativePath="..\scripts\zone\zuldrak\zuldrak.cpp" + > + </File> + </Filter> <Filter Name="Wetlands" > @@ -2444,6 +2458,10 @@ <Filter Name="Sholazar Basin" > + <File + RelativePath="..\scripts\zone\sholazar_basin\sholazar_basin.cpp" + > + </File> </Filter> <Filter Name="Dalaran" @@ -2817,6 +2835,10 @@ > </File> <File + RelativePath="..\scripts\zone\vault_of_archavon\boss_emalon.cpp" + > + </File> + <File RelativePath="..\scripts\zone\vault_of_archavon\def_vault_of_archavon.h" > </File> diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp index 361385c85a9..66c4fa58bb9 100644 --- a/src/bindings/scripts/include/sc_creature.cpp +++ b/src/bindings/scripts/include/sc_creature.cpp @@ -79,7 +79,7 @@ void SummonList::DespawnAll() } } -ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature), m_creature(creature), IsFleeing(false), CombatMovement(true) +ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature), m_creature(creature), IsFleeing(false), CombatMovement(true), m_uiEvadeCheckCooldown(2500) { HeroicMode = m_creature->GetMap()->IsHeroic(); } @@ -174,14 +174,14 @@ void ScriptedAI::DoWhisper(const char* text, Unit* reciever, bool IsBossWhisper) m_creature->MonsterWhisper(text, reciever->GetGUID(), IsBossWhisper); } -void ScriptedAI::DoPlaySoundToSet(Unit* pSource, uint32 uiSoundId) +void ScriptedAI::DoPlaySoundToSet(WorldObject* pSource, uint32 uiSoundId) { if (!pSource) return; if (!GetSoundEntriesStore()->LookupEntry(uiSoundId)) { - error_log("TSCR: Invalid soundId %u used in DoPlaySoundToSet (by unit TypeId %u, guid %u)", uiSoundId, pSource->GetTypeId(), pSource->GetGUID()); + error_log("TSCR: Invalid soundId %u used in DoPlaySoundToSet (Source: TypeId %u, GUID %u)", uiSoundId, pSource->GetTypeId(), pSource->GetGUIDLow()); return; } @@ -533,6 +533,25 @@ std::list<Creature*> ScriptedAI::DoFindFriendlyMissingBuff(float range, uint32 s return pList; } +Player* ScriptedAI::GetPlayerAtMinimumRange(float fMinimumRange) +{ + Player* pPlayer = NULL; + + CellPair pair(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Trinity::PlayerAtMinimumRangeAway check(m_creature, fMinimumRange); + Trinity::PlayerSearcher<Trinity::PlayerAtMinimumRangeAway> searcher(m_creature, pPlayer, check); + TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::PlayerAtMinimumRangeAway>, GridTypeMapContainer> visitor(searcher); + + CellLock<GridReadGuard> cell_lock(cell, pair); + cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap())); + + return pPlayer; +} + void ScriptedAI::SetEquipmentSlots(bool bLoadDefault, int32 uiMainHand, int32 uiOffHand, int32 uiRanged) { if (bLoadDefault) @@ -553,14 +572,55 @@ void ScriptedAI::SetEquipmentSlots(bool bLoadDefault, int32 uiMainHand, int32 ui m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, uint32(uiRanged)); } -void ScriptedAI::SetSheathState(SheathState newState) +void ScriptedAI::SetCombatMovement(bool CombatMove) { - m_creature->SetByteValue(UNIT_FIELD_BYTES_2, 0, newState); + CombatMovement = CombatMove; } -void ScriptedAI::SetCombatMovement(bool CombatMove) +// Hacklike storage used for misc creatures that are expected to evade of outside of a certain area. +// It is assumed the information is found elswehere and can be handled by mangos. So far no luck finding such information/way to extract it. +bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) { - CombatMovement = CombatMove; + if (m_uiEvadeCheckCooldown < uiDiff) + m_uiEvadeCheckCooldown = 2500; + else + { + m_uiEvadeCheckCooldown -= uiDiff; + return false; + } + + if (m_creature->IsInEvadeMode() || !m_creature->getVictim()) + return false; + + float fX = m_creature->GetPositionX(); + float fY = m_creature->GetPositionY(); + float fZ = m_creature->GetPositionZ(); + + switch(m_creature->GetEntry()) + { + case 12017: // broodlord (not move down stairs) + if (fZ > 448.60f) + return false; + break; + case 19516: // void reaver (calculate from center of room) + if (m_creature->GetDistance2d(432.59f, 371.93f) < 105.0f) + return false; + break; + case 23578: // jan'alai (calculate by Z) + if (fZ > 12.0f) + return false; + break; + case 28860: // sartharion (calculate box) + if (fX > 3218.86f && fX < 3275.69f && fY > 572.40f && fY < 484.68f) + return false; + break; + default: + error_log("TSCR: EnterEvadeIfOutOfCombatArea used for creature entry %u, but does not have any definition.", m_creature->GetEntry()); + return false; + } + + EnterEvadeMode(); + return true; } /*void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who) @@ -730,7 +790,7 @@ void LoadOverridenDBCData() spellInfo->DurationIndex = 21; spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AREA_AURA_ENEMY; break; - // Naxxramas: Gothik : Inform Inf range + // Naxxramas : Gothik : Inform Inf range case 27892: case 27928: case 27935: @@ -739,6 +799,33 @@ void LoadOverridenDBCData() case 27937: spellInfo->rangeIndex = 13; break; + // Ulduar : Flame Leviathan : Pursued + case 62374: + spellInfo->MaxAffectedTargets = 1; + spellInfo->EffectImplicitTargetB[0] = TARGET_UNIT_AREA_ENTRY_SRC; + spellInfo->EffectImplicitTargetB[1] = TARGET_UNIT_AREA_ENTRY_SRC; + break; } } } + + +Creature* GetClosestCreatureWithEntry(WorldObject* pSource, uint32 Entry, float MaxSearchRange) +{ + Creature* pCreature = NULL; + + CellPair pair(Trinity::ComputeCellPair(pSource->GetPositionX(), pSource->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*pSource, Entry, true, MaxSearchRange); + Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pSource, pCreature, creature_check); + + TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer> creature_searcher(searcher); + + CellLock<GridReadGuard> cell_lock(cell, pair); + cell_lock->Visit(cell_lock, creature_searcher,*(pSource->GetMap())); + + return pCreature; +} diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h index f145ff09942..b4328f2fd66 100644 --- a/src/bindings/scripts/include/sc_creature.h +++ b/src/bindings/scripts/include/sc_creature.h @@ -143,7 +143,7 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI void DoWhisper(const char* text, Unit* reciever, bool IsBossWhisper = false); //Plays a sound to all nearby players - void DoPlaySoundToSet(Unit* unit, uint32 sound); + void DoPlaySoundToSet(WorldObject* pSource, uint32 sound); //Drops all threat to 0%. Does not remove players from the threat list void DoResetThreat(); @@ -169,6 +169,9 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI //Returns a list of all friendly units missing a specific buff within range std::list<Creature*> DoFindFriendlyMissingBuff(float range, uint32 spellid); + //Return a player with at least minimumRange from m_creature + Player* GetPlayerAtMinimumRange(float fMinimumRange); + //Spawns a creature relative to m_creature Creature* DoSpawnCreature(uint32 id, float x, float y, float z, float angle, uint32 type, uint32 despawntime); Creature *DoSummon(uint32 entry, const float pos[4], uint32 despawntime = 30000, TempSummonType type = TEMPSUMMON_CORPSE_TIMED_DESPAWN); @@ -186,13 +189,16 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI bool CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered = false); void SetEquipmentSlots(bool bLoadDefault, int32 uiMainHand = EQUIP_NO_CHANGE, int32 uiOffHand = EQUIP_NO_CHANGE, int32 uiRanged = EQUIP_NO_CHANGE); - - void SetSheathState(SheathState newState); void SetCombatMovement(bool CombatMove); + + bool EnterEvadeIfOutOfCombatArea(const uint32 uiDiff); protected: bool CombatMovement; + + private: + uint32 m_uiEvadeCheckCooldown; }; struct TRINITY_DLL_DECL Scripted_NoMovementAI : public ScriptedAI @@ -243,5 +249,10 @@ struct TRINITY_DLL_DECL BossAI : public ScriptedAI void TeleportCheaters(); }; +// SD2's grid searchers + +//return closest creature alive in grid, with range from pSource +Creature* GetClosestCreatureWithEntry(WorldObject* pSource, uint32 Entry, float MaxSearchRange); + #endif diff --git a/src/bindings/scripts/include/sc_gossip.h b/src/bindings/scripts/include/sc_gossip.h index 9665a7e1123..0bee1dca5c8 100644 --- a/src/bindings/scripts/include/sc_gossip.h +++ b/src/bindings/scripts/include/sc_gossip.h @@ -73,60 +73,59 @@ #define GOSSIP_TEXT_JEWELCRAFTING "Jewelcrafting" #define GOSSIP_TEXT_INSCRIPTION "Inscription" +enum +{ // Skill defines - -#define TRADESKILL_ALCHEMY 1 -#define TRADESKILL_BLACKSMITHING 2 -#define TRADESKILL_COOKING 3 -#define TRADESKILL_ENCHANTING 4 -#define TRADESKILL_ENGINEERING 5 -#define TRADESKILL_FIRSTAID 6 -#define TRADESKILL_HERBALISM 7 -#define TRADESKILL_LEATHERWORKING 8 -#define TRADESKILL_POISONS 9 -#define TRADESKILL_TAILORING 10 -#define TRADESKILL_MINING 11 -#define TRADESKILL_FISHING 12 -#define TRADESKILL_SKINNING 13 -#define TRADESKILL_JEWLCRAFTING 14 -#define TRADESKILL_INSCRIPTION 15 - -#define TRADESKILL_LEVEL_NONE 0 -#define TRADESKILL_LEVEL_APPRENTICE 1 -#define TRADESKILL_LEVEL_JOURNEYMAN 2 -#define TRADESKILL_LEVEL_EXPERT 3 -#define TRADESKILL_LEVEL_ARTISAN 4 -#define TRADESKILL_LEVEL_MASTER 5 -#define TRADESKILL_LEVEL_GRAND_MASTER 6 + TRADESKILL_ALCHEMY = 1, + TRADESKILL_BLACKSMITHING = 2, + TRADESKILL_COOKING = 3, + TRADESKILL_ENCHANTING = 4, + TRADESKILL_ENGINEERING = 5, + TRADESKILL_FIRSTAID = 6, + TRADESKILL_HERBALISM = 7, + TRADESKILL_LEATHERWORKING = 8, + TRADESKILL_POISONS = 9, + TRADESKILL_TAILORING = 10, + TRADESKILL_MINING = 11, + TRADESKILL_FISHING = 12, + TRADESKILL_SKINNING = 13, + TRADESKILL_JEWLCRAFTING = 14, + TRADESKILL_INSCRIPTION = 15, + + TRADESKILL_LEVEL_NONE = 0, + TRADESKILL_LEVEL_APPRENTICE = 1, + TRADESKILL_LEVEL_JOURNEYMAN = 2, + TRADESKILL_LEVEL_EXPERT = 3, + TRADESKILL_LEVEL_ARTISAN = 4, + TRADESKILL_LEVEL_MASTER = 5, + TRADESKILL_LEVEL_GRAND_MASTER = 6, // Gossip defines - -#define GOSSIP_ACTION_TRADE 1 -#define GOSSIP_ACTION_TRAIN 2 -#define GOSSIP_ACTION_TAXI 3 -#define GOSSIP_ACTION_GUILD 4 -#define GOSSIP_ACTION_BATTLE 5 -#define GOSSIP_ACTION_BANK 6 -#define GOSSIP_ACTION_INN 7 -#define GOSSIP_ACTION_HEAL 8 -#define GOSSIP_ACTION_TABARD 9 -#define GOSSIP_ACTION_AUCTION 10 -#define GOSSIP_ACTION_INN_INFO 11 -#define GOSSIP_ACTION_UNLEARN 12 -#define GOSSIP_ACTION_INFO_DEF 1000 - -#define GOSSIP_SENDER_MAIN 1 -#define GOSSIP_SENDER_INN_INFO 2 -#define GOSSIP_SENDER_INFO 3 -#define GOSSIP_SENDER_SEC_PROFTRAIN 4 -#define GOSSIP_SENDER_SEC_CLASSTRAIN 5 -#define GOSSIP_SENDER_SEC_BATTLEINFO 6 -#define GOSSIP_SENDER_SEC_BANK 7 -#define GOSSIP_SENDER_SEC_INN 8 -#define GOSSIP_SENDER_SEC_MAILBOX 9 -#define GOSSIP_SENDER_SEC_STABLEMASTER 10 - -#define DEFAULT_GOSSIP_MESSAGE 0xffffff + GOSSIP_ACTION_TRADE = 1, + GOSSIP_ACTION_TRAIN = 2, + GOSSIP_ACTION_TAXI = 3, + GOSSIP_ACTION_GUILD = 4, + GOSSIP_ACTION_BATTLE = 5, + GOSSIP_ACTION_BANK = 6, + GOSSIP_ACTION_INN = 7, + GOSSIP_ACTION_HEAL = 8, + GOSSIP_ACTION_TABARD = 9, + GOSSIP_ACTION_AUCTION = 10, + GOSSIP_ACTION_INN_INFO = 11, + GOSSIP_ACTION_UNLEARN = 12, + GOSSIP_ACTION_INFO_DEF = 1000, + + GOSSIP_SENDER_MAIN = 1, + GOSSIP_SENDER_INN_INFO = 2, + GOSSIP_SENDER_INFO = 3, + GOSSIP_SENDER_SEC_PROFTRAIN = 4, + GOSSIP_SENDER_SEC_CLASSTRAIN = 5, + GOSSIP_SENDER_SEC_BATTLEINFO = 6, + GOSSIP_SENDER_SEC_BANK = 7, + GOSSIP_SENDER_SEC_INN = 8, + GOSSIP_SENDER_SEC_MAILBOX = 9, + GOSSIP_SENDER_SEC_STABLEMASTER = 10 +}; extern uint32 GetSkillLevel(Player *player,uint32 skill); diff --git a/src/bindings/scripts/scripts/go/go_scripts.cpp b/src/bindings/scripts/scripts/go/go_scripts.cpp index bd0e621c3c4..b50a0b79bf4 100644 --- a/src/bindings/scripts/scripts/go/go_scripts.cpp +++ b/src/bindings/scripts/scripts/go/go_scripts.cpp @@ -17,7 +17,7 @@ /* ScriptData SDName: GO_Scripts SD%Complete: 100 -SDComment: Quest support: 4285,4287,4288(crystal pylons), 4296, 10990, 10991, 10992, Field_Repair_Bot->Teaches spell 22704. Barov_journal->Teaches spell 26089 +SDComment: Quest support: 4285,4287,4288(crystal pylons), 4296, 6481, 10990, 10991, 10992, Field_Repair_Bot->Teaches spell 22704. Barov_journal->Teaches spell 26089 SDCategory: Game Objects EndScriptData */ @@ -33,6 +33,7 @@ go_sacred_fire_of_life go_shrine_of_the_birds go_field_repair_bot_74A go_orb_of_command +go_resonite_cask go_tablet_of_madness go_tablet_of_the_seven go_tele_to_dalaran_crystal @@ -275,6 +276,23 @@ bool GOHello_go_ethereum_stasis(Player* pPlayer, GameObject* pGo) } /*###### +## go_resonite_cask +######*/ + +enum +{ + NPC_GOGGEROC = 11920 +}; + +bool GOHello_go_resonite_cask(Player* pPlayer, GameObject* pGO) +{ + if (pGO->GetGoType() == GAMEOBJECT_TYPE_GOOBER) + pGO->SummonCreature(NPC_GOGGEROC, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000); + + return false; +} + +/*###### ## go_sacred_fire_of_life ######*/ @@ -434,6 +452,11 @@ void AddSC_go_scripts() newscript->RegisterSelf(); newscript = new Script; + newscript->Name = "go_resonite_cask"; + newscript->pGOHello = &GOHello_go_resonite_cask; + newscript->RegisterSelf(); + + newscript = new Script; newscript->Name = "go_sacred_fire_of_life"; newscript->pGOHello = &GOHello_go_sacred_fire_of_life; newscript->RegisterSelf(); diff --git a/src/bindings/scripts/scripts/item/item_scripts.cpp b/src/bindings/scripts/scripts/item/item_scripts.cpp index f577d0fed9c..10c3069e1dc 100644 --- a/src/bindings/scripts/scripts/item/item_scripts.cpp +++ b/src/bindings/scripts/scripts/item/item_scripts.cpp @@ -22,53 +22,24 @@ SDCategory: Items EndScriptData */ /* ContentData -item_area_52_special(i28132) Prevents abuse of this item -item_attuned_crystal_cores(i34368) Prevent abuse(quest 11524 & 11525) -item_blackwhelp_net(i31129) Quest Whelps of the Wyrmcult (q10747). Prevents abuse item_draenei_fishing_net(i23654) Hacklike implements chance to spawn item or creature -item_disciplinary_rod Prevents abuse item_nether_wraith_beacon(i31742) Summons creatures for quest Becoming a Spellfire Tailor (q10832) item_flying_machine(i34060,i34061) Engineering crafted flying machines item_gor_dreks_ointment(i30175) Protecting Our Own(q10488) -item_muiseks_vessel Cast on creature, they must be dead(q 3123,3124,3125,3126,3127) item_only_for_flight Items which should only useable while flying -item_protovoltaic_magneto_collector Prevents abuse -item_razorthorn_flayer_gland Quest Discovering Your Roots (q11520) and Rediscovering Your Roots (q11521). Prevents abuse -item_tame_beast_rods(many) Prevent cast on any other creature than the intended (for all tame beast quests) -item_soul_cannon(i32825) Prevents abuse of this item -item_sparrowhawk_net(i32321) Quest To Catch A Sparrowhawk (q10987). Prevents abuse -item_voodoo_charm Provide proper error message and target(q2561) -item_vorenthals_presence(i30259) Prevents abuse of this item -item_yehkinyas_bramble(i10699) Allow cast spell on vale screecher only and remove corpse if cast sucessful (q3520) -item_zezzak_shard(i31463) Quest The eyes of Grillok (q10813). Prevents abuse -item_inoculating_crystal Quest Inoculating. Prevent abuse EndContentData */ #include "precompiled.h" -#include "SpellMgr.h" #include "Spell.h" -#include "WorldPacket.h" /*##### -# item_area_52_special +# item_only_for_flight #####*/ -bool ItemUse_item_area_52_special(Player *player, Item* _Item, SpellCastTargets const& targets) +enum { - if ( player->GetAreaId() == 3803 ) - { - return false; - } - else - { - player->SendEquipError(EQUIP_ERR_OUT_OF_RANGE,_Item,NULL); - return true; - } -} - -/*##### -# item_only_for_flight -#####*/ + SPELL_ARCANE_CHARGES = 45072 +}; bool ItemUse_item_only_for_flight(Player *player, Item* _Item, SpellCastTargets const& targets) { @@ -86,6 +57,10 @@ bool ItemUse_item_only_for_flight(Player *player, Item* _Item, SpellCastTargets if(player->GetZoneId() != 4080) disabled = true; break; + case 34475: + if (const SpellEntry* pSpellInfo = GetSpellStore()->LookupEntry(SPELL_ARCANE_CHARGES)) + Spell::SendCastResult(player, pSpellInfo, 1, SPELL_FAILED_NOT_ON_GROUND); + break; } // allow use in flight only @@ -98,38 +73,6 @@ bool ItemUse_item_only_for_flight(Player *player, Item* _Item, SpellCastTargets } /*##### -# item_attuned_crystal_cores -#####*/ - -bool ItemUse_item_attuned_crystal_cores(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 24972 && targets.getUnitTarget()->isDead() && - (player->GetQuestStatus(11524) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(11525) == QUEST_STATUS_INCOMPLETE) ) - { - CAST_CRE(targets.getUnitTarget())->RemoveCorpse(); - return false; - } - - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); - return true; -} - -/*##### -# item_blackwhelp_net -#####*/ - -bool ItemUse_item_blackwhelp_net(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 21387 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### # item_draenei_fishing_net #####*/ @@ -166,20 +109,6 @@ bool ItemUse_item_draenei_fishing_net(Player *player, Item* _Item, SpellCastTarg } /*##### -# item_disciplinary_rod -#####*/ - -bool ItemUse_item_disciplinary_rod(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - (targets.getUnitTarget()->GetEntry() == 15941 || targets.getUnitTarget()->GetEntry() == 15945) ) - return false; - - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); - return true; -} - -/*##### # item_nether_wraith_beacon #####*/ @@ -231,261 +160,49 @@ bool ItemUse_item_gor_dreks_ointment(Player *player, Item* _Item, SpellCastTarge } /*##### -# item_muiseks_vessel +# item_incendiary_explosives #####*/ -bool ItemUse_item_muiseks_vessel(Player *player, Item* _Item, SpellCastTargets const& targets) +bool ItemUse_item_incendiary_explosives(Player *player, Item* _Item, SpellCastTargets const& targets) { - Unit* uTarget = targets.getUnitTarget(); - uint32 itemSpell = _Item->GetProto()->Spells[0].SpellId; - uint32 cEntry = 0; - uint32 cEntry2 = 0; - uint32 cEntry3 = 0; - uint32 cEntry4 = 0; - - if(itemSpell) + if ( player->FindNearestCreature(26248,15) || player->FindNearestCreature(26249,15) ) { - switch(itemSpell) - { - case 11885: //Wandering Forest Walker - cEntry = 7584; - break; - case 11886: //Owlbeasts - cEntry = 2927; - cEntry2 = 2928; - cEntry3 = 2929; - cEntry4 = 7808; - break; - case 11887: //Freyfeather Hippogryphs - cEntry = 5300; - cEntry2 = 5304; - cEntry3 = 5305; - cEntry4 = 5306; - break; - case 11888: //Sprite Dragon Sprite Darters - cEntry = 5276; - cEntry2 = 5278; - break; - case 11889: //Zapped Land Walker Land Walker Zapped Cliff Giant Cliff Giant - cEntry = 5357; - cEntry2 = 5358; - cEntry3 = 14640; - cEntry4 = 14604; - break; - } - if( uTarget && uTarget->GetTypeId()==TYPEID_UNIT && uTarget->isDead() && - (uTarget->GetEntry()==cEntry || uTarget->GetEntry()==cEntry2 || uTarget->GetEntry()==cEntry3 || uTarget->GetEntry()==cEntry4) ) - { - CAST_CRE(uTarget)->RemoveCorpse(); - return false; - } - } - - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(_Item->GetEntry()); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Invalid target - - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_inoculating_crystal -#####*/ - -bool ItemUse_item_inoculating_crystal(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 16518 ) return false; - - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(_Item->GetEntry()); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Invalid target - - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_razorthorn_flayer_gland -#####*/ - -bool ItemUse_item_razorthorn_flayer_gland(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 24922 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_tame_beast_rods -#####*/ - -bool ItemUse_item_tame_beast_rods(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - uint32 itemSpell = _Item->GetProto()->Spells[0].SpellId; - uint32 cEntry = 0; - - if(itemSpell) + } + else { - switch(itemSpell) - { - case 19548: cEntry = 1196; break; //Ice Claw Bear - case 19674: cEntry = 1126; break; //Large Crag Boar - case 19687: cEntry = 1201; break; //Snow Leopard - case 19688: cEntry = 2956; break; //Adult Plainstrider - case 19689: cEntry = 2959; break; //Prairie Stalker - case 19692: cEntry = 2970; break; //Swoop - case 19693: cEntry = 1998; break; //Webwood Lurker - case 19694: cEntry = 3099; break; //Dire Mottled Boar - case 19696: cEntry = 3107; break; //Surf Crawler - case 19697: cEntry = 3126; break; //Armored Scorpid - case 19699: cEntry = 2043; break; //Nightsaber Stalker - case 19700: cEntry = 1996; break; //Strigid Screecher - case 30646: cEntry = 17217; break; //Barbed Crawler - case 30653: cEntry = 17374; break; //Greater Timberstrider - case 30654: cEntry = 17203; break; //Nightstalker - case 30099: cEntry = 15650; break; //Crazed Dragonhawk - case 30102: cEntry = 15652; break; //Elder Springpaw - case 30105: cEntry = 16353; break; //Mistbat - } - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == cEntry ) - return false; + player->SendEquipError(EQUIP_ERR_OUT_OF_RANGE,_Item,NULL); + return true; } - - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(_Item->GetEntry()); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Invalid target - - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_protovoltaic_magneto_collector -#####*/ - -bool ItemUse_item_protovoltaic_magneto_collector(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 21729 ) - return false; - - player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,_Item,NULL); - return true; -} - -/*##### -# item_soul_cannon -#####*/ - -bool ItemUse_item_soul_cannon(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - // allow use - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 22357 ) - return false; - - // error - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_sparrowhawk_net -#####*/ - -bool ItemUse_item_sparrowhawk_net(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 22979 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; -} - -/*##### -# item_voodoo_charm -#####*/ - -bool ItemUse_item_voodoo_charm(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && targets.getUnitTarget()->isDead() && - targets.getUnitTarget()->GetEntry()==7318 ) - return false; - - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(_Item->GetEntry()); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Invalid target - - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell - return true; -} - -/*##### -# item_vorenthals_presence -#####*/ - -bool ItemUse_item_vorenthals_presence(Player *player, Item* _Item, SpellCastTargets const& targets) -{ - // allow use - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 20132 ) - return false; - - // error - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); - return true; } /*##### -# item_yehkinyas_bramble +# item_mysterious_egg #####*/ -bool ItemUse_item_yehkinyas_bramble(Player *player, Item* _Item, SpellCastTargets const& targets) +bool ItemExpire_item_mysterious_egg(Player *player, ItemPrototype const * _ItemProto) { - if (player->GetQuestStatus(3520) == QUEST_STATUS_INCOMPLETE) + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 39883, 1); // Cracked Egg + if( msg == EQUIP_ERR_OK ) { - Unit * unit_target = targets.getUnitTarget(); - if( unit_target && - unit_target->GetTypeId()==TYPEID_UNIT && - unit_target->isDead() && - // cast only on corpse 5307 or 5308 - (unit_target->GetEntry()==5307 || unit_target->GetEntry()==5308) ) - { - CAST_CRE(unit_target)->RemoveCorpse(); // remove corpse for cancelling second use - return false; // all ok - } + player->StoreNewItem( dest, 39883, true, Item::GenerateItemRandomPropertyId(39883)); } - WorldPacket data(SMSG_CAST_FAILED, (4+2)); // prepare packet error message - data << uint32(10699); // itemId - data << uint8(SPELL_FAILED_BAD_TARGETS); // reason - player->GetSession()->SendPacket(&data); // send message: Bad target - player->SendEquipError(EQUIP_ERR_NONE,_Item,NULL); // break spell return true; } /*##### -# item_zezzak_shard +# item_disgusting_jar #####*/ -bool ItemUse_item_zezzak_shard(Player *player, Item* _Item, SpellCastTargets const& targets) +bool ItemExpire_item_disgusting_jar(Player *player, ItemPrototype const * _ItemProto) { - if( targets.getUnitTarget() && targets.getUnitTarget()->GetTypeId()==TYPEID_UNIT && - targets.getUnitTarget()->GetEntry() == 19440 ) - return false; - - player->SendEquipError(EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM,_Item,NULL); + ItemPosCountVec dest; + uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, 44718, 1); // Ripe Disgusting Jar + if( msg == EQUIP_ERR_OK ) + { + player->StoreNewItem( dest, 44718, true, Item::GenerateItemRandomPropertyId(44718)); + } return true; } @@ -494,31 +211,11 @@ void AddSC_item_scripts() Script *newscript; newscript = new Script; - newscript->Name="item_area_52_special"; - newscript->pItemUse = &ItemUse_item_area_52_special; - newscript->RegisterSelf(); - - newscript = new Script; newscript->Name="item_only_for_flight"; newscript->pItemUse = &ItemUse_item_only_for_flight; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="item_attuned_crystal_cores"; - newscript->pItemUse = &ItemUse_item_attuned_crystal_cores; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_blackwhelp_net"; - newscript->pItemUse = &ItemUse_item_blackwhelp_net; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_disciplinary_rod"; - newscript->pItemUse = &ItemUse_item_disciplinary_rod; - newscript->RegisterSelf(); - - newscript = new Script; newscript->Name="item_draenei_fishing_net"; newscript->pItemUse = &ItemUse_item_draenei_fishing_net; newscript->RegisterSelf(); @@ -539,58 +236,18 @@ void AddSC_item_scripts() newscript->RegisterSelf(); newscript = new Script; - newscript->Name="item_muiseks_vessel"; - newscript->pItemUse = &ItemUse_item_muiseks_vessel; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_inoculating_crystal"; - newscript->pItemUse = &ItemUse_item_inoculating_crystal; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_razorthorn_flayer_gland"; - newscript->pItemUse = &ItemUse_item_razorthorn_flayer_gland; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_tame_beast_rods"; - newscript->pItemUse = &ItemUse_item_tame_beast_rods; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_protovoltaic_magneto_collector"; - newscript->pItemUse = &ItemUse_item_protovoltaic_magneto_collector; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_soul_cannon"; - newscript->pItemUse = &ItemUse_item_soul_cannon; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_sparrowhawk_net"; - newscript->pItemUse = &ItemUse_item_sparrowhawk_net; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_voodoo_charm"; - newscript->pItemUse = &ItemUse_item_voodoo_charm; - newscript->RegisterSelf(); - - newscript = new Script; - newscript->Name="item_vorenthals_presence"; - newscript->pItemUse = &ItemUse_item_vorenthals_presence; + newscript->Name="item_incendiary_explosives"; + newscript->pItemUse = &ItemUse_item_incendiary_explosives; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="item_yehkinyas_bramble"; - newscript->pItemUse = &ItemUse_item_yehkinyas_bramble; + newscript->Name="item_mysterious_egg"; + newscript->pItemExpire = &ItemExpire_item_mysterious_egg; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="item_zezzaks_shard"; - newscript->pItemUse = &ItemUse_item_zezzak_shard; + newscript->Name="item_disgusting_jar"; + newscript->pItemExpire = &ItemExpire_item_disgusting_jar; newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/npc/npc_escortAI.cpp b/src/bindings/scripts/scripts/npc/npc_escortAI.cpp index 7b70b66831a..b93fada1931 100644 --- a/src/bindings/scripts/scripts/npc/npc_escortAI.cpp +++ b/src/bindings/scripts/scripts/npc/npc_escortAI.cpp @@ -114,9 +114,6 @@ void npc_escortAI::UpdateAI(const uint32 diff) debug_log("TSCR: EscortAI reached end of waypoints"); m_creature->setDeathState(JUST_DIED); - m_creature->SetHealth(0); - m_creature->CombatStop(true); - m_creature->DeleteThreatList(); m_creature->Respawn(); m_creature->GetMotionMaster()->Clear(true); diff --git a/src/bindings/scripts/scripts/npc/npc_escortAI.h b/src/bindings/scripts/scripts/npc/npc_escortAI.h index 3431e84c6f8..fe352b6e277 100644 --- a/src/bindings/scripts/scripts/npc/npc_escortAI.h +++ b/src/bindings/scripts/scripts/npc/npc_escortAI.h @@ -61,6 +61,8 @@ struct TRINITY_DLL_DECL npc_escortAI : public ScriptedAI void SetMaxPlayerDistance(float newMax) { MaxPlayerDistance = newMax; } float GetMaxPlayerDistance() { return MaxPlayerDistance; } + bool IsEscorted() {return IsBeingEscorted;} + void SetCanMelee(bool usemelee) { CanMelee = usemelee; } void SetDespawnAtEnd(bool despawn) { DespawnAtEnd = despawn; } void SetDespawnAtFar(bool despawn) { DespawnAtFar = despawn; } diff --git a/src/bindings/scripts/scripts/npc/npcs_special.cpp b/src/bindings/scripts/scripts/npc/npcs_special.cpp index c53865a56f5..f6922745953 100644 --- a/src/bindings/scripts/scripts/npc/npcs_special.cpp +++ b/src/bindings/scripts/scripts/npc/npcs_special.cpp @@ -154,7 +154,7 @@ struct TRINITY_DLL_DECL npc_air_force_botsAI : public ScriptedAI Creature* GetSummonedGuard() { - Creature* pCreature = (Creature*)Unit::GetUnit(*m_creature, m_uiSpawnedGUID); + Creature* pCreature = Unit::GetCreature(*m_creature, m_uiSpawnedGUID); if (pCreature && pCreature->isAlive()) return pCreature; @@ -169,7 +169,7 @@ struct TRINITY_DLL_DECL npc_air_force_botsAI : public ScriptedAI if (pWho->isTargetableForAttack() && m_creature->IsHostileTo(pWho)) { - Player* pPlayerTarget = pWho->GetTypeId() == TYPEID_PLAYER ? (Player*)pWho : NULL; + Player* pPlayerTarget = pWho->GetTypeId() == TYPEID_PLAYER ? CAST_PLR(pWho) : NULL; // airforce guards only spawn for players if (!pPlayerTarget) @@ -1467,22 +1467,22 @@ struct TRINITY_DLL_DECL npc_snake_trap_serpentsAI : public ScriptedAI npc_snake_trap_serpentsAI(Creature *c) : ScriptedAI(c) {} uint32 SpellTimer; - Unit *Owner; bool IsViper; + bool Spawn; void EnterCombat(Unit *who) {} void Reset() { - Owner = m_creature->GetOwner(); - - if (!m_creature->isPet() || !Owner) - return; + Spawn = true; + SpellTimer = 0; CreatureInfo const *Info = m_creature->GetCreatureInfo(); if(Info->Entry == C_VIPER) IsViper = true; + else + IsViper = false; //We have to reload the states from db for summoned guardians m_creature->SetMaxHealth(Info->maxhealth); @@ -1499,10 +1499,7 @@ struct TRINITY_DLL_DECL npc_snake_trap_serpentsAI : public ScriptedAI //Redefined for random target selection: void MoveInLineOfSight(Unit *who) { - if (!m_creature->isPet() || !Owner) - return; - - if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) && Owner->IsHostileTo(who))//don't attack not-pvp-flaged + if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature)) { if (m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) return; @@ -1522,25 +1519,20 @@ struct TRINITY_DLL_DECL npc_snake_trap_serpentsAI : public ScriptedAI void UpdateAI(const uint32 diff) { - if (!m_creature->isPet() || !Owner) - return; - - //Follow if not in combat - if (!m_creature->hasUnitState(UNIT_STAT_FOLLOW)&& !m_creature->isInCombat()) + if(Spawn) { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveFollow(Owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); + Spawn = false; + // Start attacking attacker of owner on first ai update after spawn - move in line of sight may choose better target + if (!m_creature->getVictim() && m_creature->isSummon()) + if (Unit * Owner = CAST_SUM(m_creature)->GetSummoner()) + if(Owner->getAttackerForHelper()) + AttackStart(Owner->getAttackerForHelper()); } - //No victim -> get new from owner (need this because MoveInLineOfSight won't work while following -> corebug) if (!m_creature->getVictim()) { if (m_creature->isInCombat()) DoStopAttack(); - - if(Owner->getAttackerForHelper()) - AttackStart(Owner->getAttackerForHelper()); - return; } @@ -1577,6 +1569,158 @@ CreatureAI* GetAI_npc_snake_trap_serpents(Creature *_Creature) return new npc_snake_trap_serpentsAI(_Creature); } +struct TRINITY_DLL_DECL mob_mojoAI : public ScriptedAI +{ + mob_mojoAI(Creature *c) : ScriptedAI(c) {Reset();} + uint32 hearts; + uint64 victimGUID; + void Reset() + { + victimGUID = 0; + hearts = 15000; + Unit* own = m_creature->GetOwner(); + if (own) + m_creature->GetMotionMaster()->MoveFollow(own,0,0); + } + void Aggro(Unit *who){} + void UpdateAI(const uint32 diff) + { + if(m_creature->HasAura(20372,0)) + { + if(hearts<diff) + { + m_creature->RemoveAurasDueToSpell(20372); + hearts = 15000; + }hearts-=diff; + } + } + void ReceiveEmote(Player *player, uint32 emote) + { + m_creature->HandleEmoteCommand(emote); + Unit* own = m_creature->GetOwner(); + if (!own || own->GetTypeId() != TYPEID_PLAYER || CAST_PLR(own)->GetTeam() != player->GetTeam()) + return; + if (emote == TEXTEMOTE_KISS) + { + std::string whisp = ""; + switch (rand()%8) + { + case 0:whisp.append("Now that's what I call froggy-style!");break; + case 1:whisp.append("Your lily pad or mine?");break; + case 2:whisp.append("This won't take long, did it?");break; + case 3:whisp.append("I thought you'd never ask!");break; + case 4:whisp.append("I promise not to give you warts...");break; + case 5:whisp.append("Feelin' a little froggy, are ya?");break; + case 6: + whisp.append("Listen, "); + whisp.append(player->GetName()); + whisp.append(", I know of a little swamp not too far from here...."); + break; + case 7:whisp.append("There's just never enough Mojo to go around...");break; + } + m_creature->MonsterWhisper(whisp.c_str(),player->GetGUID()); + if(victimGUID) + { + Player* victim = Unit::GetPlayer(victimGUID); + if(victim) + victim->RemoveAura(43906);//remove polymorph frog thing + } + m_creature->AddAura(43906,player);//add polymorph frog thing + victimGUID = player->GetGUID(); + m_creature->CastSpell(m_creature,20372,true);//tag.hearts + m_creature->GetMotionMaster()->MoveFollow(player,0,0); + hearts = 15000; + } + } +}; + +CreatureAI* GetAI_mob_mojo(Creature *_Creature) +{ + return new mob_mojoAI (_Creature); +} + +struct TRINITY_DLL_DECL npc_mirror_image : SpellCasterAI +{ + npc_mirror_image(Creature *c) : SpellCasterAI(c) {} + + void InitializeAI() + { + SpellCasterAI::InitializeAI(); + Unit * owner = me->GetOwner(); + if (!owner) + return; + // Inherit Master's Threat List (not yet implemented) + owner->CastSpell((Unit*)NULL, 58838, true); + // here mirror image casts on summoner spell (not present in client dbc) 49866 + // here should be auras (not present in client dbc): 35657, 35658, 35659, 35660 selfcasted by mirror images (stats related?) + // Clone Me! + owner->CastSpell(me, 45204, false); + } + + // Do not reload creature templates on evade mode enter - prevent visual lost + void EnterEvadeMode() + { + if(me->IsInEvadeMode() || !me->isAlive()) + return; + + Unit *owner = me->GetCharmerOrOwner(); + + me->CombatStop(true); + if(owner && !me->hasUnitState(UNIT_STAT_FOLLOW) ) + { + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, m_creature->GetFollowAngle(), MOTION_SLOT_ACTIVE); + } + } +}; + +CreatureAI* GetAI_npc_mirror_image(Creature *_Creature) +{ + return new npc_mirror_image (_Creature); +} + +struct TRINITY_DLL_DECL npc_training_dummy : Scripted_NoMovementAI +{ + npc_training_dummy(Creature *c) : Scripted_NoMovementAI(c) {} + + uint32 ResetTimer; + void Reset() + { + m_creature->SetControlled(true,UNIT_STAT_STUNNED);//disable rotate + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);//imune to knock aways like blast wave + m_creature->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); + ResetTimer = 10000; + } + + void DamageTaken(Unit *done_by, uint32 &damage) + { + ResetTimer = 10000; + damage = 0; + } + + void EnterCombat(Unit *who){return;} + + void UpdateAI(const uint32 diff) + { + if(!UpdateVictim()) + return; + if(!m_creature->hasUnitState(UNIT_STAT_STUNNED)) + m_creature->SetControlled(true,UNIT_STAT_STUNNED);//disable rotate + if(ResetTimer <= diff) + { + EnterEvadeMode(); + ResetTimer = 10000; + }else ResetTimer -= diff; + return; + } + void MoveInLineOfSight(Unit *who){return;} +}; + +CreatureAI* GetAI_npc_training_dummy(Creature *_Creature) +{ + return new npc_training_dummy (_Creature); +} + void AddSC_npcs_special() { Script *newscript; @@ -1667,5 +1811,20 @@ void AddSC_npcs_special() newscript->Name="npc_snake_trap_serpents"; newscript->GetAI = &GetAI_npc_snake_trap_serpents; newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_mirror_image"; + newscript->GetAI = &GetAI_npc_mirror_image; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="mob_mojo"; + newscript->GetAI = &GetAI_mob_mojo; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_training_dummy"; + newscript->GetAI = &GetAI_npc_training_dummy; + newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp b/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp index 128583163ae..46be478f939 100644 --- a/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp +++ b/src/bindings/scripts/scripts/zone/alterac_mountains/alterac_mountains.cpp @@ -41,7 +41,7 @@ struct TRINITY_DLL_DECL npc_ravenholdtAI : public ScriptedAI { if( who->GetTypeId() == TYPEID_PLAYER ) if( CAST_PLR(who)->GetQuestStatus(6681) == QUEST_STATUS_INCOMPLETE ) - CAST_PLR(who)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID() ); + CAST_PLR(who)->KilledMonsterCredit(m_creature->GetEntry(),m_creature->GetGUID() ); } void EnterCombat(Unit* who) { } diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp index 68a3f60a197..5ae5921409b 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp @@ -228,7 +228,7 @@ struct TRINITY_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI { DoScriptText(SAY_DEATH, m_creature); //When Exarch Maladar is defeated D'ore appear. - DoSpawnCreature(19412,0,0,0,0, TEMPSUMMON_TIMED_DESPAWN, 600000); + m_creature->SummonCreature(19412, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 600000); } void UpdateAI(const uint32 diff) @@ -268,7 +268,7 @@ struct TRINITY_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI soulclass = target->getClass(); DoCast(target,SPELL_STOLEN_SOUL); - DoSpawnCreature(ENTRY_STOLEN_SOUL,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,10000); + m_creature->SummonCreature(ENTRY_STOLEN_SOUL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); StolenSoul_Timer = 20000 + rand()% 10000; } else StolenSoul_Timer = 1000; diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp index b46705ddf5e..45892af7401 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp @@ -315,7 +315,7 @@ struct TRINITY_DLL_DECL mob_ethereal_beaconAI : public ScriptedAI m_creature->InterruptNonMeleeSpells(true); m_creature->CastSpell(m_creature,SPELL_ETHEREAL_APPRENTICE,true); - KillSelf(); + m_creature->ForcedDespawn(); return; }else Apprentice_Timer -= diff; } diff --git a/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/boss_elder_nadox.cpp b/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/boss_elder_nadox.cpp index 38b5b55d1d7..e0bb2360ad1 100644 --- a/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/boss_elder_nadox.cpp +++ b/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/boss_elder_nadox.cpp @@ -26,6 +26,10 @@ EndScriptData */ #include "precompiled.h" #include "def_ahnkahet.h" +bool DeadAhnkaharGuardian; // needed for achievement: Respect Your Elders(2038) + +#define ACHIEVEMENT_RESPECT_YOUR_ELDERS 2038 + #define SAY_AGGRO -1619014 #define SAY_SLAY_1 -1619015 #define SAY_SLAY_2 -1619016 @@ -42,7 +46,7 @@ EndScriptData */ #define MOB_AHNKAHAR_SWARMER 30178 #define SPELL_SUMMON_SWARMERS 56119//2x 30178 -- 2x every 10secs -#define MOB_AHNKAHAR_SWARM_GUARD 30176 +#define MOB_AHNKAHAR_GUARDIAN_ENTRY 30176 #define SPELL_SUMMON_SWARM_GUARD 56120//1x 30176 -- every 25secs #define SPELL_GUARDIAN_AURA 56151 @@ -75,6 +79,8 @@ struct TRINITY_DLL_DECL boss_elder_nadoxAI : public ScriptedAI enrage_Timer = 5000; + DeadAhnkaharGuardian = false; + if(pInstance) pInstance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED); } @@ -103,6 +109,21 @@ struct TRINITY_DLL_DECL boss_elder_nadoxAI : public ScriptedAI { DoScriptText(SAY_SLAY_3,m_creature); + if(HeroicMode && !DeadAhnkaharGuardian) + { + AchievementEntry const *AchievRespectYourElders = GetAchievementStore()->LookupEntry(ACHIEVEMENT_RESPECT_YOUR_ELDERS); + if(AchievRespectYourElders) + { + Map *map = m_creature->GetMap(); + if(map && map->IsDungeon()) + { + Map::PlayerList const &players = map->GetPlayers(); + for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievRespectYourElders); + } + } + } + if(pInstance) pInstance->SetData(DATA_ELDER_NADOX_EVENT, DONE); } @@ -177,13 +198,14 @@ CreatureAI* GetAI_boss_elder_nadox(Creature *_Creature) { return new boss_elder_nadoxAI(_Creature); } + #define SPELL_SPRINT 56354 + struct TRINITY_DLL_DECL mob_ahnkahar_nerubianAI : public ScriptedAI { mob_ahnkahar_nerubianAI(Creature *c) : ScriptedAI(c) { pInstance = c->GetInstanceData(); - Reset(); } ScriptedInstance *pInstance; @@ -195,7 +217,15 @@ struct TRINITY_DLL_DECL mob_ahnkahar_nerubianAI : public ScriptedAI DoCast(m_creature,SPELL_GUARDIAN_AURA,true); sprint_Timer = 10000; } + + void JustDied(Unit *killer) + { + if(m_creature->GetEntry() == MOB_AHNKAHAR_GUARDIAN_ENTRY) + DeadAhnkaharGuardian = true; + } + void EnterCombat(Unit *who){} + void UpdateAI(const uint32 diff) { if(m_creature->GetEntry() == 30176) diff --git a/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp b/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp index 2c8c1664f76..3f4c04a328c 100644 --- a/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp +++ b/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp @@ -153,16 +153,9 @@ struct TRINITY_DLL_DECL npc_draenei_survivorAI : public ScriptedAI if (RunAwayTimer) { if (RunAwayTimer <= diff) - { - m_creature->RemoveAllAuras(); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->setDeathState(JUST_DIED); - m_creature->SetHealth(0); - m_creature->CombatStop(true); - m_creature->DeleteThreatList(); - m_creature->RemoveCorpse(); - }else RunAwayTimer -= diff; + m_creature->ForcedDespawn(); + else + RunAwayTimer -= diff; return; } @@ -441,8 +434,6 @@ struct TRINITY_DLL_DECL npc_geezleAI : public ScriptedAI { npc_geezleAI(Creature *c) : ScriptedAI(c) {} - std::list<GameObject*> FlagList; - uint64 SparkGUID; uint32 Step; @@ -516,17 +507,8 @@ struct TRINITY_DLL_DECL npc_geezleAI : public ScriptedAI void DespawnNagaFlag(bool despawn) { - CellPair pair(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::AllGameObjectsWithEntryInGrid go_check(GO_NAGA_FLAG); - Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInGrid> go_search(m_creature, FlagList, go_check); - TypeContainerVisitor - <Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInGrid>, GridTypeMapContainer> go_visit(go_search); - CellLock<GridReadGuard> cell_lock(cell, pair); - cell_lock->Visit(cell_lock, go_visit, *(m_creature->GetMap())); + std::list<GameObject*> FlagList; + m_creature->GetGameObjectListWithEntryInGrid(FlagList,GO_NAGA_FLAG, 50.0f); Player* player = NULL; if (!FlagList.empty()) @@ -579,7 +561,6 @@ struct TRINITY_DLL_DECL npc_nestlewood_owlkinAI : public ScriptedAI void Reset() { DespawnTimer = 0; - m_creature->SetVisibility(VISIBILITY_ON); } void UpdateAI(const uint32 diff) @@ -590,12 +571,8 @@ struct TRINITY_DLL_DECL npc_nestlewood_owlkinAI : public ScriptedAI if (DespawnTimer <= diff) { //once we are able to, despawn us - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->setDeathState(JUST_DIED); - m_creature->SetHealth(0); - m_creature->CombatStop(true); - m_creature->DeleteThreatList(); - m_creature->RemoveCorpse(); + m_creature->ForcedDespawn(); + return; }else DespawnTimer -= diff; } @@ -665,6 +642,7 @@ void AddSC_azuremyst_isle() newscript = new Script; newscript->Name="npc_nestlewood_owlkin"; newscript->GetAI = &GetAI_npc_nestlewood_owlkinAI; + newscript->pEffectDummyCreature = &EffectDummyCreature_npc_nestlewood_owlkin; newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp b/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp index b13881a02ee..dcf9263ad07 100644 --- a/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp +++ b/src/bindings/scripts/scripts/zone/barrens/the_barrens.cpp @@ -52,7 +52,7 @@ bool GossipSelect_npc_beaten_corpse(Player *player, Creature *_Creature, uint32 if(action == GOSSIP_ACTION_INFO_DEF +1) { player->SEND_GOSSIP_MENU(3558, _Creature->GetGUID()); - player->KilledMonster( 10668,_Creature->GetGUID() ); + player->KilledMonsterCredit( 10668,_Creature->GetGUID() ); } return true; } @@ -159,7 +159,7 @@ struct TRINITY_DLL_DECL npc_taskmaster_fizzuleAI : public ScriptedAI DoMeleeAttackIfReady(); } - void ReciveEmote(Player* pPlayer, uint32 emote) + void ReceiveEmote(Player* pPlayer, uint32 emote) { if (emote == TEXTEMOTE_SALUTE) { diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp index 04cd1799195..92c203232ab 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_bloodboil.cpp @@ -52,16 +52,6 @@ EndScriptData */ #define SPELL_BERSERK 45078 //This is used to sort the players by distance in preparation for the Bloodboil cast. -struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool> -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator ">" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return !MainTarget->GetDistanceOrder(_Left, _Right); - } -}; struct TRINITY_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI { @@ -160,7 +150,7 @@ struct TRINITY_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI } //Sort the list of players - targets.sort(TargetDistanceOrder(m_creature)); + targets.sort(ObjectDistanceOrderReversed(m_creature)); //Resize so we only get top 5 targets.resize(5); diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp index 0c0303b0f40..25d8abfa242 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp @@ -24,7 +24,7 @@ EndScriptData */ #include "precompiled.h" #include "def_black_temple.h" -#define GETGO(obj, guid) GameObject* obj = pInstance->instance->GetGameObject(pInstance->GetData64(guid)) +#define GETGO(obj, guid) GameObject* obj = pInstance->instance->GetGameObject(guid) #define GETUNIT(unit, guid) Unit* unit = Unit::GetUnit(*m_creature, guid) #define GETCRE(cre, guid) Creature* cre = Unit::GetCreature(*m_creature, guid) #define HPPCT(unit) unit->GetHealth()*100 / unit->GetMaxHealth() @@ -999,10 +999,10 @@ struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI DoorGUID[0] = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_DOOR_R); DoorGUID[1] = pInstance->GetData64(DATA_GAMEOBJECT_ILLIDAN_DOOR_L); - pInstance->HandleGameObject(pInstance->GetData64(GateGUID), false); + pInstance->HandleGameObject(GateGUID, false); for(uint8 i = 0; i < 2; i++) - pInstance->HandleGameObject(pInstance->GetData64(DoorGUID[i]), false); + pInstance->HandleGameObject(DoorGUID[i], false); } else @@ -1073,7 +1073,7 @@ struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI pInstance->SetData(DATA_ILLIDANSTORMRAGEEVENT, IN_PROGRESS); for(uint8 i = 0; i < 2; i++) - pInstance->HandleGameObject(pInstance->GetData64(DoorGUID[i]), false); + pInstance->HandleGameObject(DoorGUID[i], false); if(GETCRE(Illidan, IllidanGUID)) { @@ -1094,6 +1094,8 @@ struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI float x, y, z; if(GETGO(Gate, GateGUID)) Gate->GetPosition(x, y, z); + else + return;//if door not spawned, don't crash server if(Creature* Channel = m_creature->SummonCreature(ILLIDAN_DOOR_TRIGGER, x, y, z+5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000)) { @@ -1104,7 +1106,7 @@ struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI } for(uint8 i = 0; i < 2; ++i) - if(Creature* Spirit = m_creature->SummonCreature(i ? SPIRIT_OF_OLUM : SPIRIT_OF_UDALO, SpiritSpawns[i].x, SpiritSpawns[i].y, SpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000)) + if(Creature* Spirit = m_creature->SummonCreature(i ? SPIRIT_OF_OLUM : SPIRIT_OF_UDALO, SpiritSpawns[i].x, SpiritSpawns[i].y, SpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000)) { Spirit->SetVisibility(VISIBILITY_OFF); SpiritGUID[i] = Spirit->GetGUID(); @@ -1238,7 +1240,7 @@ struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI m_creature->InterruptNonMeleeSpells(true); Spirit[0]->InterruptNonMeleeSpells(true); Spirit[1]->InterruptNonMeleeSpells(true); - pInstance->HandleGameObject(pInstance->GetData64(GateGUID), true); + pInstance->HandleGameObject(GateGUID, true); Timer = 2000; break; case 4: @@ -1249,8 +1251,8 @@ struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI DoYell(SAY_AKAMA_BEWARE, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_AKAMA_BEWARE); Channel->setDeathState(JUST_DIED); - Spirit[0]->setDeathState(JUST_DIED); - Spirit[1]->setDeathState(JUST_DIED); + Spirit[0]->SetVisibility(VISIBILITY_OFF); + Spirit[1]->SetVisibility(VISIBILITY_OFF); Timer = 3000; break; case 6: @@ -1268,7 +1270,7 @@ struct TRINITY_DLL_DECL npc_akama_illidanAI : public ScriptedAI { case 6: for(uint8 i = 0; i < 2; i++) - pInstance->HandleGameObject(pInstance->GetData64(DoorGUID[i]), true); + pInstance->HandleGameObject(DoorGUID[i], true); break; case 8: if(Phase == PHASE_WALK) @@ -1648,30 +1650,15 @@ struct TRINITY_DLL_DECL cage_trap_triggerAI : public ScriptedAI } }; -bool GOHello_cage_trap(Player* plr, GameObject* go) +bool GOHello_cage_trap(Player* pPlayer, GameObject* pGo) { float x, y, z; - plr->GetPosition(x, y, z); - - Creature* trigger = NULL; - - CellPair pair(Trinity::ComputeCellPair(x, y)); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); + pPlayer->GetPosition(x, y, z); // Grid search for nearest live creature of entry 23304 within 10 yards - Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck check(*plr, 23304, true, 10); - Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(plr, trigger, check); - - TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer> cSearcher(searcher); - - CellLock<GridReadGuard> cell_lock(cell, pair); - cell_lock->Visit(cell_lock, cSearcher, *(plr->GetMap())); - - if(trigger) - CAST_AI(cage_trap_triggerAI, trigger->AI())->Active = true; - go->SetGoState(GO_STATE_ACTIVE); + if(Creature* pTrigger = pGo->FindNearestCreature(23304, 10.0f)) + CAST_AI(cage_trap_triggerAI, pTrigger->AI())->Active = true; + pGo->SetGoState(GO_STATE_ACTIVE); return true; } @@ -1746,7 +1733,9 @@ struct TRINITY_DLL_DECL mob_parasitic_shadowfiendAI : public ScriptedAI if(!m_creature->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND) && !m_creature->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND2)) { - m_creature->CastSpell(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND2, true, 0, 0, IllidanGUID); //do not stack + if(Creature* illidan = Unit::GetCreature((*m_creature),IllidanGUID))//summon only in 1. phase + if(((boss_illidan_stormrageAI*)illidan->AI())->Phase == PHASE_NORMAL) + m_creature->CastSpell(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND2, true, 0, 0, IllidanGUID); //do not stack } m_creature->AttackerStateUpdate(m_creature->getVictim()); m_creature->resetAttackTimer(); diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp index c6f4ae92c21..66f4d3b4c63 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp @@ -184,6 +184,26 @@ struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI return true; } + void MergeThreatList(Creature* target) + { + if (!target) + return; + + std::list<HostilReference*>& m_threatlist = target->getThreatManager().getThreatList(); + std::list<HostilReference*>::iterator itr = m_threatlist.begin(); + for(; itr != m_threatlist.end(); itr++) + { + Unit* pUnit = Unit::GetUnit((*m_creature), (*itr)->getUnitGuid()); + if (pUnit) + { + m_creature->AddThreat(pUnit, 1.0f); // This is so that we make sure the unit is in Reliquary's threat list before we reset the unit's threat. + m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); + float threat = target->getThreatManager().getThreat(pUnit); + m_creature->AddThreat(pUnit, threat); // This makes it so that the unit has the same amount of threat in Reliquary's threatlist as in the target creature's (One of the Essences). + } + } + } + void JustDied(Unit* killer) { if(pInstance) @@ -218,20 +238,23 @@ struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI { case 0: m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H); // I R ANNNGRRRY! + DoStartNoMovement(m_creature); Timer = 3000; break; case 1: Timer = 2800; - //m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SUBMERGE); // Release the cube + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SUBMERGE); // Release the cube DoCast(m_creature,SPELL_SUBMERGE); + DoStartNoMovement(m_creature); break; case 2: Timer = 5000; if(Creature* Summon = DoSpawnCreature(23417+Phase, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) { - //m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED); // Ribs: open + m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED); // Ribs: open Summon->AI()->AttackStart(SelectUnit(SELECT_TARGET_TOPAGGRO, 0)); EssenceGUID = Summon->GetGUID(); + DoStartNoMovement(m_creature); }else EnterEvadeMode(); break; case 3: @@ -246,19 +269,26 @@ struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI { if(Essence->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) { - Essence->AI()->EnterEvadeMode(); - Essence->GetMotionMaster()->MoveFollow(m_creature, 0, 0); + MergeThreatList(Essence); + Essence->RemoveAllAuras(); + Essence->DeleteThreatList(); + Essence->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); }else return; } break; case 4: Timer = 1500; if(Essence->IsWithinDistInMap(m_creature, 10)) + { + Essence->SetUInt32Value(UNIT_NPC_EMOTESTATE,374); //rotate and disappear + Timer = 2000; m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); - //Essence->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SUBMERGE); //rotate and disappear + } else { - Essence->AI()->EnterEvadeMode(); + MergeThreatList(Essence); + Essence->RemoveAllAuras(); + Essence->DeleteThreatList(); Essence->GetMotionMaster()->MoveFollow(m_creature, 0, 0); return; } @@ -273,7 +303,7 @@ struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI DoScriptText(DESI_SAY_AFTER, Essence); } Essence->SetVisibility(VISIBILITY_OFF); - Essence->setDeathState(DEAD); + Essence->setDeathState(JUST_DIED); m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); EssenceGUID = 0; SoulCount = 0; @@ -304,18 +334,6 @@ struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI } }; -//This is used to sort the players by distance in preparation for the Fixate cast. -struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool> -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator "<" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return MainTarget->GetDistanceOrder(_Left, _Right); - } -}; - struct TRINITY_DLL_DECL boss_essence_of_sufferingAI : public ScriptedAI { boss_essence_of_sufferingAI(Creature *c) : ScriptedAI(c) {} @@ -352,11 +370,15 @@ struct TRINITY_DLL_DECL boss_essence_of_sufferingAI : public ScriptedAI void EnterCombat(Unit *who) { - DoScriptText(SUFF_SAY_FREED, m_creature); - DoZoneInCombat(); - m_creature->CastSpell(m_creature, AURA_OF_SUFFERING, true); // linked aura need core support - m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true); - m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE2, true); + if(!m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + { + DoScriptText(SUFF_SAY_FREED, m_creature); + DoZoneInCombat(); + m_creature->CastSpell(m_creature, AURA_OF_SUFFERING, true); // linked aura need core support + m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, true); + m_creature->CastSpell(m_creature, ESSENCE_OF_SUFFERING_PASSIVE2, true); + } + else return; } void KilledUnit(Unit *victim) @@ -384,7 +406,7 @@ struct TRINITY_DLL_DECL boss_essence_of_sufferingAI : public ScriptedAI } if(targets.empty()) return; // No targets added for some reason. No point continuing. - targets.sort(TargetDistanceOrder(m_creature)); // Sort players by distance. + targets.sort(ObjectDistanceOrder(m_creature)); // Sort players by distance. targets.resize(1); // Only need closest target. Unit* target = targets.front(); // Get the first target. if(target) diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp index 502101f260e..0cf81a8cd67 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_shade_of_akama.cpp @@ -107,11 +107,11 @@ const uint32 spawnEntries[4]= { 23523, 23318, 23524 }; struct TRINITY_DLL_DECL mob_ashtongue_channelerAI : public ScriptedAI { - mob_ashtongue_channelerAI(Creature* c) : ScriptedAI(c) {} + mob_ashtongue_channelerAI(Creature* c) : ScriptedAI(c) {ShadeGUID = 0;} uint64 ShadeGUID; - void Reset() { ShadeGUID = 0; } + void Reset() {} void JustDied(Unit* killer); void EnterCombat(Unit* who) {} void AttackStart(Unit* who) {} @@ -121,7 +121,7 @@ struct TRINITY_DLL_DECL mob_ashtongue_channelerAI : public ScriptedAI struct TRINITY_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI { - mob_ashtongue_sorcererAI(Creature* c) : ScriptedAI(c) {} + mob_ashtongue_sorcererAI(Creature* c) : ScriptedAI(c) {ShadeGUID = 0;} uint64 ShadeGUID; uint32 CheckTimer; @@ -130,8 +130,7 @@ struct TRINITY_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI void Reset() { StartBanishing = false; - CheckTimer = 5000; - ShadeGUID = 0; + CheckTimer = 5000; } void JustDied(Unit* killer); @@ -237,8 +236,20 @@ struct TRINITY_DLL_DECL boss_shade_of_akamaAI : public ScriptedAI reseting = false; } - void JustSummoned(Creature *summon) {summons.Summon(summon);} - void SummonedCreatureDespawn(Creature *summon) {summons.Despawn(summon);} + void JustDied(Unit* killer) + { + summons.DespawnAll(); + } + void JustSummoned(Creature *summon) + { + if(summon->GetEntry() == CREATURE_DEFENDER || summon->GetEntry() == 23523 || summon->GetEntry() == 23318 || summon->GetEntry() == 23524) + summons.Summon(summon); + } + void SummonedCreatureDespawn(Creature *summon) + { + if(summon->GetEntry() == CREATURE_DEFENDER || summon->GetEntry() == 23523 || summon->GetEntry() == 23318 || summon->GetEntry() == 23524) + summons.Despawn(summon); + } void MoveInLineOfSight(Unit *who) { @@ -331,19 +342,8 @@ struct TRINITY_DLL_DECL boss_shade_of_akamaAI : public ScriptedAI void FindChannelers() { - CellPair pair(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - std::list<Creature*> ChannelerList; - - Trinity::AllCreaturesOfEntryInRange check(m_creature, CREATURE_CHANNELER, 50); - Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(m_creature, ChannelerList, check); - TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange>, GridTypeMapContainer> visitor(searcher); - - CellLock<GridReadGuard> cell_lock(cell, pair); - cell_lock->Visit(cell_lock, visitor, *(m_creature->GetMap())); + m_creature->GetCreatureListWithEntryInGrid(ChannelerList,CREATURE_CHANNELER,50.0f); if(!ChannelerList.empty()) { @@ -498,7 +498,7 @@ void mob_ashtongue_sorcererAI::JustDied(Unit* killer) struct TRINITY_DLL_DECL npc_akamaAI : public ScriptedAI { - npc_akamaAI(Creature* c) : ScriptedAI(c) + npc_akamaAI(Creature* c) : ScriptedAI(c), summons(m_creature) { ShadeHasDied = false; StartCombat = false; @@ -536,6 +536,7 @@ struct TRINITY_DLL_DECL npc_akamaAI : public ScriptedAI bool ShadeHasDied; bool StartCombat; bool HasYelledOnce; + SummonList summons; void Reset() { @@ -548,6 +549,18 @@ struct TRINITY_DLL_DECL npc_akamaAI : public ScriptedAI m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); // Database sometimes has very very strange values m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } + summons.DespawnAll(); + } + + void JustSummoned(Creature *summon) + { + if(summon->GetEntry() == CREATURE_BROKEN) + summons.Summon(summon); + } + void SummonedCreatureDespawn(Creature *summon) + { + if(summon->GetEntry() == CREATURE_BROKEN) + summons.Despawn(summon); } void EnterCombat(Unit* who) {} @@ -617,6 +630,7 @@ struct TRINITY_DLL_DECL npc_akamaAI : public ScriptedAI Creature* Shade = Unit::GetCreature((*m_creature), ShadeGUID); if(Shade && Shade->isAlive()) CAST_AI(boss_shade_of_akamaAI, Shade->AI())->HasKilledAkama = true; + summons.DespawnAll(); } void UpdateAI(const uint32 diff) diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp index 6fc202f2105..2c64c7657e4 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp @@ -58,8 +58,10 @@ struct TRINITY_DLL_DECL molten_flameAI : public NullCreatureAI void InitializeAI() { float x, y, z; - me->GetNearPoint(me, x, y, z, 1, 50, M_PI*2*rand_norm()); + me->GetNearPoint(me, x, y, z, 1, 100, M_PI*2*rand_norm()); me->GetMotionMaster()->MovePoint(0, x, y, z); + me->SetVisibility(VISIBILITY_OFF); + me->CastSpell(me,SPELL_MOLTEN_FLAME,true); } }; @@ -205,7 +207,8 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI if(!target) target = m_creature->getVictim(); if(target) { - DoCast(target, SPELL_VOLCANIC_SUMMON); + //DoCast(target, SPELL_VOLCANIC_SUMMON);//movement bugged + m_creature->SummonCreature(CREATURE_VOLCANO,target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN,30000); DoScriptText(EMOTE_GROUND_CRACK, m_creature); events.DelayEvents(1500, GCD_CAST); } @@ -222,17 +225,19 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI } }; -struct TRINITY_DLL_DECL npc_volcanoAI : public ScriptedAI +struct TRINITY_DLL_DECL npc_volcanoAI : public Scripted_NoMovementAI { - npc_volcanoAI(Creature *c) : ScriptedAI(c) {} + npc_volcanoAI(Creature *c) : Scripted_NoMovementAI(c) {} void Reset() { m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoCast(m_creature, SPELL_VOLCANIC_ERUPTION); + //DoCast(m_creature, SPELL_VOLCANIC_ERUPTION); me->SetReactState(REACT_PASSIVE); + wait = 3000; } + uint32 wait; void EnterCombat(Unit *who) {} @@ -243,7 +248,15 @@ struct TRINITY_DLL_DECL npc_volcanoAI : public ScriptedAI m_creature->RemoveAura(SPELL_VOLCANIC_ERUPTION); } - void UpdateAI(const uint32 diff) {} + void UpdateAI(const uint32 diff) + { + if(wait<=diff)//wait 3secs before casting + { + DoCast(m_creature, SPELL_VOLCANIC_ERUPTION); + wait = 60000; + } + else wait -= diff; + } }; diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp index 633a38c4b00..4382be2c8ca 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp @@ -103,18 +103,6 @@ struct TRINITY_DLL_DECL mob_doom_blossomAI : public ScriptedAI void SetTeronGUID(uint64 guid){ TeronGUID = guid; } }; -//This is used to sort the players by distance for Constructs to see who to cast Atrophy on -struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool> -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator "<" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return MainTarget->GetDistanceOrder(_Left, _Right); - } -}; - struct TRINITY_DLL_DECL mob_shadowy_constructAI : public ScriptedAI { mob_shadowy_constructAI(Creature* c) : ScriptedAI(c) {} @@ -165,7 +153,7 @@ struct TRINITY_DLL_DECL mob_shadowy_constructAI : public ScriptedAI if(pUnit && pUnit->isAlive()) targets.push_back(pUnit); } - targets.sort(TargetDistanceOrder(m_creature)); + targets.sort(ObjectDistanceOrder(m_creature)); Unit* target = targets.front(); if(target && m_creature->IsWithinDistInMap(target, m_creature->GetAttackDistance(target))) { @@ -239,23 +227,11 @@ struct TRINITY_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI void EnterCombat(Unit *who) {} - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) { - if(!who || (!who->isAlive())) return; - - if(who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who)) + if (!Intro && pWho->GetTypeId() == TYPEID_PLAYER && pWho->isTargetableForAttack() && m_creature->IsHostileTo(pWho) && pWho->isInAccessiblePlaceFor(m_creature)) { - float attackRadius = m_creature->GetAttackDistance(who); - - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who)) - { - //if(who->HasStealthAura()) - // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - m_creature->AddThreat(who, 1.0f); - } - - if(!m_creature->isInCombat() && !Intro && m_creature->IsWithinDistInMap(who, 60.0f) && (who->GetTypeId() == TYPEID_PLAYER)) + if (m_creature->IsWithinDistInMap(pWho, VISIBLE_RANGE) && m_creature->IsWithinLOSInMap(pWho)) { if(pInstance) pInstance->SetData(DATA_TERONGOREFIENDEVENT, IN_PROGRESS); @@ -264,10 +240,12 @@ struct TRINITY_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); DoScriptText(SAY_INTRO, m_creature); m_creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); - AggroTargetGUID = who->GetGUID(); + AggroTargetGUID = pWho->GetGUID(); Intro = true; } } + + ScriptedAI::MoveInLineOfSight(pWho); } void KilledUnit(Unit *victim) diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp index f70b82c0e3c..b7b44da4f80 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp @@ -200,8 +200,7 @@ bool GOHello_go_najentus_spine(Player *player, GameObject* _GO) if(CAST_AI(boss_najentusAI, Najentus->AI())->RemoveImpalingSpine()) { player->CastSpell(player, SPELL_CREATE_NAJENTUS_SPINE, true); - _GO->SetLootState(GO_NOT_READY); - _GO->Delete(); + _GO->DeleteObjectWithOwner(); } return true; } diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp index 378f8163f9d..0e0639fa14a 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_emperor_dagran_thaurissan.cpp @@ -47,6 +47,7 @@ struct TRINITY_DLL_DECL boss_draganthaurissanAI : public ScriptedAI void EnterCombat(Unit *who) { DoScriptText(SAY_AGGRO, m_creature); + m_creature->CallForHelp(VISIBLE_RANGE); } void KilledUnit(Unit* victim) diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_tomb_of_seven.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_tomb_of_seven.cpp index 4b201705924..321952f2e60 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/boss_tomb_of_seven.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/boss_tomb_of_seven.cpp @@ -24,17 +24,15 @@ EndScriptData */ #include "precompiled.h" #include "def_blackrock_depths.h" -#define FACTION_NEUTRAL 734 -#define FACTION_HOSTILE 754 - #define SPELL_SUNDERARMOR 24317 #define SPELL_SHIELDBLOCK 12169 #define SPELL_STRIKE 15580 struct TRINITY_DLL_DECL boss_angerrelAI : public ScriptedAI { - boss_angerrelAI(Creature *c) : ScriptedAI(c) {} + boss_angerrelAI(Creature *c) : ScriptedAI(c) {pInstance = c->GetInstanceData();} + ScriptedInstance* pInstance; uint32 SunderArmor_Timer; uint32 ShieldBlock_Timer; uint32 Strike_Timer; @@ -43,13 +41,32 @@ struct TRINITY_DLL_DECL boss_angerrelAI : public ScriptedAI { SunderArmor_Timer = 8000; ShieldBlock_Timer = 15000; - Strike_Timer = 12000; + Strike_Timer = 12000; } void EnterCombat(Unit *who) { } + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreaturesAddon(); + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_creature->SetLootRecipient(NULL); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER, 0); + } + + void JustDied(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_GHOSTKILL, 1); + } + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) @@ -91,8 +108,9 @@ CreatureAI* GetAI_boss_angerrel(Creature *_Creature) struct TRINITY_DLL_DECL boss_doperelAI : public ScriptedAI { - boss_doperelAI(Creature *c) : ScriptedAI(c) {} - + boss_doperelAI(Creature *c) : ScriptedAI(c) {pInstance = c->GetInstanceData();} + + ScriptedInstance* pInstance; uint32 SinisterStrike_Timer; uint32 BackStab_Timer; uint32 Gouge_Timer; @@ -108,6 +126,25 @@ struct TRINITY_DLL_DECL boss_doperelAI : public ScriptedAI { } + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreaturesAddon(); + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_creature->SetLootRecipient(NULL); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER, 0); + } + + void JustDied(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_GHOSTKILL, 1); + } + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) @@ -149,8 +186,9 @@ CreatureAI* GetAI_boss_doperel(Creature *_Creature) struct TRINITY_DLL_DECL boss_haterelAI : public ScriptedAI { - boss_haterelAI(Creature *c) : ScriptedAI(c) {} + boss_haterelAI(Creature *c) : ScriptedAI(c) {pInstance = c->GetInstanceData();} + ScriptedInstance* pInstance; uint32 ShadowBolt_Timer; uint32 ManaBurn_Timer; uint32 ShadowShield_Timer; @@ -168,6 +206,25 @@ struct TRINITY_DLL_DECL boss_haterelAI : public ScriptedAI { } + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreaturesAddon(); + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_creature->SetLootRecipient(NULL); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER, 0); + } + + void JustDied(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_GHOSTKILL, 1); + } + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) @@ -221,8 +278,9 @@ CreatureAI* GetAI_boss_haterel(Creature *_Creature) struct TRINITY_DLL_DECL boss_vilerelAI : public ScriptedAI { - boss_vilerelAI(Creature *c) : ScriptedAI(c) {} + boss_vilerelAI(Creature *c) : ScriptedAI(c) {pInstance = c->GetInstanceData();} + ScriptedInstance* pInstance; uint32 MindBlast_Timer; uint32 Heal_Timer; uint32 PrayerOfHealing_Timer; @@ -240,6 +298,25 @@ struct TRINITY_DLL_DECL boss_vilerelAI : public ScriptedAI { } + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreaturesAddon(); + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_creature->SetLootRecipient(NULL); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER, 0); + } + + void JustDied(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_GHOSTKILL, 1); + } + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) @@ -290,8 +367,9 @@ CreatureAI* GetAI_boss_vilerel(Creature *_Creature) struct TRINITY_DLL_DECL boss_seethrelAI : public ScriptedAI { - boss_seethrelAI(Creature *c) : ScriptedAI(c) {} + boss_seethrelAI(Creature *c) : ScriptedAI(c) {pInstance = c->GetInstanceData();} + ScriptedInstance* pInstance; uint32 FrostArmor_Timer; uint32 Frostbolt_Timer; uint32 Blizzard_Timer; @@ -313,6 +391,25 @@ struct TRINITY_DLL_DECL boss_seethrelAI : public ScriptedAI { } + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreaturesAddon(); + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_creature->SetLootRecipient(NULL); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER, 0); + } + + void JustDied(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_GHOSTKILL, 1); + } + void UpdateAI(const uint32 diff) { if (!UpdateVictim()) @@ -370,8 +467,9 @@ CreatureAI* GetAI_boss_seethrel(Creature *_Creature) struct TRINITY_DLL_DECL boss_gloomrelAI : public ScriptedAI { - boss_gloomrelAI(Creature *c) : ScriptedAI(c) {} + boss_gloomrelAI(Creature *c) : ScriptedAI(c) {pInstance = c->GetInstanceData();} + ScriptedInstance* pInstance; uint32 Hamstring_Timer; uint32 Cleave_Timer; uint32 MortalStrike_Timer; @@ -382,13 +480,32 @@ struct TRINITY_DLL_DECL boss_gloomrelAI : public ScriptedAI Cleave_Timer = 6000; MortalStrike_Timer = 10000; - m_creature->setFaction(FACTION_NEUTRAL); + m_creature->setFaction(FACTION_FRIEND); } void EnterCombat(Unit *who) { } + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreaturesAddon(); + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_creature->SetLootRecipient(NULL); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER, 0); + } + + void JustDied(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_GHOSTKILL, 1); + } + void UpdateAI(const uint32 diff) { if (!UpdateVictim() ) @@ -436,6 +553,7 @@ bool GossipHello_boss_gloomrel(Player *player, Creature *_Creature) if (player->GetQuestRewardStatus(4083) == 0 && player->GetSkillValue(SKILL_MINING) >= 230) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TRIBUTE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); return true; } @@ -457,7 +575,7 @@ bool GossipSelect_boss_gloomrel(Player *player, Creature *_Creature, uint32 send break; case GOSSIP_ACTION_INFO_DEF+22: player->CLOSE_GOSSIP_MENU(); - if (ScriptedInstance* pInstance = (ScriptedInstance*)_Creature->GetInstanceData()) + if (ScriptedInstance* pInstance = _Creature->GetInstanceData()) { //are 5 minutes expected? go template may have data to despawn when used at quest pInstance->DoRespawnGameObject(pInstance->GetData64(DATA_GO_CHALICE),MINUTE*5); @@ -474,8 +592,9 @@ bool GossipSelect_boss_gloomrel(Player *player, Creature *_Creature, uint32 send struct TRINITY_DLL_DECL boss_doomrelAI : public ScriptedAI { - boss_doomrelAI(Creature *c) : ScriptedAI(c) {} + boss_doomrelAI(Creature *c) : ScriptedAI(c) {pInstance = c->GetInstanceData();} + ScriptedInstance* pInstance; uint32 ShadowVolley_Timer; uint32 Immolate_Timer; uint32 CurseOfWeakness_Timer; @@ -494,13 +613,37 @@ struct TRINITY_DLL_DECL boss_doomrelAI : public ScriptedAI DemonArmor_Timer = 16000; Voidwalkers = false; - m_creature->setFaction(FACTION_NEUTRAL); + m_creature->setFaction(FACTION_FRIEND); + if(pInstance) + if(pInstance->GetData(DATA_GHOSTKILL) >= 7) + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + else + m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } void EnterCombat(Unit *who) { } + void EnterEvadeMode() + { + m_creature->RemoveAllAuras(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreaturesAddon(); + if(m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_creature->SetLootRecipient(NULL); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER, 0); + } + + void JustDied(Unit *who) + { + if(pInstance) + pInstance->SetData(DATA_GHOSTKILL, 1); + } + void SummonVoidwalkers(Unit* victim) { Rand = rand()%5; @@ -595,8 +738,13 @@ bool GossipSelect_boss_doomrel(Player *player, Creature *_Creature, uint32 sende break; case GOSSIP_ACTION_INFO_DEF+2: player->CLOSE_GOSSIP_MENU(); - //start event here, below code just temporary + //start event here _Creature->setFaction(FACTION_HOSTILE); + _Creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + _Creature->AI()->AttackStart(player); + ScriptedInstance* pInstance = _Creature->GetInstanceData(); + if(pInstance) + pInstance->SetData64(DATA_EVENSTARTER,player->GetGUID()); break; } return true; diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/def_blackrock_depths.h b/src/bindings/scripts/scripts/zone/blackrock_depths/def_blackrock_depths.h index 8c3a04a16df..6ce124a7c3e 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/def_blackrock_depths.h +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/def_blackrock_depths.h @@ -5,6 +5,10 @@ #ifndef DEF_BRD_H #define DEF_BRD_H +#define FACTION_NEUTRAL 734 +#define FACTION_HOSTILE 754 +#define FACTION_FRIEND 35 + enum { TYPE_RING_OF_LAW = 1, @@ -25,7 +29,10 @@ enum DATA_GO_BAR_KEG = 16, DATA_GO_BAR_KEG_TRAP = 17, DATA_GO_BAR_DOOR = 18, - DATA_GO_CHALICE = 19 + DATA_GO_CHALICE = 19, + + DATA_GHOSTKILL = 20, + DATA_EVENSTARTER = 21 }; #endif diff --git a/src/bindings/scripts/scripts/zone/blackrock_depths/instance_blackrock_depths.cpp b/src/bindings/scripts/scripts/zone/blackrock_depths/instance_blackrock_depths.cpp index 3d77ced9d94..8f2afcbe926 100644 --- a/src/bindings/scripts/scripts/zone/blackrock_depths/instance_blackrock_depths.cpp +++ b/src/bindings/scripts/scripts/zone/blackrock_depths/instance_blackrock_depths.cpp @@ -32,12 +32,21 @@ update `instance_template` set `script`='instance_blackrock_depths' where `map`= #include "precompiled.h" #include "def_blackrock_depths.h" +#define TIMER_TOMBOFTHESEVEN 15000 + enum { ENCOUNTERS = 6, NPC_EMPEROR = 9019, NPC_PHALANX = 9502, + NPC_ANGERREL = 9035, + NPC_DOPEREL = 9040, + NPC_HATEREL = 9034, + NPC_VILEREL = 9036, + NPC_SEETHREL = 9038, + NPC_GLOOMREL = 9037, + NPC_DOOMREL = 9039, GO_ARENA1 = 161525, GO_ARENA2 = 161522, @@ -88,8 +97,14 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance uint64 GoGolemNGUID; uint64 GoGolemSGUID; uint64 GoThoneGUID; + uint64 GoChestGUID; uint32 BarAleCount; + uint32 GhostKillCount; + uint64 TombBossGUIDs[7]; + uint64 TombEventStarterGUID; + uint32 TombTimer; + uint32 TombEventCounter; void Initialize() { @@ -113,11 +128,18 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance GoGolemNGUID = 0; GoGolemSGUID = 0; GoThoneGUID = 0; + GoChestGUID = 0; BarAleCount = 0; + GhostKillCount = 0; + TombEventStarterGUID = 0; + TombTimer = TIMER_TOMBOFTHESEVEN; + TombEventCounter = 0; for(uint8 i = 0; i < ENCOUNTERS; i++) Encounter[i] = NOT_STARTED; + for(uint8 i = 0; i < 7; i++) + TombBossGUIDs[i] = 0; } void OnCreatureCreate(Creature *creature, bool add) @@ -126,6 +148,13 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance { case NPC_EMPEROR: EmperorGUID = creature->GetGUID(); break; case NPC_PHALANX: PhalanxGUID = creature->GetGUID(); break; + case NPC_DOOMREL: TombBossGUIDs[0] = creature->GetGUID(); break; + case NPC_DOPEREL: TombBossGUIDs[1] = creature->GetGUID(); break; + case NPC_HATEREL: TombBossGUIDs[2] = creature->GetGUID(); break; + case NPC_VILEREL: TombBossGUIDs[3] = creature->GetGUID(); break; + case NPC_SEETHREL: TombBossGUIDs[4] = creature->GetGUID(); break; + case NPC_GLOOMREL: TombBossGUIDs[5] = creature->GetGUID(); break; + case NPC_ANGERREL: TombBossGUIDs[6] = creature->GetGUID(); break; } } @@ -145,11 +174,34 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance case GO_BAR_KEG_TRAP: GoBarKegTrapGUID = go->GetGUID(); break; case GO_BAR_DOOR: GoBarDoorGUID = go->GetGUID(); break; case GO_TOMB_ENTER: GoTombEnterGUID = go->GetGUID(); break; - case GO_TOMB_EXIT: GoTombExitGUID = go->GetGUID(); break; + case GO_TOMB_EXIT: + GoTombExitGUID = go->GetGUID(); + if(GhostKillCount >= 7) + HandleGameObject(0, true, go); + else + HandleGameObject(0, false, go); + break; case GO_LYCEUM: GoLyceumGUID = go->GetGUID(); break; case GO_GOLEM_ROOM_N: GoGolemNGUID = go->GetGUID(); break; case GO_GOLEM_ROOM_S: GoGolemSGUID = go->GetGUID(); break; case GO_THONE_ROOM: GoThoneGUID = go->GetGUID(); break; + case GO_CHEST_SEVEN: GoChestGUID = go->GetGUID(); break; + } + } + + void SetData64(uint32 type, uint64 data) + { + debug_log("TSCR: Instance Blackrock Depths: SetData64 update (Type: %u Data %u)", type, data); + + switch(type) + { + case DATA_EVENSTARTER: + TombEventStarterGUID = data; + if(!TombEventStarterGUID) + TombOfSevenReset();//reset + else + TombOfSevenStart();//start + break; } } @@ -180,15 +232,18 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance case TYPE_IRON_HALL: Encounter[5] = data; break; + case DATA_GHOSTKILL: + GhostKillCount += data; + break; } - if (data == DONE) + if (data == DONE || GhostKillCount >= 7) { OUT_SAVE_INST_DATA; std::ostringstream saveStream; saveStream << Encounter[0] << " " << Encounter[1] << " " << Encounter[2] << " " - << Encounter[3] << " " << Encounter[4] << " " << Encounter[5]; + << Encounter[3] << " " << Encounter[4] << " " << Encounter[5] << " " << GhostKillCount; str_data = saveStream.str(); @@ -216,6 +271,8 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance return Encounter[4]; case TYPE_IRON_HALL: return Encounter[5]; + case DATA_GHOSTKILL: + return GhostKillCount; } return 0; } @@ -242,6 +299,8 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance return GoBarKegTrapGUID; case DATA_GO_BAR_DOOR: return GoBarDoorGUID; + case DATA_EVENSTARTER: + return TombEventStarterGUID; } return 0; } @@ -263,14 +322,90 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance std::istringstream loadStream(in); loadStream >> Encounter[0] >> Encounter[1] >> Encounter[2] >> Encounter[3] - >> Encounter[4] >> Encounter[5]; + >> Encounter[4] >> Encounter[5] >> GhostKillCount; for(uint8 i = 0; i < ENCOUNTERS; ++i) if (Encounter[i] == IN_PROGRESS) Encounter[i] = NOT_STARTED; + if(GhostKillCount > 0 && GhostKillCount < 7) + GhostKillCount = 0;//reset tomb of seven event + if(GhostKillCount > 7) + GhostKillCount = 7; OUT_LOAD_INST_DATA_COMPLETE; } + + void TombOfSevenEvent() + { + if(GhostKillCount < 7 && TombBossGUIDs[TombEventCounter]) + { + if(Creature* boss = instance->GetCreature(TombBossGUIDs[TombEventCounter])) + { + boss->setFaction(FACTION_HOSTILE); + boss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + if(Unit* target = boss->SelectNearestTarget(500)) + boss->AI()->AttackStart(target); + } + } + } + + void TombOfSevenReset() + { + HandleGameObject(GoTombExitGUID,false);//event reseted, close exit door + HandleGameObject(GoTombEnterGUID,true);//event reseted, open entrance door + for(uint8 i = 0; i < 7; i++) + { + if(Creature* boss = instance->GetCreature(TombBossGUIDs[i])) + { + if(!boss->isAlive()) + {//do not call EnterEvadeMode(), it will create infinit loops + boss->Respawn(); + boss->RemoveAllAuras(); + boss->DeleteThreatList(); + boss->CombatStop(true); + boss->LoadCreaturesAddon(); + boss->GetMotionMaster()->MoveTargetedHome(); + boss->SetLootRecipient(NULL); + } + boss->setFaction(FACTION_FRIEND); + } + } + GhostKillCount = 0; + TombEventStarterGUID = 0; + TombEventCounter = 0; + TombTimer = TIMER_TOMBOFTHESEVEN; + SetData(TYPE_TOMB_OF_SEVEN, NOT_STARTED); + } + + void TombOfSevenStart() + { + HandleGameObject(GoTombExitGUID,false);//event started, close exit door + HandleGameObject(GoTombEnterGUID,false);//event started, close entrance door + SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS); + } + + void TombOfSevenEnd() + { + DoRespawnGameObject(GoChestGUID,DAY); + HandleGameObject(GoTombExitGUID,true);//event done, open exit door + HandleGameObject(GoTombEnterGUID,true);//event done, open entrance door + TombEventStarterGUID = 0; + SetData(TYPE_TOMB_OF_SEVEN, DONE); + } + void Update(uint32 diff) + { + if(TombEventStarterGUID && GhostKillCount < 7) + { + if(TombTimer <= diff) + { + TombTimer = TIMER_TOMBOFTHESEVEN; + TombEventCounter++; + TombOfSevenEvent(); + }else TombTimer -= diff; + } + if(GhostKillCount >= 7 && TombEventStarterGUID) + TombOfSevenEnd(); + } }; InstanceData* GetInstanceData_instance_blackrock_depths(Map* map) diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp index c2582ffb600..a4654ee575b 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_broodlord_lashlayer.cpp @@ -39,7 +39,6 @@ struct TRINITY_DLL_DECL boss_broodlordAI : public ScriptedAI uint32 BlastWave_Timer; uint32 MortalStrike_Timer; uint32 KnockBack_Timer; - uint32 LeashCheck_Timer; void Reset() { @@ -47,10 +46,6 @@ struct TRINITY_DLL_DECL boss_broodlordAI : public ScriptedAI BlastWave_Timer = 12000; MortalStrike_Timer = 20000; KnockBack_Timer = 30000; - LeashCheck_Timer = 2000; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void EnterCombat(Unit *who) @@ -64,20 +59,6 @@ struct TRINITY_DLL_DECL boss_broodlordAI : public ScriptedAI if (!UpdateVictim()) return; - //LeashCheck_Timer - if (LeashCheck_Timer < diff) - { - float rx,ry,rz; - m_creature->GetRespawnCoord(rx, ry, rz); - if(!m_creature->IsWithinDist3d(rx,ry,rz,250.0f)) - { - DoScriptText(SAY_LEASH, m_creature); - EnterEvadeMode(); - return; - } - LeashCheck_Timer = 2000; - }else LeashCheck_Timer -= diff; - //Cleave_Timer if (Cleave_Timer < diff) { @@ -109,6 +90,9 @@ struct TRINITY_DLL_DECL boss_broodlordAI : public ScriptedAI KnockBack_Timer = 15000 + rand()%15000; }else KnockBack_Timer -= diff; + if (EnterEvadeIfOutOfCombatArea(diff)) + DoScriptText(SAY_LEASH, m_creature); + DoMeleeAttackIfReady(); } }; diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp index 808f381d197..c71b1871d94 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_nefarian.cpp @@ -79,9 +79,6 @@ struct TRINITY_DLL_DECL boss_nefarianAI : public ScriptedAI TailLash_Timer = 10000; ClassCall_Timer = 35000; //35-40 seconds Phase3 = false; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void KilledUnit(Unit* Victim) diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp index 5267f1ef4b6..77e22a4d543 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_razorgore.cpp @@ -50,9 +50,6 @@ struct TRINITY_DLL_DECL boss_razorgoreAI : public ScriptedAI WarStomp_Timer = 35000; FireballVolley_Timer = 7000; Conflagration_Timer = 12000; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void EnterCombat(Unit *who) diff --git a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp index 9925cd6d3bc..a1b87ae6f01 100644 --- a/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp +++ b/src/bindings/scripts/scripts/zone/blackwing_lair/boss_vaelastrasz.cpp @@ -72,9 +72,6 @@ struct TRINITY_DLL_DECL boss_vaelAI : public ScriptedAI TailSwipe_Timer = 20000; HasYelled = false; DoingSpeach = false; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void BeginSpeach(Unit* target) diff --git a/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp b/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp index dc38bb3268a..0a90b870926 100644 --- a/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp +++ b/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp @@ -61,7 +61,7 @@ struct TRINITY_DLL_DECL mobs_bladespire_ogreAI : public ScriptedAI void JustDied(Unit* Killer) { if (Killer->GetTypeId() == TYPEID_PLAYER) - CAST_PLR(Killer)->KilledMonster(19995, m_creature->GetGUID()); + CAST_PLR(Killer)->KilledMonsterCredit(19995, m_creature->GetGUID()); } }; CreatureAI* GetAI_mobs_bladespire_ogre(Creature *_Creature) @@ -261,8 +261,7 @@ struct TRINITY_DLL_DECL npc_daranelleAI : public ScriptedAI { DoScriptText(SAY_SPELL_INFLUENCE, m_creature, who); //TODO: Move the below to updateAI and run if this statement == true - CAST_PLR(who)->KilledMonster(21511, m_creature->GetGUID()); - CAST_PLR(who)->RemoveAurasDueToSpell(36904); + DoCast(who,37028,true); } } diff --git a/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp b/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp index 34fc8e02057..b13330d4bd6 100644 --- a/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp +++ b/src/bindings/scripts/scripts/zone/bloodmyst_isle/bloodmyst_isle.cpp @@ -56,7 +56,7 @@ struct TRINITY_DLL_DECL mob_webbed_creatureAI : public ScriptedAI case 0: spawnCreatureID = 17681; if (Killer->GetTypeId() == TYPEID_PLAYER) - CAST_PLR(Killer)->KilledMonster(spawnCreatureID, m_creature->GetGUID()); + CAST_PLR(Killer)->KilledMonsterCredit(spawnCreatureID, m_creature->GetGUID()); break; case 1: case 2: @@ -65,7 +65,7 @@ struct TRINITY_DLL_DECL mob_webbed_creatureAI : public ScriptedAI } if(spawnCreatureID) - DoSpawnCreature(spawnCreatureID,0,0,0,m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + m_creature->SummonCreature(spawnCreatureID, 0.0f, 0.0f, 0.0f, m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); } }; CreatureAI* GetAI_mob_webbed_creature(Creature *_Creature) diff --git a/src/bindings/scripts/scripts/zone/borean_tundra/borean_tundra.cpp b/src/bindings/scripts/scripts/zone/borean_tundra/borean_tundra.cpp index 94c93c8e449..10cf10c6c95 100644 --- a/src/bindings/scripts/scripts/zone/borean_tundra/borean_tundra.cpp +++ b/src/bindings/scripts/scripts/zone/borean_tundra/borean_tundra.cpp @@ -87,6 +87,150 @@ bool GossipSelect_npc_surristrasz(Player *player, Creature *_Creature, uint32 se return true; } +/*###### +## npc_sinkhole_kill_credit +######*/ + +enum +{ + SPELL_SET_CART = 46797, + SPELL_EXPLODE_CART = 46799, + SPELL_SUMMON_CART = 46798, + SPELL_SUMMON_WORM = 46800, +}; + +struct TRINITY_DLL_DECL npc_sinkhole_kill_creditAI : public ScriptedAI +{ + npc_sinkhole_kill_creditAI(Creature* c) : ScriptedAI(c){} + + uint32 Phase_Timer; + uint8 Phase; + Unit* Caster; + + void Reset() + { + Phase_Timer = 500; + Phase = 0; + Caster = NULL; + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (Phase) + return; + + if (spell->Id == SPELL_SET_CART && CAST_PLR(caster)->GetQuestStatus(11897) == QUEST_STATUS_INCOMPLETE) + { + Phase = 1; + Caster = caster; + } + } + + void EnterCombat(Unit* who) { } + + void UpdateAI(const uint32 diff) + { + if (!Phase) + return; + + if (Phase_Timer < diff) + { + switch (Phase) + { + case 1: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + DoCast(m_creature, SPELL_SUMMON_CART, true); + if (GameObject* cart = m_creature->FindNearestGameObject(188160,3)) + cart->SetUInt32Value(GAMEOBJECT_FACTION, 14); + Phase_Timer = 3000; + Phase = 2; + break; + case 2: + if (GameObject* cart = m_creature->FindNearestGameObject(188160,3)) + cart->UseDoorOrButton(); + DoCast(m_creature, SPELL_EXPLODE_CART, true); + Phase_Timer = 3000; + Phase = 3; + break; + case 3: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + Phase_Timer = 2000; + Phase = 4; + case 5: + DoCast(m_creature, SPELL_SUMMON_WORM, true); + if (Unit* worm = m_creature->FindNearestCreature(26250, 3)) + { + worm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + worm->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + } + Phase_Timer = 1000; + Phase = 6; + break; + case 6: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + if (Unit* worm = m_creature->FindNearestCreature(26250, 3)) + { + m_creature->DealDamage(worm, worm->GetHealth()); + worm->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + Phase_Timer = 2000; + Phase = 7; + break; + case 7: + DoCast(m_creature, SPELL_EXPLODE_CART, true); + CAST_PLR(Caster)->KilledMonster(m_creature->GetCreatureInfo(),m_creature->GetGUID()); + Phase_Timer = 5000; + Phase = 8; + break; + case 8: + EnterEvadeMode(); + break; + } + } else Phase_Timer -= diff; + + } + +}; + +CreatureAI* GetAI_npc_sinkhole_kill_credit(Creature* pCreature) +{ + return new npc_sinkhole_kill_creditAI(pCreature); +} + +/*###### +## npc_khunok_the_behemoth +######*/ + +struct TRINITY_DLL_DECL npc_khunok_the_behemothAI : public ScriptedAI +{ + npc_khunok_the_behemothAI(Creature *c) : ScriptedAI(c) {} + + void MoveInLineOfSight(Unit *who) + { + ScriptedAI::MoveInLineOfSight(who); + + if(who->GetTypeId() != TYPEID_UNIT) + return; + + if(who->GetEntry() == 25861 && me->IsWithinDistInMap(who, 10.0f)) + { + if(Unit *owner = who->GetOwner()) + { + if(owner->GetTypeId() == TYPEID_PLAYER) + { + DoCast(owner, 46231, true); + CAST_CRE(who)->ForcedDespawn(); + } + } + } + } +}; + +CreatureAI* GetAI_npc_khunok_the_behemoth(Creature *_Creature) +{ + return new npc_khunok_the_behemothAI(_Creature); +} + void AddSC_borean_tundra() { Script *newscript; @@ -102,4 +246,14 @@ void AddSC_borean_tundra() newscript->pGossipHello = &GossipHello_npc_surristrasz; newscript->pGossipSelect = &GossipSelect_npc_surristrasz; newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_sinkhole_kill_credit"; + newscript->GetAI = &GetAI_npc_sinkhole_kill_credit; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_khunok_the_behemoth"; + newscript->GetAI = &GetAI_npc_khunok_the_behemoth; + newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp index eea9a28da36..a2e28a19d5b 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp @@ -45,7 +45,7 @@ struct TRINITY_DLL_DECL boss_temporusAI : public ScriptedAI boss_temporusAI(Creature *c) : ScriptedAI(c) { pInstance = c->GetInstanceData(); - HeroicMode = m_creature->GetMap()->IsHeroic(); + HeroicMode = c->GetMap()->IsHeroic(); } ScriptedInstance *pInstance; @@ -58,9 +58,6 @@ struct TRINITY_DLL_DECL boss_temporusAI : public ScriptedAI void Reset() { - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - Haste_Timer = 15000+rand()%8000; SpellReflection_Timer = 30000; MortalWound_Timer = 8000; diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp index 423ada87927..25e0ed6b38d 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_archimonde.cpp @@ -183,18 +183,6 @@ struct TRINITY_DLL_DECL mob_doomfire_targettingAI : public ScriptedAI For Doomfire, we summon a mob (Doomfire Spirit) for the Doomfire mob to follow. It's spirit will randomly select it's target to follow and then we create the random movement making it unpredictable. */ -// This is used to sort by distance in order to see who is the closest target, when checking for Finger of Death -struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool> -{ - const Unit* MainTarget; - TargetDistanceOrder(const Unit* Target) : MainTarget(Target) {}; - // functor for operator "<" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return MainTarget->GetDistanceOrder(_Left, _Right); - } -}; - struct TRINITY_DLL_DECL boss_archimondeAI : public hyjal_trashAI { boss_archimondeAI(Creature *c) : hyjal_trashAI(c) @@ -335,7 +323,7 @@ struct TRINITY_DLL_DECL boss_archimondeAI : public hyjal_trashAI if (targets.empty()) return false; - targets.sort(TargetDistanceOrder(m_creature)); + targets.sort(ObjectDistanceOrder(m_creature)); Unit* target = targets.front(); if (target) { diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp index dc9946e468a..04490cf13a8 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp @@ -89,7 +89,7 @@ struct TRINITY_DLL_DECL instance_old_hillsbrad : public ScriptedInstance player->SendUpdateWorldState(WORLD_STATE_OH,mBarrelCount); if (mBarrelCount == 5) - player->KilledMonster(LODGE_QUEST_TRIGGER,0); + player->KilledMonsterCredit(LODGE_QUEST_TRIGGER,0); } } }else diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp index 11d6ff3b1ab..80542b9a1db 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp @@ -235,7 +235,7 @@ struct TRINITY_DLL_DECL npc_thrall_old_hillsbradAI : public npc_escortAI break; case 29: DoScriptText(SAY_TH_SKARLOC_MEET, m_creature); - m_creature->SummonCreature(17862,2036.48,271.22,63.43,5.27,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); + m_creature->SummonCreature(ENTRY_SCARLOC,2036.48,271.22,63.43,5.27,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,30000); //temporary,skarloc should rather be triggered to walk up to thrall break; case 30: @@ -347,7 +347,7 @@ struct TRINITY_DLL_DECL npc_thrall_old_hillsbradAI : public npc_escortAI for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if (Player* pPlayer = itr->getSource()) - pPlayer->KilledMonster(20156,m_creature->GetGUID()); + pPlayer->KilledMonsterCredit(20156,m_creature->GetGUID()); } } diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp index dd19dad0e16..f37b448caea 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_fathomlord_karathress.cpp @@ -56,7 +56,8 @@ EndScriptData */ #define SPELL_FROST_SHOCK 38234 #define SPELL_SPITFIRE_TOTEM 38236 #define SPELL_POISON_CLEANSING_TOTEM 38306 -#define SPELL_POISON_CLEANSING_EFFECT 8167 +// Spell obsolete +// #define SPELL_POISON_CLEANSING_EFFECT 8167 #define SPELL_EARTHBIND_TOTEM 38304 #define SPELL_EARTHBIND_TOTEM_EFFECT 6474 #define SPELL_WINDFURY_WEAPON 38184 diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp index e34dd9cf807..bd7f786defe 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_hydross_the_unstable.cpp @@ -56,7 +56,7 @@ EndScriptData */ #define SPELL_ENRAGE 27680 //this spell need verification #define SPELL_SUMMON_WATER_ELEMENT 36459 //not in use yet(in use ever?) #define SPELL_ELEMENTAL_SPAWNIN 25035 -#define SPELL_BLUE_BEAM /*40227*/40227 //channeled Hydross Beam Helper (not in use yet) +#define SPELL_BLUE_BEAM 40227 //channeled Hydross Beam Helper (not in use yet) #define ENTRY_PURE_SPAWN 22035 #define ENTRY_TAINTED_SPAWN 22036 @@ -324,7 +324,7 @@ struct TRINITY_DLL_DECL boss_hydross_the_unstableAI : public ScriptedAI //WaterTomb_Timer if (WaterTomb_Timer < diff) { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (target) DoCast(target, SPELL_WATER_TOMB); diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp index 8c183685815..36938488d12 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp @@ -260,11 +260,10 @@ struct TRINITY_DLL_DECL boss_lady_vashjAI : public ScriptedAI } } } - if(Phase != 2) - AttackStart(who); + StartEvent();//this is EnterCombat(), so were are 100% in combat, start the event - if(!m_creature->isInCombat()) - StartEvent(); + if(Phase != 2) + AttackStart(who); } void MoveInLineOfSight(Unit *who) @@ -287,11 +286,11 @@ struct TRINITY_DLL_DECL boss_lady_vashjAI : public ScriptedAI //if(who->HasStealthAura()) // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - if(Phase != 2) - AttackStart(who); - - if(!m_creature->isInCombat()) + if(!m_creature->isInCombat())//AttackStart() sets UNIT_FLAG_IN_COMBAT, so this msut be before attacking StartEvent(); + + if(Phase != 2) + AttackStart(who); } } } @@ -365,7 +364,7 @@ struct TRINITY_DLL_DECL boss_lady_vashjAI : public ScriptedAI //Static Charge //Used on random people (only 1 person at any given time) in Phases 1 and 3, it's a debuff doing 2775 to 3225 Nature damage to the target and everybody in about 5 yards around it, every 1 seconds for 30 seconds. It can be removed by Cloak of Shadows, Iceblock, Divine Shield, etc, but not by Cleanse or Dispel Magic. Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true); if(target && !target->HasAura(SPELL_STATIC_CHARGE_TRIGGER)) //cast Static Charge every 2 seconds for 20 seconds diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp index d0abd5edbd6..243cf223157 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp @@ -111,10 +111,19 @@ struct TRINITY_DLL_DECL mob_inner_demonAI : public ScriptedAI if (m_creature->getVictim()->GetGUID() != victimGUID) { + DoModifyThreatPercent(m_creature->getVictim(), -100); Unit* owner = Unit::GetUnit((*m_creature),victimGUID); - if (owner) - AttackStart(owner); + if (owner && owner->isAlive()) + { + m_creature->AddThreat(owner,999999); + AttackStart(owner); + }else if(owner && owner->isDead()) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + return; + } } + if(Link_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_SOUL_LINK, true); @@ -201,14 +210,9 @@ struct TRINITY_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI for(uint8 i = 0; i < 3; i++) { Creature *add = Unit::GetCreature(*m_creature,SpellBinderGUID[i]); - if (add && add->isAlive()) - { - add->setDeathState(DEAD); - add->RemoveCorpse(); - }else{ - if(add && add->isDead()) - add->RemoveCorpse(); - } + if (add) + add->RemoveFromWorld(); + float nx = x; float ny = y; float o = 2.4f; @@ -433,6 +437,7 @@ struct TRINITY_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI //Enrage_Timer ( 10 min ) if(Berserk_Timer < diff && !EnrageUsed) { + m_creature->InterruptNonMeleeSpells(false); DoCast(m_creature, SPELL_BERSERK); EnrageUsed = true; }else Berserk_Timer -= diff; @@ -550,6 +555,8 @@ struct TRINITY_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI if (!IsFinalForm && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 15) { //at this point he divides himself in two parts + CastConsumingMadness(); + DespawnDemon(); Creature *Copy = NULL; Copy = DoSpawnCreature(DEMON_FORM, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 6000); if(Copy) diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp index a832cc1c938..5a73a93f386 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/boss_warlord_kalithresh.cpp @@ -133,26 +133,6 @@ struct TRINITY_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI } } - Creature* SelectCreatureInGrid(uint32 entry, float range) - { - Creature* pCreature = NULL; - - CellPair pair(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*m_creature, entry, true, range); - Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_creature, pCreature, creature_check); - - TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer> creature_searcher(searcher); - - CellLock<GridReadGuard> cell_lock(cell, pair); - cell_lock->Visit(cell_lock, creature_searcher,*(m_creature->GetMap())); - - return pCreature; - } - void SpellHit(Unit *caster, const SpellEntry *spell) { //hack :( @@ -177,8 +157,7 @@ struct TRINITY_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI if (Rage_Timer < diff) { - Creature* distiller = SelectCreatureInGrid(17954, 100); - if (distiller) + if (Creature* distiller = me->FindNearestCreature(17954, 100.0f)) { DoScriptText(SAY_REGEN, m_creature); DoCast(m_creature,SPELL_WARLORDS_RAGE); diff --git a/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp b/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp index bb4009956f9..d266e3721ae 100644 --- a/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp +++ b/src/bindings/scripts/scripts/zone/darkshore/darkshore.cpp @@ -227,7 +227,7 @@ struct TRINITY_DLL_DECL npc_threshwackonatorAI : public ScriptedAI if(me->isAlive()) { if(Player* pPlayer = Unit::GetPlayer(PlayerGUID)) - me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle()); else { me->GetMotionMaster()->MovementExpired(); @@ -246,7 +246,7 @@ struct TRINITY_DLL_DECL npc_threshwackonatorAI : public ScriptedAI me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); if(Player* pPlayer = Unit::GetPlayer(PlayerGUID)) - me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + me->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle()); DoScriptText(EMOTE_START, me); } diff --git a/src/bindings/scripts/scripts/zone/desolace/desolace.cpp b/src/bindings/scripts/scripts/zone/desolace/desolace.cpp index e1366d51727..1f0e2e71286 100644 --- a/src/bindings/scripts/scripts/zone/desolace/desolace.cpp +++ b/src/bindings/scripts/scripts/zone/desolace/desolace.cpp @@ -137,7 +137,7 @@ bool EffectDummyCreature_npc_aged_dying_ancient_kodo(Unit *pCaster, uint32 spell if (pCreatureTarget->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) pCreatureTarget->GetMotionMaster()->MoveIdle(); - pCreatureTarget->GetMotionMaster()->MoveFollow(pCaster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + pCreatureTarget->GetMotionMaster()->MoveFollow(pCaster, PET_FOLLOW_DIST, pCreatureTarget->GetFollowAngle()); } //always return true when we are handling this spell and effect diff --git a/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp b/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp index 8a1e991a6e6..7357789a5aa 100644 --- a/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp +++ b/src/bindings/scripts/scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp @@ -45,7 +45,7 @@ struct TRINITY_DLL_DECL mobs_ghoul_flayerAI : public ScriptedAI void JustDied(Unit* Killer) { if( Killer->GetTypeId() == TYPEID_PLAYER ) - DoSpawnCreature(11064, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 60000); + m_creature->SummonCreature(11064, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000); } }; diff --git a/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp b/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp index 7780ef26ff0..1717b8e619b 100644 --- a/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp +++ b/src/bindings/scripts/scripts/zone/eastern_plaguelands/the_scarlet_enclave.cpp @@ -22,25 +22,495 @@ #define GCD_CAST 1 /*###### -##Quest 12848 +## npc_a_special_surprise ######*/ -#define SAY_EVENT_START "I will dismantle this festering hellhole!" -#define SAY_EVENT_ATTACK "It ends here!" +enum SpecialSurprise +{ + SAY_EXEC_START_1 = -1609025, // speech for all + SAY_EXEC_START_2 = -1609026, + SAY_EXEC_START_3 = -1609027, + SAY_EXEC_PROG_1 = -1609028, + SAY_EXEC_PROG_2 = -1609029, + SAY_EXEC_PROG_3 = -1609030, + SAY_EXEC_PROG_4 = -1609031, + SAY_EXEC_PROG_5 = -1609032, + SAY_EXEC_PROG_6 = -1609033, + SAY_EXEC_PROG_7 = -1609034, + SAY_EXEC_NAME_1 = -1609035, + SAY_EXEC_NAME_2 = -1609036, + SAY_EXEC_RECOG_1 = -1609037, + SAY_EXEC_RECOG_2 = -1609038, + SAY_EXEC_RECOG_3 = -1609039, + SAY_EXEC_RECOG_4 = -1609040, + SAY_EXEC_RECOG_5 = -1609041, + SAY_EXEC_RECOG_6 = -1609042, + SAY_EXEC_NOREM_1 = -1609043, + SAY_EXEC_NOREM_2 = -1609044, + SAY_EXEC_NOREM_3 = -1609045, + SAY_EXEC_NOREM_4 = -1609046, + SAY_EXEC_NOREM_5 = -1609047, + SAY_EXEC_NOREM_6 = -1609048, + SAY_EXEC_NOREM_7 = -1609049, + SAY_EXEC_NOREM_8 = -1609050, + SAY_EXEC_NOREM_9 = -1609051, + SAY_EXEC_THINK_1 = -1609052, + SAY_EXEC_THINK_2 = -1609053, + SAY_EXEC_THINK_3 = -1609054, + SAY_EXEC_THINK_4 = -1609055, + SAY_EXEC_THINK_5 = -1609056, + SAY_EXEC_THINK_6 = -1609057, + SAY_EXEC_THINK_7 = -1609058, + SAY_EXEC_THINK_8 = -1609059, + SAY_EXEC_THINK_9 = -1609060, + SAY_EXEC_THINK_10 = -1609061, + SAY_EXEC_LISTEN_1 = -1609062, + SAY_EXEC_LISTEN_2 = -1609063, + SAY_EXEC_LISTEN_3 = -1609064, + SAY_EXEC_LISTEN_4 = -1609065, + SAY_PLAGUEFIST = -1609066, + SAY_EXEC_TIME_1 = -1609067, + SAY_EXEC_TIME_2 = -1609068, + SAY_EXEC_TIME_3 = -1609069, + SAY_EXEC_TIME_4 = -1609070, + SAY_EXEC_TIME_5 = -1609071, + SAY_EXEC_TIME_6 = -1609072, + SAY_EXEC_TIME_7 = -1609073, + SAY_EXEC_TIME_8 = -1609074, + SAY_EXEC_TIME_9 = -1609075, + SAY_EXEC_TIME_10 = -1609076, + SAY_EXEC_WAITING = -1609077, + EMOTE_DIES = -1609078, + + NPC_PLAGUEFIST = 29053 +}; -#define SPELL_SOUL_PRISON_CHAIN_SELF 54612 -#define SPELL_SOUL_PRISON_CHAIN 54613 +struct TRINITY_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI +{ + npc_a_special_surpriseAI(Creature *pCreature) : ScriptedAI(pCreature) {} + + uint32 ExecuteSpeech_Timer; + uint32 ExecuteSpeech_Counter; + uint64 PlayerGUID; + + void Reset() + { + ExecuteSpeech_Timer = 0; + ExecuteSpeech_Counter = 0; + PlayerGUID = 0; -#define SPELL_ICY_TOUCH 52372 -#define SPELL_PLAGUE_STRIKE 52373 -#define SPELL_BLOOD_STRIKE 52374 -#define SPELL_DEATH_COIL 52375 + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + } + + bool MeetQuestCondition(Unit* pPlayer) + { + switch(me->GetEntry()) + { + case 29061: // Ellen Stanbridge + if (CAST_PLR(pPlayer)->GetQuestStatus(12742) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29072: // Kug Ironjaw + if (CAST_PLR(pPlayer)->GetQuestStatus(12748) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29067: // Donovan Pulfrost + if (CAST_PLR(pPlayer)->GetQuestStatus(12744) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29065: // Yazmina Oakenthorn + if (CAST_PLR(pPlayer)->GetQuestStatus(12743) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29071: // Antoine Brack + if (CAST_PLR(pPlayer)->GetQuestStatus(12750) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29032: // Malar Bravehorn + if (CAST_PLR(pPlayer)->GetQuestStatus(12739) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29068: // Goby Blastenheimer + if (CAST_PLR(pPlayer)->GetQuestStatus(12745) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29073: // Iggy Darktusk + if (CAST_PLR(pPlayer)->GetQuestStatus(12749) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29074: // Lady Eonys + if (CAST_PLR(pPlayer)->GetQuestStatus(12747) == QUEST_STATUS_INCOMPLETE) + return true; + break; + case 29070: // Valok the Righteous + if (CAST_PLR(pPlayer)->GetQuestStatus(12746) == QUEST_STATUS_INCOMPLETE) + return true; + break; + } + + return false; + } + + void MoveInLineOfSight(Unit* pWho) + { + if (PlayerGUID || pWho->GetTypeId() != TYPEID_PLAYER || !pWho->IsWithinDist(me, INTERACTION_DISTANCE)) + return; + + if (MeetQuestCondition(pWho)) + PlayerGUID = pWho->GetGUID(); + } + + void UpdateAI(const uint32 diff) + { + if (PlayerGUID && !me->getVictim() && me->isAlive()) + { + if (ExecuteSpeech_Timer < diff) + { + Player* pPlayer = Unit::GetPlayer(PlayerGUID); + + if (!pPlayer) + { + Reset(); + return; + } + + //TODO: simplify text's selection + + switch(pPlayer->getRace()) + { + case RACE_HUMAN: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_5, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_1, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_5, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_7, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_1, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_6, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_ORC: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_6, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_1, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_7, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_8, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_1, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_8, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_DWARF: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_2, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_2, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_3, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_2, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_5, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_2, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_3, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_NIGHTELF: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_5, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_1, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_6, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_2, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_1, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_7, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_UNDEAD_PLAYER: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_3, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_4, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_3, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_1, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_3, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_4, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_TAUREN: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_1, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_5, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_8, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_9, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_1, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_9, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_GNOME: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_4, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_1, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_4, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_6, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_1, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_5, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_TROLL: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_3, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_7, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_2, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_6, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_9, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_10, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_4, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_10, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_BLOODELF: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_1, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_1, me, pPlayer); break; + //case 5: //unknown + case 6: DoScriptText(SAY_EXEC_THINK_3, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_1, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_1, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + case RACE_DRAENEI: + switch(ExecuteSpeech_Counter) + { + case 0: DoScriptText(SAY_EXEC_START_1, me, pPlayer); break; + case 1: me->SetStandState(UNIT_STAND_STATE_STAND); break; + case 2: DoScriptText(SAY_EXEC_PROG_1, me, pPlayer); break; + case 3: DoScriptText(SAY_EXEC_NAME_1, me, pPlayer); break; + case 4: DoScriptText(SAY_EXEC_RECOG_2, me, pPlayer); break; + case 5: DoScriptText(SAY_EXEC_NOREM_1, me, pPlayer); break; + case 6: DoScriptText(SAY_EXEC_THINK_4, me, pPlayer); break; + case 7: DoScriptText(SAY_EXEC_LISTEN_1, me, pPlayer); break; + case 8: + if (Creature* Plaguefist = GetClosestCreatureWithEntry(me, NPC_PLAGUEFIST, 85.0f)) + DoScriptText(SAY_PLAGUEFIST, Plaguefist, pPlayer); + break; + case 9: + DoScriptText(SAY_EXEC_TIME_2, me, pPlayer); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + break; + case 10: DoScriptText(SAY_EXEC_WAITING, me, pPlayer); break; + case 11: + DoScriptText(EMOTE_DIES, me); + me->setDeathState(JUST_DIED); + me->SetHealth(0); + return; + } + break; + } + + if (ExecuteSpeech_Counter >= 9) + ExecuteSpeech_Timer = 15000; + else + ExecuteSpeech_Timer = 7000; + + ++ExecuteSpeech_Counter; + } + else + ExecuteSpeech_Timer -= diff; + } + } +}; + +CreatureAI* GetAI_npc_a_special_surprise(Creature* pCreature) +{ + return new npc_a_special_surpriseAI(pCreature); +} + +/*###### +##Quest 12848 +######*/ + +enum +{ + SPELL_SOUL_PRISON_CHAIN_SELF = 54612, + SPELL_SOUL_PRISON_CHAIN = 54613, + SPELL_DK_INITIATE_VISUAL = 51519, + + SPELL_ICY_TOUCH = 52372, + SPELL_PLAGUE_STRIKE = 52373, + SPELL_BLOOD_STRIKE = 52374, + SPELL_DEATH_COIL = 52375 +}; #define EVENT_ICY_TOUCH 1 #define EVENT_PLAGUE_STRIKE 2 #define EVENT_BLOOD_STRIKE 3 #define EVENT_DEATH_COIL 4 +int32 say_event_start[8] = +{ + -1609000,-1609001,-1609002,-1609003, + -1609004,-1609005,-1609006,-1609007 +}; + +int32 say_event_attack[9] = +{ + -1609008,-1609009,-1609010,-1609011,-1609012, + -1609013,-1609014,-1609015,-1609016 +}; + uint32 acherus_soul_prison[12] = { 191577, @@ -75,54 +545,6 @@ enum initiate_phase Attacking }; -float modelid_dk_armor[20] = -{ - 25432, // bloodelf female - 25422, // bloodelf male - 25412, // draenei female - 25420, // draenei male - 25406, // dwarf female - 25414, // dwarf male - 25438, // forsaken female - 25426, // forsaken male - 25408, // gnome female - 25426, // gnome male - 25404, // human female - 25375, // human male - 25410, // nightelf female - 25418, // nightelf male - 25436, // orc female - 25424, // orc male - 25440, // tauren female - 25430, // tauren male - 25434, // troll female - 25428 // troll male -}; - -float modelid_dk_unworthy[20] = -{ - 25369, // bloodelf female - 25373, // bloodelf male - 25363, // draenei female - 25357, // draenei male - 25361, // dwarf female - 25356, // dwarf male - 25372, // forsaken female - 25367, // forsaken male - 25362, // gnome female - 25359, // gnome male - 25355, // human female - 25354, // human male - 25360, // nightelf female - 25358, // nightelf male - 25368, // orc female - 25364, // orc male - 25371, // tauren female - 25366, // tauren male - 25370, // troll female - 25365 // troll male -}; - struct TRINITY_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI { npc_unworthy_initiateAI(Creature *c) : ScriptedAI(c) @@ -146,12 +568,12 @@ struct TRINITY_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI phase = Chained; events.Reset(); m_creature->setFaction(7); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 8); m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID , 0); m_creature->SetDisplayId(m_creature->GetNativeDisplayId()); event_starter = 0; event_startet = false; - m_creature->SetHomePosition(home_x,home_y,home_z,home_ori); m_creature->GetMotionMaster()->MoveTargetedHome(); } @@ -168,23 +590,7 @@ struct TRINITY_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI { if(m_creature->GetEntry() != 29519) if(killer->GetTypeId() == TYPEID_PLAYER) - CAST_PLR(killer)->KilledMonster(29519,m_creature->GetGUID()); - } - - void AddEquipp() - { - int model_counter = 0; - for(uint8 i = 0; i< 20; i++) - { - if(m_creature->GetDisplayId() == modelid_dk_unworthy[i]) - { - model_counter = i; - break; - } - } - - m_creature->SetDisplayId(modelid_dk_armor[model_counter]); - m_creature->LoadEquipment(m_creature->GetEquipmentId()); + CAST_PLR(killer)->KilledMonsterCredit(29519,m_creature->GetGUID()); } void MovementInform(uint32 type, uint32 id) @@ -195,9 +601,10 @@ struct TRINITY_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI if(id == 1) { wait_timer = 5000; - AddEquipp(); + m_creature->CastSpell(m_creature,SPELL_DK_INITIATE_VISUAL,true); - DoSay(SAY_EVENT_ATTACK,LANG_UNIVERSAL,NULL,true); + if(Unit* starter = Unit::GetUnit((*m_creature),event_starter)) + DoScriptText(say_event_attack[rand()%9],m_creature,starter); phase = ToAttacking; } @@ -215,8 +622,9 @@ struct TRINITY_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI m_creature->RemoveAurasDueToSpell(SPELL_SOUL_PRISON_CHAIN_SELF); m_creature->RemoveAurasDueToSpell(SPELL_SOUL_PRISON_CHAIN); - DoSay(SAY_EVENT_START,LANG_UNIVERSAL,NULL,true); event_starter = target->GetGUID(); + if(Unit* starter = Unit::GetUnit((*m_creature),event_starter)) + DoScriptText(say_event_start[rand()%8],m_creature,starter); } void UpdateAI(const uint32 diff); @@ -383,126 +791,256 @@ bool GOHello_go_acherus_soul_prison(Player *player, GameObject* _GO) ## npc_death_knight_initiate ######*/ -#define GOSSIP_DKI "Duel with me!" +#define GOSSIP_ACCEPT_DUEL "[PH] I challenge you!" -const char * SAY_DKI_DUEL1 = "Remember this day, $N, for it is the day that you will be thoroughly owned."; -const char * SAY_DKI_DUEL2 = "I'm going to tear your heart out, cupcake!"; -const char * SAY_DKI_DUEL3 = "You have challenged death itself!"; -const char * SAY_DKI_DUEL4 = "Don't make me laugh."; -const char * SAY_DKI_DUEL5 = "Here come the tears..."; -const char * SAY_DKI_DUEL6 = "No potions!"; -#define SAY_DKI_DUEL RAND(SAY_DKI_DUEL1,SAY_DKI_DUEL2,SAY_DKI_DUEL3,SAY_DKI_DUEL4,SAY_DKI_DUEL5,SAY_DKI_DUEL6) +enum +{ + SAY_DUEL_A = -1609017, + SAY_DUEL_B = -1609018, + SAY_DUEL_C = -1609019, + SAY_DUEL_D = -1609020, + SAY_DUEL_E = -1609021, + SAY_DUEL_F = -1609022, + + SPELL_DUEL = 52996, + SPELL_DUEL_TRIGGERED = 52990, + SPELL_DUEL_VICTORY = 52994, + SPELL_DUEL_FLAG = 52991, + + QUEST_DEATH_CHALLENGE = 12733, + FACTION_HOSTILE = 2068 +}; -#define SPELL_DUEL_FLAG 52991 +int32 m_auiRandomSay[] = +{ + SAY_DUEL_A, SAY_DUEL_B, SAY_DUEL_C, SAY_DUEL_D, SAY_DUEL_E, SAY_DUEL_F +}; -struct TRINITY_DLL_DECL npc_death_knight_initiateAI : public SpellAI +struct TRINITY_DLL_DECL npc_death_knight_initiateAI : public ScriptedAI { - npc_death_knight_initiateAI(Creature *c) : SpellAI(c) {} + npc_death_knight_initiateAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint64 m_uiDuelerGUID; + uint32 m_uiDuelTimer; + bool m_bIsDuelInProgress; void Reset() { me->RestoreFaction(); - lose = false; - SpellAI::Reset(); - } - bool lose; + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15); - void EnterCombat(Unit *who) + m_uiDuelerGUID = 0; + m_uiDuelTimer = 5000; + m_bIsDuelInProgress = false; + } + + void AttackedBy(Unit* pAttacker) { - if(who->GetTypeId() == TYPEID_PLAYER) - me->MonsterSay(SAY_DKI_DUEL, LANG_UNIVERSAL, who->GetGUID()); - SpellAI::EnterCombat(who); + if (m_creature->getVictim()) + return; + + if (m_creature->IsFriendlyTo(pAttacker)) + return; + + AttackStart(pAttacker); } - void UpdateAI(const uint32 diff) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) { - if(me->getVictim() && me->getVictim()->GetTypeId() == TYPEID_PLAYER) + if (!m_bIsDuelInProgress && pSpell->Id == SPELL_DUEL_TRIGGERED) { - if(lose) - { - if(!me->HasAura(7267)) // beg aura has faded - { - CAST_PLR(me->getVictim())->KilledMonster(29025,m_creature->GetGUID()); - EnterEvadeMode(); - } - return; - } - else if(me->getVictim()->GetHealth() * 10 < me->getVictim()->GetMaxHealth()) - { - me->getVictim()->CastSpell(me->getVictim(), 7267, true); // beg - me->getVictim()->RemoveGameObject(SPELL_DUEL_FLAG, true); - EnterEvadeMode(); - return; // must return after enterevademode - } + m_uiDuelerGUID = pCaster->GetGUID(); + m_bIsDuelInProgress = true; } + } + + void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + { + if (m_bIsDuelInProgress && uiDamage > m_creature->GetHealth()) + { + uiDamage = 0; - SpellAI::UpdateAI(diff); + if (Unit* pUnit = Unit::GetUnit(*m_creature, m_uiDuelerGUID)) + m_creature->CastSpell(pUnit, SPELL_DUEL_VICTORY, true); + + //possibly not evade, but instead have end sequenze + EnterEvadeMode(); + } } - void DamageTaken(Unit *done_by, uint32 & damage) + void UpdateAI(const uint32 uiDiff) { - if(done_by->GetTypeId() == TYPEID_PLAYER) + if (!UpdateVictim()) { - if(done_by != me->getVictim()) - damage = 0; // not allow other player to help - else if(damage > me->GetHealth()) + if (m_bIsDuelInProgress) { - damage = 0; - done_by->AttackStop(); - if(!lose) + if (m_uiDuelTimer < uiDiff) { - lose = true; - me->CastSpell(me, 7267, true); // beg - me->getVictim()->RemoveGameObject(SPELL_DUEL_FLAG, true); - me->RestoreFaction(); + m_creature->setFaction(FACTION_HOSTILE); + + if (Unit* pUnit = Unit::GetUnit(*m_creature, m_uiDuelerGUID)) + AttackStart(pUnit); } + else + m_uiDuelTimer -= uiDiff; } + return; } + + // TODO: spells + + DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_npc_death_knight_initiate(Creature *_Creature) +CreatureAI* GetAI_npc_death_knight_initiate(Creature* pCreature) { - return new npc_death_knight_initiateAI(_Creature); + return new npc_death_knight_initiateAI(pCreature); } -bool GossipHello_npc_death_knight_initiate(Player *player, Creature *_Creature) +bool GossipHello_npc_death_knight_initiate(Player* pPlayer, Creature* pCreature) { - if( player->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE && _Creature->GetHealth() == _Creature->GetMaxHealth()) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_DKI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(),_Creature->GetGUID()); + if (pPlayer->GetQuestStatus(QUEST_DEATH_CHALLENGE) == QUEST_STATUS_INCOMPLETE && pCreature->GetHealth() == pCreature->GetMaxHealth()) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ACCEPT_DUEL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->SEND_GOSSIP_MENU(pCreature->GetNpcTextId(),pCreature->GetGUID()); + } return true; } -bool GossipSelect_npc_death_knight_initiate(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +bool GossipSelect_npc_death_knight_initiate(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) { - if( action == GOSSIP_ACTION_INFO_DEF ) + if( uiAction == GOSSIP_ACTION_INFO_DEF ) { - player->CastSpell(player, SPELL_DUEL_FLAG, true); - if (player->GetTeam() == HORDE ) // Check the player team, then choose faction - _Creature->setFaction(1); - else - _Creature->setFaction(2); - _Creature->AI()->AttackStart(player); + pPlayer->CLOSE_GOSSIP_MENU(); + + if (((npc_death_knight_initiateAI*)pCreature)->m_bIsDuelInProgress) + return true; + + pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15); + + int32 uiSayId = rand()% (sizeof(m_auiRandomSay)/sizeof(int32)); + DoScriptText(m_auiRandomSay[uiSayId], pCreature, pPlayer); + + pCreature->CastSpell(pPlayer, SPELL_DUEL, false); + pCreature->CastSpell(pPlayer, SPELL_DUEL_FLAG, true); } return true; } /*###### +## npc_dark_rider_of_acherus +######*/ + +#define DESPAWN_HORSE 52267 + +struct TRINITY_DLL_DECL npc_dark_rider_of_acherusAI : public ScriptedAI +{ + npc_dark_rider_of_acherusAI(Creature *c) : ScriptedAI(c) {} + + uint32 PhaseTimer; + uint32 Phase; + bool Intro; + Unit *Target; + + void Reset() + { + PhaseTimer = 4000; + Phase = 0; + Intro = false; + Target = NULL; + } + + void UpdateAI(const uint32 diff) + { + if (!Intro) + return; + + if (PhaseTimer < diff) + { + switch(Phase) + { + case 0: + DoSay("The realm of shadows awaits...", LANG_UNIVERSAL, NULL); + PhaseTimer = 5000; + Phase = 1; + break; + case 1: + DoCast(Target, DESPAWN_HORSE, true); + PhaseTimer = 3000; + Phase = 2; + break; + case 2: + m_creature->SetVisibility(VISIBILITY_OFF); + PhaseTimer = 2000; + Phase = 3; + break; + case 3: + m_creature->ForcedDespawn(); + break; + default: + break; + } + }else PhaseTimer -= diff; + + } + + void InitDespawnHorse(Unit *who) + { + if (!who) + return; + + Target = who; + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + m_creature->SetSpeed(MOVE_RUN, 0.4f); + m_creature->GetMotionMaster()->MoveChase(Target); + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Target->GetGUID()); + Intro = true; + } + +}; + +CreatureAI* GetAI_npc_dark_rider_of_acherus(Creature *_Creature) +{ + return new npc_dark_rider_of_acherusAI(_Creature); +} + +/*###### ## npc_salanar_the_horseman ######*/ enum { - REALM_OF_SHADOWS = 52693 + REALM_OF_SHADOWS = 52693, + DELIVER_STOLEN_HORSE = 52264, + CALL_DARK_RIDER = 52266 }; struct TRINITY_DLL_DECL npc_salanar_the_horsemanAI : public ScriptedAI { npc_salanar_the_horsemanAI(Creature *c) : ScriptedAI(c) {} + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (spell->Id == DELIVER_STOLEN_HORSE) + { + if(caster->GetTypeId() == TYPEID_UNIT && CAST_CRE(caster)->isVehicle()) + { + if( Unit *charmer = caster->GetCharmer() ) + { + CAST_PLR(charmer)->ExitVehicle(); + caster->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + caster->setFaction(35); + DoCast(caster, CALL_DARK_RIDER, true); + Creature* Dark_Rider = m_creature->FindNearestCreature(28654, 15); + if (Dark_Rider) + CAST_AI(npc_dark_rider_of_acherusAI, Dark_Rider->AI())->InitDespawnHorse(caster); + } + } + } + } + void MoveInLineOfSight(Unit *who) { ScriptedAI::MoveInLineOfSight(who); @@ -515,11 +1053,6 @@ struct TRINITY_DLL_DECL npc_salanar_the_horsemanAI : public ScriptedAI { switch(me->GetEntry()) { - // for quest Grand Theft Palomino(12680) - case 28653: - if( CAST_PLR(charmer)->GetQuestStatus(12680) == QUEST_STATUS_INCOMPLETE ) - CAST_PLR(charmer)->KilledMonster(28767, me->GetGUID()); - break; // for quest Into the Realm of Shadows(12687) case 28788: if( CAST_PLR(charmer)->GetQuestStatus(12687) == QUEST_STATUS_INCOMPLETE ) @@ -604,8 +1137,8 @@ struct TRINITY_DLL_DECL npc_dkc1_gothikAI : public ScriptedAI { if(CAST_PLR(owner)->GetQuestStatus(12698) == QUEST_STATUS_INCOMPLETE) { - CAST_PLR(owner)->KilledMonster(28845, me->GetGUID()); - who->setDeathState(DEAD); + DoCast(owner, 52517, true); + CAST_CRE(who)->ForcedDespawn(); } } } @@ -620,6 +1153,107 @@ CreatureAI* GetAI_npc_dkc1_gothik(Creature *_Creature) // npc 28912 quest 17217 boss 29001 mob 29007 go 191092 +/*#### +## npc_valkyr_battle_maiden +####*/ +#define SPELL_REVIVE 51918 +#define VALK_WHISPER "It is not yet your time, champion. Rise! Rise and fight once more!" + +struct TRINITY_DLL_DECL npc_valkyr_battle_maidenAI : public ScriptedAI +{ + npc_valkyr_battle_maidenAI(Creature *c) : ScriptedAI(c) {} + + Player *Owner; + uint32 FlyBackTimer; + uint64 TargetGUID; + float x, y, z; + uint32 phase; + + void Reset() + { + m_creature->SetVisibility(VISIBILITY_OFF); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlying(true); + FlyBackTimer = 500; + phase = 0; + + Owner = NULL; + m_creature->GetPosition(x, y, z); + z += 4; x -= 3.5; y -= 5; + m_creature->GetMotionMaster()->Clear(false); + m_creature->Relocate(x, y, z); + } + + void Aggro(Unit *who){} + + void AttackStart(Unit *who){} + + void UpdateAI(const uint32 diff) + { + if (!Owner) + { + TargetGUID = m_creature->GetOwnerGUID(); + Owner = Unit::GetPlayer(TargetGUID); + return; + } + + if (Owner->isAlive()) + phase = 4; + + if (FlyBackTimer < diff) + { + switch(phase) + { + case 0: + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + m_creature->HandleEmoteCommand(EMOTE_STATE_FLYGRABCLOSED); + FlyBackTimer = 500; + phase = 1; + break; + case 1: + Owner->GetClosePoint(x,y,z, m_creature->GetObjectSize()); + z += 2.5; x -= 2; y -= 1.5; + m_creature->GetMotionMaster()->MovePoint(0, x, y, z); + m_creature->SetUInt64Value(UNIT_FIELD_TARGET, Owner->GetGUID()); + m_creature->SetVisibility(VISIBILITY_ON); + FlyBackTimer = 4500; + phase = 2; + break; + case 2: + if(!Owner->isRessurectRequested()) + { + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOMSPELL01); + DoCast(Owner, SPELL_REVIVE,true); + DoWhisper(VALK_WHISPER,Owner); + } + FlyBackTimer = 5000; + phase = 3; + break; + case 3: + m_creature->SetVisibility(VISIBILITY_OFF); + FlyBackTimer = 2000; + phase = 4; + break; + case 4: + m_creature->setDeathState(JUST_DIED); + m_creature->RemoveCorpse(); + break; + default: + //Nothing To DO + break; + } + }else FlyBackTimer-=diff; + } + + void MoveInLineOfSight(Unit *who){} + +}; + +CreatureAI* GetAI_npc_valkyr_battle_maiden(Creature *_Creature) +{ + return new npc_valkyr_battle_maidenAI (_Creature); +} + void AddSC_the_scarlet_enclave() { Script *newscript; @@ -641,9 +1275,14 @@ void AddSC_the_scarlet_enclave() newscript = new Script; newscript->Name="npc_death_knight_initiate"; + newscript->GetAI = &GetAI_npc_death_knight_initiate; newscript->pGossipHello = &GossipHello_npc_death_knight_initiate; newscript->pGossipSelect = &GossipSelect_npc_death_knight_initiate; - newscript->GetAI = &GetAI_npc_death_knight_initiate; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_dark_rider_of_acherus"; + newscript->GetAI = &GetAI_npc_dark_rider_of_acherus; newscript->RegisterSelf(); newscript = new Script; @@ -660,4 +1299,14 @@ void AddSC_the_scarlet_enclave() newscript->Name="npc_dkc1_gothik"; newscript->GetAI = &GetAI_npc_dkc1_gothik; newscript->RegisterSelf(); -}
\ No newline at end of file + + newscript = new Script; + newscript->Name = "npc_a_special_surprise"; + newscript->GetAI = &GetAI_npc_a_special_surprise; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_valkyr_battle_maiden"; + newscript->GetAI = &GetAI_npc_valkyr_battle_maiden; + newscript->RegisterSelf(); +} diff --git a/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp b/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp index e195929408e..07b9179b9af 100644 --- a/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp +++ b/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp @@ -497,24 +497,11 @@ CreatureAI* GetAI_npc_secondTrial(Creature *_Creature) ## go_second_trial ######*/ -bool GOHello_go_second_trial(Player *player, GameObject* _GO) +bool GOHello_go_second_trial(Player *player, GameObject* pGO) { // find spawn :: master_kelerun_bloodmourn - CellPair p(Trinity::ComputeCellPair(_GO->GetPositionX(), _GO->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - CellLock<GridReadGuard> cell_lock(cell, p); - - Creature* event_controller = NULL; - Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*_GO, MASTER_KELERUN_BLOODMOURN, true, 30); - Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(player, event_controller, u_check); - TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); - //cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(_GO->GetMap(), _GO)); - cell_lock->Visit(cell_lock, grid_unit_searcher, *(_GO->GetMap())); - - if ( event_controller ) - CAST_AI(master_kelerun_bloodmournAI, event_controller->AI())->StartEvent(); + if (Creature* pCreature = pGO->FindNearestCreature(MASTER_KELERUN_BLOODMOURN, 30.0f)) + CAST_AI(master_kelerun_bloodmournAI, pCreature->AI())->StartEvent(); return true; } diff --git a/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp b/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp index e2283c638e7..32e0d5dcee9 100644 --- a/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp +++ b/src/bindings/scripts/scripts/zone/ghostlands/ghostlands.cpp @@ -169,8 +169,7 @@ struct TRINITY_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI case 0: { m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - GameObject* Cage = me->FindNearestGameObject(GO_CAGE, 20); - if(Cage) + if(GameObject* Cage = me->FindNearestGameObject(GO_CAGE, 20)) Cage->SetGoState(GO_STATE_ACTIVE); DoScriptText(SAY_START, m_creature, player); break; diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp index a0b4f632c42..26520fc16df 100644 --- a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp +++ b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_gruul.cpp @@ -80,9 +80,6 @@ struct TRINITY_DLL_DECL boss_gruulAI : public ScriptedAI if (pInstance) pInstance->SetData(DATA_GRUULEVENT, NOT_STARTED); - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void EnterCombat(Unit *who) diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp index ede59d50f53..88de477d238 100644 --- a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp +++ b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp @@ -324,6 +324,21 @@ struct TRINITY_DLL_DECL boss_olm_the_summonerAI : public ScriptedAI pInstance->SetData(DATA_MAULGAREVENT, NOT_STARTED); } + void AttackStart(Unit* pWho) + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + m_creature->GetMotionMaster()->MoveChase(pWho, 30.0f); + } + } + void EnterCombat(Unit *who) { if(pInstance) @@ -718,8 +733,6 @@ struct TRINITY_DLL_DECL boss_krosh_firehandAI : public ScriptedAI DoCast(target, SPELL_BLAST_WAVE); BlastWave_Timer = 60000; }else BlastWave_Timer -= diff; - - DoMeleeAttackIfReady(); } }; diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp index 219256f4da8..f08c822a19f 100644 --- a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp +++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp @@ -191,9 +191,6 @@ struct TRINITY_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI ThunderClap_Timer = 15000; ResetThreat_Timer = 30000; - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - if (pInstance) pInstance->SetData(TYPE_OMROGG, NOT_STARTED); //End boss can use this later. O'mrogg must be defeated(DONE) or he will come to aid. } @@ -218,8 +215,8 @@ struct TRINITY_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI void EnterCombat(Unit *who) { - DoSpawnCreature(NPC_LEFT_HEAD,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN,90000); - DoSpawnCreature(NPC_RIGHT_HEAD,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,90000); + m_creature->SummonCreature(NPC_LEFT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_RIGHT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); if (Unit *pLeftHead = Unit::GetUnit(*m_creature,LeftHeadGUID)) { diff --git a/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp b/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp index 1a79bead96c..3dd7c83a30f 100644 --- a/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp +++ b/src/bindings/scripts/scripts/zone/isle_of_queldanas/isle_of_queldanas.cpp @@ -114,7 +114,7 @@ struct TRINITY_DLL_DECL npc_greengill_slaveAI : public ScriptedAI { Unit* plr = Unit::GetUnit((*m_creature), PlayerGUID); if(plr && CAST_PLR(plr)->GetQuestStatus(QUESTG) == QUEST_STATUS_INCOMPLETE) - CAST_PLR(plr)->KilledMonster(25086, m_creature->GetGUID()); + DoCast(plr, 45110, true); } DoCast(m_creature, ENRAGE); Unit* Myrmidon = me->FindNearestCreature(DM, 70); diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp index 4906f02281a..9fb9d2226bd 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_curator.cpp @@ -131,8 +131,6 @@ struct TRINITY_DLL_DECL boss_curatorAI : public ScriptedAI { AstralFlare->CastSpell(AstralFlare, SPELL_ASTRAL_FLARE_PASSIVE, false); AstralFlare->AI()->AttackStart(target); - AstralFlare->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - AstralFlare->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } //Reduce Mana by 10% of max health diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp index ab40ad745ef..b02e373d953 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_midnight.cpp @@ -81,8 +81,7 @@ struct TRINITY_DLL_DECL boss_midnightAI : public ScriptedAI if(Phase == 1 && (m_creature->GetHealth()*100)/m_creature->GetMaxHealth() < 95) { Phase = 2; - Creature *pAttumen = DoSpawnCreature(SUMMON_ATTUMEN, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); - if(pAttumen) + if (Creature* pAttumen = m_creature->SummonCreature(SUMMON_ATTUMEN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000)) { Attumen = pAttumen->GetGUID(); pAttumen->AI()->AttackStart(m_creature->getVictim()); @@ -185,9 +184,6 @@ struct TRINITY_DLL_DECL boss_attumenAI : public ScriptedAI void Reset() { ResetTimer = 2000; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void EnterCombat(Unit* who) {} diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp index 269295361e4..f94d0bf05b5 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_shade_of_aran.cpp @@ -415,12 +415,10 @@ struct TRINITY_DLL_DECL boss_aranAI : public ScriptedAI else DoScriptText(SAY_BLIZZARD2, m_creature); - Creature* Spawn = NULL; - Spawn = DoSpawnCreature(CREATURE_ARAN_BLIZZARD, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 25000); - if (Spawn) + if (Creature* pSpawn = m_creature->SummonCreature(CREATURE_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000)) { - Spawn->setFaction(m_creature->getFaction()); - Spawn->CastSpell(Spawn, SPELL_CIRCULAR_BLIZZARD, false); + pSpawn->setFaction(m_creature->getFaction()); + pSpawn->CastSpell(pSpawn, SPELL_CIRCULAR_BLIZZARD, false); } break; } @@ -434,8 +432,7 @@ struct TRINITY_DLL_DECL boss_aranAI : public ScriptedAI for (uint32 i = 0; i < 4; i++) { - Creature* pUnit = DoSpawnCreature(CREATURE_WATER_ELEMENTAL, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 90000); - if (pUnit) + if (Creature* pUnit = m_creature->SummonCreature(CREATURE_WATER_ELEMENTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 90000)) { pUnit->Attack(m_creature->getVictim(), true); pUnit->setFaction(m_creature->getFaction()); @@ -449,8 +446,7 @@ struct TRINITY_DLL_DECL boss_aranAI : public ScriptedAI { for (uint32 i = 0; i < 5; i++) { - Creature* pUnit = DoSpawnCreature(CREATURE_SHADOW_OF_ARAN, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - if (pUnit) + if (Creature* pUnit = m_creature->SummonCreature(CREATURE_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) { pUnit->Attack(m_creature->getVictim(), true); pUnit->setFaction(m_creature->getFaction()); diff --git a/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp b/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp index 510ff2f2b81..55933b8854b 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/bosses_opera.cpp @@ -243,12 +243,11 @@ struct TRINITY_DLL_DECL mob_titoAI : public ScriptedAI void boss_dorotheeAI::SummonTito() { - Creature* Tito = DoSpawnCreature(CREATURE_TITO, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - if(Tito) + if (Creature* pTito = m_creature->SummonCreature(CREATURE_TITO, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) { DoScriptText(SAY_DOROTHEE_SUMMON, m_creature); - CAST_AI(mob_titoAI, Tito->AI())->DorotheeGUID = m_creature->GetGUID(); - Tito->AI()->AttackStart(m_creature->getVictim()); + CAST_AI(mob_titoAI, pTito->AI())->DorotheeGUID = m_creature->GetGUID(); + pTito->AI()->AttackStart(m_creature->getVictim()); SummonedTito = true; TitoDied = false; } diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp index b34e7124371..7d576989055 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_felblood_kaelthas.cpp @@ -511,7 +511,7 @@ struct TRINITY_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI void JustDied(Unit* slayer) { - DoSpawnCreature(CREATURE_PHOENIX_EGG, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); + m_creature->SummonCreature(CREATURE_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); } void UpdateAI(const uint32 diff) @@ -531,7 +531,7 @@ struct TRINITY_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI if (Death_Timer < diff) { - DoSpawnCreature(CREATURE_PHOENIX_EGG, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); + m_creature->SummonCreature(CREATURE_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); m_creature->setDeathState(JUST_DIED); m_creature->RemoveCorpse(); Rebirth = false; @@ -576,7 +576,7 @@ struct TRINITY_DLL_DECL mob_felkael_phoenix_eggAI : public ScriptedAI { if (HatchTimer < diff) { - DoSpawnCreature(CREATURE_PHOENIX, 0, 0, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + m_creature->SummonCreature(CREATURE_PHOENIX, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); }else HatchTimer -= diff; diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp index 8176a7b7353..718881759bb 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp @@ -372,7 +372,7 @@ struct TRINITY_DLL_DECL boss_priestess_lackey_commonAI : public ScriptedAI ResetThreatTimer = 5000 + rand()%15000; // in case she is not alive and Reset was for some reason called, respawn her (most likely party wipe after killing her) - if (Creature* pDelrissa = (Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))) + if (Creature* pDelrissa = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_DELRISSA))) { if (!pDelrissa->isAlive()) pDelrissa->Respawn(); @@ -398,7 +398,7 @@ struct TRINITY_DLL_DECL boss_priestess_lackey_commonAI : public ScriptedAI } } - if (Creature* pDelrissa = (Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA))) + if (Creature* pDelrissa = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_DELRISSA))) { if (pDelrissa->isAlive() && !pDelrissa->getVictim()) { @@ -414,7 +414,7 @@ struct TRINITY_DLL_DECL boss_priestess_lackey_commonAI : public ScriptedAI if (!pInstance) return; - Creature* pDelrissa = (Creature*)Unit::GetUnit(*m_creature, pInstance->GetData64(DATA_DELRISSA)); + Creature* pDelrissa = Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_DELRISSA)); uint32 uiLackeyDeathCount = pInstance->GetData(DATA_DELRISSA_DEATH_COUNT); if (!pDelrissa) @@ -458,7 +458,7 @@ struct TRINITY_DLL_DECL boss_priestess_lackey_commonAI : public ScriptedAI if (Creature* Delrissa = (Unit::GetCreature(*m_creature, pInstance->GetData64(DATA_DELRISSA)))) { for(uint8 i = 0; i < MAX_ACTIVE_LACKEY; ++i) - m_auiLackeyGUIDs[i] = ((boss_priestess_delrissaAI*)Delrissa->AI())->m_auiLackeyGUID[i]; + m_auiLackeyGUIDs[i] = CAST_AI(boss_priestess_delrissaAI, Delrissa->AI())->m_auiLackeyGUID[i]; } } diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp index 352b8563732..9f79c07d2ef 100644 --- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_vexallus.cpp @@ -143,10 +143,10 @@ struct TRINITY_DLL_DECL boss_vexallusAI : public ScriptedAI m_creature->CastSpell(m_creature,SPELL_SUMMON_PURE_ENERGY,false); //below are workaround summons, remove when summoning spells w/implicitTarget 73 implemented in Mangos - DoSpawnCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); if (Heroic) - DoSpawnCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_PURE_ENERGY, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); } if (ChainLightningTimer < diff) diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/magisters_terrace.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/magisters_terrace.cpp new file mode 100644 index 00000000000..d9b33bbf4fc --- /dev/null +++ b/src/bindings/scripts/scripts/zone/magisters_terrace/magisters_terrace.cpp @@ -0,0 +1,174 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Magisters_Terrace +SD%Complete: 100 +SDComment: Quest support: 11490(post-event) +SDCategory: Magisters Terrace +EndScriptData */ + +/* ContentData +npc_kalecgos +EndContentData */ + +#include "precompiled.h" + +/*###### +## npc_kalecgos +######*/ + +enum +{ + SPELL_TRANSFORM_TO_KAEL = 44670, + SPELL_ORB_KILL_CREDIT = 46307, + NPC_KAEL = 24848, //human form entry + POINT_ID_LAND = 1 +}; + +const float afKaelLandPoint[] = {225.045, -276.236, -5.434}; + +#define GOSSIP_ITEM_KAEL_1 "Who are you?" +#define GOSSIP_ITEM_KAEL_2 "What can we do to assist you?" +#define GOSSIP_ITEM_KAEL_3 "What brings you to the Sunwell?" +#define GOSSIP_ITEM_KAEL_4 "You're not alone here?" +#define GOSSIP_ITEM_KAEL_5 "What would Kil'jaeden want with a mortal woman?" + +// This is friendly keal that appear after used Orb. +// If we assume DB handle summon, summon appear somewhere outside the platform where Orb is +struct TRINITY_DLL_DECL npc_kalecgosAI : public ScriptedAI +{ + npc_kalecgosAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 m_uiTransformTimer; + + void Reset() + { + m_uiTransformTimer = 0; + + // we must assume he appear as dragon somewhere outside the platform of orb, and then move directly to here + if (m_creature->GetEntry() != NPC_KAEL) + m_creature->GetMotionMaster()->MovePoint(POINT_ID_LAND, afKaelLandPoint[0], afKaelLandPoint[1], afKaelLandPoint[2]); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (uiPointId == POINT_ID_LAND) + m_uiTransformTimer = MINUTE*IN_MILISECONDS; + } + + // some targeting issues with the spell, so use this workaround as temporary solution + void DoWorkaroundForQuestCredit() + { + Map* pMap = m_creature->GetMap(); + + if (!pMap || pMap->IsHeroic()) + return; + + Map::PlayerList const &lList = pMap->GetPlayers(); + + if (lList.isEmpty()) + return; + + SpellEntry const* pSpell = GetSpellStore()->LookupEntry(SPELL_ORB_KILL_CREDIT); + + for(Map::PlayerList::const_iterator i = lList.begin(); i != lList.end(); ++i) + { + if (Player* pPlayer = i->getSource()) + { + if (pSpell && pSpell->EffectMiscValue[0]) + pPlayer->KilledMonsterCredit(pSpell->EffectMiscValue[0], 0); + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (m_uiTransformTimer) + { + if (m_uiTransformTimer < uiDiff) + { + m_creature->CastSpell(m_creature,SPELL_ORB_KILL_CREDIT,false); + DoWorkaroundForQuestCredit(); + + // Transform and update entry, now ready for quest/read gossip + m_creature->CastSpell(m_creature,SPELL_TRANSFORM_TO_KAEL,false); + m_creature->UpdateEntry(NPC_KAEL); + + m_uiTransformTimer = 0; + }else m_uiTransformTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_kalecgos(Creature* pCreature) +{ + return new npc_kalecgosAI(pCreature); +} + +bool GossipHello_npc_kalecgos(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetGUID()); + + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->SEND_GOSSIP_MENU(12498, pCreature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_kalecgos(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +{ + switch(uiAction) + { + case GOSSIP_ACTION_INFO_DEF: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(12500, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(12502, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(12606, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->SEND_GOSSIP_MENU(12607, pCreature->GetGUID()); + break; + case GOSSIP_ACTION_INFO_DEF+4: + pPlayer->SEND_GOSSIP_MENU(12608, pCreature->GetGUID()); + break; + } + + return true; +} + +void AddSC_magisters_terrace() +{ + Script *newscript; + + newscript = new Script; + newscript->Name = "npc_kalecgos"; + newscript->GetAI = &GetAI_npc_kalecgos; + newscript->pGossipHello = &GossipHello_npc_kalecgos; + newscript->pGossipSelect = &GossipSelect_npc_kalecgos; + newscript->RegisterSelf(); +} diff --git a/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp b/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp index d90c8b1d817..a89c0c3325a 100644 --- a/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp +++ b/src/bindings/scripts/scripts/zone/nagrand/nagrand.cpp @@ -547,7 +547,7 @@ struct TRINITY_DLL_DECL npc_creditmarker_visit_with_ancestorsAI : public Scripte { // 18840: Sunspring, 18841: Laughing, 18842: Garadar, 18843: Bleeding if(!CAST_PLR(who)->GetReqKillOrCastCurrentCount(10085, creditMarkerId)) - CAST_PLR(who)->KilledMonster(creditMarkerId, m_creature->GetGUID()); + CAST_PLR(who)->KilledMonsterCredit(creditMarkerId, m_creature->GetGUID()); } } } diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp index e29143b6d12..ef0142cfd42 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp @@ -67,6 +67,13 @@ struct TRINITY_DLL_DECL boss_nothAI : public BossAI uint32 waveCount, balconyCount; + void Reset() + { + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + _Reset(); + } + void EnterCombat(Unit *who) { _EnterCombat(); @@ -77,6 +84,8 @@ struct TRINITY_DLL_DECL boss_nothAI : public BossAI void EnterPhaseGround() { + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); DoZoneInCombat(); if(me->getThreatManager().isThreatListEmpty()) EnterEvadeMode(); @@ -147,7 +156,7 @@ struct TRINITY_DLL_DECL boss_nothAI : public BossAI return; case EVENT_BALCONY: me->SetReactState(REACT_PASSIVE); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->AttackStop(); me->RemoveAllAuras(); me->NearTeleportTo(TELE_X, TELE_Y, TELE_Z, TELE_O); @@ -172,8 +181,6 @@ struct TRINITY_DLL_DECL boss_nothAI : public BossAI case EVENT_GROUND: { ++balconyCount; - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); float x, y, z, o; me->GetHomePosition(x, y, z, o); me->NearTeleportTo(x, y, z, o); diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp index 05dea45ed25..47b991e8346 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp @@ -161,7 +161,7 @@ struct TRINITY_DLL_DECL boss_sapphironAI : public BossAI if(Player *player = Unit::GetPlayer(itr->first)) player->RemoveAura(SPELL_ICEBOLT); if(GameObject *go = GameObject::GetGameObject(*me, itr->second)) - go->Delete(); + go->DeleteObjectWithOwner(); } iceblocks.clear(); } diff --git a/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp b/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp index e1e6ba011e6..1a8a41649e0 100644 --- a/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp +++ b/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp @@ -255,7 +255,7 @@ struct TRINITY_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI { Unit* u = Unit::GetUnit((*m_creature),someplayer); if( u && u->GetTypeId() == TYPEID_PLAYER ) - CAST_PLR(u)->KilledMonster(m_creature->GetEntry(),m_creature->GetGUID()); + CAST_PLR(u)->KilledMonsterCredit(m_creature->GetEntry(),m_creature->GetGUID()); DoCast(m_creature,SPELL_DISABLE_VISUAL); } if( goConsole ) @@ -391,27 +391,6 @@ struct TRINITY_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI void EnterCombat(Unit *who) { } - //Select any creature in a grid - Creature* SelectCreatureInGrid(uint32 entry, float range) - { - Creature* pCreature = NULL; - - CellPair pair(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*m_creature, entry, true, range); - Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_creature, pCreature, creature_check); - - TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer> creature_searcher(searcher); - - CellLock<GridReadGuard> cell_lock(cell, pair); - cell_lock->Visit(cell_lock, creature_searcher,*(m_creature->GetMap())); - - return pCreature; - } - void JustSummoned(Creature *summoned) { pathaleonGUID = summoned->GetGUID(); @@ -473,7 +452,7 @@ struct TRINITY_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI { if (!isEvent) { - Creature *ardonis = SelectCreatureInGrid(CreatureEntry[0], 10.0f); + Creature* ardonis = me->FindNearestCreature(CreatureEntry[0], 10.0f); if (!ardonis) return false; @@ -627,26 +606,6 @@ CreatureAI* GetAI_npc_commander_dawnforge(Creature* _Creature) return new npc_commander_dawnforgeAI(_Creature); } -Creature* SearchDawnforge(Player *source, uint32 entry, float range) -{ - Creature* pCreature = NULL; - - CellPair pair(Trinity::ComputeCellPair(source->GetPositionX(), source->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*source, entry, true, range); - Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(source, pCreature, creature_check); - - TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer> creature_searcher(searcher); - - CellLock<GridReadGuard> cell_lock(cell, pair); - cell_lock->Visit(cell_lock, creature_searcher,*(source->GetMap())); - - return pCreature; -} - bool AreaTrigger_at_commander_dawnforge(Player *player, AreaTriggerEntry *at) { //if player lost aura or not have at all, we should not try start event. @@ -655,7 +614,7 @@ bool AreaTrigger_at_commander_dawnforge(Player *player, AreaTriggerEntry *at) if (player->isAlive() && player->GetQuestStatus(QUEST_INFO_GATHERING) == QUEST_STATUS_INCOMPLETE) { - Creature* Dawnforge = SearchDawnforge(player, CreatureEntry[1], 30.0f); + Creature* Dawnforge = player->FindNearestCreature(CreatureEntry[1], 30.0f); if (!Dawnforge) return false; diff --git a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_anomalus.cpp b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_anomalus.cpp index cf16afba616..e5fda84fa95 100644 --- a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_anomalus.cpp +++ b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_anomalus.cpp @@ -24,25 +24,28 @@ EndScriptData */ #include "precompiled.h" #include "def_nexus.h" +enum +{ //Spells -#define SPELL_SPARK_N 47751 -#define SPELL_SPARK_H 57062 -#define SPELL_RIFT_SHIELD 47748 -#define SPELL_CHARGE_RIFT 47747 //Works wrong (affect players, not rifts) -#define SPELL_CREATE_RIFT 47743 //Don't work, using WA -#define SPELL_ARCANE_ATTRACTION 57063 //No idea, when it's used - -#define MOB_CRAZED_MANA_WRAITH 26746 -#define MOB_CHAOTIC_RIFT 26918 -#define SPELL_CHAOTIC_ENERGY_BURST 47688 -#define SPELL_CHARGED_CHAOTIC_ENERGY_BURST 47737 -#define SPELL_ARCANEFORM 48019 //Chaotic Rift visual + SPELL_SPARK_N = 47751, + SPELL_SPARK_H = 57062, + SPELL_RIFT_SHIELD = 47748, + SPELL_CHARGE_RIFT = 47747, //Works wrong (affect players, not rifts) + SPELL_CREATE_RIFT = 47743, //Don't work, using WA + SPELL_ARCANE_ATTRACTION = 57063, //No idea, when it's used + + MOB_CRAZED_MANA_WRAITH = 26746, + MOB_CHAOTIC_RIFT = 26918, + SPELL_CHAOTIC_ENERGY_BURST = 47688, + SPELL_CHARGED_CHAOTIC_ENERGY_BURST = 47737, + SPELL_ARCANEFORM = 48019, //Chaotic Rift visual //Yell -#define SAY_AGGRO -1576010 -#define SAY_DEATH -1576011 -#define SAY_RIFT -1576012 -#define SAY_SHIELD -1576013 + SAY_AGGRO = -1576010, + SAY_DEATH = -1576011, + SAY_RIFT = -1576012, + SAY_SHIELD = -1576013 +}; float RiftLocation[6][3]= { diff --git a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_keristrasza.cpp b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_keristrasza.cpp index 02bcebb7b49..6bba503e777 100644 --- a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_keristrasza.cpp +++ b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_keristrasza.cpp @@ -24,22 +24,25 @@ EndScriptData */ #include "precompiled.h" #include "def_nexus.h" +enum +{ //Spells -#define SPELL_FROZEN_PRISON 47854 -#define SPELL_TAIL_SWEEP 50155 -#define SPELL_CRYSTAL_CHAINS 50997 -#define SPELL_ENRAGE 8599 -#define SPELL_CRYSTALFIRE_BREATH_N 48096 -#define SPELL_CRYSTALFIRE_BREATH_H 57091 -#define SPELL_CRYSTALIZE 48179 -#define SPELL_INTENSE_COLD 48094 + SPELL_FROZEN_PRISON = 47854, + SPELL_TAIL_SWEEP = 50155, + SPELL_CRYSTAL_CHAINS = 50997, + SPELL_ENRAGE = 8599, + SPELL_CRYSTALFIRE_BREATH_N = 48096, + SPELL_CRYSTALFIRE_BREATH_H = 57091, + SPELL_CRYSTALIZE = 48179, + SPELL_INTENSE_COLD = 48094, //Yell -#define SAY_AGGRO -1576040 -#define SAY_SLAY -1576041 -#define SAY_ENRAGE -1576042 -#define SAY_DEATH -1576043 -#define SAY_CRYSTAL_NOVA -1576044 + SAY_AGGRO = -1576040, + SAY_SLAY = -1576041, + SAY_ENRAGE = -1576042, + SAY_DEATH = -1576043, + SAY_CRYSTAL_NOVA = -1576044 +}; struct TRINITY_DLL_DECL boss_keristraszaAI : public ScriptedAI { diff --git a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_magus_telestra.cpp b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_magus_telestra.cpp index cec5e3546e5..5bce7c4c7e3 100644 --- a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_magus_telestra.cpp +++ b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_magus_telestra.cpp @@ -24,37 +24,38 @@ EndScriptData */ #include "precompiled.h" #include "def_nexus.h" -//Spells - -#define SPELL_ICE_NOVA_N 47772 -#define SPELL_ICE_NOVA_H 56935 -#define SPELL_FIREBOMB_N 47773 -#define SPELL_FIREBOMB_H 56934 -#define SPELL_GRAVITY_WELL 47756 -#define SPELL_TELESTRA_BACK 47714 - -float CenterOfRoom[1][4] = +enum { - {504.80, 89.07, -16.12, 6.27} -}; +//Spells + SPELL_ICE_NOVA_N = 47772, + SPELL_ICE_NOVA_H = 56935, + SPELL_FIREBOMB_N = 47773, + SPELL_FIREBOMB_H = 56934, + SPELL_GRAVITY_WELL = 47756, + SPELL_TELESTRA_BACK = 47714, //At 50% HP - 3 clones, Frost, Fire, Arcane (and in 10% HP in Heroic) -#define MOB_FIRE_MAGUS 26928 -#define MOB_FROST_MAGUS 26930 -#define MOB_ARCANE_MAGUS 26929 + MOB_FIRE_MAGUS = 26928, + MOB_FROST_MAGUS = 26930, + MOB_ARCANE_MAGUS = 26929, -#define SPELL_FIRE_MAGUS_VISUAL 47705 -#define SPELL_FROST_MAGUS_VISUAL 47706 -#define SPELL_ARCANE_MAGUS_VISUAL 47704 + SPELL_FIRE_MAGUS_VISUAL = 47705, + SPELL_FROST_MAGUS_VISUAL = 47706, + SPELL_ARCANE_MAGUS_VISUAL = 47704, //Yell -#define SAY_AGGRO -1576000 -#define SAY_KILL -1576001 -#define SAY_DEATH -1576002 -#define SAY_MERGE -1576003 -#define SAY_SPLIT_1 -1576004 -#define SAY_SPLIT_2 -1576005 + SAY_AGGRO = -1576000, + SAY_KILL = -1576001, + SAY_DEATH = -1576002, + SAY_MERGE = -1576003, + SAY_SPLIT_1 = -1576004, + SAY_SPLIT_2 = -1576005 +}; +float CenterOfRoom[1][4] = +{ + {504.80, 89.07, -16.12, 6.27} +}; struct TRINITY_DLL_DECL boss_magus_telestraAI : public ScriptedAI { @@ -83,6 +84,7 @@ struct TRINITY_DLL_DECL boss_magus_telestraAI : public ScriptedAI uint32 SPELL_ICE_NOVA_Timer; uint32 SPELL_FIREBOMB_Timer; uint32 SPELL_GRAVITY_WELL_Timer; + uint32 Cooldown; void Reset() { @@ -91,6 +93,7 @@ struct TRINITY_DLL_DECL boss_magus_telestraAI : public ScriptedAI SPELL_ICE_NOVA_Timer = 7000; SPELL_FIREBOMB_Timer = 0; SPELL_GRAVITY_WELL_Timer = 15000; + Cooldown = 0; FireMagusGUID = 0; FrostMagusGUID = 0; @@ -238,26 +241,44 @@ struct TRINITY_DLL_DECL boss_magus_telestraAI : public ScriptedAI return; } + if(Cooldown) + { + if(Cooldown < diff) + Cooldown = 0; + else + { + Cooldown -= diff; + return; + } + } + if (SPELL_ICE_NOVA_Timer < diff) { - m_creature->CastStop(); if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { DoCast(target, HeroicMode ? SPELL_ICE_NOVA_H : SPELL_ICE_NOVA_N); + Cooldown = 1500; + } SPELL_ICE_NOVA_Timer = 15000; }else SPELL_ICE_NOVA_Timer -=diff; if (SPELL_GRAVITY_WELL_Timer < diff) { - m_creature->CastStop(); if (Unit* target = m_creature->getVictim()) + { DoCast(target, SPELL_GRAVITY_WELL); + Cooldown = 6000; + } SPELL_GRAVITY_WELL_Timer = 15000; }else SPELL_GRAVITY_WELL_Timer -=diff; if (SPELL_FIREBOMB_Timer < diff) { if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { DoCast(target, HeroicMode ? SPELL_FIREBOMB_H : SPELL_FIREBOMB_N); + Cooldown = 2000; + } SPELL_FIREBOMB_Timer = 2000; }else SPELL_FIREBOMB_Timer -=diff; diff --git a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_ormorok.cpp b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_ormorok.cpp index db9bf2317bb..1cda12197a2 100644 --- a/src/bindings/scripts/scripts/zone/nexus/nexus/boss_ormorok.cpp +++ b/src/bindings/scripts/scripts/zone/nexus/nexus/boss_ormorok.cpp @@ -24,29 +24,32 @@ EndScriptData */ #include "precompiled.h" #include "def_nexus.h" +enum +{ //Spells -#define SPELL_CRYSTAL_SPIKES_N 47958 //Don't work, using walkaround -#define SPELL_CRYSTAL_SPIKES_H 57082 //Don't work, using walkaround + SPELL_CRYSTAL_SPIKES_N = 47958, //Don't work, using walkaround + SPELL_CRYSTAL_SPIKES_H = 57082, //Don't work, using walkaround //Walkaround for spells Crystal Spikes ----------------- -#define SPELL_CRYSTALL_SPIKE_DAMAGE_N 47944 -#define SPELL_CRYSTALL_SPIKE_DAMAGE_H 57067 -#define SPELL_CRYSTAL_SPIKE_PREVISUAL 50442 -#define MOB_CRYSTAL_SPIKE 27099 + SPELL_CRYSTALL_SPIKE_DAMAGE_N = 47944, + SPELL_CRYSTALL_SPIKE_DAMAGE_H = 57067, + SPELL_CRYSTAL_SPIKE_PREVISUAL = 50442, + MOB_CRYSTAL_SPIKE = 27099, //------------------------------------------------------ -#define SPELL_SPELL_REFLECTION 47981 -#define SPELL_TRAMPLE_N 48016 -#define SPELL_TRAMPLE_H 57066 -#define SPELL_FRENZY 48017 -#define SPELL_SUMMON_CRYSTALLINE_TANGLER 61564 //summons npc 32665 -#define MOB_CRYSTALLINE_TANGLER 32665 -#define SPELL_ROOTS 28858 //proper spell id is unknown + SPELL_SPELL_REFLECTION = 47981, + SPELL_TRAMPLE_N = 48016, + SPELL_TRAMPLE_H = 57066, + SPELL_FRENZY = 48017, + SPELL_SUMMON_CRYSTALLINE_TANGLER = 61564, //summons npc 32665 + MOB_CRYSTALLINE_TANGLER = 32665, + SPELL_ROOTS = 28858, //proper spell id is unknown //Yell -#define SAY_AGGRO -1576020 -#define SAY_DEATH -1576021 -#define SAY_REFLECT -1576022 -#define SAY_CRYSTAL_SPIKES -1576023 -#define SAY_KILL -1576024 + SAY_AGGRO = -1576020, + SAY_DEATH = -1576021, + SAY_REFLECT = -1576022, + SAY_CRYSTAL_SPIKES = -1576023, + SAY_KILL = -1576024 +}; #define SPIKE_DISTANCE 5.0f diff --git a/src/bindings/scripts/scripts/zone/obsidian_sanctum/boss_sartharion.cpp b/src/bindings/scripts/scripts/zone/obsidian_sanctum/boss_sartharion.cpp index c7034655b11..98439172b21 100644 --- a/src/bindings/scripts/scripts/zone/obsidian_sanctum/boss_sartharion.cpp +++ b/src/bindings/scripts/scripts/zone/obsidian_sanctum/boss_sartharion.cpp @@ -1,272 +1,1075 @@ -/* Script Data Start -SDName: Boss sartharion -SDAuthor: LordVanMartin -SD%Complete: -SDComment: -SDCategory: -Script Data End */ - -/*** SQL START *** -update creature_template set scriptname = '' where entry = ''; -*** SQL END ***/ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss Sartharion +SD%Complete: 70% +SDComment: Flame wave, achievement and portal events need to be implemented +SDCategory: Obsidian Sanctum +EndScriptData */ + #include "precompiled.h" +#include "def_obsidian_sanctum.h" + +enum +{ + //Sartharion Yell + SAY_SARTHARION_AGGRO = -1615018, + SAY_SARTHARION_BERSERK = -1615019, + SAY_SARTHARION_BREATH = -1615020, + SAY_SARTHARION_CALL_SHADRON = -1615021, + SAY_SARTHARION_CALL_TENEBRON = -1615022, + SAY_SARTHARION_CALL_VESPERON = -1615023, + SAY_SARTHARION_DEATH = -1615024, + SAY_SARTHARION_SPECIAL_1 = -1615025, + SAY_SARTHARION_SPECIAL_2 = -1615026, + SAY_SARTHARION_SPECIAL_3 = -1615027, + SAY_SARTHARION_SPECIAL_4 = -1615028, + SAY_SARTHARION_SLAY_1 = -1615029, + SAY_SARTHARION_SLAY_2 = -1615030, + SAY_SARTHARION_SLAY_3 = -1615031, + + WHISPER_LAVA_CHURN = -1615032, + + WHISPER_SHADRON_DICIPLE = -1615008, + WHISPER_VESPERON_DICIPLE = -1615041, + WHISPER_HATCH_EGGS = -1615017, + WHISPER_OPEN_PORTAL = -1615042, // whisper, shared by two dragons + + //Sartharion Spells + SPELL_BERSERK = 61632, // Increases the caster's attack speed by 150% and all damage it deals by 500% for 5 min. + SPELL_CLEAVE = 56909, // Inflicts 35% weapon damage to an enemy and its nearest allies, affecting up to 10 targets. + SPELL_FLAME_BREATH = 56908, // Inflicts 8750 to 11250 Fire damage to enemies in a cone in front of the caster. + SPELL_FLAME_BREATH_H = 58956, // Inflicts 10938 to 14062 Fire damage to enemies in a cone in front of the caster. + SPELL_TAIL_LASH = 56910, // A sweeping tail strike hits all enemies behind the caster, inflicting 3063 to 3937 damage and stunning them for 2 sec. + SPELL_TAIL_LASH_H = 58957, // A sweeping tail strike hits all enemies behind the caster, inflicting 4375 to 5625 damage and stunning them for 2 sec. + SPELL_WILL_OF_SARTHARION = 61254, // Sartharion's presence bolsters the resolve of the Twilight Drakes, increasing their total health by 25%. This effect also increases Sartharion's health by 25%. + SPELL_LAVA_STRIKE = 57571, // (Real spell casted should be 57578) 57571 then trigger visual missile, then summon Lava Blaze on impact(spell 57572) + SPELL_TWILIGHT_REVENGE = 60639, + + SPELL_TWILIGHT_SHIFT_ENTER = 57620, // enter phase. Player get this when click GO + SPELL_TWILIGHT_SHIFT_REMOVAL = 61187, // leave phase + SPELL_TWILIGHT_SHIFT_REMOVAL_ALL = 61190, // leave phase (probably version to make all leave) + + //Mini bosses common spells + SPELL_TWILIGHT_RESIDUE = 61885, // makes immune to shadow damage, applied when leave phase + + //Miniboses (Vesperon, Shadron, Tenebron) + SPELL_SHADOW_BREATH_H = 59126, // Inflicts 8788 to 10212 Fire damage to enemies in a cone in front of the caster. + SPELL_SHADOW_BREATH = 57570, // Inflicts 6938 to 8062 Fire damage to enemies in a cone in front of the caster. + + SPELL_SHADOW_FISSURE_H = 59127, // Deals 9488 to 13512 Shadow damage to any enemy within the Shadow fissure after 5 sec. + SPELL_SHADOW_FISSURE = 57579, // Deals 6188 to 8812 Shadow damage to any enemy within the Shadow fissure after 5 sec. + + //Vesperon + //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times + NPC_ACOLYTE_OF_VESPERON = 31219, // Acolyte of Vesperon + SPELL_POWER_OF_VESPERON = 61251, // Vesperon's presence decreases the maximum health of all enemies by 25%. + SPELL_TWILIGHT_TORMENT_VESP = 57948, // (Shadow only) trigger 57935 then 57988 + SPELL_TWILIGHT_TORMENT_VESP_ACO = 58853, // (Fire and Shadow) trigger 58835 then 57988 + + //Shadron + //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times + NPC_ACOLYTE_OF_SHADRON = 31218, // Acolyte of Shadron + SPELL_POWER_OF_SHADRON = 58105, // Shadron's presence increases Fire damage taken by all enemies by 100%. + SPELL_GIFT_OF_TWILIGTH_SHA = 57835, // TARGET_SCRIPT shadron + SPELL_GIFT_OF_TWILIGTH_SAR = 58766, // TARGET_SCRIPT sartharion -//Sartharion Spells -#define SPELL_BERSERK 61632 // Increases the caster's attack speed by 150% and all damage it deals by 500% for 5 min. -#define SPELL_CLEAVE 56909 // Inflicts 35% weapon damage to an enemy and its nearest allies, affecting up to 10 targets. -#define SPELL_FLAME_BREATH_N 56908 // Inflicts 8750 to 11250 Fire damage to enemies in a cone in front of the caster. -#define SPELL_FLAME_BREATH_H 58956 // Inflicts 10938 to 14062 Fire damage to enemies in a cone in front of the caster. -#define SPELL_TAIL_LASH_N 56910 // A sweeping tail strike hits all enemies behind the caster, inflicting 3063 to 3937 damage and stunning them for 2 sec. -#define SPELL_TAIL_LASH_H 58957 // A sweeping tail strike hits all enemies behind the caster, inflicting 4375 to 5625 damage and stunning them for 2 sec. -#define SPELL_WILL_OF_SARTHARION 61254 // Sartharion's presence bolsters the resolve of the Twilight Drakes, increasing their total health by 25%. This effect also increases Sartharion's health by 25%. -#define SPELL_POWER_OF_SARTHARION 61254 //Shadron's presence increases Fire damage taken by all enemies by 100%. - -//Sartharion Yell -#define SAY_SARTHARION_AGGRO -1615016 -#define SAY_SARTHARION_BERSERK -1615017 -#define SAY_SARTHARION_BREATH -1615018 -#define SAY_SARTHARION_CALL_SHADRON -1615019 -#define SAY_SARTHARION_CALL_TENEBRON -1615020 -#define SAY_SARTHARION_CALL_VESPERON -1615021 -#define SAY_SARTHARION_DEATH -1615022 -#define SAY_SARTHARION_SPECIAL_1 -1615023 -#define SAY_SARTHARION_SPECIAL_2 -1615024 -#define SAY_SARTHARION_SPECIAL_3 -1615025 -#define SAY_SARTHARION_SPECIAL_4 -1615026 -#define SAY_SARTHARION_SLAY_1 -1615027 -#define SAY_SARTHARION_SLAY_2 -1615028 -#define SAY_SARTHARION_SLAY_3 -1615029 - -//Miniboses (Vesperon, Shadron, Tenebron) -#define SPELL_SHADOW_BREATH_H 59126 //Inflicts 8788 to 10212 Fire damage to enemies in a cone in front of the caster. -#define SPELL_SHADOW_BREATH_N 57570 //Inflicts 6938 to 8062 Fire damage to enemies in a cone in front of the caster. -//TAIL LASH the same as Sartharion's -#define SPELL_SHADOW_FISSURE_H 59127 //Deals 9488 to 13512 Shadow damage to any enemy within the Shadow fissure after 5 sec. -#define SPELL_SHADOW_FISSURE_N 57579 //Deals 6188 to 8812 Shadow damage to any enemy within the Shadow fissure after 5 sec. - -//Vesperon -#define MINIBOSS_VESPERON 30449 //npc 30449 //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal spawns multiple times -#define BUFF_POWER_OF_VESPERON 61251 //Vesperon's presence decreases the maximum health of all enemies by 25%. - -//Shadron -#define MINIBOSS_SHADRON 30451 //npc 30451 //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal spawns multiple times -#define BUFF_POWER_OF_SHADRON 58105 //Shadron's presence increases Fire damage taken by all enemies by 100%. - -//Tenebron -#define MINIBOSS_TENEBRON 30452 //npc 30452 //in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 -#define BUFF_POWER_OF_TENEBRON 61248 //Tenebron's presence increases Shadow damage taken by all enemies by 100%. - -//Minibosses common spells -#define SPELL_SHADOW_BREATH_N 57570 -#define SPELL_SHADOW_BREATH_H 59126 -#define SPELL_SHADOW_FISSURE_N 57579 -#define SPELL_SHADOW_FISSURE_H 59127 -#define SPELL_TWILIGHT_REVENGE 60639 - -//Tenebron, dummy spell -#define SPELL_HATCH_EGGS 58793 - -//Whelps -#define TWILIGHT_WHELP 30890 //npc 30890 -#define SHARTHARION_TWILIGHT_WHELP 31214 //npc 31214 -#define SPELL_FADE_ARMOR 60708 //Reduces the armor of an enemy by 1500 for 15s - -/*Summons a portal, which all DPS and one healer should go through and proceed to kill all eggs. After about 20 seconds these eggs will hatch into whelplings with 60k health. Whelplings that hatched should be picked up by a tank and killed. -Hatch Eggs Tenebron summons a portal in which eggs are spawned. After about 20s the eggs hatches into Whelps (156,396 hp - amount of whelps determined by Normal or Heroic mode) that do Fade Armor. */ + //Tenebron + //in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 + SPELL_POWER_OF_TENEBRON = 61248, // Tenebron's presence increases Shadow damage taken by all enemies by 100%. + //Tenebron, dummy spell + SPELL_SUMMON_TWILIGHT_WHELP = 58035, // doesn't work, will spawn NPC_TWILIGHT_WHELP + SPELL_SUMMON_SARTHARION_TWILIGHT_WHELP = 58826, // doesn't work, will spawn NPC_SHARTHARION_TWILIGHT_WHELP + + SPELL_HATCH_EGGS_H = 59189, + SPELL_HATCH_EGGS = 58542, + SPELL_HATCH_EGGS_EFFECT_H = 59190, + SPELL_HATCH_EGGS_EFFECT = 58685, + + //Whelps + NPC_TWILIGHT_WHELP = 30890, + NPC_SHARTHARION_TWILIGHT_WHELP = 31214, + SPELL_FADE_ARMOR = 60708, // Reduces the armor of an enemy by 1500 for 15s + + //flame tsunami + SPELL_FLAME_TSUNAMI = 57494, // the visual dummy + SPELL_FLAME_TSUNAMI_LEAP = 60241, // SPELL_EFFECT_138 some leap effect, causing caster to move in direction + SPELL_FLAME_TSUNAMI_DMG_AURA = 57492, // periodic damage, npc has this aura + + NPC_FLAME_TSUNAMI = 30616, // for the flame waves + NPC_LAVA_BLAZE = 30643, // adds spawning from flame strike + + //using these custom points for dragons start and end + POINT_ID_INIT = 100, + POINT_ID_LAND = 200 +}; + +//POS_SARTHARION_X = 3246.57, +//POS_SARTHARION_Y = 551.263, + +struct Waypoint +{ + float m_fX, m_fY, m_fZ; +}; + +//each dragons special points. First where fly to before connect to connon, second where land point is. +Waypoint m_aTene[]= +{ + {3212.854, 575.597, 109.856}, //init + {3246.425, 565.367, 61.249} //end +}; + +Waypoint m_aShad[]= +{ + {3293.238, 472.223, 106.968}, + {3271.669, 526.907, 61.931} +}; + +Waypoint m_aVesp[]= +{ + {3193.310, 472.861, 102.697}, + {3227.268, 533.238, 59.995} +}; + +//points around raid "isle", counter clockwise. should probably be adjusted to be more alike +Waypoint m_aDragonCommon[]= +{ + {3214.012, 468.932, 98.652}, + {3244.950, 468.427, 98.652}, + {3283.520, 496.869, 98.652}, + {3287.316, 555.875, 98.652}, + {3250.479, 585.827, 98.652}, + {3209.969, 566.523, 98.652} +}; + +/*###### +## Boss Sartharion +######*/ struct TRINITY_DLL_DECL boss_sartharionAI : public ScriptedAI { - boss_sartharionAI(Creature *c) : ScriptedAI(c) {} + boss_sartharionAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsHeroic(); + } - bool berserk; + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; - void Reset() + bool m_bIsBerserk; + uint32 m_uiEnrageTimer; + + uint32 m_uiTenebronTimer; + uint32 m_uiShadronTimer; + uint32 m_uiVesperonTimer; + + uint32 m_uiFlameTsunamiTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiTailSweepTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiLavaStrikeTimer; + + bool m_bHasCalledTenebron; + bool m_bHasCalledShadron; + bool m_bHasCalledVesperon; + + void Reset() { - berserk = false; + m_bIsBerserk = false; + m_uiEnrageTimer = MINUTE*15*IN_MILISECONDS; + + m_uiTenebronTimer = 30000; + m_uiShadronTimer = 75000; + m_uiVesperonTimer = 120000; + + m_uiFlameTsunamiTimer = 30000; + m_uiFlameBreathTimer = 20000; + m_uiTailSweepTimer = 20000; + m_uiCleaveTimer = 7000; + m_uiLavaStrikeTimer = 5000; + + m_bHasCalledTenebron = false; + m_bHasCalledShadron = false; + m_bHasCalledVesperon = false; + + if (m_pInstance) + { + if (!m_creature->isAlive()) + return; + + m_pInstance->SetData(TYPE_SARTHARION_EVENT, NOT_STARTED); + + //do dragons actually respawn like this? Commented for now, until confirmed. + + /*if (Unit* Temp1 = Unit::GetUnit((*m_creature),m_pInstance->GetData64(DATA_TENEBRON))) + if (Temp1->isDead()) + ((Creature*)Temp1)->Respawn(); + + if (Unit* Temp2 = Unit::GetUnit((*m_creature),m_pInstance->GetData64(DATA_SHADRON))) + if (Temp2->isDead()) + ((Creature*)Temp2)->Respawn(); + + if (Unit* Temp3 = Unit::GetUnit((*m_creature),m_pInstance->GetData64(DATA_VESPERON))) + if (Temp3->isDead()) + ((Creature*)Temp3)->Respawn();*/ + } + + if (m_creature->HasAura(SPELL_TWILIGHT_REVENGE)) + m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_REVENGE); + } + + void Aggro(Unit* pWho) + { + DoScriptText(SAY_SARTHARION_AGGRO,m_creature); + DoZoneInCombat(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SARTHARION_EVENT, IN_PROGRESS); + + FetchDragons(); } - void EnterCombat(Unit* who) + + void JustDied(Unit* pKiller) { DoScriptText(SAY_SARTHARION_DEATH,m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SARTHARION_EVENT, DONE); + } + + void KilledUnit(Unit* pVictim) + { + switch(rand()%3) + { + case 0: DoScriptText(SAY_SARTHARION_SLAY_1, m_creature); break; + case 1: DoScriptText(SAY_SARTHARION_SLAY_2, m_creature); break; + case 2: DoScriptText(SAY_SARTHARION_SLAY_3, m_creature); break; + } + } + + void FetchDragons() + { + Unit* pTene = Unit::GetUnit(*m_creature,m_pInstance->GetData64(DATA_TENEBRON)); + Unit* pShad = Unit::GetUnit(*m_creature,m_pInstance->GetData64(DATA_SHADRON)); + Unit* pVesp = Unit::GetUnit(*m_creature,m_pInstance->GetData64(DATA_VESPERON)); + + if (pTene && pTene->isAlive() && !pTene->getVictim()) + { + pTene->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aTene[0].m_fX, m_aTene[0].m_fY, m_aTene[0].m_fZ); + + if (!pTene->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pTene->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + if (pShad && pShad->isAlive() && !pShad->getVictim()) + { + pShad->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aShad[0].m_fX, m_aShad[0].m_fY, m_aShad[0].m_fZ); + + if (!pShad->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pShad->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + + if (pVesp && pVesp->isAlive() && !pVesp->getVictim()) + { + pVesp->GetMotionMaster()->MovePoint(POINT_ID_INIT, m_aVesp[0].m_fX, m_aVesp[0].m_fY, m_aVesp[0].m_fZ); + + if (!pVesp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pVesp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + void CallDragon(uint32 uiDataId) + { + if (m_pInstance) + { + Creature* pTemp = Unit::GetCreature((*m_creature),m_pInstance->GetData64(uiDataId)); + + if (pTemp && pTemp->isAlive() && !pTemp->getVictim()) + { + if (pTemp->HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE)) + pTemp->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); + + if (pTemp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + int32 iTextId = 0; + + switch(pTemp->GetEntry()) + { + case NPC_TENEBRON: + iTextId = SAY_SARTHARION_CALL_TENEBRON; + pTemp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aTene[1].m_fX, m_aTene[1].m_fY, m_aTene[1].m_fZ); + break; + case NPC_SHADRON: + iTextId = SAY_SARTHARION_CALL_SHADRON; + pTemp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aShad[1].m_fX, m_aShad[1].m_fY, m_aShad[1].m_fZ); + break; + case NPC_VESPERON: + iTextId = SAY_SARTHARION_CALL_VESPERON; + pTemp->GetMotionMaster()->MovePoint(POINT_ID_LAND, m_aVesp[1].m_fX, m_aVesp[1].m_fY, m_aVesp[1].m_fZ); + break; + } + + DoScriptText(iTextId, m_creature); + } + } } - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void UpdateAI(const uint32 diff) + + void SendFlameTsunami() + { + Map* pMap = m_creature->GetMap(); + + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + + if (!PlayerList.isEmpty()) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (i->getSource()->isAlive()) + DoScriptText(WHISPER_LAVA_CHURN,m_creature,i->getSource()); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) { //Return since we have no target - if(!UpdateVictim()) + if (!UpdateVictim()) return; - if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 10) + //reset if out of his platform, must find better/faster way to do this + //if (m_creature->GetDistance2d(POS_SARTHARION_X, POS_SARTHARION_Y) > 55) + //{ + //EnterEvadeMode(); + //return; + //} + + if (!m_bIsBerserk && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) <= 10) { - if(!berserk){ - DoCast(m_creature,SPELL_BERSERK); - berserk = true; - } + DoScriptText(SAY_SARTHARION_BERSERK,m_creature); + DoCast(m_creature,SPELL_BERSERK); + m_bIsBerserk = true; + } + + // enrage + if (m_uiEnrageTimer) + { + if (m_uiEnrageTimer < uiDiff) + { + DoCast(m_creature, SPELL_WILL_OF_SARTHARION); + m_uiEnrageTimer = 0; + }else m_uiEnrageTimer -= uiDiff; } + // flame tsunami + if (m_uiFlameTsunamiTimer < uiDiff) + { + SendFlameTsunami(); + m_uiFlameTsunamiTimer = 30000; + }else m_uiFlameTsunamiTimer -= uiDiff; + + // flame breath + if (m_uiFlameBreathTimer < uiDiff) + { + DoScriptText(SAY_SARTHARION_BREATH, m_creature); + DoCast(m_creature->getVictim(), m_bIsHeroic ? SPELL_FLAME_BREATH_H : SPELL_FLAME_BREATH); + m_uiFlameBreathTimer = 25000 + rand()%10000; + }else m_uiFlameBreathTimer -= uiDiff; + + // Tail Sweep + if (m_uiTailSweepTimer < uiDiff) + { + DoCast(m_creature->getVictim(), m_bIsHeroic ? SPELL_TAIL_LASH_H : SPELL_TAIL_LASH); + m_uiTailSweepTimer = 15000 + rand()%5000; + }else m_uiTailSweepTimer -= uiDiff; + + // Cleave + if (m_uiCleaveTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + m_uiCleaveTimer = 7000 + rand()%3000; + }else m_uiCleaveTimer -= uiDiff; + + // Lavas Strike + if (m_uiLavaStrikeTimer < uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + DoCast(pTarget, SPELL_LAVA_STRIKE); + + switch(rand()%15) + { + case 0: DoScriptText(SAY_SARTHARION_SPECIAL_1, m_creature); break; + case 1: DoScriptText(SAY_SARTHARION_SPECIAL_2, m_creature); break; + case 2: DoScriptText(SAY_SARTHARION_SPECIAL_3, m_creature); break; + } + } + m_uiLavaStrikeTimer = 5000 + rand()%15000; + }else m_uiLavaStrikeTimer -= uiDiff; + + // call tenebron + if (!m_bHasCalledTenebron && m_uiTenebronTimer < uiDiff) + { + CallDragon(DATA_TENEBRON); + m_bHasCalledTenebron = true; + }else m_uiTenebronTimer -= uiDiff; + + // call shadron + if (!m_bHasCalledShadron && m_uiShadronTimer < uiDiff) + { + CallDragon(DATA_SHADRON); + m_bHasCalledShadron = true; + }else m_uiShadronTimer -= uiDiff; + + // call vesperon + if (!m_bHasCalledVesperon && m_uiVesperonTimer < uiDiff) + { + CallDragon(DATA_VESPERON); + m_bHasCalledVesperon = true; + }else m_uiVesperonTimer -= uiDiff; + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(uiDiff); } - void JustDied(Unit* killer) +}; + +CreatureAI* GetAI_boss_sartharion(Creature* pCreature) +{ + return new boss_sartharionAI(pCreature); +} + +enum TeneText +{ + SAY_TENEBRON_AGGRO = -1615009, + SAY_TENEBRON_SLAY_1 = -1615010, + SAY_TENEBRON_SLAY_2 = -1615011, + SAY_TENEBRON_DEATH = -1615012, + SAY_TENEBRON_BREATH = -1615013, + SAY_TENEBRON_RESPOND = -1615014, + SAY_TENEBRON_SPECIAL_1 = -1615015, + SAY_TENEBRON_SPECIAL_2 = -1615016 +}; + +enum ShadText +{ + SAY_SHADRON_AGGRO = -1615000, + SAY_SHADRON_SLAY_1 = -1615001, + SAY_SHADRON_SLAY_2 = -1615002, + SAY_SHADRON_DEATH = -1615003, + SAY_SHADRON_BREATH = -1615004, + SAY_SHADRON_RESPOND = -1615005, + SAY_SHADRON_SPECIAL_1 = -1615006, + SAY_SHADRON_SPECIAL_2 = -1615007 +}; + +enum VespText +{ + SAY_VESPERON_AGGRO = -1615033, + SAY_VESPERON_SLAY_1 = -1615034, + SAY_VESPERON_SLAY_2 = -1615035, + SAY_VESPERON_DEATH = -1615036, + SAY_VESPERON_BREATH = -1615037, + SAY_VESPERON_RESPOND = -1615038, + SAY_VESPERON_SPECIAL_1 = -1615039, + SAY_VESPERON_SPECIAL_2 = -1615040 +}; + +//to control each dragons common abilities +struct TRINITY_DLL_DECL dummy_dragonAI : public ScriptedAI +{ + dummy_dragonAI(Creature* pCreature) : ScriptedAI(pCreature) { - DoScriptText(SAY_SARTHARION_DEATH,m_creature); + m_pInstance = pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsHeroic(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiWaypointId; + uint32 m_uiMoveNextTimer; + int32 m_iPortalRespawnTime; + bool m_bCanMoveFree; + + void Reset() + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + m_uiWaypointId = 0; + m_uiMoveNextTimer = 500; + m_iPortalRespawnTime = 30000; + m_bCanMoveFree = false; + } + + void MovementInform(uint32 uiType, uint32 uiPointId) + { + if (!m_pInstance || uiType != POINT_MOTION_TYPE) + return; + + debug_log("dummy_dragonAI: %s reached point %u", m_creature->GetName(), uiPointId); + + //if healers messed up the raid and we was already initialized + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) + { + EnterEvadeMode(); + return; + } + + //this is end, if we reach this, don't do much + if (uiPointId == POINT_ID_LAND) + { + m_creature->GetMotionMaster()->Clear(); + m_bCanMoveFree = false; + return; + } + + //get amount of common points + uint32 uiCommonWPCount = sizeof(m_aDragonCommon)/sizeof(Waypoint); + + //increase + m_uiWaypointId = uiPointId+1; + + //if we have reached a point bigger or equal to count, it mean we must reset to point 0 + if (m_uiWaypointId >= uiCommonWPCount) + { + if (!m_bCanMoveFree) + m_bCanMoveFree = true; + + m_uiWaypointId = 0; + } + + m_uiMoveNextTimer = 500; + } + + //used when open portal and spawn mobs in phase + void DoRaidWhisper(int32 iTextId) + { + Map* pMap = m_creature->GetMap(); + + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + + if (!PlayerList.isEmpty()) + { + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + DoScriptText(iTextId, m_creature, i->getSource()); + } + } + } + + //"opens" the portal and does the "opening" whisper + void OpenPortal() + { + int32 iTextId = 0; + + //there are 4 portal spawn locations, each are expected to be spawned with negative spawntimesecs in database + + //using a grid search here seem to be more efficient than caching all four guids + //in instance script and calculate range to each. + GameObject* pPortal = m_creature->FindNearestGameObject(GO_TWILIGHT_PORTAL,50.0f); + + switch(m_creature->GetEntry()) + { + case NPC_TENEBRON: + iTextId = WHISPER_HATCH_EGGS; + break; + case NPC_SHADRON: + case NPC_VESPERON: + iTextId = WHISPER_OPEN_PORTAL; + break; + } + + DoRaidWhisper(iTextId); + + //By using SetRespawnTime() we will actually "spawn" the object with our defined time. + //Once time is up, portal will disappear again. + if (pPortal && !pPortal->isSpawned()) + pPortal->SetRespawnTime(m_iPortalRespawnTime); + + //Unclear what are expected to happen if one drake has a portal open already + //Refresh respawnTime so time again are set to 30secs? + } + + //Removes each drakes unique debuff from players + void RemoveDebuff(uint32 uiSpellId) + { + Map* pMap = m_creature->GetMap(); + + if (pMap && pMap->IsDungeon()) + { + Map::PlayerList const &PlayerList = pMap->GetPlayers(); + + if (PlayerList.isEmpty()) + return; + + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (i->getSource()->isAlive() && i->getSource()->HasAura(uiSpellId)) + i->getSource()->RemoveAurasDueToSpell(uiSpellId); + } + } + } + + void JustDied(Unit* pKiller) + { + int32 iTextId = 0; + uint32 uiSpellId = 0; + + switch(m_creature->GetEntry()) + { + case NPC_TENEBRON: + iTextId = SAY_TENEBRON_DEATH; + uiSpellId = SPELL_POWER_OF_TENEBRON; + break; + case NPC_SHADRON: + iTextId = SAY_SHADRON_DEATH; + uiSpellId = SPELL_POWER_OF_SHADRON; + break; + case NPC_VESPERON: + iTextId = SAY_VESPERON_DEATH; + uiSpellId = SPELL_POWER_OF_VESPERON; + break; + } + + DoScriptText(iTextId, m_creature); + + RemoveDebuff(uiSpellId); + + if (m_pInstance) + { + // not if solo mini-boss fight + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) + return; + + // Twilight Revenge to main boss + if (Unit* pSartharion = Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_SARTHARION))) + { + if (pSartharion->isAlive()) + m_creature->CastSpell(pSartharion,SPELL_TWILIGHT_REVENGE,true); + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (m_bCanMoveFree && m_uiMoveNextTimer) + { + if (m_uiMoveNextTimer < uiDiff) + { + m_creature->GetMotionMaster()->MovePoint(m_uiWaypointId, + m_aDragonCommon[m_uiWaypointId].m_fX, m_aDragonCommon[m_uiWaypointId].m_fY, m_aDragonCommon[m_uiWaypointId].m_fZ); + + debug_log("dummy_dragonAI: %s moving to point %u", m_creature->GetName(), m_uiWaypointId); + m_uiMoveNextTimer = 0; + } else m_uiMoveNextTimer -= uiDiff; + } } }; /*###### -## Mob Vesperon +## Mob Tenebron ######*/ -//Vesperon Yell -#define SAY_VESPERON_AGGRO -1615030 -#define SAY_VESPERON_SLAY_1 -1615031 -#define SAY_VESPERON_SLAY_2 -1615032 -#define SAY_VESPERON_DEATH -1615033 -#define SAY_VESPERON_BREATH -1615034 -#define SAY_VESPERON_RESPOND -1615035 -#define SAY_VESPERON_SPECIAL_1 -1615036 -#define SAY_VESPERON_SPECIAL_2 -1615037 - -struct TRINITY_DLL_DECL mob_vesperonAI : public ScriptedAI +struct TRINITY_DLL_DECL mob_tenebronAI : public dummy_dragonAI { - mob_vesperonAI(Creature *c) : ScriptedAI(c) {} + mob_tenebronAI(Creature* pCreature) : dummy_dragonAI(pCreature) { } + + uint32 m_uiShadowBreathTimer; + uint32 m_uiShadowFissureTimer; + uint32 m_uiHatchEggTimer; - void Reset() {} - void EnterCombat(Unit* who) + void Reset() { - DoScriptText(SAY_VESPERON_AGGRO,m_creature); + m_uiShadowBreathTimer = 20000; + m_uiShadowFissureTimer = 5000; + m_uiHatchEggTimer = 30000; } - void UpdateAI(const uint32 diff) + + void Aggro(Unit* pWho) { - //Return since we have no target - if(!UpdateVictim()) - return; + DoScriptText(SAY_TENEBRON_AGGRO, m_creature); + DoZoneInCombat(); + DoCast(m_creature, SPELL_POWER_OF_TENEBRON); + } - DoMeleeAttackIfReady(); + void KilledUnit(Unit* pVictim) + { + switch(rand()%2) + { + case 0: DoScriptText(SAY_TENEBRON_SLAY_1, m_creature); break; + case 1: DoScriptText(SAY_TENEBRON_SLAY_2, m_creature); break; + } } - void JustDied(Unit* killer) + + void UpdateAI(const uint32 uiDiff) { - DoScriptText(SAY_VESPERON_DEATH,m_creature); + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(uiDiff); + return; + } + + // shadow fissure + if (m_uiShadowFissureTimer < uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsHeroic ? SPELL_SHADOW_FISSURE_H : SPELL_SHADOW_FISSURE); + + m_uiShadowFissureTimer = 15000 + rand()%5000; + }else m_uiShadowFissureTimer -= uiDiff; + + // shadow breath + if (m_uiShadowBreathTimer < uiDiff) + { + DoScriptText(SAY_TENEBRON_BREATH, m_creature); + DoCast(m_creature->getVictim(), m_bIsHeroic ? SPELL_SHADOW_BREATH_H : SPELL_SHADOW_BREATH); + m_uiShadowBreathTimer = 20000 + rand()%5000; + }else m_uiShadowBreathTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; +CreatureAI* GetAI_mob_tenebron(Creature* pCreature) +{ + return new mob_tenebronAI(pCreature); +} + /*###### ## Mob Shadron ######*/ -//Shadron Yell -#define SAY_SHADRON_AGGRO -1615000 -#define SAY_SHADRON_SLAY_1 -1615001 -#define SAY_SHADRON_SLAY_2 -1615002 -#define SAY_SHADRON_DEATH -1615003 -#define SAY_SHADRON_BREATH -1615004 -#define SAY_SHADRON_RESPOND -1615005 -#define SAY_SHADRON_SPECIAL_1 -1615006 -#define SAY_SHADRON_SPECIAL_2 -1615007 - -struct TRINITY_DLL_DECL mob_shadronAI : public ScriptedAI +struct TRINITY_DLL_DECL mob_shadronAI : public dummy_dragonAI { - mob_shadronAI(Creature *c) : ScriptedAI(c) {} + mob_shadronAI(Creature* pCreature) : dummy_dragonAI(pCreature) { } + + uint32 m_uiShadowBreathTimer; + uint32 m_uiShadowFissureTimer; + uint32 m_uiAcolyteShadronTimer; + + void Reset() + { + m_uiShadowBreathTimer = 20000; + m_uiShadowFissureTimer = 5000; + m_uiAcolyteShadronTimer = 60000; + + if (m_creature->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) + m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + + if (m_creature->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) + m_creature->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); + } - void Reset(){} - void EnterCombat(Unit* who) + void Aggro(Unit* pWho) { DoScriptText(SAY_SHADRON_AGGRO,m_creature); + DoZoneInCombat(); + DoCast(m_creature, SPELL_POWER_OF_SHADRON); } - void UpdateAI(const uint32 diff) + + void KilledUnit(Unit* pVictim) { - //Return since we have no target - if(!UpdateVictim()) + switch(rand()%2) + { + case 0: DoScriptText(SAY_SHADRON_SLAY_1, m_creature); break; + case 1: DoScriptText(SAY_SHADRON_SLAY_2, m_creature); break; + } + } + + void UpdateAI(const uint32 uiDiff) + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(uiDiff); return; + } + + // shadow fissure + if (m_uiShadowFissureTimer < uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsHeroic ? SPELL_SHADOW_FISSURE_H : SPELL_SHADOW_FISSURE); + + m_uiShadowFissureTimer = 15000 + rand()%5000; + }else m_uiShadowFissureTimer -= uiDiff; + + // shadow breath + if (m_uiShadowBreathTimer < uiDiff) + { + DoScriptText(SAY_SHADRON_BREATH, m_creature); + DoCast(m_creature->getVictim(), m_bIsHeroic ? SPELL_SHADOW_BREATH_H : SPELL_SHADOW_BREATH); + m_uiShadowBreathTimer = 20000 + rand()%5000; + }else m_uiShadowBreathTimer -= uiDiff; DoMeleeAttackIfReady(); } - void JustDied(Unit* killer) - { - DoScriptText(SAY_SHADRON_DEATH,m_creature); - } }; + +CreatureAI* GetAI_mob_shadron(Creature* pCreature) +{ + return new mob_shadronAI(pCreature); +} + /*###### -## Mob Tenebron +## Mob Vesperon ######*/ -//Yell -#define SAY_TENEBRON_AGGRO -1615008 -#define SAY_TENEBRON_SLAY_1 -1615009 -#define SAY_TENEBRON_SLAY_2 -1615010 -#define SAY_TENEBRON_DEATH -1615011 -#define SAY_TENEBRON_BREATH -1615012 -#define SAY_TENEBRON_RESPOND -1615013 -#define SAY_TENEBRON_SPECIAL_1 -1615014 -#define SAY_TENEBRON_SPECIAL_2 -1615015 - -struct TRINITY_DLL_DECL mob_tenebronAI : public ScriptedAI +struct TRINITY_DLL_DECL mob_vesperonAI : public dummy_dragonAI { - mob_tenebronAI(Creature *c) : ScriptedAI(c) {} + mob_vesperonAI(Creature* pCreature) : dummy_dragonAI(pCreature) { } - void Reset() {} - void EnterCombat(Unit* who) + uint32 m_uiShadowBreathTimer; + uint32 m_uiShadowFissureTimer; + uint32 m_uiAcolyteVesperonTimer; + + void Reset() { - DoScriptText(SAY_TENEBRON_AGGRO,m_creature); + m_uiShadowBreathTimer = 20000; + m_uiShadowFissureTimer = 5000; + m_uiAcolyteVesperonTimer = 60000; } - void UpdateAI(const uint32 diff) + + void Aggro(Unit* pWho) { - //Return since we have no target - if(!UpdateVictim()) + DoScriptText(SAY_VESPERON_AGGRO,m_creature); + DoZoneInCombat(); + DoCast(m_creature, SPELL_POWER_OF_VESPERON); + } + + void KilledUnit(Unit* pVictim) + { + switch(rand()%2) + { + case 0: DoScriptText(SAY_VESPERON_SLAY_1, m_creature); break; + case 1: DoScriptText(SAY_VESPERON_SLAY_2, m_creature); break; + } + } + + void UpdateAI(const uint32 uiDiff) + { + //if no target, update dummy and return + if (!UpdateVictim()) + { + dummy_dragonAI::UpdateAI(uiDiff); return; + } + + // shadow fissure + if (m_uiShadowFissureTimer < uiDiff) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(pTarget, m_bIsHeroic ? SPELL_SHADOW_FISSURE_H : SPELL_SHADOW_FISSURE); + + m_uiShadowFissureTimer = 15000 + rand()%5000; + }else m_uiShadowFissureTimer -= uiDiff; + + // shadow breath + if (m_uiShadowBreathTimer < uiDiff) + { + DoScriptText(SAY_VESPERON_BREATH, m_creature); + DoCast(m_creature->getVictim(), m_bIsHeroic ? SPELL_SHADOW_BREATH_H : SPELL_SHADOW_BREATH); + m_uiShadowBreathTimer = 20000 + rand()%5000; + }else m_uiShadowBreathTimer -= uiDiff; DoMeleeAttackIfReady(); } +}; + +CreatureAI* GetAI_mob_vesperon(Creature* pCreature) +{ + return new mob_vesperonAI(pCreature); +} + +/*###### +## Mob Acolyte of Shadron +######*/ + +struct TRINITY_DLL_DECL mob_acolyte_of_shadronAI : public ScriptedAI +{ + mob_acolyte_of_shadronAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + } + + ScriptedInstance* m_pInstance; + + void Reset() + { + if (m_pInstance) + { + //if not solo figth, buff main boss, else place debuff on mini-boss. both spells TARGET_SCRIPT + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + DoCast(m_creature, SPELL_GIFT_OF_TWILIGTH_SAR); + else + DoCast(m_creature, SPELL_GIFT_OF_TWILIGTH_SHA); + } + } + void JustDied(Unit* killer) { - DoScriptText(SAY_TENEBRON_DEATH,m_creature); + if (m_pInstance) + { + Creature* pDebuffTarget = NULL; + + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + { + //not solo fight, so main boss has deduff + pDebuffTarget = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_SARTHARION)); + + if (pDebuffTarget && pDebuffTarget->isAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SAR)) + pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SAR); + } + else + { + //event not in progress, then solo fight and must remove debuff mini-boss + pDebuffTarget = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_SHADRON)); + + if (pDebuffTarget && pDebuffTarget->isAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) + pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); } }; +CreatureAI* GetAI_mob_acolyte_of_shadron(Creature* pCreature) +{ + return new mob_acolyte_of_shadronAI(pCreature); +} + /*###### -## Mob Whelps +## Mob Acolyte of Vesperon ######*/ -struct TRINITY_DLL_DECL mob_whelpAI : public ScriptedAI + +struct TRINITY_DLL_DECL mob_acolyte_of_vesperonAI : public ScriptedAI { - mob_whelpAI(Creature *c) : ScriptedAI(c) {} + mob_acolyte_of_vesperonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = pCreature->GetInstanceData(); + } - uint32 Fade_armor_Timer; + ScriptedInstance* m_pInstance; - void Reset() {} - void EnterCombat(Unit* who) {} - void UpdateAI(const uint32 diff) + void Reset() { - //Return since we have no target - if(!UpdateVictim()) + DoCast(m_creature, SPELL_TWILIGHT_TORMENT_VESP_ACO); + } + + void JustDied(Unit* pKiller) + { + // remove twilight torment on Vesperon + if (m_pInstance) + { + Creature* pVesperon = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_VESPERON)); + + if (pVesperon && pVesperon->isAlive() && pVesperon->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) + pVesperon->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) return; DoMeleeAttackIfReady(); } - void JustDied(Unit* killer) {} }; -CreatureAI* GetAI_mob_whelp(Creature *_Creature) +CreatureAI* GetAI_mob_acolyte_of_vesperon(Creature* pCreature) { - return new mob_whelpAI (_Creature); + return new mob_acolyte_of_vesperonAI(pCreature); } -CreatureAI* GetAI_mob_tenebron(Creature *_Creature) +/*###### +## Mob Twilight Eggs +######*/ + +struct TRINITY_DLL_DECL mob_twilight_eggsAI : public ScriptedAI { - return new mob_tenebronAI (_Creature); -} + mob_twilight_eggsAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 m_uiFadeArmorTimer; + + void Reset() + { + m_uiFadeArmorTimer = 1000; + } -CreatureAI* GetAI_mob_shadron(Creature *_Creature) + void AttackStart(Unit* pWho) { } + void MoveInLineOfSight(Unit* pWho) { } +}; + +CreatureAI* GetAI_mob_twilight_eggs(Creature* pCreature) { - return new mob_shadronAI (_Creature); + return new mob_twilight_eggsAI(pCreature); } -CreatureAI* GetAI_mob_vesperon(Creature *_Creature) +/*###### +## Mob Twilight Whelps +######*/ + +struct TRINITY_DLL_DECL mob_twilight_whelpAI : public ScriptedAI { - return new mob_vesperonAI (_Creature); -} + mob_twilight_whelpAI(Creature* pCreature) : ScriptedAI(pCreature) { } -CreatureAI* GetAI_boss_sartharion(Creature *_Creature) + uint32 m_uiFadeArmorTimer; + + void Reset() + { + m_uiFadeArmorTimer = 1000; + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) + return; + + // twilight torment + if (m_uiFadeArmorTimer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_FADE_ARMOR); + m_uiFadeArmorTimer = 5000 + rand()%5000; + }else m_uiFadeArmorTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_twilight_whelp(Creature* pCreature) { - return new boss_sartharionAI (_Creature); + return new mob_twilight_whelpAI(pCreature); } void AddSC_boss_sartharion() @@ -294,7 +1097,22 @@ void AddSC_boss_sartharion() newscript->RegisterSelf(); newscript = new Script; - newscript->Name="mob_whelp"; - newscript->GetAI = &GetAI_mob_whelp; + newscript->Name="mob_acolyte_of_shadron"; + newscript->GetAI = &GetAI_mob_acolyte_of_shadron; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="mob_acolyte_of_vesperon"; + newscript->GetAI = &GetAI_mob_acolyte_of_vesperon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="mob_twilight_eggs"; + newscript->GetAI = &GetAI_mob_twilight_eggs; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="mob_twilight_whelp"; + newscript->GetAI = &GetAI_mob_twilight_whelp; newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/obsidian_sanctum/def_obsidian_sanctum.h b/src/bindings/scripts/scripts/zone/obsidian_sanctum/def_obsidian_sanctum.h index 59d76502af3..461834a2386 100644 --- a/src/bindings/scripts/scripts/zone/obsidian_sanctum/def_obsidian_sanctum.h +++ b/src/bindings/scripts/scripts/zone/obsidian_sanctum/def_obsidian_sanctum.h @@ -1,4 +1,20 @@ #ifndef DEF_OBSIDIAN_SANCTUM_H #define DEF_OBSIDIAN_SANCTUM_H +enum +{ + TYPE_SARTHARION_EVENT = 1, + + DATA_SARTHARION = 10, + DATA_TENEBRON = 11, + DATA_SHADRON = 12, + DATA_VESPERON = 13, + + NPC_SARTHARION = 28860, + NPC_TENEBRON = 30452, + NPC_SHADRON = 30451, + NPC_VESPERON = 30449, + GO_TWILIGHT_PORTAL = 193988 +}; + #endif diff --git a/src/bindings/scripts/scripts/zone/obsidian_sanctum/instance_obsidian_sanctum.cpp b/src/bindings/scripts/scripts/zone/obsidian_sanctum/instance_obsidian_sanctum.cpp index 898574c99eb..8eacaf77880 100644 --- a/src/bindings/scripts/scripts/zone/obsidian_sanctum/instance_obsidian_sanctum.cpp +++ b/src/bindings/scripts/scripts/zone/obsidian_sanctum/instance_obsidian_sanctum.cpp @@ -1,9 +1,86 @@ #include "precompiled.h" #include "def_obsidian_sanctum.h" +#define ENCOUNTERS 1 + +/* Obsidian Sanctum encounters: +0 - Sartharion +*/ + struct TRINITY_DLL_DECL instance_obsidian_sanctum : public ScriptedInstance { instance_obsidian_sanctum(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + uint32 m_uiEncounter[ENCOUNTERS]; + uint64 m_uiSartharionGUID; + uint64 m_uiTenebronGUID; + uint64 m_uiShadronGUID; + uint64 m_uiVesperonGUID; + + void Initialize() + { + m_uiSartharionGUID = 0; + m_uiTenebronGUID = 0; + m_uiShadronGUID = 0; + m_uiVesperonGUID = 0; + + for(uint8 i = 0; i < ENCOUNTERS; ++i) + m_uiEncounter[i] = NOT_STARTED; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case NPC_SARTHARION: + m_uiSartharionGUID = pCreature->GetGUID(); + break; + //three dragons below set to active state once created. + //we must expect bigger raid to encounter main boss, and then three dragons must be active due to grid differences + case NPC_TENEBRON: + m_uiTenebronGUID = pCreature->GetGUID(); + pCreature->setActive(true); + break; + case NPC_SHADRON: + m_uiShadronGUID = pCreature->GetGUID(); + pCreature->setActive(true); + break; + case NPC_VESPERON: + m_uiVesperonGUID = pCreature->GetGUID(); + pCreature->setActive(true); + break; + } + } + + void SetData(uint32 uiType, uint32 uiData) + { + if (uiType == TYPE_SARTHARION_EVENT) + m_uiEncounter[0] = uiData; + } + + uint32 GetData(uint32 uiType) + { + if (uiType == TYPE_SARTHARION_EVENT) + return m_uiEncounter[0]; + + return 0; + } + + uint64 GetData64(uint32 uiData) + { + switch(uiData) + { + case DATA_SARTHARION: + return m_uiSartharionGUID; + case DATA_TENEBRON: + return m_uiTenebronGUID; + case DATA_SHADRON: + return m_uiShadronGUID; + case DATA_VESPERON: + return m_uiVesperonGUID; + } + return 0; + } }; InstanceData* GetInstanceData_instance_obsidian_sanctum(Map* map) diff --git a/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp b/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp index 96885e7e672..ceea0a66d85 100644 --- a/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp +++ b/src/bindings/scripts/scripts/zone/onyxias_lair/boss_onyxia.cpp @@ -97,9 +97,6 @@ struct TRINITY_DLL_DECL boss_onyxiaAI : public ScriptedAI FireballTimer = 18000; InitialSpawn = true; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void EnterCombat(Unit* who) diff --git a/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp b/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp index 7e6c439b4a8..daf71a0324d 100644 --- a/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp +++ b/src/bindings/scripts/scripts/zone/orgrimmar/orgrimmar.cpp @@ -126,13 +126,13 @@ struct TRINITY_DLL_DECL npc_shenthulAI : public ScriptedAI DoMeleeAttackIfReady(); } - void ReciveEmote_npc_shenthul(Player *player, uint32 emote) + void ReceiveEmote(Player* pPlayer, uint32 emote) { - if( emote == TEXTEMOTE_SALUTE && player->GetQuestStatus(QUEST_SHATTERED_SALUTE) == QUEST_STATUS_INCOMPLETE ) + if( emote == TEXTEMOTE_SALUTE && pPlayer->GetQuestStatus(QUEST_SHATTERED_SALUTE) == QUEST_STATUS_INCOMPLETE ) { if(CanEmote) { - player->AreaExploredOrEventHappens(QUEST_SHATTERED_SALUTE); + pPlayer->AreaExploredOrEventHappens(QUEST_SHATTERED_SALUTE); Reset(); } } diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp index d477483b125..12f2a66e885 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp @@ -15,44 +15,45 @@ */ /* ScriptData -SDName: Boss_High_Inquisitor_Faribanks +SDName: Boss_High_Inquisitor_Fairbanks SD%Complete: 100 -SDComment: +SDComment: TODO: if this guy not involved in some special event, remove (and let ACID script) SDCategory: Scarlet Monastery EndScriptData */ #include "precompiled.h" -#define SPELL_SLEEP2 1090 -#define SPELL_CURSEOFBLOOD 16098 -#define SPELL_SMITE 6060 -#define SPELL_SHADOWWORDPAIN 2767 -#define SPELL_FLASHHEAL4 9474 -#define SPELL_RENEW6 6078 -#define SPELL_DEVOURINGPLAGUE3 19277 -#define SPELL_MINDBLAST5 8105 +enum +{ + SPELL_CURSEOFBLOOD = 8282, + SPELL_DISPELMAGIC = 15090, + SPELL_FEAR = 12096, + SPELL_HEAL = 12039, + SPELL_POWERWORDSHIELD = 11647, + SPELL_SLEEP = 8399 +}; struct TRINITY_DLL_DECL boss_high_inquisitor_fairbanksAI : public ScriptedAI { boss_high_inquisitor_fairbanksAI(Creature *c) : ScriptedAI(c) {} - uint32 Healing_Timer; - uint32 Sleep2_Timer; - uint32 Smite_Timer; - uint32 ShadowWordPain_Timer; uint32 CurseOfBlood_Timer; - uint32 DevouringPlague3_Timer; - uint32 MindBlast5_Timer; + uint32 DispelMagic_Timer; + uint32 Fear_Timer; + uint32 Heal_Timer; + uint32 Sleep_Timer; + uint32 Dispel_Timer; + bool PowerWordShield; void Reset() { - Healing_Timer = 300; - Sleep2_Timer = 45000; - Smite_Timer = 30000; - ShadowWordPain_Timer = 30000; - CurseOfBlood_Timer = 45000; - DevouringPlague3_Timer = 60000; - MindBlast5_Timer = 20000; + CurseOfBlood_Timer = 10000; + DispelMagic_Timer = 30000; + Fear_Timer = 40000; + Heal_Timer = 30000; + Sleep_Timer = 30000; + Dispel_Timer = 20000; + PowerWordShield = false; } void EnterCombat(Unit *who) @@ -64,33 +65,46 @@ struct TRINITY_DLL_DECL boss_high_inquisitor_fairbanksAI : public ScriptedAI if (!UpdateVictim()) return; - //If we are <45% hp cast Renew rank 6 or Flash heal rank 4 - if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 45 && !m_creature->IsNonMeleeSpellCasted(false) && Healing_Timer < diff) + //If we are <25% hp cast Heal + if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 25 && !m_creature->IsNonMeleeSpellCasted(false) && Heal_Timer < diff) + { + DoCast(m_creature,SPELL_HEAL); + Heal_Timer = 30000; + }else Heal_Timer -= diff; + + //Fear_Timer + if (Fear_Timer < diff) { - DoCast(m_creature->getVictim(),SPELL_RENEW6 || SPELL_FLASHHEAL4); - Healing_Timer = 30000; - }else Healing_Timer -= diff; + if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM,1)) + DoCast(target,SPELL_FEAR); + + Fear_Timer = 40000; + }else Fear_Timer -= diff; - //Sleep2_Timer - if (Sleep2_Timer < diff) + //Sleep_Timer + if (Sleep_Timer < diff) { - DoCast(m_creature->getVictim(),SPELL_SLEEP2); - Sleep2_Timer = 45000; - }else Sleep2_Timer -= diff; + if (Unit* target = SelectUnit(SELECT_TARGET_TOPAGGRO,0)) + DoCast(target,SPELL_SLEEP); + + Sleep_Timer = 30000; + }else Sleep_Timer -= diff; - //Smite_Timer - if (Smite_Timer < diff) + //PowerWordShield_Timer + if (!PowerWordShield && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 25) { - DoCast(m_creature->getVictim(),SPELL_SMITE); - Smite_Timer = 20000; - }else Smite_Timer -= diff; + DoCast(m_creature,SPELL_POWERWORDSHIELD); + PowerWordShield = true; + } - //ShadowWordPain_Timer - if (ShadowWordPain_Timer < diff) + //Dispel_Timer + if (Dispel_Timer < diff) { - DoCast(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); - ShadowWordPain_Timer = 30000; - }else ShadowWordPain_Timer -= diff; + if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0)) + DoCast(target, SPELL_DISPELMAGIC); + + DispelMagic_Timer = 30000; + }else DispelMagic_Timer -= diff; //CurseOfBlood_Timer if (CurseOfBlood_Timer < diff) @@ -99,20 +113,6 @@ struct TRINITY_DLL_DECL boss_high_inquisitor_fairbanksAI : public ScriptedAI CurseOfBlood_Timer = 25000; }else CurseOfBlood_Timer -= diff; - //DevouringPlague3_Timer - if (DevouringPlague3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_DEVOURINGPLAGUE3); - DevouringPlague3_Timer = 35000; - }else DevouringPlague3_Timer -= diff; - - //MindBlast5_Timer - if (MindBlast5_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST5); - MindBlast5_Timer = 30000; - }else MindBlast5_Timer -= diff; - DoMeleeAttackIfReady(); } }; diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp index 370ed9aedc8..641432604af 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_houndmaster_loksey.cpp @@ -23,20 +23,22 @@ EndScriptData */ #include "precompiled.h" -#define SAY_AGGRO -1189021 - -#define SPELL_SUMMONSCARLETHOUND 17164 -#define SPELL_ENRAGE 6742 +enum +{ + SAY_AGGRO = -1189021, + SPELL_SUMMONSCARLETHOUND = 17164, + SPELL_BLOODLUST = 6742 +}; struct TRINITY_DLL_DECL boss_houndmaster_lokseyAI : public ScriptedAI { boss_houndmaster_lokseyAI(Creature *c) : ScriptedAI(c) {} - uint32 Enrage_Timer; + uint32 BloodLust_Timer; void Reset() { - Enrage_Timer = 0; + BloodLust_Timer = 20000; } void EnterCombat(Unit *who) @@ -49,12 +51,11 @@ struct TRINITY_DLL_DECL boss_houndmaster_lokseyAI : public ScriptedAI if (!UpdateVictim()) return; - //If we are <25% hp, bloodlust - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 25 && Enrage_Timer < diff) + if (BloodLust_Timer < diff) { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 60000; - }else Enrage_Timer -= diff; + DoCast(m_creature,SPELL_BLOODLUST); + BloodLust_Timer = 20000; + }else BloodLust_Timer -= diff; DoMeleeAttackIfReady(); } diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_mograine_and_whitemane.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_mograine_and_whitemane.cpp index 68bdcf9fa10..e523fc1dea6 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_mograine_and_whitemane.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/boss_mograine_and_whitemane.cpp @@ -16,280 +16,318 @@ /* ScriptData SDName: Boss_Mograine_And_Whitemane -SD%Complete: 75 -SDComment: Event not implemented +SD%Complete: 90 +SDComment: SDCategory: Scarlet Monastery EndScriptData */ #include "precompiled.h" #include "def_scarlet_monastery.h" -#define SAY_MO_AGGRO -1189005 -#define SAY_MO_KILL -1189006 -#define SAY_MO_RESSURECTED -1189007 - -#define SAY_WH_INTRO -1189008 -#define SAY_WH_KILL -1189009 -#define SAY_WH_RESSURECT -1189010 - -#define SPELL_DIVINESHIELD2 1020 -#define SPELL_CRUSADERSTRIKE5 35395 -#define SPELL_HAMMEROFJUSTICE3 5589 -#define SPELL_HOLYLIGHT6 3472 -#define SPELL_CONSECRATION3 20922 -#define SPELL_BLESSINGOFWISDOM 1044 -#define SPELL_RETRIBUTIONAURA3 10299 -#define SPELL_BLESSINGOFPROTECTION3 10278 -#define SPELL_FLASHHEAL6 10916 +enum +{ + //Mograine says + SAY_MO_AGGRO = -1189005, + SAY_MO_KILL = -1189006, + SAY_MO_RESSURECTED = -1189007, + + //Whitemane says + SAY_WH_INTRO = -1189008, + SAY_WH_KILL = -1189009, + SAY_WH_RESSURECT = -1189010, + + //Mograine Spells + SPELL_CRUSADERSTRIKE = 14518, + SPELL_HAMMEROFJUSTICE = 5589, + SPELL_LAYONHANDS = 9257, + SPELL_RETRIBUTIONAURA = 8990, + + //Whitemanes Spells + SPELL_DEEPSLEEP = 9256, + SPELL_SCARLETRESURRECTION = 9232, + SPELL_DOMINATEMIND = 14515, + SPELL_HOLYSMITE = 9481, + SPELL_HEAL = 12039, + SPELL_POWERWORDSHIELD = 22187 +}; struct TRINITY_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI { - boss_scarlet_commander_mograineAI(Creature *c) : ScriptedAI(c) + boss_scarlet_commander_mograineAI(Creature* pCreature) : ScriptedAI(pCreature) { - pInstance = m_creature->GetInstanceData(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); } - ScriptedInstance* pInstance; + ScriptedInstance* m_pInstance; + + uint32 m_uiCrusaderStrike_Timer; + uint32 m_uiHammerOfJustice_Timer; - uint32 Heal_Timer; - uint32 DivineShield2_Timer; - uint32 CrusaderStrike5_Timer; - uint32 HammerOfJustice3_Timer; - uint32 Consecration3_Timer; - uint32 BlessingOfWisdom_Timer; - uint32 BlessingOfProtection3_Timer; + bool m_bHasDied; + bool m_bHeal; + bool m_bFakeDeath; void Reset() { - Heal_Timer = 80000; - DivineShield2_Timer = 60000; - CrusaderStrike5_Timer = 20000; - HammerOfJustice3_Timer = 80000; - Consecration3_Timer = 30000; - BlessingOfWisdom_Timer = 45000; - BlessingOfProtection3_Timer = 45000; + m_uiCrusaderStrike_Timer = 10000; + m_uiHammerOfJustice_Timer = 10000; + + //Incase wipe during phase that mograine fake death + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + if (m_pInstance) + if (m_creature->isAlive()) + m_pInstance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT,NOT_STARTED); + + m_bHasDied = false; + m_bHeal = false; + m_bFakeDeath = false; + } + + void JustReachedHome() + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT != NOT_STARTED)) + m_pInstance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, FAIL); + } } - void EnterCombat(Unit *who) + void EnterCombat(Unit* pWho) { DoScriptText(SAY_MO_AGGRO, m_creature); - DoCast(m_creature,SPELL_RETRIBUTIONAURA3); + DoCast(m_creature,SPELL_RETRIBUTIONAURA); + + m_creature->CallForHelp(VISIBLE_RANGE); } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* pVictim) { DoScriptText(SAY_MO_KILL, m_creature); } - void UpdateAI(const uint32 diff) + void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) { - if (!UpdateVictim()) + if (uiDamage < m_creature->GetHealth() || m_bHasDied || m_bFakeDeath) return; - //If we are <50% hp cast Arcane Bubble and start casting SPECIAL Arcane Explosion - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50 && !m_creature->IsNonMeleeSpellCasted(false)) + if (!m_pInstance) + return; + + //On first death, fake death and open door, as well as initiate whitemane if exist + if (Unit* Whitemane = Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_WHITEMANE))) { - //heal_Timer - if (Heal_Timer < diff) - { - //Switch between 2 different charge methods - switch (rand()%2) - { - case 0: - DoCast(m_creature,SPELL_HOLYLIGHT6); - break; - case 1: - DoCast(m_creature,SPELL_FLASHHEAL6); - break; - } - return; + m_pInstance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); - //60 seconds until we should cast this agian - Heal_Timer = 60000; - }else Heal_Timer -= diff; + Whitemane->GetMotionMaster()->MovePoint(1,1163.113370,1398.856812,32.527786); + + m_creature->GetMotionMaster()->MovementExpired(); + m_creature->GetMotionMaster()->MoveIdle(); + + m_creature->SetHealth(0); + + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); + + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAuras(); + m_creature->ClearAllReactives(); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + m_bHasDied = true; + m_bFakeDeath = true; + + uiDamage = 0; } + } - //DivineShield2_Timer - if (DivineShield2_Timer < diff) + void SpellHit(Unit* pWho, const SpellEntry* pSpell) + { + //When hit with ressurection say text + if (pSpell->Id == SPELL_SCARLETRESURRECTION) { - DoCast(m_creature,SPELL_DIVINESHIELD2); - DivineShield2_Timer = 60000; - }else DivineShield2_Timer -= diff; + DoScriptText(SAY_MO_RESSURECTED, m_creature); + m_bFakeDeath = false; - //CrusaderStrike5_Timer - if (CrusaderStrike5_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE5); - CrusaderStrike5_Timer = 20000; - }else CrusaderStrike5_Timer -= diff; + if (m_pInstance) + m_pInstance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, SPECIAL); + } + } - //HammerOfJustice3_Timer - if (HammerOfJustice3_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE3); - HammerOfJustice3_Timer = 30000; - }else HammerOfJustice3_Timer -= diff; - //Consecration3_Timer - if (Consecration3_Timer < diff) + void UpdateAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + return; + + if (m_bHasDied && !m_bHeal && m_pInstance && m_pInstance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) { - DoCast(m_creature->getVictim(),SPELL_CONSECRATION3); - Consecration3_Timer = 20000; - }else Consecration3_Timer -= diff; + //On ressurection, stop fake death and heal whitemane and resume fight + if (Unit* Whitemane = Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_WHITEMANE))) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(Whitemane, SPELL_LAYONHANDS); + + m_uiCrusaderStrike_Timer = 10000; + m_uiHammerOfJustice_Timer = 10000; + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - //BlessingOfWisdom_Timer - if (BlessingOfWisdom_Timer < diff) + m_bHeal = true; + } + } + + //This if-check to make sure mograine does not attack while fake death + if (m_bFakeDeath) + return; + + //m_uiCrusaderStrike_Timer + if (m_uiCrusaderStrike_Timer < uiDiff) { - DoCast(m_creature,SPELL_BLESSINGOFWISDOM); - BlessingOfWisdom_Timer = 45000; - }else BlessingOfWisdom_Timer -= diff; + DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); + m_uiCrusaderStrike_Timer = 10000; + }else m_uiCrusaderStrike_Timer -= uiDiff; - //BlessingOfProtection3_Timer - if (BlessingOfProtection3_Timer < diff) + //m_uiHammerOfJustice_Timer + if (m_uiHammerOfJustice_Timer < uiDiff) { - DoCast(m_creature,SPELL_BLESSINGOFPROTECTION3); - BlessingOfProtection3_Timer = 50000; - }else BlessingOfProtection3_Timer -= diff; + DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE); + m_uiHammerOfJustice_Timer = 60000; + }else m_uiHammerOfJustice_Timer -= uiDiff; DoMeleeAttackIfReady(); } }; -#define SPELL_DEEPSLEEP 9256 -#define SPELL_SCARLETRESURRECTION 9232 - -#define SPELL_CRUSADERSTRIKE 17281 -#define SPELL_HAMMEROFJUSTICE 13005 -#define SPELL_HOLYSMITE6 9481 -#define SPELL_HOLYFIRE5 15265 -#define SPELL_MINDBLAST6 8106 - -#define SPELL_POWERWORDSHIELD 6065 - -#define SPELL_RENEW 6078 -#define SPELL_FLASHHEAL6 10916 - struct TRINITY_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI { - boss_high_inquisitor_whitemaneAI(Creature *c) : ScriptedAI(c) + boss_high_inquisitor_whitemaneAI(Creature* pCreature) : ScriptedAI(pCreature) { - pInstance = m_creature->GetInstanceData(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); } - ScriptedInstance* pInstance; + ScriptedInstance* m_pInstance; - uint32 Healing_Timer; - uint32 Renew_Timer; - uint32 PowerWordShield_Timer; - uint32 CrusaderStrike_Timer; - uint32 HammerOfJustice_Timer; - uint32 HolySmite6_Timer; - uint32 HolyFire5_Timer; - uint32 MindBlast6_Timer; + uint32 m_uiHeal_Timer; + uint32 m_uiPowerWordShield_Timer; + uint32 m_uiHolySmite_Timer; + uint32 m_uiWait_Timer; + + bool m_bCanResurrectCheck; + bool m_bCanResurrect; void Reset() { - Healing_Timer = 0; - Renew_Timer= 0; - PowerWordShield_Timer = 2000; - CrusaderStrike_Timer = 12000; - HammerOfJustice_Timer = 18000; - HolySmite6_Timer = 10000; - HolyFire5_Timer = 20000; - MindBlast6_Timer = 6000; + m_uiWait_Timer = 7000; + m_uiHeal_Timer = 10000; + m_uiPowerWordShield_Timer = 15000; + m_uiHolySmite_Timer = 6000; + + m_bCanResurrectCheck = false; + m_bCanResurrect = false; + + if (m_pInstance) + if (m_creature->isAlive()) + m_pInstance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); + } + + void AttackStart(Unit* pWho) + { + if (m_pInstance && m_pInstance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED) + return; + + ScriptedAI::AttackStart(pWho); } - void EnterCombat(Unit *who) + void EnterCombat(Unit* pWho) { DoScriptText(SAY_WH_INTRO, m_creature); } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* pVictim) { DoScriptText(SAY_WH_KILL, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) { if (!UpdateVictim()) return; - /* - //This is going to be a routine to make the resurrection event... - if (m_creature->isAlive && m_creature->isAlive) + if (m_bCanResurrect) { - m_creature->Relocate(1163.113370,1398.856812,32.527786,3.171014); - - DoScriptText(SAY_WH_RESSURECT, m_creature); - - DoCast(m_creature->getVictim(),SPELL_DEEPSLEEP); - DoCast(m-creature->GetGUID(51117),SPELL_SCARLETRESURRECTION) + //When casting resuruction make sure to delay so on rez when reinstate battle deepsleep runs out + if (m_pInstance && m_uiWait_Timer < uiDiff) + { + if (Unit* Mograine = Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_MOGRAINE))) + { + DoCast(Mograine, SPELL_SCARLETRESURRECTION); + DoScriptText(SAY_WH_RESSURECT, m_creature); + m_bCanResurrect = false; + } + } + else m_uiWait_Timer -= uiDiff; } - */ - //If we are <75% hp cast healing spells at self and Mograine - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 75 ) + //Cast Deep sleep when health is less than 50% + if (!m_bCanResurrectCheck && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 50) { - if (Healing_Timer < diff) - { - DoCast(m_creature,SPELL_FLASHHEAL6); - return; + if (m_creature->IsNonMeleeSpellCasted(false)) + m_creature->InterruptNonMeleeSpells(false); - //22-32 seconds until we should cast this agian - Healing_Timer = 22000 + rand()%10000; - }else Healing_Timer -= diff; + DoCast(m_creature->getVictim(), SPELL_DEEPSLEEP); + m_bCanResurrectCheck = true; + m_bCanResurrect = true; + return; } - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() <= 30) - { - if (Renew_Timer < diff) - { - DoCast(m_creature,SPELL_RENEW); - Renew_Timer = 30000; - }else Renew_Timer -= diff; - } + //while in "resurrect-mode", don't do anything + if (m_bCanResurrect) + return; - //PowerWordShield_Timer - if (PowerWordShield_Timer < diff) + //If we are <75% hp cast healing spells at self or Mograine + if (m_uiHeal_Timer < uiDiff) { - DoCast(m_creature,SPELL_POWERWORDSHIELD); - PowerWordShield_Timer = 25000; - }else PowerWordShield_Timer -= diff; + Creature* pTarget = NULL; - //CrusaderStrike_Timer - if (CrusaderStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); - CrusaderStrike_Timer = 15000; - }else CrusaderStrike_Timer -= diff; + if (m_creature->GetHealth() <= m_creature->GetMaxHealth()*0.75f) + pTarget = m_creature; - //HammerOfJustice_Timer - if (HammerOfJustice_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE); - HammerOfJustice_Timer = 12000; - }else HammerOfJustice_Timer -= diff; + if (m_pInstance) + { + if (Creature* pMograine = (Creature*)Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_MOGRAINE))) + { + // checking m_bCanResurrectCheck prevents her healing Mograine while he is "faking death" + if (m_bCanResurrectCheck && pMograine->isAlive() && pMograine->GetHealth() <= pMograine->GetMaxHealth()*0.75f) + pTarget = pMograine; + } + } - //HolySmite6_Timer - if (HolySmite6_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_HOLYSMITE6); - HolySmite6_Timer = 10000; - }else HolySmite6_Timer -= diff; + if (pTarget) + DoCast(pTarget, SPELL_HEAL); - //HolyFire5_Timer - if (HolyFire5_Timer < diff) + m_uiHeal_Timer = 13000; + }else m_uiHeal_Timer -= uiDiff; + + //m_uiPowerWordShield_Timer + if (m_uiPowerWordShield_Timer < uiDiff) { - DoCast(m_creature->getVictim(),SPELL_HOLYFIRE5); - HolyFire5_Timer = 15000; - }else HolyFire5_Timer -= diff; + DoCast(m_creature,SPELL_POWERWORDSHIELD); + m_uiPowerWordShield_Timer = 15000; + }else m_uiPowerWordShield_Timer -= uiDiff; - //MindBlast6_Timer - if (MindBlast6_Timer < diff) + //m_uiHolySmite_Timer + if (m_uiHolySmite_Timer < uiDiff) { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST6); - MindBlast6_Timer = 8000; - }else MindBlast6_Timer -= diff; + DoCast(m_creature->getVictim(),SPELL_HOLYSMITE); + m_uiHolySmite_Timer = 6000; + }else m_uiHolySmite_Timer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/src/bindings/scripts/scripts/zone/scarlet_monastery/instance_scarlet_monastery.cpp b/src/bindings/scripts/scripts/zone/scarlet_monastery/instance_scarlet_monastery.cpp index 280a2869948..61576780cec 100644 --- a/src/bindings/scripts/scripts/zone/scarlet_monastery/instance_scarlet_monastery.cpp +++ b/src/bindings/scripts/scripts/zone/scarlet_monastery/instance_scarlet_monastery.cpp @@ -91,6 +91,11 @@ struct TRINITY_DLL_DECL instance_scarlet_monastery : public ScriptedInstance switch(type) { case TYPE_MOGRAINE_AND_WHITE_EVENT: + if (data == IN_PROGRESS) + DoUseDoorOrButton(DoorHighInquisitorGUID); + if (data == FAIL) + DoUseDoorOrButton(DoorHighInquisitorGUID); + Encounter[0] = data; break; case GAMEOBJECT_PUMPKIN_SHRINE: diff --git a/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp b/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp index ca40ff16322..e02d077f927 100644 --- a/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp +++ b/src/bindings/scripts/scripts/zone/shadowmoon_valley/shadowmoon_valley.cpp @@ -139,7 +139,7 @@ struct TRINITY_DLL_DECL mob_mature_netherwing_drakeAI : public ScriptedAI DoScriptText(SAY_JUST_EATEN, m_creature); if (Player* pPlr = Unit::GetPlayer(uiPlayerGUID)) - pPlr->KilledMonster(NPC_EVENT_PINGER, m_creature->GetGUID()); + pPlr->KilledMonsterCredit(NPC_EVENT_PINGER, m_creature->GetGUID()); Reset(); m_creature->GetMotionMaster()->Clear(); @@ -269,7 +269,7 @@ struct TRINITY_DLL_DECL mob_enslaved_netherwing_drakeAI : public ScriptedAI Player* plr = Unit::GetPlayer(PlayerGUID); if(plr && plr->GetQuestStatus(10854) == QUEST_STATUS_INCOMPLETE) { - plr->KilledMonster(22316, m_creature->GetGUID()); + DoCast(plr, SPELL_FORCE_OF_NELTHARAKU, true); /* float x,y,z; m_creature->GetPosition(x,y,z); @@ -366,7 +366,7 @@ struct TRINITY_DLL_DECL mob_dragonmaw_peonAI : public ScriptedAI { Player* plr = Unit::GetPlayer(PlayerGUID); if(plr && plr->GetQuestStatus(11020) == QUEST_STATUS_INCOMPLETE) - plr->KilledMonster(23209, m_creature->GetGUID()); + plr->KilledMonsterCredit(23209, m_creature->GetGUID()); } PoisonTimer = 0; m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); @@ -1681,13 +1681,13 @@ CreatureAI* GetAI_mob_torloth_the_magnificent(Creature* c) #define ENTRY_ENRAGED_AIRY_SOUL 21116 #define ENTRY_ENRAGED_WATERY_SOUL 21109 // wrong model -/* SPELL KILLCREDIT - not working!?! - using KilledMonster */ +/* SPELL KILLCREDIT - not working!?! - using KilledMonsterCredit */ #define SPELL_EARTHEN_SOUL_CAPTURED_CREDIT 36108 #define SPELL_FIERY_SOUL_CAPTURED_CREDIT 36117 #define SPELL_AIRY_SOUL_CAPTURED_CREDIT 36182 #define SPELL_WATERY_SOUL_CAPTURED_CREDIT 36171 -/* KilledMonster Workaround */ +/* KilledMonsterCredit Workaround */ #define CREDIT_FIRE 21094 #define CREDIT_WATER 21095 #define CREDIT_AIR 21096 @@ -1758,7 +1758,7 @@ struct TRINITY_DLL_DECL npc_enraged_spiritAI : public ScriptedAI Unit* Owner = totemOspirits->GetOwner(); if (Owner && Owner->GetTypeId() == TYPEID_PLAYER) // DoCast(Owner, credit); -- not working! - CAST_PLR(Owner)->KilledMonster(credit, Summoned->GetGUID()); + CAST_PLR(Owner)->KilledMonsterCredit(credit, Summoned->GetGUID()); DoCast(totemOspirits,SPELL_SOUL_CAPTURED); } } diff --git a/src/bindings/scripts/scripts/zone/sholazar_basin/sholazar_basin.cpp b/src/bindings/scripts/scripts/zone/sholazar_basin/sholazar_basin.cpp new file mode 100644 index 00000000000..d48f4377a09 --- /dev/null +++ b/src/bindings/scripts/scripts/zone/sholazar_basin/sholazar_basin.cpp @@ -0,0 +1,180 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Sholazar_Basin +SD%Complete: 100 +SDComment: Quest support: 12570 +SDCategory: Sholazar_Basin +EndScriptData */ + +/* ContentData +npc_injured_rainspeaker_oracle +EndContentData */ + +#include "precompiled.h" +#include "../../npc/npc_escortAI.h" + +/*###### +## npc_injured_rainspeaker_oracle +######*/ + +#define GOSSIP_ITEM1 "I am ready to travel to your village now." + +enum +{ + SAY_START_IRO = -1571000, + SAY_QUEST_ACCEPT_IRO = -1571001, + SAY_END_IRO = -1571002, + + QUEST_FORTUNATE_MISUNDERSTANDINGS = 12570, + FACTION_ESCORTEE_A = 774, + FACTION_ESCORTEE_H = 775 +}; + +struct TRINITY_DLL_DECL npc_injured_rainspeaker_oracleAI : public npc_escortAI +{ + npc_injured_rainspeaker_oracleAI(Creature* c) : npc_escortAI(c) { c_guid = c->GetGUID(); } + + uint64 c_guid; + + void Reset() + { + me->RestoreFaction(); + // if we will have other way to assign this to only one npc remove this part + if(GUID_LOPART(me->GetGUID()) != 101030) + { + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + } + + void WaypointReached(uint32 i) + { + Player* player = Unit::GetPlayer(PlayerGUID); + + if(!player) + return; + + switch(i) + { + case 1: SetRun(); break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING); + m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_JUMPING); + m_creature->SetSpeed(MOVE_SWIM, 0.85f, true); + m_creature->AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING + MOVEMENTFLAG_LEVITATING); + break; + case 19: + m_creature->SetUnitMovementFlags(MOVEMENTFLAG_JUMPING); + break; + case 28: + if(Player* pPlayer = Unit::GetPlayer( PlayerGUID)) + player->GroupEventHappens(QUEST_FORTUNATE_MISUNDERSTANDINGS, m_creature); + // me->RestoreFaction(); + DoScriptText(SAY_END_IRO,m_creature); + SetRun(false); + break; + } + } + + void JustDied(Unit* killer) + { + if (!IsBeingEscorted) + return; + + if(Player* pPlayer = Unit::GetPlayer(PlayerGUID)) + { + if(pPlayer->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) != QUEST_STATUS_COMPLETE) + pPlayer->FailQuest(QUEST_FORTUNATE_MISUNDERSTANDINGS); + } + } + + void UpdateAI(Player *player, Creature *_Creature,const uint32 diff) + { + npc_escortAI::UpdateAI(diff); + } +}; + + +bool GossipHello_npc_injured_rainspeaker_oracle(Player *player, Creature *_Creature ) +{ + if( _Creature->isQuestGiver() ) + player->PrepareQuestMenu( _Creature->GetGUID() ); + + if( player->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) == QUEST_STATUS_INCOMPLETE ) + player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + + player->SEND_GOSSIP_MENU(_Creature->GetNpcTextId(), _Creature->GetGUID()); + + return true; +} + +bool GossipSelect_npc_injured_rainspeaker_oracle(Player *player, Creature *_Creature, uint32 sender, uint32 action ) +{ + if( action == GOSSIP_ACTION_INFO_DEF+1 ) + { + CAST_AI(npc_escortAI, (_Creature->AI()))->Start(true, true, false, player->GetGUID()); + CAST_AI(npc_escortAI, (_Creature->AI()))->SetMaxPlayerDistance(35.0f); + _Creature->SetUnitMovementFlags(MOVEMENTFLAG_JUMPING); + DoScriptText(SAY_START_IRO,_Creature); + + switch (player->GetTeam()){ + case ALLIANCE: + _Creature->setFaction(FACTION_ESCORTEE_A); + break; + case HORDE: + _Creature->setFaction(FACTION_ESCORTEE_H); + break; + } + } + return true; +} + +bool QuestAccept_npc_injured_rainspeaker_oracle(Player *player, Creature *_Creature, Quest const *_Quest) +{ + DoScriptText(SAY_QUEST_ACCEPT_IRO,_Creature); + return false; +} + +CreatureAI* GetAI_npc_injured_rainspeaker_oracle(Creature *_Creature) +{ + npc_injured_rainspeaker_oracleAI* thisAI = new npc_injured_rainspeaker_oracleAI(_Creature); + + thisAI->FillPointMovementListForCreature(); + + return thisAI; +} + +void AddSC_sholazar_basin() +{ + Script *newscript; + newscript = new Script; + newscript->Name = "npc_injured_rainspeaker_oracle"; + newscript->GetAI = &GetAI_npc_injured_rainspeaker_oracle; + newscript->pGossipHello = &GossipHello_npc_injured_rainspeaker_oracle; + newscript->pGossipSelect = &GossipSelect_npc_injured_rainspeaker_oracle; + newscript->pQuestAccept = &QuestAccept_npc_injured_rainspeaker_oracle; + newscript->RegisterSelf(); +} diff --git a/src/bindings/scripts/scripts/zone/silithus/silithus.cpp b/src/bindings/scripts/scripts/zone/silithus/silithus.cpp index b05fa68bbf6..e748f39eab9 100644 --- a/src/bindings/scripts/scripts/zone/silithus/silithus.cpp +++ b/src/bindings/scripts/scripts/zone/silithus/silithus.cpp @@ -168,7 +168,7 @@ bool GossipSelect_npcs_rutgar_and_frankal(Player *player, Creature *_Creature, u case GOSSIP_ACTION_INFO_DEF + 6: player->SEND_GOSSIP_MENU(7761, _Creature->GetGUID()); //'kill' our trigger to update quest status - player->KilledMonster( TRIGGER_RUTGAR, _Creature->GetGUID() ); + player->KilledMonsterCredit( TRIGGER_RUTGAR, _Creature->GetGUID() ); break; case GOSSIP_ACTION_INFO_DEF + 9: @@ -194,7 +194,7 @@ bool GossipSelect_npcs_rutgar_and_frankal(Player *player, Creature *_Creature, u case GOSSIP_ACTION_INFO_DEF + 14: player->SEND_GOSSIP_MENU(7767, _Creature->GetGUID()); //'kill' our trigger to update quest status - player->KilledMonster( TRIGGER_FRANKAL, _Creature->GetGUID() ); + player->KilledMonsterCredit( TRIGGER_FRANKAL, _Creature->GetGUID() ); break; } return true; diff --git a/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp b/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp index a02fa8ebfdd..114732a2015 100644 --- a/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp +++ b/src/bindings/scripts/scripts/zone/stormwind/stormwind_city.cpp @@ -104,7 +104,7 @@ struct TRINITY_DLL_DECL npc_bartlebyAI : public ScriptedAI uiDamage = 0; if (pDoneBy->GetTypeId() == TYPEID_PLAYER) - ((Player*)pDoneBy)->AreaExploredOrEventHappens(QUEST_BEAT); + CAST_PLR(pDoneBy)->AreaExploredOrEventHappens(QUEST_BEAT); EnterEvadeMode(); } } @@ -168,7 +168,7 @@ struct TRINITY_DLL_DECL npc_dashel_stonefistAI : public ScriptedAI uiDamage = 0; if (pDoneBy->GetTypeId() == TYPEID_PLAYER) - ((Player*)pDoneBy)->AreaExploredOrEventHappens(QUEST_MISSING_DIPLO_PT8); + CAST_PLR(pDoneBy)->AreaExploredOrEventHappens(QUEST_MISSING_DIPLO_PT8); EnterEvadeMode(); } diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp index 092318fd7af..9d46ad70807 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_baron_rivendare.cpp @@ -98,12 +98,15 @@ struct TRINITY_DLL_DECL boss_baron_rivendareAI : public ScriptedAI MortalStrike_Timer = 12000; // RaiseDead_Timer = 30000; SummonSkeletons_Timer = 34000; + if (pInstance && pInstance->GetData(TYPE_RAMSTEIN) == DONE) + pInstance->SetData(TYPE_BARON,NOT_STARTED); } - void EnterCombat(Unit *who) + void AttackStart(Unit* who) { - if (pInstance) + if (pInstance)//can't use entercombat(), boss' dmg aura sets near players in combat, before entering the room's door pInstance->SetData(TYPE_BARON,IN_PROGRESS); + ScriptedAI::AttackStart(who); } void JustSummoned(Creature* summoned) diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp index 411df116e6c..1942b99f056 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_dathrohan_balnazzar.cpp @@ -15,9 +15,9 @@ */ /* ScriptData -SDName: boss_darhrohan_balnazzar -SD%Complete: 75 -SDComment: Fix timers, fix spells, possibly fix summons after death +SDName: Boss_Dathrohan_Balnazzar +SD%Complete: 95 +SDComment: Possibly need to fix/improve summons after death SDCategory: Stratholme EndScriptData */ @@ -28,17 +28,16 @@ enum //Dathrohan spells SPELL_CRUSADERSHAMMER = 17286, //AOE stun SPELL_CRUSADERSTRIKE = 17281, - SPELL_MINDBLAST = 17287, SPELL_HOLYSTRIKE = 17284, //weapon dmg +3 //Transform SPELL_BALNAZZARTRANSFORM = 17288, //restore full HP/mana, trigger spell Balnazzar Transform Stun //Balnazzar spells - SPELL_SHADOWSHOCK = 20603, //AOE 740-860dmg - SPELL_PSYCHICSCREAM = 15398, //One target, might want to make a code selecting random target + SPELL_SHADOWSHOCK = 17399, + SPELL_MINDBLAST = 17287, + SPELL_PSYCHICSCREAM = 13704, SPELL_SLEEP = 12098, - SPELL_SHADOWBOLTVOLLEY = 20741, //AOE, 255-345dmg SPELL_MINDCONTROL = 15690, NPC_DATHROHAN = 10812, @@ -75,20 +74,18 @@ struct TRINITY_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI uint32 m_uiShadowShock_Timer; uint32 m_uiPsychicScream_Timer; uint32 m_uiDeepSleep_Timer; - uint32 m_uiShadowBoltVolley_Timer; uint32 m_uiMindControl_Timer; bool m_bTransformed; void Reset() { m_uiCrusadersHammer_Timer = 8000; - m_uiCrusaderStrike_Timer = 14000; - m_uiMindBlast_Timer = 17000; + m_uiCrusaderStrike_Timer = 12000; + m_uiMindBlast_Timer = 6000; m_uiHolyStrike_Timer = 18000; m_uiShadowShock_Timer = 4000; m_uiPsychicScream_Timer = 16000; m_uiDeepSleep_Timer = 20000; - m_uiShadowBoltVolley_Timer = 9000; m_uiMindControl_Timer = 10000; m_bTransformed = false; @@ -118,6 +115,13 @@ struct TRINITY_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI //START NOT TRANSFORMED if (!m_bTransformed) { + //MindBlast + if (m_uiMindBlast_Timer < uiDiff) + { + DoCast(m_creature->getVictim(),SPELL_MINDBLAST); + m_uiMindBlast_Timer = 15000 + rand()%5000; + }else m_uiMindBlast_Timer -= uiDiff; + //CrusadersHammer if (m_uiCrusadersHammer_Timer < uiDiff) { @@ -132,13 +136,6 @@ struct TRINITY_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI m_uiCrusaderStrike_Timer = 15000; }else m_uiCrusaderStrike_Timer -= uiDiff; - //MindBlast - if (m_uiMindBlast_Timer < uiDiff) - { - DoCast(m_creature->getVictim(),SPELL_MINDBLAST); - m_uiMindBlast_Timer = 10000; - }else m_uiMindBlast_Timer -= uiDiff; - //HolyStrike if (m_uiHolyStrike_Timer < uiDiff) { @@ -164,7 +161,7 @@ struct TRINITY_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI if (m_uiMindBlast_Timer < uiDiff) { DoCast(m_creature->getVictim(),SPELL_MINDBLAST); - m_uiMindBlast_Timer = 10000; + m_uiMindBlast_Timer = 15000 + rand()%5000; }else m_uiMindBlast_Timer -= uiDiff; //ShadowShock @@ -192,13 +189,6 @@ struct TRINITY_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI m_uiDeepSleep_Timer = 15000; }else m_uiDeepSleep_Timer -= uiDiff; - //ShadowBoltVolley - if (m_uiShadowBoltVolley_Timer < uiDiff) - { - DoCast(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); - m_uiShadowBoltVolley_Timer = 13000; - }else m_uiShadowBoltVolley_Timer -= uiDiff; - //MindControl if (m_uiMindControl_Timer < uiDiff) { diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp index 4405a50461b..4d6dc2a6b06 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_order_of_silver_hand.cpp @@ -108,7 +108,7 @@ struct TRINITY_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI break; } if(pInstance->GetData(TYPE_SH_QUEST) && Killer->GetTypeId() == TYPEID_PLAYER) - CAST_PLR(Killer)->KilledMonster(SH_QUEST_CREDIT,m_creature->GetGUID()); + CAST_PLR(Killer)->KilledMonsterCredit(SH_QUEST_CREDIT,m_creature->GetGUID()); } } diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp index 1ecb95333c4..e1ae2b643c8 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/boss_ramstein_the_gorger.cpp @@ -54,7 +54,10 @@ struct TRINITY_DLL_DECL boss_ramstein_the_gorgerAI : public ScriptedAI void JustDied(Unit* Killer) { for(uint8 i = 0; i < 30; i++) - m_creature->SummonCreature(C_MINDLESS_UNDEAD,3969.35,-3391.87,119.11,5.91,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,1800000); + { + if(Creature* mob = m_creature->SummonCreature(C_MINDLESS_UNDEAD,3969.35+irand(-10,10),-3391.87+irand(-10,10),119.11,5.91,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,1800000)) + mob->AI()->AttackStart(m_creature->SelectNearestTarget(500)); + } if (pInstance) pInstance->SetData(TYPE_RAMSTEIN,DONE); diff --git a/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp b/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp index 03977287d71..1b0e7137df3 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/instance_stratholme.cpp @@ -156,8 +156,16 @@ struct TRINITY_DLL_DECL instance_stratholme : public ScriptedInstance case GO_ZIGGURAT1: ziggurat1GUID = go->GetGUID(); break; case GO_ZIGGURAT2: ziggurat2GUID = go->GetGUID(); break; case GO_ZIGGURAT3: ziggurat3GUID = go->GetGUID(); break; - case GO_ZIGGURAT4: ziggurat4GUID = go->GetGUID(); break; - case GO_ZIGGURAT5: ziggurat5GUID = go->GetGUID(); break; + case GO_ZIGGURAT4: + ziggurat4GUID = go->GetGUID(); + if(TYPE_BARON == DONE || TYPE_RAMSTEIN == DONE) + HandleGameObject(0, true, go); + break; + case GO_ZIGGURAT5: + ziggurat5GUID = go->GetGUID(); + if(TYPE_BARON == DONE || TYPE_RAMSTEIN == DONE) + HandleGameObject(0, true, go); + break; case GO_PORT_GAUNTLET: portGauntletGUID = go->GetGUID(); break; case GO_PORT_SLAUGTHER: portSlaugtherGUID = go->GetGUID(); break; case GO_PORT_ELDERS: portElderGUID = go->GetGUID(); break; @@ -248,6 +256,8 @@ struct TRINITY_DLL_DECL instance_stratholme : public ScriptedInstance case TYPE_BARON: if (data == IN_PROGRESS) { + HandleGameObject(ziggurat4GUID, false); + HandleGameObject(ziggurat5GUID, false); if (GetData(TYPE_BARON_RUN) == IN_PROGRESS) { Map::PlayerList const& players = instance->GetPlayers(); @@ -270,6 +280,11 @@ struct TRINITY_DLL_DECL instance_stratholme : public ScriptedInstance SetData(TYPE_BARON_RUN,DONE); } } + if (data == DONE || data == NOT_STARTED) + { + HandleGameObject(ziggurat4GUID, true); + HandleGameObject(ziggurat5GUID, true); + } Encounter[5] = data; break; case TYPE_SH_AELMAR: @@ -288,6 +303,40 @@ struct TRINITY_DLL_DECL instance_stratholme : public ScriptedInstance IsSilverHandDead[4] = (data) ? true : false; break; } + if(data == DONE)SaveToDB(); + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << Encounter[0] << " " << Encounter[1] << " " << Encounter[2] << " " + << Encounter[3] << " " << Encounter[4] << " " << Encounter[5]; + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); + } + + void Load(const char* in) + { + if (!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(in); + + std::istringstream loadStream(in); + loadStream >> Encounter[0] >> Encounter[1] >> Encounter[2] >> Encounter[3] + >> Encounter[4] >> Encounter[5]; + + for(uint8 i = 0; i < ENCOUNTERS; ++i) + if (Encounter[i] == IN_PROGRESS) + Encounter[i] = NOT_STARTED; + + OUT_LOAD_INST_DATA_COMPLETE; } uint32 GetData(uint32 type) diff --git a/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp b/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp index 7bbc3b91e98..8441831165a 100644 --- a/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp +++ b/src/bindings/scripts/scripts/zone/stratholme/stratholme.cpp @@ -147,7 +147,7 @@ struct TRINITY_DLL_DECL mob_restless_soulAI : public ScriptedAI void JustDied(Unit* Killer) { if (Tagged) - DoSpawnCreature(ENTRY_FREED, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 300000); + m_creature->SummonCreature(ENTRY_FREED, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000); } void UpdateAI(const uint32 diff) @@ -172,7 +172,11 @@ CreatureAI* GetAI_mob_restless_soul(Creature *_Creature) ## mobs_spectral_ghostly_citizen ######*/ -#define SPELL_HAUNTING_PHANTOM 16336 +enum +{ + SPELL_HAUNTING_PHANTOM = 16336, + SPELL_SLAP = 6754 +}; struct TRINITY_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI { @@ -228,7 +232,7 @@ struct TRINITY_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI DoMeleeAttackIfReady(); } - void ReciveEmote(Player *player, uint32 emote) + void ReceiveEmote(Player* pPlayer, uint32 emote) { switch(emote) { @@ -236,9 +240,8 @@ struct TRINITY_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI EnterEvadeMode(); break; case TEXTEMOTE_RUDE: - //Should instead cast spell, kicking player back. Spell not found. - if (m_creature->IsWithinDistInMap(player, 5)) - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_RUDE); + if (m_creature->IsWithinDistInMap(pPlayer, 5)) + m_creature->CastSpell(pPlayer,SPELL_SLAP,false); else m_creature->HandleEmoteCommand(EMOTE_ONESHOT_RUDE); break; diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp index 5fac071128f..debfd7da595 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp @@ -115,36 +115,40 @@ float Humanoides[6][5] = uint32 EnrageTimer = 600000; struct TRINITY_DLL_DECL boss_entropiusAI : public ScriptedAI { - boss_entropiusAI(Creature *c) : ScriptedAI(c), Summons(m_creature){ + boss_entropiusAI(Creature *c) : ScriptedAI(c), Summons(m_creature) + { pInstance = c->GetInstanceData(); - Combat = false; } ScriptedInstance* pInstance; SummonList Summons; - bool Combat; uint32 BlackHoleSummonTimer; - void Reset() { - if (!Combat){ - BlackHoleSummonTimer = 15000; - DoCastAOE(SPELL_NEGATIVE_ENERGY_E, false); - }else{ - if(pInstance) - pInstance->SetData(DATA_MURU_EVENT, NOT_STARTED); - Summons.DespawnAll(); - } + void Reset() + { + BlackHoleSummonTimer = 15000; + DoCastAOE(SPELL_NEGATIVE_ENERGY_E, false); + + Summons.DespawnAll(); + + if(pInstance) + pInstance->SetData(DATA_MURU_EVENT, NOT_STARTED); } - void EnterCombat(Unit *who) { + void EnterCombat(Unit *who) + { DoCastAOE(SPELL_NEGATIVE_ENERGY_E, true); DoCast(m_creature, SPELL_ENTROPIUS_SPAWN, false); + + if(pInstance) + pInstance->SetData(DATA_MURU_EVENT, IN_PROGRESS); } void JustSummoned(Creature* summoned) { - switch(summoned->GetEntry()){ + switch(summoned->GetEntry()) + { case CREATURE_DARK_FIENDS: summoned->CastSpell(summoned,SPELL_DARKFIEND_VISUAL,false); break; @@ -159,13 +163,12 @@ struct TRINITY_DLL_DECL boss_entropiusAI : public ScriptedAI Summons.Summon(summoned); } - void KilledUnit(Unit* victim){ - - } - - void JustDied(Unit* killer){ - if(pInstance)pInstance->SetData(DATA_MURU_EVENT, DONE); + void JustDied(Unit* killer) + { Summons.DespawnAll(); + + if(pInstance) + pInstance->SetData(DATA_MURU_EVENT, DONE); } void UpdateAI(const uint32 diff) @@ -173,25 +176,29 @@ struct TRINITY_DLL_DECL boss_entropiusAI : public ScriptedAI if(!UpdateVictim()) return; - if(!Combat)Combat = true; - - if(EnrageTimer < diff && !m_creature->HasAura(SPELL_ENRAGE, 0)){ + if(EnrageTimer < diff && !m_creature->HasAura(SPELL_ENRAGE, 0)) + { DoCast(m_creature,SPELL_ENRAGE, false); }else EnrageTimer -= diff; - if(BlackHoleSummonTimer < diff){ + if(BlackHoleSummonTimer < diff) + { Unit* random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if(!random)return; + if(!random) + return; + DoCast(random, SPELL_DARKNESS_E, false); + random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); - if(!random)return; + if(!random) + return; + random->CastSpell(random, SPELL_BLACKHOLE, false); BlackHoleSummonTimer = 15000; }else BlackHoleSummonTimer -= diff; DoMeleeAttackIfReady(); } - }; CreatureAI* GetAI_boss_entropius(Creature *_Creature) @@ -201,7 +208,8 @@ CreatureAI* GetAI_boss_entropius(Creature *_Creature) struct TRINITY_DLL_DECL boss_muruAI : public Scripted_NoMovementAI { - boss_muruAI(Creature *c) : Scripted_NoMovementAI(c), Summons(m_creature){ + boss_muruAI(Creature *c) : Scripted_NoMovementAI(c), Summons(m_creature) + { pInstance = c->GetInstanceData(); } @@ -223,36 +231,42 @@ struct TRINITY_DLL_DECL boss_muruAI : public Scripted_NoMovementAI Timer[TIMER_HUMANOIDES] = 10000; Timer[TIMER_PHASE] = 2000; Timer[TIMER_SENTINEL] = 31500; - Summons.DespawnAll(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetVisibility(VISIBILITY_ON); + + Summons.DespawnAll(); + if(pInstance) pInstance->SetData(DATA_MURU_EVENT, NOT_STARTED); } void EnterCombat(Unit *who) { + DoCastAOE(SPELL_NEGATIVE_ENERGY,false); + if(pInstance) pInstance->SetData(DATA_MURU_EVENT, IN_PROGRESS); - DoCastAOE(SPELL_NEGATIVE_ENERGY,false); } - void KilledUnit(Unit* victim){} - - void DamageTaken(Unit *done_by, uint32 &damage) { - if(damage > m_creature->GetHealth() && Phase == 1){ + void DamageTaken(Unit *done_by, uint32 &damage) + { + if(damage > m_creature->GetHealth() && Phase == 1) + { damage = 0; Phase = 2; m_creature->RemoveAllAuras(); DoCast(m_creature, SPELL_OPEN_ALL_PORTALS, false); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - if(Phase > 1 && Phase < 4)damage = 0; + if(Phase > 1 && Phase < 4) + damage = 0; } void JustSummoned(Creature* summoned) { - switch(summoned->GetEntry()){ + switch(summoned->GetEntry()) + { case BOSS_ENTROPIUS: m_creature->SetVisibility(VISIBILITY_OFF); break; @@ -269,9 +283,12 @@ struct TRINITY_DLL_DECL boss_muruAI : public Scripted_NoMovementAI if(!UpdateVictim()) return; - if(Phase == 3){ - if(Timer[TIMER_PHASE] <diff){ - switch(pInstance->GetData(DATA_MURU_EVENT)){ + if(Phase == 3) + { + if(Timer[TIMER_PHASE] <diff) + { + switch(pInstance->GetData(DATA_MURU_EVENT)) + { case NOT_STARTED: Reset(); break; @@ -287,52 +304,58 @@ struct TRINITY_DLL_DECL boss_muruAI : public Scripted_NoMovementAI } if (EnrageTimer < diff && !m_creature->HasAura(SPELL_ENRAGE, 0)) + { DoCast(m_creature, SPELL_ENRAGE, false); - else EnrageTimer -= diff; + }else EnrageTimer -= diff; - for (uint8 i = 0; i < 4; ++i){ - if(Timer[i] < diff){ - switch(i){ + for (uint8 i = 0; i < 4; ++i) + { + if(Timer[i] < diff) + { + switch(i) + { case TIMER_DARKNESS: - if(!DarkFiend){ + if(!DarkFiend) + { DoCastAOE(SPELL_DARKNESS, false); Timer[TIMER_DARKNESS] = 3000; DarkFiend = true; - }else{ + } + else + { DarkFiend = false; for(uint8 i = 0; i < 8; ++i) m_creature->SummonCreature(CREATURE_DARK_FIENDS,DarkFiends[i][0],DarkFiends[i][1],DarkFiends[i][2], DarkFiends[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); Timer[TIMER_DARKNESS] = 42000; } break; - case TIMER_HUMANOIDES: for(uint8 i = 0; i < 6; ++i) m_creature->SummonCreature(Humanoides[i][0],Humanoides[i][1],Humanoides[i][2],Humanoides[i][3], Humanoides[i][4], TEMPSUMMON_CORPSE_DESPAWN, 0); Timer[TIMER_HUMANOIDES] = 60000; break; - case TIMER_PHASE: m_creature->RemoveAllAuras(); DoCast(m_creature, SPELL_SUMMON_ENTROPIUS, false); Timer[TIMER_PHASE] = 3000; Phase = 3; return; - case TIMER_SENTINEL: DoCastAOE(SPELL_OPEN_PORTAL_2, false); Timer[TIMER_SENTINEL] = 30000; break; - }break;} + } + break; + } } //Timer - for(uint8 i = 0; i < 4; ++i){ + for(uint8 i = 0; i < 4; ++i) + { if(i != TIMER_PHASE)Timer[i] -= diff; else if(Phase == 2) Timer[i] -= diff; } } - }; CreatureAI* GetAI_boss_muru(Creature *_Creature) @@ -342,37 +365,50 @@ CreatureAI* GetAI_boss_muru(Creature *_Creature) struct TRINITY_DLL_DECL npc_muru_portalAI : public Scripted_NoMovementAI { - npc_muru_portalAI(Creature *c) : Scripted_NoMovementAI(c), Summons(m_creature){ + npc_muru_portalAI(Creature *c) : Scripted_NoMovementAI(c), Summons(m_creature) + { pInstance = c->GetInstanceData(); } ScriptedInstance* pInstance; + SummonList Summons; Creature* Muru; + bool SummonSentinel; bool InAction; + uint32 SummonTimer; - void Reset(){ - m_creature->addUnitState(UNIT_STAT_STUNNED); + void Reset() + { SummonTimer = 5000; + InAction = false; SummonSentinel = false; + + m_creature->addUnitState(UNIT_STAT_STUNNED); + Summons.DespawnAll(); } - void JustSummoned(Creature* summoned){ + void JustSummoned(Creature* summoned) + { Player* Target = Unit::GetPlayer(pInstance->GetData64(DATA_PLAYER_GUID)); - if(Target)summoned->AI()->AttackStart(Target); + if(Target) + summoned->AI()->AttackStart(Target); + Summons.Summon(summoned); } - void SpellHit(Unit* caster, const SpellEntry* Spell){ + void SpellHit(Unit* caster, const SpellEntry* Spell) + { float x,y,z,o; m_creature->GetHomePosition(x,y,z,o); DoTeleportTo(x,y,z); InAction = true; - switch(Spell->Id){ + switch(Spell->Id) + { case SPELL_OPEN_ALL_PORTALS: DoCastAOE(SPELL_OPEN_PORTAL, false); break; @@ -383,19 +419,20 @@ struct TRINITY_DLL_DECL npc_muru_portalAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 diff){ - if(!SummonSentinel){ + void UpdateAI(const uint32 diff) + { + if(!SummonSentinel) + { if(InAction && pInstance->GetData(DATA_MURU_EVENT) == NOT_STARTED)Reset(); return; } - if(SummonTimer < diff){ + if(SummonTimer < diff) + { DoCastAOE(SPELL_SUMMON_VOID_SENTINEL, false); SummonTimer = 5000; SummonSentinel = false; }else SummonTimer -= diff; } - - }; CreatureAI* GetAI_npc_muru_portal(Creature *_Creature) @@ -405,23 +442,29 @@ CreatureAI* GetAI_npc_muru_portal(Creature *_Creature) struct TRINITY_DLL_DECL npc_dark_fiendAI : public ScriptedAI { - npc_dark_fiendAI(Creature *c) : ScriptedAI(c){ + npc_dark_fiendAI(Creature *c) : ScriptedAI(c) + { pInstance = c->GetInstanceData(); } ScriptedInstance* pInstance; - bool InAction; + uint32 WaitTimer; + bool InAction; - void Reset() { + void Reset() + { WaitTimer = 2000; InAction = false; + m_creature->addUnitState(UNIT_STAT_STUNNED); - }; + } - void SpellHit(Unit* caster, const SpellEntry* Spell){ + void SpellHit(Unit* caster, const SpellEntry* Spell) + { for(uint8 i = 0; i < 3; ++i) - if(Spell->Effect[i] == 38){ + if(Spell->Effect[i] == 38) + { m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); m_creature->RemoveCorpse(); } @@ -433,23 +476,28 @@ struct TRINITY_DLL_DECL npc_dark_fiendAI : public ScriptedAI return; if (WaitTimer < diff) - if(!InAction){ + { + if(!InAction) + { m_creature->clearUnitState(UNIT_STAT_STUNNED); DoCastAOE(SPELL_DARKFIEND_SKIN, false); AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)); InAction = true; WaitTimer = 500; - }else{ - if(m_creature->IsWithinDist(m_creature->getVictim(), 5)){ + } + else + { + + if(m_creature->IsWithinDist(m_creature->getVictim(), 5)) + { DoCastAOE(SPELL_DARKFIEND_AOE, false); m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); m_creature->RemoveCorpse(); } WaitTimer = 500; } - else WaitTimer -= diff; + }else WaitTimer -= diff; } - }; CreatureAI* GetAI_npc_dark_fiend(Creature *_Creature) @@ -459,7 +507,8 @@ CreatureAI* GetAI_npc_dark_fiend(Creature *_Creature) struct TRINITY_DLL_DECL npc_void_sentinelAI : public ScriptedAI { - npc_void_sentinelAI(Creature *c) : ScriptedAI(c){ + npc_void_sentinelAI(Creature *c) : ScriptedAI(c) + { pInstance = c->GetInstanceData(); } @@ -468,39 +517,42 @@ struct TRINITY_DLL_DECL npc_void_sentinelAI : public ScriptedAI uint32 PulseTimer; uint32 VoidBlastTimer; - - void Reset() { + void Reset() + { PulseTimer = 3000; VoidBlastTimer = 45000; //is this a correct timer? + float x,y,z,o; m_creature->GetHomePosition(x,y,z,o); DoTeleportTo(x,y,71); - }; + } - void JustDied(Unit* killer){ + void JustDied(Unit* killer) + { for (uint8 i = 0; i < 8; ++i){ m_creature->SummonCreature(CREATURE_VOID_SPAWN, m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(), rand()%6, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 180000); } - } + void UpdateAI(const uint32 diff) { if(!UpdateVictim()) return; - if(PulseTimer < diff){ + if(PulseTimer < diff) + { DoCastAOE(SPELL_SHADOW_PULSE, true); PulseTimer = 3000; }else PulseTimer -= diff; - if(VoidBlastTimer < diff){ + if(VoidBlastTimer < diff) + { DoCast(m_creature->getVictim(), SPELL_VOID_BLAST, false); VoidBlastTimer = 45000; }else VoidBlastTimer -= diff; DoMeleeAttackIfReady(); } - }; CreatureAI* GetAI_npc_void_sentinel(Creature *_Creature) @@ -510,7 +562,8 @@ CreatureAI* GetAI_npc_void_sentinel(Creature *_Creature) struct TRINITY_DLL_DECL npc_blackholeAI : public ScriptedAI { - npc_blackholeAI(Creature *c) : ScriptedAI(c){ + npc_blackholeAI(Creature *c) : ScriptedAI(c) + { pInstance = c->GetInstanceData(); } @@ -521,23 +574,28 @@ struct TRINITY_DLL_DECL npc_blackholeAI : public ScriptedAI uint8 Phase; uint8 NeedForAHack; - void Reset(){ + void Reset() + { DespawnTimer = 15000; SpellTimer = 5000; Phase = 0; + m_creature->addUnitState(UNIT_STAT_STUNNED); DoCastAOE(SPELL_BLACKHOLE_SPAWN, true); } void UpdateAI(const uint32 diff) { - if(SpellTimer < diff){ + if(SpellTimer < diff) + { Unit* Victim = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_PLAYER_GUID)); - switch(NeedForAHack){ + switch(NeedForAHack) + { case 0: m_creature->clearUnitState(UNIT_STAT_STUNNED); DoCastAOE(SPELL_BLACKHOLE_GROW, false); - if(Victim)AttackStart(Victim); + if(Victim) + AttackStart(Victim); SpellTimer = 700; NeedForAHack = 2; break; @@ -555,13 +613,15 @@ struct TRINITY_DLL_DECL npc_blackholeAI : public ScriptedAI SpellTimer = 400+rand()%500; NeedForAHack = 1; Unit* Temp = m_creature->getVictim(); - if(!Temp) return; + if(!Temp) + return; if(Temp->GetPositionZ() > 73 && Victim) AttackStart(Victim); } }else SpellTimer -= diff; - if (DespawnTimer < diff){ + if (DespawnTimer < diff) + { m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); m_creature->RemoveCorpse(); }else DespawnTimer -= diff; @@ -577,32 +637,32 @@ void AddSC_boss_muru() { Script *newscript; newscript = new Script; - newscript->Name="boss_muru"; + newscript->Name = "boss_muru"; newscript->GetAI = &GetAI_boss_muru; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="boss_entropius"; + newscript->Name = "boss_entropius"; newscript->GetAI = &GetAI_boss_entropius; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="npc_muru_portal"; + newscript->Name = "npc_muru_portal"; newscript->GetAI = &GetAI_npc_muru_portal; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="npc_dark_fiend"; + newscript->Name = "npc_dark_fiend"; newscript->GetAI = &GetAI_npc_dark_fiend; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="npc_void_sentinel"; + newscript->Name = "npc_void_sentinel"; newscript->GetAI = &GetAI_npc_void_sentinel; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="npc_blackhole"; + newscript->Name = "npc_blackhole"; newscript->GetAI = &GetAI_npc_blackhole; newscript->RegisterSelf(); -}
\ No newline at end of file +} diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h b/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h index 9fbb5de7300..ca8c014d9df 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/def_sunwell_plateau.h @@ -30,12 +30,6 @@ /*** GameObjects ***/ #define DATA_GO_FORCEFIELD 20 -#define DATA_GO_FIRE_BARRIER 21 -#define DATA_GATE_1 22 -#define DATA_GATE_2 23 -#define DATA_GATE_3 24 -#define DATA_GATE_4 25 -#define DATA_GATE_5 26 /*** Misc ***/ #define DATA_PLAYER_GUID 27 diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp index f8c7dde1ca2..9a8497a2df9 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/instance_sunwell_plateau.cpp @@ -4,8 +4,8 @@ /* ScriptData SDName: Instance_Sunwell_Plateau -SD%Complete: 20 -SDComment: VERIFY SCRIPT, rename Gates +SD%Complete: 25 +SDComment: VERIFY SCRIPT SDCategory: Sunwell_Plateau EndScriptData */ @@ -14,11 +14,6 @@ EndScriptData */ #define ENCOUNTERS 6 -enum GoState{ -CLOSE = 1, -OPEN = 0 -}; - /* Sunwell Plateau: 0 - Kalecgos and Sathrovarr 1 - Brutallus @@ -51,8 +46,8 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance /** GameObjects **/ uint64 ForceField; // Kalecgos Encounter - uint64 FireBarrier; // Brutallus Encounter - uint64 Gate[5]; // Rename this to be more specific after door placement is verified. + uint64 FireBarrier; // Felmysts Encounter + uint64 MurusGate[2]; // Murus Encounter /*** Misc ***/ uint32 SpectralRealmTimer; @@ -78,11 +73,8 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance /*** GameObjects ***/ ForceField = 0; FireBarrier = 0; - Gate[0] = 0; // TODO: Rename Gate[n] with gate_<boss name> for better specificity - Gate[1] = 0; - Gate[2] = 0; - Gate[3] = 0; - Gate[4] = 0; + MurusGate[0] = 0; + MurusGate[1] = 0; /*** Encounters ***/ for(uint8 i = 0; i < ENCOUNTERS; ++i) @@ -144,12 +136,17 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance switch(go->GetEntry()) { case 188421: ForceField = go->GetGUID(); break; - case 188075: FireBarrier = go->GetGUID(); break; - case 187979: Gate[0] = go->GetGUID(); break; - case 187770: Gate[1] = go->GetGUID(); break; - case 187896: Gate[2] = go->GetGUID(); break; - case 187990: Gate[3] = go->GetGUID(); break; - case 188118: Gate[4] = go->GetGUID(); break; + case 188075: + if(Encounters[2] == DONE) + HandleGameObject(NULL, true, go); + FireBarrier = go->GetGUID(); + break; + case 187990: MurusGate[0] = go->GetGUID(); break; + case 188118: + if(Encounters[4] == DONE) + HandleGameObject(NULL, true, go); + MurusGate[1]= go->GetGUID(); + break; } } @@ -157,14 +154,13 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance { switch(id) { - case DATA_KALECGOS_EVENT: return Encounters[0]; break; - case DATA_BRUTALLUS_EVENT: return Encounters[1]; break; - case DATA_FELMYST_EVENT: return Encounters[2]; break; - case DATA_EREDAR_TWINS_EVENT: return Encounters[3]; break; - case DATA_MURU_EVENT: return Encounters[4]; break; - case DATA_KILJAEDEN_EVENT: return Encounters[5]; break; + case DATA_KALECGOS_EVENT: return Encounters[0]; + case DATA_BRUTALLUS_EVENT: return Encounters[1]; + case DATA_FELMYST_EVENT: return Encounters[2]; + case DATA_EREDAR_TWINS_EVENT: return Encounters[3]; + case DATA_MURU_EVENT: return Encounters[4]; + case DATA_KILJAEDEN_EVENT: return Encounters[5]; } - return 0; } @@ -172,25 +168,24 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance { switch(id) { - case DATA_KALECGOS_DRAGON: return Kalecgos_Dragon; break; - case DATA_KALECGOS_HUMAN: return Kalecgos_Human; break; - case DATA_SATHROVARR: return Sathrovarr; break; - case DATA_BRUTALLUS: return Brutallus; break; - case DATA_MADRIGOSA: return Madrigosa; break; - case DATA_FELMYST: return Felmyst; break; - case DATA_ALYTHESS: return Alythess; break; - case DATA_SACROLASH: return Sacrolash; break; - case DATA_MURU: return Muru; break; - case DATA_KILJAEDEN: return KilJaeden; break; - case DATA_KILJAEDEN_CONTROLLER: return KilJaedenController; break; - case DATA_ANVEENA: return Anveena; break; - case DATA_KALECGOS_KJ: return KalecgosKJ; break; + case DATA_KALECGOS_DRAGON: return Kalecgos_Dragon; + case DATA_KALECGOS_HUMAN: return Kalecgos_Human; + case DATA_SATHROVARR: return Sathrovarr; + case DATA_GO_FORCEFIELD: return ForceField; + case DATA_BRUTALLUS: return Brutallus; + case DATA_MADRIGOSA: return Madrigosa; + case DATA_FELMYST: return Felmyst; + case DATA_ALYTHESS: return Alythess; + case DATA_SACROLASH: return Sacrolash; + case DATA_MURU: return Muru; + case DATA_KILJAEDEN: return KilJaeden; + case DATA_KILJAEDEN_CONTROLLER: return KilJaedenController; + case DATA_ANVEENA: return Anveena; + case DATA_KALECGOS_KJ: return KalecgosKJ; case DATA_PLAYER_GUID: Player* Target = GetPlayerInMap(); return Target->GetGUID(); - break; } - return 0; } @@ -202,22 +197,23 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance case DATA_BRUTALLUS_EVENT: Encounters[1] = data; break; case DATA_FELMYST_EVENT: if(data == DONE) - HandleGameObject(FireBarrier, OPEN); + HandleGameObject(FireBarrier, true); Encounters[2] = data; break; case DATA_EREDAR_TWINS_EVENT: Encounters[3] = data; break; case DATA_MURU_EVENT: - switch(data){ + switch(data) + { case DONE: - HandleGameObject(Gate[4], OPEN); - HandleGameObject(Gate[3], OPEN); + HandleGameObject(MurusGate[0], true); + HandleGameObject(MurusGate[1], true); break; case IN_PROGRESS: - HandleGameObject(Gate[4], CLOSE); - HandleGameObject(Gate[3], CLOSE); + HandleGameObject(MurusGate[0], false); + HandleGameObject(MurusGate[1], false); break; case NOT_STARTED: - HandleGameObject(Gate[4], CLOSE); - HandleGameObject(Gate[3], OPEN); + HandleGameObject(MurusGate[0], true); + HandleGameObject(MurusGate[1], false); break; } Encounters[4] = data; break; @@ -228,14 +224,6 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance SaveToDB(); } - void SetData64(uint32 id, uint64 guid) - { - } - - void Update(uint32 diff) - { - } - std::string GetSaveData() { OUT_SAVE_INST_DATA; @@ -249,7 +237,6 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance OUT_SAVE_INST_DATA_COMPLETE; return out; } - return NULL; } @@ -280,6 +267,7 @@ InstanceData* GetInstanceData_instance_sunwell_plateau(Map* map) void AddSC_instance_sunwell_plateau() { Script *newscript; + newscript = new Script; newscript->Name = "instance_sunwell_plateau"; newscript->GetInstanceData = &GetInstanceData_instance_sunwell_plateau; diff --git a/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp b/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp index eff160843de..9efc1e890b6 100644 --- a/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp +++ b/src/bindings/scripts/scripts/zone/teldrassil/teldrassil.cpp @@ -81,7 +81,7 @@ struct TRINITY_DLL_DECL npc_mistAI : public ScriptedAI if (m_creature->isAlive()) { if (Player* pPlayer = Unit::GetPlayer(uiPlayerGUID)) - m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle()); else { m_creature->GetMotionMaster()->MovementExpired(); @@ -100,7 +100,7 @@ struct TRINITY_DLL_DECL npc_mistAI : public ScriptedAI m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); if (Player* pPlayer = Unit::GetPlayer(uiPlayer)) - m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, m_creature->GetFollowAngle()); } void DoComplete() diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp index 130a247736c..b8dd3cc6db3 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp @@ -98,12 +98,15 @@ struct TRINITY_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI } } - void AttackStart(Unit* who) + void AttackStart(Unit* pWho) { - if (m_creature->Attack(who, true)) + if (m_creature->Attack(pWho, true)) { - //TODO: Make it so he moves when target out of range - DoStartNoMovement(who); + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + m_creature->GetMotionMaster()->MoveChase(pWho, 25.0f); } } diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp index ea2c8902c4a..8d6f9aebcf4 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp @@ -24,48 +24,49 @@ EndScriptData */ #include "precompiled.h" #include "def_the_eye.h" -#define SAY_AGGRO -1550007 -#define SAY_SUMMON1 -1550008 -#define SAY_SUMMON2 -1550009 -#define SAY_KILL1 -1550010 -#define SAY_KILL2 -1550011 -#define SAY_KILL3 -1550012 -#define SAY_DEATH -1550013 -#define SAY_VOIDA -1550014 -#define SAY_VOIDB -1550015 - -#define SPELL_ARCANE_MISSILES 33031 -#define SPELL_MARK_OF_THE_ASTROMANCER 33045 -#define MARK_OF_SOLARIAN 33023 -#define SPELL_BLINDING_LIGHT 33009 -#define SPELL_FEAR 29321 -#define SPELL_VOID_BOLT 39329 -#define SPELL_SPOTLIGHT 25824 -#define SPELL_WRATH_OF_THE_ASTROMANCER 42783 - -#define CENTER_X 432.909f -#define CENTER_Y -373.424f -#define CENTER_Z 17.9608f -#define CENTER_O 1.06421f -#define SMALL_PORTAL_RADIUS 12.6f -#define LARGE_PORTAL_RADIUS 26.0f -#define PORTAL_Z 17.005f - -#define SOLARIUM_AGENT 18925 -#define SOLARIUM_PRIEST 18806 -#define ASTROMANCER_SOLARIAN_SPOTLIGHT 18928 - -#define MODEL_HUMAN 18239 -#define MODEL_VOIDWALKER 18988 - -#define SOLARIUM_HEAL 41378 -#define SOLARIUM_SMITE 31740 -#define SOLARIUM_SILENCE 37160 - -#define WV_ARMOR 31000 -#define MIN_RANGE_FOR_DOT_JUMP 20.0f - - // x, y, z, o +enum +{ + SAY_AGGRO = -1550007, + SAY_SUMMON1 = -1550008, + SAY_SUMMON2 = -1550009, + SAY_KILL1 = -1550010, + SAY_KILL2 = -1550011, + SAY_KILL3 = -1550012, + SAY_DEATH = -1550013, + SAY_VOIDA = -1550014, + SAY_VOIDB = -1550015, + + SPELL_ARCANE_MISSILES = 33031, + SPELL_WRATH_OF_THE_ASTROMANCER = 42783, + SPELL_BLINDING_LIGHT = 33009, + SPELL_FEAR = 34322, + SPELL_VOID_BOLT = 39329, + + SPELL_SPOTLIGHT = 25824, + NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT = 18928, + + NPC_SOLARIUM_AGENT = 18925, + NPC_SOLARIUM_PRIEST = 18806, + + MODEL_HUMAN = 18239, + MODEL_VOIDWALKER = 18988, + + SPELL_SOLARIUM_GREAT_HEAL = 33387, + SPELL_SOLARIUM_HOLY_SMITE = 25054, + SPELL_SOLARIUM_ARCANE_TORRENT = 33390, + + WV_ARMOR = 31000 +}; + +const float CENTER_X = 432.909f; +const float CENTER_Y = -373.424f; +const float CENTER_Z = 17.9608f; +const float CENTER_O = 1.06421f; +const float SMALL_PORTAL_RADIUS = 12.6f; +const float LARGE_PORTAL_RADIUS = 26.0f; +const float PORTAL_Z = 17.005f; + + // x, y, z, o static float SolarianPos[4] = {432.909, -373.424, 17.9608, 1.06421}; struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI @@ -84,7 +85,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI uint8 Phase; uint32 ArcaneMissiles_Timer; - uint32 MarkOfTheAstromancer_Timer; + uint32 m_uiWrathOfTheAstromancer_Timer; uint32 BlindingLight_Timer; uint32 Fear_Timer; uint32 VoidBolt_Timer; @@ -92,8 +93,6 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI uint32 Phase2_Timer; uint32 Phase3_Timer; uint32 AppearDelay_Timer; - uint32 MarkOfTheSolarian_Timer; - uint32 Jump_Timer; uint32 defaultarmor; uint32 Wrath_Timer; @@ -106,7 +105,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI void Reset() { ArcaneMissiles_Timer = 2000; - MarkOfTheAstromancer_Timer = 15000; + m_uiWrathOfTheAstromancer_Timer = 15000; BlindingLight_Timer = 41000; Fear_Timer = 20000; VoidBolt_Timer = 10000; @@ -116,8 +115,6 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI AppearDelay_Timer = 2000; BlindingLight = false; AppearDelay = false; - MarkOfTheSolarian_Timer=45000; - Jump_Timer=8000; Wrath_Timer = 20000+rand()%5000;//twice in phase one Phase = 1; Wrath_Timer = 20000+rand()%5000;//twice in phase one @@ -134,14 +131,6 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI Summons.DespawnAll(); } - void StartEvent() - { - DoScriptText(SAY_AGGRO, m_creature); - - if(pInstance) - pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS); - } - void KilledUnit(Unit *victim) { switch(rand()%3) @@ -164,7 +153,11 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI void EnterCombat(Unit *who) { - StartEvent(); + DoScriptText(SAY_AGGRO, m_creature); + DoZoneInCombat(); + + if (pInstance) + pInstance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS); } void SummonMinion(uint32 entry, float x, float y, float z) @@ -252,20 +245,20 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI ArcaneMissiles_Timer = 3000; }else ArcaneMissiles_Timer -= diff; - if (MarkOfTheSolarian_Timer < diff) + if (m_uiWrathOfTheAstromancer_Timer < diff) { - DoCast(m_creature->getVictim(), MARK_OF_SOLARIAN); - MarkOfTheSolarian_Timer = 45000; - }else MarkOfTheSolarian_Timer -= diff; + m_creature->InterruptNonMeleeSpells(false); - if (MarkOfTheAstromancer_Timer < diff) //A debuff that lasts for 5 seconds, cast several times each phase on a random raid member, but not the main tank - { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true); - if(target) - DoCast(target, SPELL_MARK_OF_THE_ASTROMANCER); - else DoCast(m_creature->getVictim(), SPELL_MARK_OF_THE_ASTROMANCER); - MarkOfTheAstromancer_Timer = 15000; - }else MarkOfTheAstromancer_Timer -= diff; + //Target the tank ? + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 1)) + if (pTarget->GetTypeId() == TYPEID_PLAYER) + { + DoCast(pTarget, SPELL_WRATH_OF_THE_ASTROMANCER); + m_uiWrathOfTheAstromancer_Timer = 25000; + } + else + m_uiWrathOfTheAstromancer_Timer = 1000; + }else m_uiWrathOfTheAstromancer_Timer -= diff; //Phase1_Timer if (Phase1_Timer < diff) @@ -300,8 +293,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI } for (int i=0; i<=2; i++) { - Creature* Summoned = m_creature->SummonCreature(ASTROMANCER_SOLARIAN_SPOTLIGHT, Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O, TEMPSUMMON_TIMED_DESPAWN, Phase2_Timer+Phase3_Timer+AppearDelay_Timer+1700); - if(Summoned) + if (Creature* Summoned = m_creature->SummonCreature(NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT, Portals[i][0], Portals[i][1], Portals[i][2], CENTER_O, TEMPSUMMON_TIMED_DESPAWN, Phase2_Timer+Phase3_Timer+AppearDelay_Timer+1700)) { Summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Summoned->CastSpell(Summoned, SPELL_SPOTLIGHT, false); @@ -320,7 +312,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI Phase = 3; for (int i=0; i<=2; i++) for (int j=1; j<=4; j++) - SummonMinion(SOLARIUM_AGENT, Portals[i][0], Portals[i][1], Portals[i][2]); + SummonMinion(NPC_SOLARIUM_AGENT, Portals[i][0], Portals[i][1], Portals[i][2]); DoScriptText(SAY_SUMMON1, m_creature); Phase2_Timer = 10000; @@ -343,7 +335,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI for (int j=0; j<=2; j++) if (j!=i) - SummonMinion(SOLARIUM_PRIEST, Portals[j][0], Portals[j][1], Portals[j][2]); + SummonMinion(NPC_SOLARIUM_PRIEST, Portals[j][0], Portals[j][1], Portals[j][2]); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetVisibility(VISIBILITY_ON); @@ -358,7 +350,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI //Fear_Timer if (Fear_Timer < diff) { - DoCast(m_creature->getVictim(), SPELL_FEAR); + DoCast(m_creature, SPELL_FEAR); Fear_Timer = 20000; }else Fear_Timer -= diff; @@ -435,20 +427,20 @@ struct TRINITY_DLL_DECL mob_solarium_priestAI : public ScriptedAI if(target) { - DoCast(target,SOLARIUM_HEAL); + DoCast(target,SPELL_SOLARIUM_GREAT_HEAL); healTimer = 9000; } } else healTimer -= diff; if(holysmiteTimer < diff) { - DoCast(m_creature->getVictim(), SOLARIUM_SMITE); + DoCast(m_creature->getVictim(), SPELL_SOLARIUM_HOLY_SMITE); holysmiteTimer = 4000; } else holysmiteTimer -= diff; if (aoesilenceTimer < diff) { - DoCast(m_creature->getVictim(), SOLARIUM_SILENCE); + DoCast(m_creature->getVictim(), SPELL_SOLARIUM_ARCANE_TORRENT); aoesilenceTimer = 13000; } else aoesilenceTimer -= diff; diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp index 1ebf18efa94..0766a0ed1f9 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp @@ -15,9 +15,9 @@ */ /* ScriptData -SDName: boss_Kaelthas +SDName: Boss_Kaelthas SD%Complete: 60 -SDComment: Mind Control, Reset Event if Weapons despawn/reset +SDComment: SQL, weapon scripts, mind control, need correct spells(interruptible/uninterruptible), phoenix spawn location & animation, phoenix behaviour & spawn during gravity lapse SDCategory: Tempest Keep, The Eye EndScriptData */ @@ -25,141 +25,158 @@ EndScriptData */ #include "def_the_eye.h" #include "WorldPacket.h" - //kael'thas Speech -#define SAY_INTRO -1550016 -#define SAY_INTRO_CAPERNIAN -1550017 -#define SAY_INTRO_TELONICUS -1550018 -#define SAY_INTRO_THALADRED -1550019 -#define SAY_INTRO_SANGUINAR -1550020 -#define SAY_PHASE2_WEAPON -1550021 -#define SAY_PHASE3_ADVANCE -1550022 -#define SAY_PHASE4_INTRO2 -1550023 -#define SAY_PHASE5_NUTS -1550024 -#define SAY_SLAY1 -1550025 -#define SAY_SLAY2 -1550026 -#define SAY_SLAY3 -1550027 -#define SAY_MINDCONTROL1 -1550028 -#define SAY_MINDCONTROL2 -1550029 -#define SAY_GRAVITYLAPSE1 -1550030 -#define SAY_GRAVITYLAPSE2 -1550031 -#define SAY_SUMMON_PHOENIX1 -1550032 -#define SAY_SUMMON_PHOENIX2 -1550033 -#define SAY_DEATH -1550034 - -//Thaladred the Darkener speech -#define SAY_THALADRED_AGGRO -1550035 -#define SAY_THALADRED_DEATH -1550036 -#define EMOTE_THALADRED_GAZE -1550037 - -//Lord Sanguinar speech -#define SAY_SANGUINAR_AGGRO -1550038 -#define SAY_SANGUINAR_DEATH -1550039 - -//Grand Astromancer Capernian speech -#define SAY_CAPERNIAN_AGGRO -1550040 -#define SAY_CAPERNIAN_DEATH -1550041 - -//Master Engineer Telonicus speech -#define SAY_TELONICUS_AGGRO -1550042 -#define SAY_TELONICUS_DEATH -1550043 - -//Phase 2 spells (Not used) -#define SPELL_SUMMON_WEAPONS 36976 -#define SPELL_SUMMON_WEAPONA 36958 -#define SPELL_SUMMON_WEAPONB 36959 -#define SPELL_SUMMON_WEAPONC 36960 -#define SPELL_SUMMON_WEAPOND 36961 -#define SPELL_SUMMON_WEAPONE 36962 -#define SPELL_SUMMON_WEAPONF 36963 -#define SPELL_SUMMON_WEAPONG 36964 -#define SPELL_RES_VISUAL 24171 -#define SPELL_WEAPON_SPAWN 41236 - -//Phase 4 spells -#define SPELL_FIREBALL 36805 -#define SPELL_PYROBLAST 36819 -#define SPELL_FLAME_STRIKE 36735 -#define SPELL_FLAME_STRIKE_VIS 36730 -#define SPELL_FLAME_STRIKE_DMG 36731 -#define SPELL_ARCANE_DISRUPTION 36834 -#define SPELL_SHOCK_BARRIER 36815 -#define SPELL_SUMMON_PHOENIX 36723 -#define SPELL_MIND_CONTROL 32830 - -//Phase 5 spells -#define SPELL_EXPLODE 36092 -#define SPELL_FULLPOWER 36187 -#define SPELL_KNOCKBACK 11027 -#define SPELL_GRAVITY_LAPSE 34480 -#define SPELL_GRAVITY_LAPSE_AURA 39432 -#define SPELL_NETHER_BEAM 35873 - -//Thaladred the Darkener spells -#define SPELL_PSYCHIC_BLOW 10689 -#define SPELL_SILENCE 30225 - -//Lord Sanguinar spells -#define SPELL_BELLOWING_ROAR 40636 - -//Grand Astromancer Capernian spells -#define CAPERNIAN_DISTANCE 20 //she casts away from the target -#define SPELL_CAPERNIAN_FIREBALL 36971 -#define SPELL_CONFLAGRATION 37018 -#define SPELL_ARCANE_EXPLOSION 36970 - -//Master Engineer Telonicus spells -#define SPELL_BOMB 37036 -#define SPELL_REMOTE_TOY 37027 - -//Nether Vapor spell -#define SPELL_NETHER_VAPOR 35859 - -//Phoenix spell -#define SPELL_BURN 36720 -#define SPELL_EMBER_BLAST 34341 -#define SPELL_REBIRTH 41587 - -//Creature IDs -#define PHOENIX 21362 -#define PHOENIX_EGG 21364 - -//Phoenix egg and phoenix model -#define PHOENIX_MODEL 19682 -#define PHOENIX_EGG_MODEL 20245 - -//weapon id + position -float KaelthasWeapons[7][5] = +enum { - {21270, 794.38, 15, 48.72, 2.9}, //[Cosmic Infuser] - {21269, 785.47, 12.12, 48.72, 3.14}, //[Devastation] - {21271, 781.25, 4.39, 48.72, 3.14}, //[Infinity Blade] - {21273, 777.38, -0.81, 48.72, 3.06}, //[Phaseshift Bulwark] - {21274, 781.48, -6.08, 48.72, 3.9}, //[Staff of Disintegration] - {21272, 785.42, -13.59, 48.72, 3.4}, //[Warp Slicer] - {21268, 793.06, -16.61, 48.72, 3.10} //[Netherstrand Longbow] + //kael'thas Speech + SAY_INTRO = -1550016, + SAY_INTRO_CAPERNIAN = -1550017, + SAY_INTRO_TELONICUS = -1550018, + SAY_INTRO_THALADRED = -1550019, + SAY_INTRO_SANGUINAR = -1550020, + SAY_PHASE2_WEAPON = -1550021, + SAY_PHASE3_ADVANCE = -1550022, + SAY_PHASE4_INTRO2 = -1550023, + SAY_PHASE5_NUTS = -1550024, + SAY_SLAY1 = -1550025, + SAY_SLAY2 = -1550026, + SAY_SLAY3 = -1550027, + SAY_MINDCONTROL1 = -1550028, + SAY_MINDCONTROL2 = -1550029, + SAY_GRAVITYLAPSE1 = -1550030, + SAY_GRAVITYLAPSE2 = -1550031, + SAY_SUMMON_PHOENIX1 = -1550032, + SAY_SUMMON_PHOENIX2 = -1550033, + SAY_DEATH = -1550034, + + //Thaladred the Darkener speech + SAY_THALADRED_AGGRO = -1550035, + SAY_THALADRED_DEATH = -1550036, + EMOTE_THALADRED_GAZE = -1550037, + + //Lord Sanguinar speech + SAY_SANGUINAR_AGGRO = -1550038, + SAY_SANGUINAR_DEATH = -1550039, + + //Grand Astromancer Capernian speech + SAY_CAPERNIAN_AGGRO = -1550040, + SAY_CAPERNIAN_DEATH = -1550041, + + //Master Engineer Telonicus speech + SAY_TELONICUS_AGGRO = -1550042, + SAY_TELONICUS_DEATH = -1550043, + + //Phase 2 spells + SPELL_SUMMON_WEAPONS = 36976, + SPELL_SUMMON_WEAPONA = 36958, + SPELL_SUMMON_WEAPONB = 36959, + SPELL_SUMMON_WEAPONC = 36960, + SPELL_SUMMON_WEAPOND = 36961, + SPELL_SUMMON_WEAPONE = 36962, + SPELL_SUMMON_WEAPONF = 36963, + SPELL_SUMMON_WEAPONG = 36964, + SPELL_RES_VISUAL = 24171, + + //Phase 4 spells + SPELL_FIREBALL = 22088, //wrong but works with CastCustomSpell + SPELL_PYROBLAST = 36819, + SPELL_FLAME_STRIKE = 36735, + SPELL_FLAME_STRIKE_VIS = 36730, + SPELL_FLAME_STRIKE_DMG = 36731, + SPELL_ARCANE_DISRUPTION = 36834, + SPELL_SHOCK_BARRIER = 36815, + SPELL_PHOENIX_ANIMATION = 36723, + SPELL_MIND_CONTROL = 32830, + + //Phase 5 spells + SPELL_EXPLODE = 36092, + SPELL_FULLPOWER = 36187, + SPELL_KNOCKBACK = 11027, + SPELL_GRAVITY_LAPSE = 34480, + SPELL_GRAVITY_LAPSE_AURA = 39432, + SPELL_NETHER_BEAM = 35873, + + //Thaladred the Darkener spells + SPELL_PSYCHIC_BLOW = 10689, + SPELL_SILENCE = 30225, + //Lord Sanguinar spells + SPELL_BELLOWING_ROAR = 40636, + //Grand Astromancer Capernian spells + + SPELL_CAPERNIAN_FIREBALL = 36971, + SPELL_CONFLAGRATION = 37018, + SPELL_ARCANE_EXPLOSION = 36970, + //Master Engineer Telonicus spells + SPELL_BOMB = 37036, + SPELL_REMOTE_TOY = 37027, + //Nether Vapor spell + SPELL_NETHER_VAPOR = 35859, + //Phoenix spell + SPELL_BURN = 36720, + SPELL_EMBER_BLAST = 34341, + SPELL_REBIRTH = 41587, + + //Creature IDs + NPC_PHOENIX = 21362, + NPC_PHOENIX_EGG = 21364, + + //Phoenix egg and phoenix model + MODEL_ID_PHOENIX = 19682, + MODEL_ID_PHOENIX_EGG = 20245, + + MAX_ADVISORS = 4 }; -#define GRAVITY_X 795.0f -#define GRAVITY_Y 0.0f -#define GRAVITY_Z 70.0f +uint32 m_auiSpellSummonWeapon[]= +{ + SPELL_SUMMON_WEAPONA, SPELL_SUMMON_WEAPONB, SPELL_SUMMON_WEAPONC, SPELL_SUMMON_WEAPOND, + SPELL_SUMMON_WEAPONE, SPELL_SUMMON_WEAPONF, SPELL_SUMMON_WEAPONG +}; -#define TIME_PHASE_2_3 120000 -#define TIME_PHASE_3_4 120000 +const float CAPERNIAN_DISTANCE = 20.0f; //she casts away from the target +const float KAEL_VISIBLE_RANGE = 50.0f; -#define KAEL_VISIBLE_RANGE 50.0f -#define ROOM_BASE_Z 49.0f +const float afGravityPos[3] = {795.0f, 0.0f, 70.0f}; + +#define TIME_PHASE_2_3 120000 +#define TIME_PHASE_3_4 180000 //Base AI for Advisors struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI { - ScriptedInstance* pInstance; + advisorbase_ai(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bDoubled_Health = false; + } + + ScriptedInstance* m_pInstance; bool FakeDeath; + bool m_bDoubled_Health; uint32 DelayRes_Timer; uint64 DelayRes_Target; - advisorbase_ai(Creature *c) : ScriptedAI(c) + void Reset() { - pInstance = c->GetInstanceData(); + if (m_bDoubled_Health) + { + m_creature->SetMaxHealth(m_creature->GetMaxHealth() / 2); + m_bDoubled_Health = false; + } + + FakeDeath = false; + DelayRes_Timer = 0; + DelayRes_Target = 0; + + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + //reset encounter + if (m_pInstance && (m_pInstance->GetData(DATA_KAELTHASEVENT) == 1 || m_pInstance->GetData(DATA_KAELTHASEVENT) == 3)) + { + if (Creature *Kaelthas = (Creature*)Unit::GetUnit((*m_creature), m_pInstance->GetData64(DATA_KAELTHAS))) + Kaelthas->AI()->EnterEvadeMode(); + } } void MoveInLineOfSight(Unit *who) @@ -178,33 +195,15 @@ struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI ScriptedAI::AttackStart(who); } - void Reset() - { - m_creature->SetNoCallAssistance(true); - FakeDeath = false; - DelayRes_Timer = 0; - DelayRes_Target = 0; - - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - //reset encounter - if(pInstance && (pInstance->GetData(DATA_KAELTHASEVENT) == 1 || pInstance->GetData(DATA_KAELTHASEVENT) == 3)) - { - Creature *Kaelthas = NULL; - Kaelthas = (Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_KAELTHAS))); - - if(Kaelthas) - Kaelthas->AI()->EnterEvadeMode(); - } - } - void Revive(Unit* Target) { m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // double health for phase 3 + m_creature->SetMaxHealth(m_creature->GetMaxHealth() * 2); + m_bDoubled_Health = true; m_creature->SetHealth(m_creature->GetMaxHealth()); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCast(m_creature, SPELL_RES_VISUAL, false); DelayRes_Timer = 2000; } @@ -215,13 +214,14 @@ struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI return; //Prevent glitch if in fake death - if (FakeDeath) + if (FakeDeath && m_pInstance && m_pInstance->GetData(DATA_KAELTHASEVENT) != 0) { damage = 0; return; } + //Don't really die in phase 1 & 3, only die after that - if(pInstance && pInstance->GetData(DATA_KAELTHASEVENT) != 0) + if (m_pInstance && m_pInstance->GetData(DATA_KAELTHASEVENT) != 0) { //prevent death damage = 0; @@ -229,6 +229,7 @@ struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI m_creature->InterruptNonMeleeSpells(false); m_creature->SetHealth(0); + m_creature->StopMoving(); m_creature->ClearComboPointHolders(); m_creature->RemoveAllAurasOnDeath(); m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); @@ -238,10 +239,8 @@ struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI m_creature->SetUInt64Value(UNIT_FIELD_TARGET,0); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1,UNIT_STAND_STATE_DEAD); - - if (pInstance->GetData(DATA_KAELTHASEVENT) == 3) - JustDied(pKiller); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + JustDied(pKiller); } } @@ -257,9 +256,8 @@ struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI Unit* Target = Unit::GetUnit((*m_creature), DelayRes_Target); if (!Target) Target = m_creature->getVictim(); + DoResetThreat(); - if(!Target) - return; AttackStart(Target); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveChase(Target); @@ -267,23 +265,19 @@ struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI }else DelayRes_Timer -= diff; } } + }; //Kael'thas AI struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI { - boss_kaelthasAI(Creature *c) : ScriptedAI(c), summons(m_creature) + boss_kaelthasAI(Creature* pCreature) : ScriptedAI(pCreature), summons(m_creature) { - pInstance = c->GetInstanceData(); - AdvisorGuid[0] = 0; - AdvisorGuid[1] = 0; - AdvisorGuid[2] = 0; - AdvisorGuid[3] = 0; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + memset(&m_auiAdvisorGuid, 0, sizeof(m_auiAdvisorGuid)); } - ScriptedInstance* pInstance; - - std::list<uint64> Phoenix; + ScriptedInstance* m_pInstance; uint32 Fireball_Timer; uint32 ArcaneDisruption_Timer; @@ -295,7 +289,6 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI uint32 NetherVapor_Timer; uint32 FlameStrike_Timer; uint32 MindControl_Timer; - uint32 Check_Timer; uint32 Phase; uint32 PhaseSubphase; //generic uint32 Phase_Timer; //generic timer @@ -305,31 +298,12 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI bool IsCastingFireball; bool ChainPyros; - uint64 AdvisorGuid[4]; - uint64 WeaponGuid[7]; SummonList summons; - void DeleteLegs() - { - Map::PlayerList const &PlayerList = m_creature->GetMap()->GetPlayers(); - for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - Player* i_pl = i->getSource(); - i_pl->DestroyItemCount(30312, 1, true); - i_pl->DestroyItemCount(30311, 1, true); - i_pl->DestroyItemCount(30317, 1, true); - i_pl->DestroyItemCount(30316, 1, true); - i_pl->DestroyItemCount(30313, 1, true); - i_pl->DestroyItemCount(30314, 1, true); - i_pl->DestroyItemCount(30318, 1, true); - i_pl->DestroyItemCount(30319, 1, true); - i_pl->DestroyItemCount(30320, 1, true); - } - } + uint64 m_auiAdvisorGuid[MAX_ADVISORS]; void Reset() { - m_creature->SetNoCallAssistance(true); Fireball_Timer = 5000+rand()%10000; ArcaneDisruption_Timer = 45000; MindControl_Timer = 40000; @@ -340,33 +314,29 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI GravityLapse_Phase = 0; NetherBeam_Timer = 8000; NetherVapor_Timer = 10000; - Check_Timer = 4000; PyrosCasted = 0; Phase = 0; InGravityLapse = false; IsCastingFireball = false; ChainPyros = false; - if(m_creature->isInCombat()) + if (m_creature->isInCombat()) PrepareAdvisors(); - DeleteLegs(); summons.DespawnAll(); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if(pInstance) - pInstance->SetData(DATA_KAELTHASEVENT, NOT_STARTED); + if (m_pInstance) + m_pInstance->SetData(DATA_KAELTHASEVENT, 0); } void PrepareAdvisors() { - Creature *pCreature; - for(uint8 i = 0; i < 4; ++i) + for(uint8 i = 0; i < MAX_ADVISORS; i++) { - pCreature = (Unit::GetCreature((*m_creature), AdvisorGuid[i])); - if(pCreature) + if (Creature *pCreature = (Creature*)Unit::GetUnit((*m_creature), m_auiAdvisorGuid[i])) { pCreature->Respawn(); pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -378,39 +348,38 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI void StartEvent() { - if(!pInstance) + if (!m_pInstance) return; - AdvisorGuid[0] = pInstance->GetData64(DATA_THALADREDTHEDARKENER); - AdvisorGuid[1] = pInstance->GetData64(DATA_LORDSANGUINAR); - AdvisorGuid[2] = pInstance->GetData64(DATA_GRANDASTROMANCERCAPERNIAN); - AdvisorGuid[3] = pInstance->GetData64(DATA_MASTERENGINEERTELONICUS); + m_auiAdvisorGuid[0] = m_pInstance->GetData64(DATA_THALADREDTHEDARKENER); + m_auiAdvisorGuid[1] = m_pInstance->GetData64(DATA_LORDSANGUINAR); + m_auiAdvisorGuid[2] = m_pInstance->GetData64(DATA_GRANDASTROMANCERCAPERNIAN); + m_auiAdvisorGuid[3] = m_pInstance->GetData64(DATA_MASTERENGINEERTELONICUS); - if(!AdvisorGuid[0] || !AdvisorGuid[1] || !AdvisorGuid[2] || !AdvisorGuid[3]) + if (!m_auiAdvisorGuid[0] || !m_auiAdvisorGuid[1] || !m_auiAdvisorGuid[2] || !m_auiAdvisorGuid[3]) { error_log("TSCR: Kael'Thas One or more advisors missing, Skipping Phases 1-3"); - DoYell("TSCR: Kael'Thas One or more advisors missing, Skipping Phases 1-3", LANG_UNIVERSAL, NULL); DoScriptText(SAY_PHASE4_INTRO2, m_creature); + Phase = 4; - pInstance->SetData(DATA_KAELTHASEVENT, 4); + m_pInstance->SetData(DATA_KAELTHASEVENT, 4); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Unit *target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) + if (Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0)) AttackStart(target); - } + + } else { PrepareAdvisors(); DoScriptText(SAY_INTRO, m_creature); - pInstance->SetData(DATA_KAELTHASEVENT, IN_PROGRESS); + m_pInstance->SetData(DATA_KAELTHASEVENT, 1); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); PhaseSubphase = 0; @@ -419,26 +388,60 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI } } + void MoveInLineOfSight(Unit *who) + { + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED) && who->isTargetableForAttack() && + m_creature->IsHostileTo(who) && who->isInAccessiblePlaceFor(m_creature)) + { + if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) + return; + + float attackRadius = m_creature->GetAttackDistance(who); + if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) + { + if (!m_creature->getVictim() && Phase >= 4) + { + who->RemoveAurasDueToSpell(SPELL_AURA_MOD_STEALTH); + AttackStart(who); + } + else if (m_creature->GetMap()->IsDungeon()) + { + if (m_pInstance && !m_pInstance->GetData(DATA_KAELTHASEVENT) && !Phase) + StartEvent(); + + who->SetInCombatWith(m_creature); + m_creature->AddThreat(who, 0.0f); + } + } + } + } + + void Aggro(Unit *who) + { + if (m_pInstance && !m_pInstance->GetData(DATA_KAELTHASEVENT) && !Phase) + StartEvent(); + } + void KilledUnit() { switch(rand()%3) { - case 0: DoScriptText(SAY_SLAY1, m_creature); break; - case 1: DoScriptText(SAY_SLAY2, m_creature); break; - case 2: DoScriptText(SAY_SLAY3, m_creature); break; + case 0: DoScriptText(SAY_SLAY1, m_creature); break; + case 1: DoScriptText(SAY_SLAY2, m_creature); break; + case 2: DoScriptText(SAY_SLAY3, m_creature); break; } } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* pSummoned) { - if(summoned->GetEntry() == PHOENIX) + // if not phoenix, then it's one of the 7 weapons + if (pSummoned->GetEntry() != NPC_PHOENIX) { - summoned->setFaction(m_creature->getFaction()); - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) - summoned->AI()->AttackStart(target); + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + summons.Summon(pSummoned); } - summons.Summon(summoned); } void SummonedCreatureDespawn(Creature *summon) {summons.Despawn(summon);} @@ -450,220 +453,177 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI DoScriptText(SAY_DEATH, m_creature); - DeleteLegs(); summons.DespawnAll(); - if(pInstance) - pInstance->SetData(DATA_KAELTHASEVENT, DONE); - - Creature *pCreature; - for(uint8 i = 0; i < 4; ++i) - { - pCreature = (Unit::GetCreature((*m_creature), AdvisorGuid[i])); - if(pCreature) - { - pCreature->setDeathState(JUST_DIED); - } - } - } - - void EnterCombat(Unit *who) - { - if (pInstance && !pInstance->GetData(DATA_KAELTHASEVENT) && !Phase) - StartEvent(); - } + if (m_pInstance) + m_pInstance->SetData(DATA_KAELTHASEVENT, 0); - void MoveInLineOfSight(Unit *who) - { - if (!m_creature->getVictim() && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who)) + for(uint8 i = 0; i < MAX_ADVISORS; i++) { - if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = m_creature->GetAttackDistance(who); - if (Phase >= 4 && m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who)) - { - AttackStart(who); - } - else if(who->isAlive()) - { - if (pInstance && !pInstance->GetData(DATA_KAELTHASEVENT) && !Phase && m_creature->IsWithinDistInMap(who, 60.0f)) - StartEvent(); - - //add to the threat list, so we can use SelectTarget - m_creature->AddThreat(who,0.0f); - } + if (Unit* pAdvisor = Unit::GetUnit((*m_creature), m_auiAdvisorGuid[i])) + pAdvisor->DealDamage(pAdvisor, pAdvisor->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } } void UpdateAI(const uint32 diff) { - - if(pInstance && Phase) - { - if(pInstance->GetData(DATA_KAELTHASEVENT) == IN_PROGRESS && m_creature->getThreatManager().getThreatList().empty()) - { - EnterEvadeMode(); - return; - } - } //Phase 1 switch (Phase) { case 1: { - Unit *target; - Creature* Advisor; + Unit *target = NULL; + Creature* Advisor = NULL; //Subphase switch switch(PhaseSubphase) { //Subphase 1 - Start case 0: - if(Phase_Timer < diff) + if (Phase_Timer < diff) { DoScriptText(SAY_INTRO_THALADRED, m_creature); //start advisor within 7 seconds Phase_Timer = 7000; - - ++PhaseSubphase; + PhaseSubphase++; }else Phase_Timer -= diff; break; - //Subphase 1 - Unlock advisor + //Subphase 1 - Unlock advisor case 1: - if(Phase_Timer < diff) + if (Phase_Timer < diff) { - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[0])); + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[0])); - if(Advisor) + if (Advisor) { Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Advisor->setFaction(m_creature->getFaction()); target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) + if (target) Advisor->AI()->AttackStart(target); } - ++PhaseSubphase; + PhaseSubphase++; }else Phase_Timer -= diff; break; - //Subphase 2 - Start + //Subphase 2 - Start case 2: - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[0])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == UNIT_STAND_STATE_DEAD)) + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[0])); + + if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD)) { DoScriptText(SAY_INTRO_SANGUINAR, m_creature); //start advisor within 12.5 seconds Phase_Timer = 12500; - - ++PhaseSubphase; + PhaseSubphase++; } break; - //Subphase 2 - Unlock advisor + //Subphase 2 - Unlock advisor case 3: - if(Phase_Timer < diff) + if (Phase_Timer < diff) { - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[1])); + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[1])); - if(Advisor) + if (Advisor) { Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Advisor->setFaction(m_creature->getFaction()); target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) + if (target) Advisor->AI()->AttackStart(target); } - ++PhaseSubphase; + PhaseSubphase++; }else Phase_Timer -= diff; break; - //Subphase 3 - Start + //Subphase 3 - Start case 4: - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[1])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == UNIT_STAND_STATE_DEAD)) + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[1])); + + if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD)) { DoScriptText(SAY_INTRO_CAPERNIAN, m_creature); //start advisor within 7 seconds Phase_Timer = 7000; - - ++PhaseSubphase; + PhaseSubphase++; } break; - //Subphase 3 - Unlock advisor + //Subphase 3 - Unlock advisor case 5: - if(Phase_Timer < diff) + if (Phase_Timer < diff) { - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[2])); + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[2])); - if(Advisor) + if (Advisor) { Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Advisor->setFaction(m_creature->getFaction()); target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) + if (target) Advisor->AI()->AttackStart(target); } - ++PhaseSubphase; + PhaseSubphase++; }else Phase_Timer -= diff; break; - //Subphase 4 - Start + //Subphase 4 - Start case 6: - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[2])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == UNIT_STAND_STATE_DEAD)) + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[2])); + + if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD)) { DoScriptText(SAY_INTRO_TELONICUS, m_creature); //start advisor within 8.4 seconds Phase_Timer = 8400; - - ++PhaseSubphase; + PhaseSubphase++; } break; - //Subphase 4 - Unlock advisor + //Subphase 4 - Unlock advisor case 7: - if(Phase_Timer < diff) + if (Phase_Timer < diff) { - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[3])); + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[3])); - if(Advisor) + if (Advisor) { Advisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Advisor->setFaction(m_creature->getFaction()); target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target) + if (target) Advisor->AI()->AttackStart(target); } Phase_Timer = 3000; - - ++PhaseSubphase; + PhaseSubphase++; }else Phase_Timer -= diff; break; - //End of phase 1 + //End of phase 1 case 8: - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[3])); - if(Advisor && (Advisor->GetUInt32Value(UNIT_FIELD_BYTES_1) == UNIT_STAND_STATE_DEAD)) + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[3])); + + if (Advisor && (Advisor->getStandState() == UNIT_STAND_STATE_DEAD)) { Phase = 2; - pInstance->SetData(DATA_KAELTHASEVENT, 2); + m_pInstance->SetData(DATA_KAELTHASEVENT, 2); DoScriptText(SAY_PHASE2_WEAPON, m_creature); + PhaseSubphase = 0; Phase_Timer = 3500; DoCast(m_creature, SPELL_SUMMON_WEAPONS); @@ -685,39 +645,27 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI //Spawn weapons if (PhaseSubphase == 1) { - Creature* Weapon; - for (uint32 i = 0; i < 7; ++i) - { - Unit* Target = SelectUnit(SELECT_TARGET_RANDOM, 0); - Weapon = m_creature->SummonCreature(((uint32)KaelthasWeapons[i][0]),KaelthasWeapons[i][1],KaelthasWeapons[i][2],KaelthasWeapons[i][3],0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + m_creature->CastSpell(m_creature, SPELL_SUMMON_WEAPONS, false); - if (!Weapon) - error_log("STSCR: Kael'thas weapon %i could not be spawned", i); - else - { - Weapon->setFaction(m_creature->getFaction()); - Weapon->AI()->AttackStart(Target); - Weapon->CastSpell(Weapon, SPELL_WEAPON_SPAWN, false); - WeaponGuid[i] = Weapon->GetGUID(); - } - } + uint8 uiMaxWeapon = sizeof(m_auiSpellSummonWeapon)/sizeof(uint32); + + for (uint32 i = 0; i < uiMaxWeapon; ++i) + m_creature->CastSpell(m_creature,m_auiSpellSummonWeapon[i],true); PhaseSubphase = 2; Phase_Timer = TIME_PHASE_2_3; } if (PhaseSubphase == 2) - if (Phase_Timer < diff) { - DoScriptText(SAY_PHASE3_ADVANCE, m_creature); - - if(pInstance) - pInstance->SetData(DATA_KAELTHASEVENT, 3); - - Phase = 3; - PhaseSubphase = 0; - }else Phase_Timer -= diff; - //missing Resetcheck + if (Phase_Timer < diff) + { + DoScriptText(SAY_PHASE3_ADVANCE, m_creature); + m_pInstance->SetData(DATA_KAELTHASEVENT, 3); + Phase = 3; + PhaseSubphase = 0; + }else Phase_Timer -= diff; + } }break; case 3: @@ -728,34 +676,36 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI Unit* Target = SelectUnit(SELECT_TARGET_RANDOM, 0); Creature* Advisor; - for (uint32 i = 0; i < 4; ++i) + for (uint32 i = 0; i < MAX_ADVISORS; i++) { - Advisor = (Unit::GetCreature((*m_creature), AdvisorGuid[i])); + Advisor = (Creature*)(Unit::GetUnit((*m_creature), m_auiAdvisorGuid[i])); + if (!Advisor) - error_log("TSCR: Kael'Thas Advisor %u does not exist. Possibly despawned? Incorrectly Killed?", i); - else if(Target) - CAST_AI(advisorbase_ai, Advisor->AI())->Revive(Target); + error_log("SD2: Kael'Thas Advisor %u does not exist. Possibly despawned? Incorrectly Killed?", i); + else + ((advisorbase_ai*)Advisor->AI())->Revive(Target); } PhaseSubphase = 1; Phase_Timer = TIME_PHASE_3_4; } - if(Phase_Timer < diff) + if (Phase_Timer < diff) { DoScriptText(SAY_PHASE4_INTRO2, m_creature); Phase = 4; - pInstance->SetData(DATA_KAELTHASEVENT, 4); + m_pInstance->SetData(DATA_KAELTHASEVENT, 4); + + // Sometimes people can collect Aggro in Phase 1-3. Reset threat before releasing Kael. + DoResetThreat(); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - { - DoResetThreat();//only healers will be at top threat, so reset(not delete) all players's threat when Kael comes to fight AttackStart(target); - } + Phase_Timer = 30000; }else Phase_Timer -= diff; } @@ -766,21 +716,22 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI case 6: { //Return since we have no target - if (!UpdateVictim() ) + if (!UpdateVictim()) return; //Fireball_Timer - if(!InGravityLapse && !ChainPyros && Phase != 5) + if (!InGravityLapse && !ChainPyros && Phase != 5) { - if(Fireball_Timer < diff) + if (Fireball_Timer < diff) { - if(!IsCastingFireball) + if (!IsCastingFireball) { - if(!m_creature->IsNonMeleeSpellCasted(false)) + if (!m_creature->IsNonMeleeSpellCasted(false)) { //interruptable m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); - m_creature->CastSpell(m_creature->getVictim(), SPELL_FIREBALL, false); + int32 dmg = 20000+rand()%5000; + m_creature->CastCustomSpell(m_creature->getVictim(), SPELL_FIREBALL, &dmg, 0, 0, false); IsCastingFireball = true; Fireball_Timer = 2500; } @@ -795,16 +746,15 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI }else Fireball_Timer -= diff; //ArcaneDisruption_Timer - if(ArcaneDisruption_Timer < diff) + if (ArcaneDisruption_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_ARCANE_DISRUPTION, true); - ArcaneDisruption_Timer = 60000; }else ArcaneDisruption_Timer -= diff; if (FlameStrike_Timer < diff) { - if (Unit* pUnit = SelectTarget(SELECT_TARGET_RANDOM, 0, 70, true)) + if (Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0)) DoCast(pUnit, SPELL_FLAME_STRIKE); FlameStrike_Timer = 30000; @@ -813,14 +763,10 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI if (MindControl_Timer < diff) { if (m_creature->getThreatManager().getThreatList().size() >= 2) - for (uint32 i = 0; i < 3; i++) + for (uint32 i = 0; i < 3; i++) { - - Unit* target =SelectTarget(SELECT_TARGET_RANDOM, 1, 70, true); - if(!target) target = m_creature->getVictim(); - debug_log("TSCR: Kael'Thas mind control not supported."); - if(target) - DoCast(target, SPELL_MIND_CONTROL); + debug_log("SD2: Kael'Thas mind control not supported."); + //DoCast(pUnit, SPELL_MIND_CONTROL); } MindControl_Timer = 60000; @@ -828,32 +774,43 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI } //Phoenix_Timer - if(Phoenix_Timer < diff) + if (Phoenix_Timer < diff) { - DoCast(m_creature, SPELL_SUMMON_PHOENIX); + DoCast(m_creature, SPELL_PHOENIX_ANIMATION); + + if (Creature* pPhoenix = m_creature->SummonCreature(NPC_PHOENIX, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000)) + { + if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) + pPhoenix->AI()->AttackStart(pTarget); + } + else + error_log("SD2: Kael'Thas Phoenix could not be spawned"); + switch(rand()%2) { - case 0: DoScriptText(SAY_SUMMON_PHOENIX1, m_creature); break; - case 1: DoScriptText(SAY_SUMMON_PHOENIX2, m_creature); break; + case 0: DoScriptText(SAY_SUMMON_PHOENIX1, m_creature); break; + case 1: DoScriptText(SAY_SUMMON_PHOENIX2, m_creature); break; } Phoenix_Timer = 60000; }else Phoenix_Timer -= diff; //Phase 4 specific spells - if(Phase == 4) + if (Phase == 4) { if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 50) { - pInstance->SetData(DATA_KAELTHASEVENT, 4); + m_pInstance->SetData(DATA_KAELTHASEVENT, 4); Phase = 5; Phase_Timer = 10000; DoScriptText(SAY_PHASE5_NUTS, m_creature); + m_creature->StopMoving(); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveIdle(); - DoTeleportTo(GRAVITY_X, GRAVITY_Y, GRAVITY_Z); + m_creature->Relocate(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0); + m_creature->SendMonsterMove(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0, 0, 0); m_creature->InterruptNonMeleeSpells(false); DoCast(m_creature, SPELL_FULLPOWER); @@ -861,73 +818,75 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI } //ShockBarrier_Timer - if(ShockBarrier_Timer < diff) + if (ShockBarrier_Timer < diff) { DoCast(m_creature, SPELL_SHOCK_BARRIER); ChainPyros = true; PyrosCasted = 0; - Check_Timer = 0; - ShockBarrier_Timer = 60000; }else ShockBarrier_Timer -= diff; //Chain Pyros (3 of them max) - if (ChainPyros){ - if (PyrosCasted < 3 && Check_Timer < diff) + if (ChainPyros && !m_creature->IsNonMeleeSpellCasted(false)) + { + if (PyrosCasted < 3) { DoCast(m_creature->getVictim(), SPELL_PYROBLAST); - ++PyrosCasted; + PyrosCasted++; - Check_Timer = 4400; - }else Check_Timer -= diff; - if(PyrosCasted > 3) + } + else { ChainPyros = false; Fireball_Timer = 2500; ArcaneDisruption_Timer = 60000; } } - }else Check_Timer -= 4100; + } if (Phase == 5) { - if(Phase_Timer < diff) + if (Phase_Timer < diff) { m_creature->InterruptNonMeleeSpells(false); m_creature->RemoveAurasDueToSpell(SPELL_FULLPOWER); + DoCast(m_creature, SPELL_EXPLODE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Phase = 6; - DoStartMovement(m_creature->getVictim()); AttackStart(m_creature->getVictim()); }else Phase_Timer -= diff; } //Phase 5 - if(Phase == 6) + if (Phase == 6) { //GravityLapse_Timer - if(GravityLapse_Timer < diff) + if (GravityLapse_Timer < diff) { std::list<HostilReference*>::iterator i = m_creature->getThreatManager().getThreatList().begin(); switch(GravityLapse_Phase) { case 0: + m_creature->StopMoving(); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveIdle(); - DoTeleportTo(GRAVITY_X, GRAVITY_Y, GRAVITY_Z); + m_creature->Relocate(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0); + m_creature->SendMonsterMove(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0, 0, 0); + // 1) Kael'thas will portal the whole raid right into his body - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();) + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();++i) { Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - ++i; - if(pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) + if (pUnit && (pUnit->GetTypeId() == TYPEID_PLAYER)) { //Use work around packet to prevent player from being dropped from combat - DoTeleportPlayer(pUnit, GRAVITY_X, GRAVITY_Y, GRAVITY_Z, pUnit->GetOrientation()); + DoTeleportPlayer(pUnit, afGravityPos[0], afGravityPos[1], afGravityPos[2], pUnit->GetOrientation()); } } + GravityLapse_Timer = 500; ++GravityLapse_Phase; InGravityLapse = true; @@ -938,16 +897,14 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI case 1: switch(rand()%2) { - case 0: DoScriptText(SAY_GRAVITYLAPSE1, m_creature); break; - case 1: DoScriptText(SAY_GRAVITYLAPSE2, m_creature); break; + case 0: DoScriptText(SAY_GRAVITYLAPSE1, m_creature); break; + case 1: DoScriptText(SAY_GRAVITYLAPSE2, m_creature); break; } // 2) At that point he will put a Gravity Lapse debuff on everyone - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();) + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();i++) { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - ++i; - if(pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) + if (Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid())) { m_creature->CastSpell(pUnit, SPELL_KNOCKBACK, true); //Gravity lapse - needs an exception in Spell system to work @@ -964,7 +921,7 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI } } GravityLapse_Timer = 10000; - ++GravityLapse_Phase; + GravityLapse_Phase++; break; case 2: @@ -973,16 +930,14 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI DoCast(m_creature, SPELL_NETHER_VAPOR); GravityLapse_Timer = 20000; - ++GravityLapse_Phase; + GravityLapse_Phase++; break; case 3: //Remove flight - for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();) + for (i = m_creature->getThreatManager().getThreatList().begin(); i!= m_creature->getThreatManager().getThreatList().end();i++) { - Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); - ++i; - if(pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) + if (Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid())) { //Using packet workaround WorldPacket data(12); @@ -992,28 +947,27 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI pUnit->SendMessageToSet(&data, true); } } + m_creature->RemoveAurasDueToSpell(SPELL_NETHER_VAPOR); InGravityLapse = false; GravityLapse_Timer = 60000; GravityLapse_Phase = 0; - DoStartMovement(m_creature->getVictim()); AttackStart(m_creature->getVictim()); - DoResetThreat(); break; } }else GravityLapse_Timer -= diff; - if(InGravityLapse) + if (InGravityLapse) { //ShockBarrier_Timer - if(ShockBarrier_Timer < diff) + if (ShockBarrier_Timer < diff) { DoCast(m_creature, SPELL_SHOCK_BARRIER); ShockBarrier_Timer = 20000; }else ShockBarrier_Timer -= diff; //NetherBeam_Timer - if(NetherBeam_Timer < diff) + if (NetherBeam_Timer < diff) { if (Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0)) DoCast(pUnit, SPELL_NETHER_BEAM); @@ -1033,7 +987,7 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI //Thaladred the Darkener AI struct TRINITY_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai { - boss_thaladred_the_darkenerAI(Creature *c) : advisorbase_ai(c) {} + boss_thaladred_the_darkenerAI(Creature* pCreature) : advisorbase_ai(pCreature) {} uint32 Gaze_Timer; uint32 Silence_Timer; @@ -1048,12 +1002,7 @@ struct TRINITY_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai advisorbase_ai::Reset(); } - void JustDied(Unit* pKiller) - { - DoScriptText(SAY_THALADRED_DEATH, m_creature); - } - - void EnterCombat(Unit *who) + void Aggro(Unit *who) { if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; @@ -1065,6 +1014,12 @@ struct TRINITY_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai m_creature->AddThreat(who, 5000000.0f); } + void JustDied(Unit* pKiller) + { + if (m_pInstance && m_pInstance->GetData(DATA_KAELTHASEVENT) == 3) + DoScriptText(SAY_THALADRED_DEATH, m_creature); + } + void UpdateAI(const uint32 diff) { advisorbase_ai::UpdateAI(diff); @@ -1074,33 +1029,30 @@ struct TRINITY_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai return; //Return since we have no target - if (!UpdateVictim() ) + if (!UpdateVictim()) return; //Gaze_Timer - if(Gaze_Timer < diff) + if (Gaze_Timer < diff) { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) + if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) { DoResetThreat(); - if(target) - { - m_creature->AddThreat(target, 5000000.0f); - DoScriptText(EMOTE_THALADRED_GAZE, m_creature, target); - } + m_creature->AddThreat(target, 5000000.0f); + DoScriptText(EMOTE_THALADRED_GAZE, m_creature, target); Gaze_Timer = 8500; } }else Gaze_Timer -= diff; //Silence_Timer - if(Silence_Timer < diff) + if (Silence_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_SILENCE); Silence_Timer = 20000; }else Silence_Timer -= diff; //PsychicBlow_Timer - if(PsychicBlow_Timer < diff) + if (PsychicBlow_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_PSYCHIC_BLOW); PsychicBlow_Timer = 20000+rand()%5000; @@ -1113,7 +1065,7 @@ struct TRINITY_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai //Lord Sanguinar AI struct TRINITY_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai { - boss_lord_sanguinarAI(Creature *c) : advisorbase_ai(c){} + boss_lord_sanguinarAI(Creature* pCreature) : advisorbase_ai(pCreature) {} uint32 Fear_Timer; @@ -1123,12 +1075,7 @@ struct TRINITY_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai advisorbase_ai::Reset(); } - void JustDied(Unit* Killer) - { - DoScriptText(SAY_SANGUINAR_DEATH, m_creature); - } - - void EnterCombat(Unit *who) + void Aggro(Unit *who) { if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; @@ -1139,6 +1086,12 @@ struct TRINITY_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai DoScriptText(SAY_SANGUINAR_AGGRO, m_creature); } + void JustDied(Unit* Killer) + { + if (m_pInstance && m_pInstance->GetData(DATA_KAELTHASEVENT) == 3) + DoScriptText(SAY_SANGUINAR_DEATH, m_creature); + } + void UpdateAI(const uint32 diff) { advisorbase_ai::UpdateAI(diff); @@ -1148,11 +1101,11 @@ struct TRINITY_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai return; //Return since we have no target - if (!UpdateVictim() ) + if (!UpdateVictim()) return; //Fear_Timer - if(Fear_Timer < diff) + if (Fear_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_BELLOWING_ROAR); Fear_Timer = 25000+rand()%10000; //approximately every 30 seconds @@ -1165,7 +1118,7 @@ struct TRINITY_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai //Grand Astromancer Capernian AI struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ai { - boss_grand_astromancer_capernianAI(Creature *c) : advisorbase_ai(c){} + boss_grand_astromancer_capernianAI(Creature* pCreature) : advisorbase_ai(pCreature) {} uint32 Fireball_Timer; uint32 Conflagration_Timer; @@ -1186,7 +1139,8 @@ struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ void JustDied(Unit* pKiller) { - DoScriptText(SAY_CAPERNIAN_DEATH, m_creature); + if (m_pInstance && m_pInstance->GetData(DATA_KAELTHASEVENT) == 3) + DoScriptText(SAY_CAPERNIAN_DEATH, m_creature); } void AttackStart(Unit* who) @@ -1196,11 +1150,15 @@ struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ if (m_creature->Attack(who, true)) { - DoStartMovement(who, CAPERNIAN_DISTANCE, M_PI/2); + m_creature->AddThreat(who, 0.0f); + m_creature->SetInCombatWith(who); + who->SetInCombatWith(m_creature); + + m_creature->GetMotionMaster()->MoveChase(who, CAPERNIAN_DISTANCE); } } - void EnterCombat(Unit *who) + void Aggro(Unit *who) { if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; @@ -1218,34 +1176,33 @@ struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ return; //Return since we have no target - if (!UpdateVictim() ) + if (!UpdateVictim()) return; //Yell_Timer - if(!Yell) + if (!Yell) { - if(Yell_Timer < diff) + if (Yell_Timer < diff) { DoScriptText(SAY_CAPERNIAN_AGGRO, m_creature); - Yell = true; }else Yell_Timer -= diff; } //Fireball_Timer - if(Fireball_Timer < diff) + if (Fireball_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_CAPERNIAN_FIREBALL); Fireball_Timer = 4000; }else Fireball_Timer -= diff; //Conflagration_Timer - if(Conflagration_Timer < diff) + if (Conflagration_Timer < diff) { Unit *target = NULL; target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target && m_creature->IsWithinDistInMap(target, 30)) + if (target && m_creature->IsWithinDistInMap(target, 30)) DoCast(target, SPELL_CONFLAGRATION); else DoCast(m_creature->getVictim(), SPELL_CONFLAGRATION); @@ -1254,7 +1211,7 @@ struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ }else Conflagration_Timer -= diff; //ArcaneExplosion_Timer - if(ArcaneExplosion_Timer < diff) + if (ArcaneExplosion_Timer < diff) { bool InMeleeRange = false; Unit *target = NULL; @@ -1263,7 +1220,7 @@ struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ { Unit* pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); //if in melee range - if(pUnit && pUnit->IsWithinDistInMap(m_creature, 5)) + if (pUnit && pUnit->IsWithinDistInMap(m_creature, 5)) { InMeleeRange = true; target = pUnit; @@ -1271,7 +1228,7 @@ struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ } } - if(InMeleeRange) + if (InMeleeRange) DoCast(target, SPELL_ARCANE_EXPLOSION); ArcaneExplosion_Timer = 4000+rand()%2000; @@ -1284,7 +1241,7 @@ struct TRINITY_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ //Master Engineer Telonicus AI struct TRINITY_DLL_DECL boss_master_engineer_telonicusAI : public advisorbase_ai { - boss_master_engineer_telonicusAI(Creature *c) : advisorbase_ai(c){} + boss_master_engineer_telonicusAI(Creature* pCreature) : advisorbase_ai(pCreature) {} uint32 Bomb_Timer; uint32 RemoteToy_Timer; @@ -1299,10 +1256,11 @@ struct TRINITY_DLL_DECL boss_master_engineer_telonicusAI : public advisorbase_ai void JustDied(Unit* pKiller) { - DoScriptText(SAY_TELONICUS_DEATH, m_creature); + if (m_pInstance && m_pInstance->GetData(DATA_KAELTHASEVENT) == 3) + DoScriptText(SAY_TELONICUS_DEATH, m_creature); } - void EnterCombat(Unit *who) + void Aggro(Unit *who) { if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; @@ -1322,18 +1280,18 @@ struct TRINITY_DLL_DECL boss_master_engineer_telonicusAI : public advisorbase_ai return; //Return since we have no target - if (!UpdateVictim() ) + if (!UpdateVictim()) return; //Bomb_Timer - if(Bomb_Timer < diff) + if (Bomb_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_BOMB); Bomb_Timer = 25000; }else Bomb_Timer -= diff; //RemoteToy_Timer - if(RemoteToy_Timer < diff) + if (RemoteToy_Timer < diff) { if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_REMOTE_TOY); @@ -1348,7 +1306,7 @@ struct TRINITY_DLL_DECL boss_master_engineer_telonicusAI : public advisorbase_ai //Flame Strike AI struct TRINITY_DLL_DECL mob_kael_flamestrikeAI : public ScriptedAI { - mob_kael_flamestrikeAI(Creature *c) : ScriptedAI(c) {} + mob_kael_flamestrikeAI(Creature* pCreature) : ScriptedAI(pCreature) {} uint32 Timer; bool Casting; @@ -1364,13 +1322,7 @@ struct TRINITY_DLL_DECL mob_kael_flamestrikeAI : public ScriptedAI m_creature->setFaction(14); } - void EnterCombat(Unit *who) - { - } - - void MoveInLineOfSight(Unit *who) - { - } + void MoveInLineOfSight(Unit *who) { } void UpdateAI(const uint32 diff) { @@ -1381,7 +1333,7 @@ struct TRINITY_DLL_DECL mob_kael_flamestrikeAI : public ScriptedAI } //Timer - if(Timer < diff) + if (Timer < diff) { if (!KillSelf) { @@ -1398,71 +1350,37 @@ struct TRINITY_DLL_DECL mob_kael_flamestrikeAI : public ScriptedAI //Phoenix AI struct TRINITY_DLL_DECL mob_phoenix_tkAI : public ScriptedAI { - mob_phoenix_tkAI(Creature *c) : ScriptedAI(c) - { - pInstance = c->GetInstanceData(); - } + mob_phoenix_tkAI(Creature* pCreature) : ScriptedAI(pCreature) {} - ScriptedInstance* pInstance; uint32 Cycle_Timer; - bool egg; - - void JustDied(Unit *victim) - { - if(egg) - { - float x,y,z; - m_creature->GetPosition(x,y,z); - z = m_creature->GetMap()->GetVmapHeight(x,y,z,true); - if(z == INVALID_HEIGHT) - z = ROOM_BASE_Z; - m_creature->SummonCreature(PHOENIX_EGG,x,y,z,m_creature->GetOrientation(),TEMPSUMMON_TIMED_DESPAWN,16000); - m_creature->RemoveCorpse(); - } - } - void Reset() { - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);//birds can fly! :) - egg = true; Cycle_Timer = 2000; m_creature->CastSpell(m_creature,SPELL_BURN,true); } - void EnterCombat(Unit *who) { } - - void DamageTaken(Unit* pKiller, uint32 &damage) + void JustDied(Unit* killer) { - + //is this spell in use anylonger? + //m_creature->CastSpell(m_creature,SPELL_EMBER_BLAST,true); + m_creature->SummonCreature(NPC_PHOENIX_EGG,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_TIMED_DESPAWN,16000); } void UpdateAI(const uint32 diff) { + if (!UpdateVictim()) + return; + if (Cycle_Timer < diff) { - if(pInstance)//check for boss reset - { - Creature* Kael = Unit::GetCreature((*m_creature), pInstance->GetData64(DATA_KAELTHAS)); - if (Kael && Kael->getThreatManager().getThreatList().empty()) - { - egg = false; - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - Cycle_Timer = 2000; - return; - } - } //spell Burn should possible do this, but it doesn't, so do this for now. uint32 dmg = urand(4500,5500); if (m_creature->GetHealth() > dmg) m_creature->SetHealth(uint32(m_creature->GetHealth()-dmg)); - else//kill itt - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); Cycle_Timer = 2000; }else Cycle_Timer -= diff; - if (!UpdateVictim()) - return; DoMeleeAttackIfReady(); } }; @@ -1470,14 +1388,13 @@ struct TRINITY_DLL_DECL mob_phoenix_tkAI : public ScriptedAI //Phoenix Egg AI struct TRINITY_DLL_DECL mob_phoenix_egg_tkAI : public ScriptedAI { - mob_phoenix_egg_tkAI(Creature *c) : ScriptedAI(c) {} + mob_phoenix_egg_tkAI(Creature* pCreature) : ScriptedAI(pCreature) {} uint32 Rebirth_Timer; - bool summoned; - void Reset(){ - Rebirth_Timer = 15000; - summoned = false; + void Reset() + { + Rebirth_Timer = 15000; } //ignore any @@ -1487,12 +1404,13 @@ struct TRINITY_DLL_DECL mob_phoenix_egg_tkAI : public ScriptedAI { if (m_creature->Attack(who, false)) { + m_creature->SetInCombatWith(who); + who->SetInCombatWith(m_creature); + DoStartNoMovement(who); } } - void EnterCombat(Unit *who) { } - void JustSummoned(Creature* summoned) { summoned->AddThreat(m_creature->getVictim(), 0.0f); @@ -1501,82 +1419,82 @@ struct TRINITY_DLL_DECL mob_phoenix_egg_tkAI : public ScriptedAI void UpdateAI(const uint32 diff) { - if (Rebirth_Timer < diff) + if (!Rebirth_Timer) + return; + + if (Rebirth_Timer <= diff) { - if(!summoned) - { - Creature* Phoenix = m_creature->SummonCreature(PHOENIX,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_CORPSE_DESPAWN,5000); - summoned = true; - } - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_creature->SummonCreature(NPC_PHOENIX,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_CORPSE_DESPAWN,5000); + Rebirth_Timer = 0; }else Rebirth_Timer -= diff; } }; -CreatureAI* GetAI_boss_kaelthas(Creature *_Creature) +CreatureAI* GetAI_boss_kaelthas(Creature* pCreature) { - return new boss_kaelthasAI (_Creature); + return new boss_kaelthasAI(pCreature); } -CreatureAI* GetAI_boss_thaladred_the_darkener(Creature *_Creature) +CreatureAI* GetAI_boss_thaladred_the_darkener(Creature* pCreature) { - return new boss_thaladred_the_darkenerAI (_Creature); + return new boss_thaladred_the_darkenerAI(pCreature); } -CreatureAI* GetAI_boss_lord_sanguinar(Creature *_Creature) +CreatureAI* GetAI_boss_lord_sanguinar(Creature* pCreature) { - return new boss_lord_sanguinarAI (_Creature); + return new boss_lord_sanguinarAI(pCreature); } -CreatureAI* GetAI_boss_grand_astromancer_capernian(Creature *_Creature) +CreatureAI* GetAI_boss_grand_astromancer_capernian(Creature* pCreature) { - return new boss_grand_astromancer_capernianAI (_Creature); + return new boss_grand_astromancer_capernianAI(pCreature); } -CreatureAI* GetAI_boss_master_engineer_telonicus(Creature *_Creature) +CreatureAI* GetAI_boss_master_engineer_telonicus(Creature* pCreature) { - return new boss_master_engineer_telonicusAI (_Creature); + return new boss_master_engineer_telonicusAI(pCreature); } -CreatureAI* GetAI_mob_kael_flamestrike(Creature *_Creature) +CreatureAI* GetAI_mob_kael_flamestrike(Creature* pCreature) { - return new mob_kael_flamestrikeAI (_Creature); + return new mob_kael_flamestrikeAI(pCreature); } -CreatureAI* GetAI_mob_phoenix_tk(Creature *_Creature) +CreatureAI* GetAI_mob_phoenix_tk(Creature* pCreature) { - return new mob_phoenix_tkAI (_Creature); + return new mob_phoenix_tkAI(pCreature); } -CreatureAI* GetAI_mob_phoenix_egg_tk(Creature *_Creature) +CreatureAI* GetAI_mob_phoenix_egg_tk(Creature* pCreature) { - return new mob_phoenix_egg_tkAI (_Creature); + return new mob_phoenix_egg_tkAI(pCreature); } + void AddSC_boss_kaelthas() { Script *newscript; newscript = new Script; - newscript->Name="boss_kaelthas"; + newscript->Name = "boss_kaelthas"; newscript->GetAI = &GetAI_boss_kaelthas; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="boss_thaladred_the_darkener"; + newscript->Name = "boss_thaladred_the_darkener"; newscript->GetAI = &GetAI_boss_thaladred_the_darkener; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="boss_lord_sanguinar"; + newscript->Name = "boss_lord_sanguinar"; newscript->GetAI = &GetAI_boss_lord_sanguinar; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="boss_grand_astromancer_capernian"; + newscript->Name = "boss_grand_astromancer_capernian"; newscript->GetAI = &GetAI_boss_grand_astromancer_capernian; newscript->RegisterSelf(); newscript = new Script; - newscript->Name="boss_master_engineer_telonicus"; + newscript->Name = "boss_master_engineer_telonicus"; newscript->GetAI = &GetAI_boss_master_engineer_telonicus; newscript->RegisterSelf(); @@ -1586,7 +1504,7 @@ void AddSC_boss_kaelthas() newscript->RegisterSelf(); newscript = new Script; - newscript->Name="mob_phoenix_tk"; + newscript->Name = "mob_phoenix_tk"; newscript->GetAI = &GetAI_mob_phoenix_tk; newscript->RegisterSelf(); @@ -1595,4 +1513,3 @@ void AddSC_boss_kaelthas() newscript->GetAI = &GetAI_mob_phoenix_egg_tk; newscript->RegisterSelf(); } - diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp index 61286347b83..5bc50a88a5a 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_void_reaver.cpp @@ -24,18 +24,21 @@ EndScriptData */ #include "precompiled.h" #include "def_the_eye.h" -#define SAY_AGGRO -1550000 -#define SAY_SLAY1 -1550001 -#define SAY_SLAY2 -1550002 -#define SAY_SLAY3 -1550003 -#define SAY_DEATH -1550004 -#define SAY_POUNDING1 -1550005 -#define SAY_POUNDING2 -1550006 - -#define SPELL_POUNDING 34162 -#define SPELL_ARCANE_ORB 34172 -#define SPELL_KNOCK_AWAY 25778 -#define SPELL_BERSERK 27680 +enum +{ + SAY_AGGRO = -1550000, + SAY_SLAY1 = -1550001, + SAY_SLAY2 = -1550002, + SAY_SLAY3 = -1550003, + SAY_DEATH = -1550004, + SAY_POUNDING1 = -1550005, + SAY_POUNDING2 = -1550006, + + SPELL_POUNDING = 34162, + SPELL_ARCANE_ORB = 34172, + SPELL_KNOCK_AWAY = 25778, + SPELL_BERSERK = 27680 +}; struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI { @@ -79,6 +82,7 @@ struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI void JustDied(Unit *victim) { DoScriptText(SAY_DEATH, m_creature); + DoZoneInCombat(); if(pInstance) pInstance->SetData(DATA_VOIDREAVEREVENT, DONE); @@ -119,16 +123,23 @@ struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI for(std::list<HostilReference *>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - //18 yard radius minimum + // exclude pets & totems + if (target->GetTypeId() != TYPEID_PLAYER) + continue; + + //18 yard radius minimum if(target && target->GetTypeId() == TYPEID_PLAYER && target->isAlive() && !target->IsWithinDist(m_creature, 18, false)) target_list.push_back(target); target = NULL; } + if(target_list.size()) target = *(target_list.begin()+rand()%target_list.size()); + else + target = m_creature->getVictim(); if (target) - m_creature->CastSpell(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), SPELL_ARCANE_ORB, false); + m_creature->CastSpell(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), SPELL_ARCANE_ORB, false, NULL, NULL, NULL, target); ArcaneOrb_Timer = 3000; }else ArcaneOrb_Timer -= diff; @@ -153,6 +164,8 @@ struct TRINITY_DLL_DECL boss_void_reaverAI : public ScriptedAI }else Berserk_Timer -= diff; DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(diff); } }; diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp index 5b9d74d72c8..a6b0338411e 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp @@ -77,7 +77,6 @@ struct TRINITY_DLL_DECL boss_pathaleon_the_calculatorAI : public ScriptedAI Enraged = false; Counter = 0; - summons.DespawnAll(); } void EnterCombat(Unit *who) diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp index 695c347a554..923612d2fe0 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp @@ -913,8 +913,8 @@ struct TRINITY_DLL_DECL eye_tentacleAI : public Scripted_NoMovementAI { eye_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) { - if (Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = p->GetGUID(); + if (Unit* pPortal = m_creature->SummonCreature(MOB_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + Portal = pPortal->GetGUID(); } uint32 MindflayTimer; @@ -972,8 +972,8 @@ struct TRINITY_DLL_DECL claw_tentacleAI : public Scripted_NoMovementAI { claw_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) { - if (Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = p->GetGUID(); + if (Unit* pPortal = m_creature->SummonCreature(MOB_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + Portal = pPortal->GetGUID(); } uint32 GroundRuptureTimer; @@ -1026,8 +1026,8 @@ struct TRINITY_DLL_DECL claw_tentacleAI : public Scripted_NoMovementAI if (!target->HasAura(SPELL_DIGESTIVE_ACID)) { m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - if (Unit* p = DoSpawnCreature(MOB_SMALL_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = p->GetGUID(); + if (Unit* pPortal = m_creature->SummonCreature(MOB_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + Portal = pPortal->GetGUID(); GroundRuptureTimer = 500; HamstringTimer = 2000; @@ -1061,8 +1061,8 @@ struct TRINITY_DLL_DECL giant_claw_tentacleAI : public Scripted_NoMovementAI { giant_claw_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) { - if (Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = p->GetGUID(); + if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + Portal = pPortal->GetGUID(); } uint32 GroundRuptureTimer; @@ -1117,8 +1117,8 @@ struct TRINITY_DLL_DECL giant_claw_tentacleAI : public Scripted_NoMovementAI if (!target->HasAura(SPELL_DIGESTIVE_ACID)) { m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - if (Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = p->GetGUID(); + if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + Portal = pPortal->GetGUID(); GroundRuptureTimer = 500; HamstringTimer = 2000; @@ -1160,8 +1160,8 @@ struct TRINITY_DLL_DECL giant_eye_tentacleAI : public Scripted_NoMovementAI { giant_eye_tentacleAI(Creature *c) : Scripted_NoMovementAI(c) { - if (Unit* p = DoSpawnCreature(MOB_GIANT_PORTAL,0,0,0,0,TEMPSUMMON_CORPSE_DESPAWN, 0)) - Portal = p->GetGUID(); + if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + Portal = pPortal->GetGUID(); } uint32 BeamTimer; diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp index 3089f3267c8..9449524412c 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp @@ -312,40 +312,18 @@ struct TRINITY_DLL_DECL boss_twinemperorsAI : public ScriptedAI } } - class AnyBugCheck - { - public: - AnyBugCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} - bool operator()(Creature* u) - { - Creature *c = u; - if (!i_obj->IsWithinDistInMap(c, i_range)) - return false; - return (c->GetEntry() == 15316 || c->GetEntry() == 15317); - } - private: - WorldObject const* i_obj; - float i_range; - }; - Creature *RespawnNearbyBugsAndGetOne() { - CellPair p(Trinity::ComputeCellPair(m_creature->GetPositionX(), m_creature->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list<Creature*> unitList; + std::list<Creature*> lUnitList; + m_creature->GetCreatureListWithEntryInGrid(lUnitList,15316,150.0f); + m_creature->GetCreatureListWithEntryInGrid(lUnitList,15317,150.0f); - AnyBugCheck u_check(m_creature, 150); - Trinity::CreatureListSearcher<AnyBugCheck> searcher(m_creature, unitList, u_check); - TypeContainerVisitor<Trinity::CreatureListSearcher<AnyBugCheck>, GridTypeMapContainer > grid_creature_searcher(searcher); - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *(m_creature->GetMap())); + if (lUnitList.empty()) + return NULL; Creature *nearb = NULL; - for(std::list<Creature*>::iterator iter = unitList.begin(); iter != unitList.end(); ++iter) + for(std::list<Creature*>::iterator iter = lUnitList.begin(); iter != lUnitList.end(); ++iter) { Creature *c = *iter; if (c) diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp index b45097d7f97..377c19ec491 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp @@ -53,21 +53,6 @@ EndScriptData */ #define SPELL_STORM_BUFF 2148 #define SPELL_STORM 26546 -class NearbyAQSentinel -{ - public: - NearbyAQSentinel(Unit const* obj) : i_obj(obj) {} - bool operator()(Unit* u) - { - if (u->GetEntry() == 15264 && i_obj->IsWithinDistInMap(u, 70) && !u->isDead()) - return true; - else - return false; - } - private: - Unit const* i_obj; -}; - struct TRINITY_DLL_DECL aqsentinelAI; class TRINITY_DLL_DECL SentinelAbilityAura : public Aura { @@ -166,18 +151,11 @@ struct TRINITY_DLL_DECL aqsentinelAI : public ScriptedAI void AddSentinelsNear(Unit *nears) { - CellPair p(Trinity::ComputeCellPair(nears->GetPositionX(), nears->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - std::list<Creature*> assistList; + m_creature->GetCreatureListWithEntryInGrid(assistList,15264,70.0f); - NearbyAQSentinel u_check(nears); - Trinity::CreatureListSearcher<NearbyAQSentinel> searcher(m_creature, assistList, u_check); - TypeContainerVisitor<Trinity::CreatureListSearcher<NearbyAQSentinel>, GridTypeMapContainer > grid_creature_searcher(searcher); - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *(nears->GetMap())); + if (assistList.empty()) + return; for(std::list<Creature*>::iterator iter = assistList.begin(); iter != assistList.end(); ++iter) AddBuddyToList((*iter)); @@ -240,8 +218,6 @@ struct TRINITY_DLL_DECL aqsentinelAI : public ScriptedAI } ClearBudyList(); gatherOthersWhenAggro = true; - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, false); } void GainSentinelAbility(uint32 id) @@ -256,12 +232,6 @@ struct TRINITY_DLL_DECL aqsentinelAI : public ScriptedAI } SentinelAbilityAura *a = new SentinelAbilityAura(this, (SpellEntry*)spell, id, eff_mask); m_creature->AddAura(a); - - if (id == SPELL_KNOCK_BUFF) - { - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); - } } void EnterCombat(Unit *who) diff --git a/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp b/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp index e70c060b6ac..d54db15dac5 100644 --- a/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp +++ b/src/bindings/scripts/scripts/zone/terokkar_forest/terokkar_forest.cpp @@ -219,14 +219,15 @@ struct TRINITY_DLL_DECL mob_netherweb_victimAI : public ScriptedAI { if( rand()%100 < 25 ) { - DoSpawnCreature(QUEST_TARGET,0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); - CAST_PLR(Killer)->KilledMonster(QUEST_TARGET, m_creature->GetGUID()); - }else - DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); + m_creature->SummonCreature(QUEST_TARGET, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + CAST_PLR(Killer)->KilledMonsterCredit(QUEST_TARGET, m_creature->GetGUID()); + } + else + m_creature->SummonCreature(netherwebVictims[rand()%6], 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); if( rand()%100 < 75 ) - DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); - DoSpawnCreature(netherwebVictims[rand()%6],0,0,0,0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,60000); + m_creature->SummonCreature(netherwebVictims[rand()%6], 0.0f, 0.0f, 0.0f,0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + m_creature->SummonCreature(netherwebVictims[rand()%6], 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); } } } diff --git a/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp b/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp index fb558dc31a3..08e88782580 100644 --- a/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp +++ b/src/bindings/scripts/scripts/zone/tirisfal_glades/tirisfal_glades.cpp @@ -33,31 +33,94 @@ EndContentData */ ## npc_calvin_montague ######*/ -#define QUEST_590 590 -#define FACTION_FRIENDLY 68 -#define FACTION_HOSTILE 16 +enum +{ + SAY_COMPLETE = -1000431, + SPELL_DRINK = 2639, // possibly not correct spell (but iconId is correct) + QUEST_590 = 590, + FACTION_HOSTILE = 168 +}; struct TRINITY_DLL_DECL npc_calvin_montagueAI : public ScriptedAI { - npc_calvin_montagueAI(Creature* c) : ScriptedAI(c) {} + npc_calvin_montagueAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + uint64 m_uiPlayerGUID; void Reset() { - m_creature->setFaction(FACTION_FRIENDLY); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + m_uiPhase = 0; + m_uiPhaseTimer = 5000; + m_uiPlayerGUID = 0; + + me->RestoreFaction(); + + if (!m_creature->HasFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_ATTACKABLE_2)) + m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_ATTACKABLE_2); } void EnterCombat(Unit* who) { } - void JustDied(Unit* Killer) + void AttackedBy(Unit* pAttacker) + { + if (m_creature->getVictim() || m_creature->IsFriendlyTo(pAttacker)) + return; + + AttackStart(pAttacker); + } + + void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) { - if( Killer->GetTypeId() == TYPEID_PLAYER ) - if( CAST_PLR(Killer)->GetQuestStatus(QUEST_590) == QUEST_STATUS_INCOMPLETE ) - CAST_PLR(Killer)->AreaExploredOrEventHappens(QUEST_590); + if (uiDamage > m_creature->GetHealth() || ((m_creature->GetHealth() - uiDamage)*100 / m_creature->GetMaxHealth() < 15)) + { + uiDamage = 0; + + me->RestoreFaction(); + m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_ATTACKABLE_2); + m_creature->CombatStop(true); + + m_uiPhase = 1; + + if (pDoneBy->GetTypeId() == TYPEID_PLAYER) + m_uiPlayerGUID = pDoneBy->GetGUID(); + } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) { + if (m_uiPhase) + { + if (m_uiPhaseTimer < uiDiff) + m_uiPhaseTimer = 7500; + else + { + m_uiPhaseTimer -= uiDiff; + return; + } + + switch(m_uiPhase) + { + case 1: + DoScriptText(SAY_COMPLETE, m_creature); + ++m_uiPhase; + break; + case 2: + if (Unit* pUnit = Unit::GetUnit(*m_creature, m_uiPlayerGUID)) + CAST_PLR(pUnit)->AreaExploredOrEventHappens(QUEST_590); + + m_creature->CastSpell(m_creature,SPELL_DRINK,true); + ++m_uiPhase; + break; + case 3: + EnterEvadeMode(); + break; + } + + return; + } + if (!UpdateVictim()) return; @@ -69,13 +132,13 @@ CreatureAI* GetAI_npc_calvin_montague(Creature *_Creature) return new npc_calvin_montagueAI (_Creature); } -bool QuestAccept_npc_calvin_montague(Player* player, Creature* creature, Quest const* quest) +bool QuestAccept_npc_calvin_montague(Player* pPlayer, Creature* pCreature, Quest const* quest) { if( quest->GetQuestId() == QUEST_590 ) { - creature->setFaction(FACTION_HOSTILE); - creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); - CAST_AI(npc_calvin_montagueAI, creature->AI())->AttackStart(player); + pCreature->setFaction(FACTION_HOSTILE); + pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + CAST_AI(npc_calvin_montagueAI, pCreature->AI())->AttackStart(pPlayer); } return true; } @@ -85,55 +148,38 @@ bool QuestAccept_npc_calvin_montague(Player* player, Creature* creature, Quest c ## go_mausoleum_trigger ######*/ -#define QUEST_ULAG 1819 -#define C_ULAG 6390 -#define GO_TRIGGER 104593 -#define GO_DOOR 176594 - -GameObject* SearchMausoleumGo(Unit *source, uint32 entry, float range) +enum { - GameObject* pGo = NULL; - - CellPair pair(Trinity::ComputeCellPair(source->GetPositionX(), source->GetPositionY())); - Cell cell(pair); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*source, entry, range); - Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> searcher(source, pGo, go_check); - - TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer> go_searcher(searcher); - - CellLock<GridReadGuard> cell_lock(cell, pair); - cell_lock->Visit(cell_lock, go_searcher,*(source->GetMap())); - - return pGo; -} + QUEST_ULAG = 1819, + NPC_ULAG = 6390, + GO_TRIGGER = 104593, + GO_DOOR = 176594 +}; -bool GOHello_go_mausoleum_door(Player *player, GameObject* _GO) +bool GOHello_go_mausoleum_door(Player* pPlayer, GameObject* pGo) { - if (player->GetQuestStatus(QUEST_ULAG) != QUEST_STATUS_INCOMPLETE) + if (pPlayer->GetQuestStatus(QUEST_ULAG) != QUEST_STATUS_INCOMPLETE) return false; - if (GameObject *trigger = SearchMausoleumGo(player, GO_TRIGGER, 30)) + if (GameObject* pTrigger = pPlayer->FindNearestGameObject(GO_TRIGGER, 30.0f)) { - trigger->SetGoState(GO_STATE_READY); - player->SummonCreature(C_ULAG, 2390.26, 336.47, 40.01, 2.26, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); + pTrigger->SetGoState(GO_STATE_READY); + pPlayer->SummonCreature(NPC_ULAG, 2390.26, 336.47, 40.01, 2.26, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); return false; } return false; } -bool GOHello_go_mausoleum_trigger(Player *player, GameObject* _GO) +bool GOHello_go_mausoleum_trigger(Player* pPlayer, GameObject* pGo) { - if (player->GetQuestStatus(QUEST_ULAG) != QUEST_STATUS_INCOMPLETE) + if (pPlayer->GetQuestStatus(QUEST_ULAG) != QUEST_STATUS_INCOMPLETE) return false; - if (GameObject *door = SearchMausoleumGo(player, GO_DOOR, 30)) + if (GameObject* pDoor = pPlayer->FindNearestGameObject(GO_DOOR, 30.0f)) { - _GO->SetGoState(GO_STATE_ACTIVE); - door->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND); + pGo->SetGoState(GO_STATE_ACTIVE); + pDoor->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND); return true; } diff --git a/src/bindings/scripts/scripts/zone/uldaman/boss_archaedas.cpp b/src/bindings/scripts/scripts/zone/uldaman/boss_archaedas.cpp index 17caebe85bb..042a0643594 100644 --- a/src/bindings/scripts/scripts/zone/uldaman/boss_archaedas.cpp +++ b/src/bindings/scripts/scripts/zone/uldaman/boss_archaedas.cpp @@ -385,12 +385,11 @@ struct TRINITY_DLL_DECL mob_stonekeepersAI : public ScriptedAI DoMeleeAttackIfReady(); } - void DamageTaken (Unit *attacker, uint32 &damage) { - if (damage > m_creature->GetHealth()) { - DoCast (m_creature, SPELL_SELF_DESTRUCT,true); - if(pInstance) - pInstance->SetData(NULL, 1); // activate next stonekeeper - } + void JustDied(Unit *attacker) + { + DoCast (m_creature, SPELL_SELF_DESTRUCT,true); + if(pInstance) + pInstance->SetData(NULL, 1); // activate next stonekeeper } }; diff --git a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_bjarngrim.cpp b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_bjarngrim.cpp index b26c3d0853d..ec2c4995dc7 100644 --- a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_bjarngrim.cpp +++ b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/boss_bjarngrim.cpp @@ -1,86 +1,429 @@ -/* Script Data Start -SDName: Boss bjarngrim -SDAuthor: LordVanMartin -SD%Complete: -SDComment: -SDCategory: -Script Data End */ - -/*** SQL START *** -update creature_template set scriptname = '' where entry = ''; -*** SQL END ***/ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Boss General Bjarngrim +SD%Complete: 70% +SDComment: Waypoint needed, we expect boss to always have 2x Stormforged Lieutenant following +SDCategory: Halls of Lightning +EndScriptData */ + #include "precompiled.h" +#include "def_halls_of_lightning.h" + +enum +{ + //Yell + SAY_AGGRO = -1602000, + SAY_SLAY_1 = -1602001, + SAY_SLAY_2 = -1602002, + SAY_SLAY_3 = -1602003, + SAY_DEATH = -1602004, + SAY_BATTLE_STANCE = -1602005, + EMOTE_BATTLE_STANCE = -1602006, + SAY_BERSEKER_STANCE = -1602007, + EMOTE_BERSEKER_STANCE = -1602008, + SAY_DEFENSIVE_STANCE = -1602009, + EMOTE_DEFENSIVE_STANCE = -1602010, + + SPELL_DEFENSIVE_STANCE = 53790, + //SPELL_DEFENSIVE_AURA = 41105, + SPELL_SPELL_REFLECTION = 36096, + SPELL_PUMMEL = 12555, + SPELL_KNOCK_AWAY = 52029, + SPELL_IRONFORM = 52022, + + SPELL_BERSEKER_STANCE = 53791, + //SPELL_BERSEKER_AURA = 41107, + SPELL_INTERCEPT = 58769, + SPELL_WHIRLWIND = 52027, + SPELL_CLEAVE = 15284, + + SPELL_BATTLE_STANCE = 53792, + //SPELL_BATTLE_AURA = 41106, + SPELL_MORTAL_STRIKE = 16856, + SPELL_SLAM = 52026, -//AURAS AND STANCES -#define BUFF_BATTLE_AURA 41106 -#define SPELL_BATTLE_STANCE 53792 -#define BUFF_BERSEKER_AURA 41107 -#define SPELL_BERSEKER_STANCE 53791 -#define BUFF_DEFENSIVE_AURA 41105 -#define SPELL_DEFENSIVE_STANCE 53790 - -//OTHER SPELLS -#define SPELL_CHARGE_UP 52098 -#define SPELL_CLEAVE 15284 -#define SPELL_INTERCEPT 58769 -#define SPELL_IRONFORM 52022 -#define SPELL_KNOCK_AWAY 52029 -#define SPELL_MORTAL_STRIKE 15708 -#define SPELL_SLAM 52026 -#define SPELL_SPELL_REFLECTION 36096 -#define SPELL_WHIRLWIND 52027 - -//Yell -#define SAY_AGGRO -1602000 -#define SAY_SLAY_1 -1602001 -#define SAY_SLAY_2 -1602002 -#define SAY_SLAY_3 -1602003 -#define SAY_DEATH -1602004 -#define SAY_BATTLE_STANCE -1602005 -#define SAY_BERSEKER_STANCE -1602006 -#define SAY_DEFENSIVE_STANCE -1602007 + //OTHER SPELLS + //SPELL_CHARGE_UP = 52098, // only used when starting walk from one platform to the other + //SPELL_TEMPORARY_ELECTRICAL_CHARGE = 52092, // triggered part of above + + NPC_STORMFORGED_LIEUTENANT = 29240, + SPELL_ARC_WELD = 59085, + SPELL_RENEW_STEEL_N = 52774, + SPELL_RENEW_STEEL_H = 59160, + + EQUIP_SWORD = 37871, + EQUIP_SHIELD = 35642, + EQUIP_MACE = 43623, + + STANCE_DEFENSIVE = 0, + STANCE_BERSERKER = 1, + STANCE_BATTLE = 2 +}; + +/*###### +## boss_bjarngrim +######*/ struct TRINITY_DLL_DECL boss_bjarngrimAI : public ScriptedAI { - boss_bjarngrimAI(Creature *c) : ScriptedAI(c) {} + boss_bjarngrimAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsHeroic = pCreature->GetMap()->IsHeroic(); + m_uiStance = STANCE_DEFENSIVE; + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bIsHeroic; + bool m_bIsChangingStance; + + uint8 m_uiChargingStatus; + uint8 m_uiStance; + + uint32 m_uiCharge_Timer; + uint32 m_uiChangeStance_Timer; + + uint32 m_uiReflection_Timer; + uint32 m_uiKnockAway_Timer; + uint32 m_uiPummel_Timer; + uint32 m_uiIronform_Timer; + + uint32 m_uiIntercept_Timer; + uint32 m_uiWhirlwind_Timer; + uint32 m_uiCleave_Timer; + + uint32 m_uiMortalStrike_Timer; + uint32 m_uiSlam_Timer; + + uint64 m_uiStormforgedLieutenantGUID[2]; + + void Reset() + { + m_bIsChangingStance = false; + + m_uiChargingStatus = 0; + m_uiCharge_Timer = 1000; + + m_uiChangeStance_Timer = 20000 + rand()%5000; + + m_uiReflection_Timer = 8000; + m_uiKnockAway_Timer = 20000; + m_uiPummel_Timer = 10000; + m_uiIronform_Timer = 25000; - uint32 whirlwind; + m_uiIntercept_Timer = 5000; + m_uiWhirlwind_Timer = 10000; + m_uiCleave_Timer = 8000; - void Reset() {} - void EnterCombat(Unit* who) + m_uiMortalStrike_Timer = 8000; + m_uiSlam_Timer = 10000; + + for(uint8 i = 0; i < 2; ++i) + { + if (Creature* pStormforgedLieutenant = ((Creature*)Unit::GetUnit((*m_creature), m_uiStormforgedLieutenantGUID[i]))) + { + if (!pStormforgedLieutenant->isAlive()) + pStormforgedLieutenant->Respawn(); + } + } + + if (m_uiStance != STANCE_DEFENSIVE) + { + DoRemoveStanceAura(m_uiStance); + DoCast(m_creature, SPELL_DEFENSIVE_STANCE); + m_uiStance = STANCE_DEFENSIVE; + } + + SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SHIELD, EQUIP_NO_CHANGE); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, NOT_STARTED); + } + + void EnterCombat(Unit* pWho) { DoScriptText(SAY_AGGRO, m_creature); + + //must get both lieutenants here and make sure they are with him + m_creature->CallForHelp(30.0f); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, IN_PROGRESS); + } + + void KilledUnit(Unit* pVictim) + { + switch(rand()%3) + { + case 0: DoScriptText(SAY_SLAY_1, m_creature); break; + case 1: DoScriptText(SAY_SLAY_2, m_creature); break; + case 2: DoScriptText(SAY_SLAY_3, m_creature); break; + } + } + + void JustDied(Unit* pKiller) + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, DONE); + } + + //TODO: remove when removal is done by mangos + void DoRemoveStanceAura(uint8 uiStance) + { + switch(uiStance) + { + case STANCE_DEFENSIVE: + m_creature->RemoveAurasDueToSpell(SPELL_DEFENSIVE_STANCE); + break; + case STANCE_BERSERKER: + m_creature->RemoveAurasDueToSpell(SPELL_BERSEKER_STANCE); + break; + case STANCE_BATTLE: + m_creature->RemoveAurasDueToSpell(SPELL_BATTLE_STANCE); + break; + } } - void AttackStart(Unit* who) {} - void MoveInLineOfSight(Unit* who) {} - void UpdateAI(const uint32 diff) + + void UpdateAI(const uint32 uiDiff) { //Return since we have no target - if(!UpdateVictim()) + if (!UpdateVictim()) + return; + + // Change stance + if (m_uiChangeStance_Timer < uiDiff) + { + //wait for current spell to finish before change stance + if (m_creature->IsNonMeleeSpellCasted(false)) + return; + + DoRemoveStanceAura(m_uiStance); + + int uiTempStance = rand()%(3-1); + + if (uiTempStance >= m_uiStance) + ++uiTempStance; + + m_uiStance = uiTempStance; + + switch(m_uiStance) + { + case STANCE_DEFENSIVE: + DoScriptText(SAY_DEFENSIVE_STANCE, m_creature); + DoScriptText(EMOTE_DEFENSIVE_STANCE, m_creature); + DoCast(m_creature, SPELL_DEFENSIVE_STANCE); + SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SHIELD, EQUIP_NO_CHANGE); + break; + case STANCE_BERSERKER: + DoScriptText(SAY_BERSEKER_STANCE, m_creature); + DoScriptText(EMOTE_BERSEKER_STANCE, m_creature); + DoCast(m_creature, SPELL_BERSEKER_STANCE); + SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SWORD, EQUIP_NO_CHANGE); + break; + case STANCE_BATTLE: + DoScriptText(SAY_BATTLE_STANCE, m_creature); + DoScriptText(EMOTE_BATTLE_STANCE, m_creature); + DoCast(m_creature, SPELL_BATTLE_STANCE); + SetEquipmentSlots(false, EQUIP_MACE, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + break; + } + + m_uiChangeStance_Timer = 20000 + rand()%5000; return; + } + else + m_uiChangeStance_Timer -= uiDiff; + + switch(m_uiStance) + { + case STANCE_DEFENSIVE: + { + if (m_uiReflection_Timer < uiDiff) + { + DoCast(m_creature, SPELL_SPELL_REFLECTION); + m_uiReflection_Timer = 8000 + rand()%1000; + } + else + m_uiReflection_Timer -= uiDiff; + + if (m_uiKnockAway_Timer < uiDiff) + { + DoCast(m_creature, SPELL_KNOCK_AWAY); + m_uiKnockAway_Timer = 20000 + rand()%1000; + } + else + m_uiKnockAway_Timer -= uiDiff; + + if (m_uiPummel_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_PUMMEL); + m_uiPummel_Timer = 10000 + rand()%1000; + } + else + m_uiPummel_Timer -= uiDiff; + + if (m_uiIronform_Timer < uiDiff) + { + DoCast(m_creature, SPELL_IRONFORM); + m_uiIronform_Timer = 25000 + rand()%1000; + } + else + m_uiIronform_Timer -= uiDiff; + + break; + } + case STANCE_BERSERKER: + { + if (m_uiIntercept_Timer < uiDiff) + { + //not much point is this, better random target and more often? + DoCast(m_creature->getVictim(), SPELL_INTERCEPT); + m_uiIntercept_Timer = 45000 + rand()%1000; + } + else + m_uiIntercept_Timer -= uiDiff; + + if (m_uiWhirlwind_Timer < uiDiff) + { + DoCast(m_creature, SPELL_WHIRLWIND); + m_uiWhirlwind_Timer = 10000 + rand()%1000; + } + else + m_uiWhirlwind_Timer -= uiDiff; + + if (m_uiCleave_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_CLEAVE); + m_uiCleave_Timer = 8000 + rand()%1000; + } + else + m_uiCleave_Timer -= uiDiff; + + break; + } + case STANCE_BATTLE: + { + if (m_uiMortalStrike_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_MORTAL_STRIKE); + m_uiMortalStrike_Timer = 20000 + rand()%1000; + } + else + m_uiMortalStrike_Timer -= uiDiff; + + if (m_uiSlam_Timer < uiDiff) + { + DoCast(m_creature->getVictim(), SPELL_SLAM); + m_uiSlam_Timer = 15000 + rand()%1000; + } + else + m_uiSlam_Timer -= uiDiff; + + break; + } + } DoMeleeAttackIfReady(); } - void JustDied(Unit* killer) +}; + +/*###### +## mob_stormforged_lieutenant +######*/ + +struct TRINITY_DLL_DECL mob_stormforged_lieutenantAI : public ScriptedAI +{ + mob_stormforged_lieutenantAI(Creature *pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((ScriptedInstance*)pCreature->GetInstanceData()); + m_bIsHeroic = pCreature->GetMap()->IsHeroic(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsHeroic; + + uint32 m_uiArcWeld_Timer; + uint32 m_uiRenewSteel_Timer; + + void Reset() { - DoScriptText(SAY_DEATH, m_creature); + m_uiArcWeld_Timer = 20000 + rand()%1000; + m_uiRenewSteel_Timer = 10000 + rand()%1000; } - void KilledUnit(Unit *victim) + + void EnterCombat(Unit* pWho) { - if(victim == m_creature) + if (m_pInstance) + { + if (Creature* pBjarngrim = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_BJARNGRIM))) + { + if (pBjarngrim->isAlive() && !pBjarngrim->getVictim()) + pBjarngrim->AI()->AttackStart(pWho); + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + //Return since we have no target + if (!UpdateVictim()) return; - switch(rand()%3) + + if (m_uiArcWeld_Timer < uiDiff) { - case 0: DoScriptText(SAY_SLAY_1, m_creature);break; - case 1: DoScriptText(SAY_SLAY_2, m_creature);break; - case 2: DoScriptText(SAY_SLAY_3, m_creature);break; + DoCast(m_creature->getVictim(), SPELL_ARC_WELD); + m_uiArcWeld_Timer = 20000 + rand()%1000; } + else + m_uiArcWeld_Timer -= uiDiff; + + if (m_uiRenewSteel_Timer < uiDiff) + { + if (m_pInstance) + { + if (Creature* pBjarngrim = m_pInstance->instance->GetCreature(m_pInstance->GetData64(DATA_BJARNGRIM))) + { + if (pBjarngrim->isAlive()) + DoCast(pBjarngrim, m_bIsHeroic ? SPELL_RENEW_STEEL_H : SPELL_RENEW_STEEL_N); + } + } + m_uiRenewSteel_Timer = 10000 + rand()%4000; + } + else + m_uiRenewSteel_Timer -= uiDiff; + + DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_boss_bjarngrim(Creature *_Creature) +CreatureAI* GetAI_boss_bjarngrim(Creature* pCreature) { - return new boss_bjarngrimAI (_Creature); + return new boss_bjarngrimAI(pCreature); +} + +CreatureAI* GetAI_mob_stormforged_lieutenant(Creature* pCreature) +{ + return new mob_stormforged_lieutenantAI(pCreature); } void AddSC_boss_bjarngrim() @@ -88,7 +431,12 @@ void AddSC_boss_bjarngrim() Script *newscript; newscript = new Script; - newscript->Name="boss_bjarngrim"; + newscript->Name = "boss_bjarngrim"; newscript->GetAI = &GetAI_boss_bjarngrim; newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name = "mob_stormforged_lieutenant"; + newscript->GetAI = &GetAI_mob_stormforged_lieutenant; + newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/def_halls_of_lightning.h b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/def_halls_of_lightning.h index 134e32850ae..8790274e599 100644 --- a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/def_halls_of_lightning.h +++ b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/def_halls_of_lightning.h @@ -1,4 +1,34 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + #ifndef DEF_HALLS_OF_LIGHTNING_H #define DEF_HALLS_OF_LIGHTNING_H +enum +{ + MAX_ENCOUNTER = 4, + + DATA_BJARNGRIM = 1, + DATA_IONAR = 2, + DATA_LOKEN = 3, + DATA_VOLKHAN = 4, + + TYPE_BJARNGRIM = 10, + TYPE_IONAR = 11, + TYPE_LOKEN = 12, + TYPE_VOLKHAN = 13, + + NPC_BJARNGRIM = 28586, + NPC_VOLKHAN = 28587, + NPC_IONAR = 28546, + NPC_LOKEN = 28923, + + GO_BJARNGRIM_DOOR = 191416, //_doors10 + GO_VOLKHAN_DOOR = 191325, //_doors07 + GO_IONAR_DOOR = 191326, //_doors05 + GO_LOKEN_DOOR = 191324, //_doors02 + GO_LOKEN_THRONE = 192654 +}; + #endif diff --git a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp index 1c7983d3b69..5b7d7a9e939 100644 --- a/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp +++ b/src/bindings/scripts/scripts/zone/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp @@ -1,14 +1,187 @@ +/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ScriptData +SDName: Instance_Halls_of_Lightning +SD%Complete: 90% +SDComment: All ready. +SDCategory: Halls of Lightning +EndScriptData */ + #include "precompiled.h" #include "def_halls_of_lightning.h" -struct TRINITY_DLL_DECL instance_halls_of_lightning : public ScriptedInstance +/* Halls of Lightning encounters: +0 - General Bjarngrim +1 - Volkhan +2 - Ionar +3 - Loken +*/ + +struct MANGOS_DLL_DECL instance_halls_of_lightning : public ScriptedInstance { - instance_halls_of_lightning(Map *Map) : ScriptedInstance(Map) {Initialize();}; + instance_halls_of_lightning(Map* pMap) : ScriptedInstance(pMap) {Initialize();}; + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + uint64 m_uiGeneralBjarngrimGUID; + uint64 m_uiIonarGUID; + uint64 m_uiLokenGUID; + uint64 m_uiVolkhanGUID; + + uint64 m_uiBjarngrimDoorGUID; + uint64 m_uiVolkhanDoorGUID; + uint64 m_uiIonarDoorGUID; + uint64 m_uiLokenDoorGUID; + uint64 m_uiLokenGlobeGUID; + + void Initialize() + { + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + m_uiGeneralBjarngrimGUID = 0; + m_uiVolkhanGUID = 0; + m_uiIonarGUID = 0; + m_uiLokenGUID = 0; + + m_uiBjarngrimDoorGUID = 0; + m_uiVolkhanDoorGUID = 0; + m_uiIonarDoorGUID = 0; + m_uiLokenDoorGUID = 0; + m_uiLokenGlobeGUID = 0; + } + + void OnCreatureCreate(Creature* pCreature, bool add) + { + switch(pCreature->GetEntry()) + { + case NPC_BJARNGRIM: + m_uiGeneralBjarngrimGUID = pCreature->GetGUID(); + break; + case NPC_VOLKHAN: + m_uiVolkhanGUID = pCreature->GetGUID(); + break; + case NPC_IONAR: + m_uiIonarGUID = pCreature->GetGUID(); + break; + case NPC_LOKEN: + m_uiLokenGUID = pCreature->GetGUID(); + break; + } + } + + void OnGameObjectCreate(GameObject* pGo, bool add) + { + switch(pGo->GetEntry()) + { + case GO_BJARNGRIM_DOOR: + m_uiBjarngrimDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[0] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_VOLKHAN_DOOR: + m_uiVolkhanDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_IONAR_DOOR: + m_uiIonarDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_LOKEN_DOOR: + m_uiLokenDoorGUID = pGo->GetGUID(); + if (m_auiEncounter[3] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_LOKEN_THRONE: + m_uiLokenGlobeGUID = pGo->GetGUID(); + break; + } + } + + void SetData(uint32 uiType, uint32 uiData) + { + switch(uiType) + { + case TYPE_BJARNGRIM: + if (uiData == DONE) + DoUseDoorOrButton(m_uiBjarngrimDoorGUID); + m_auiEncounter[0] = uiData; + break; + case TYPE_VOLKHAN: + if (uiData == DONE) + DoUseDoorOrButton(m_uiVolkhanDoorGUID); + m_auiEncounter[1] = uiData; + break; + case TYPE_IONAR: + if (uiData == DONE) + DoUseDoorOrButton(m_uiIonarDoorGUID); + m_auiEncounter[2] = uiData; + break; + case TYPE_LOKEN: + if (uiData == DONE) + { + DoUseDoorOrButton(m_uiLokenDoorGUID); + + //Appears to be type 5 GO with animation. Need to figure out how this work, code below only placeholder + if (GameObject* pGlobe = instance->GetGameObject(m_uiLokenGlobeGUID)) + pGlobe->SetGoState(GO_STATE_ACTIVE); + } + m_auiEncounter[3] = uiData; + break; + } + } + + uint32 GetData(uint32 uiType) + { + switch(uiType) + { + case TYPE_BJARNGRIM: + return m_auiEncounter[0]; + case TYPE_VOLKHAN: + return m_auiEncounter[1]; + case TYPE_IONAR: + return m_auiEncounter[2]; + case TYPE_LOKEN: + return m_auiEncounter[3]; + } + return 0; + } + + uint64 GetData64(uint32 uiData) + { + switch(uiData) + { + case DATA_BJARNGRIM: + return m_uiGeneralBjarngrimGUID; + case DATA_VOLKHAN: + return m_uiVolkhanGUID; + case DATA_IONAR: + return m_uiIonarGUID; + case DATA_LOKEN: + return m_uiLokenGUID; + } + return 0; + } }; -InstanceData* GetInstanceData_instance_halls_of_lightning(Map* map) +InstanceData* GetInstanceData_instance_halls_of_lightning(Map* pMap) { - return new instance_halls_of_lightning(map); + return new instance_halls_of_lightning(pMap); } void AddSC_instance_halls_of_lightning() diff --git a/src/bindings/scripts/scripts/zone/ulduar/ulduar/boss_flame_leviathan.cpp b/src/bindings/scripts/scripts/zone/ulduar/ulduar/boss_flame_leviathan.cpp index c1798cf8893..b00af93b0ac 100644 --- a/src/bindings/scripts/scripts/zone/ulduar/ulduar/boss_flame_leviathan.cpp +++ b/src/bindings/scripts/scripts/zone/ulduar/ulduar/boss_flame_leviathan.cpp @@ -33,6 +33,13 @@ #define SPELL_SEARING_FLAME 62402 +enum Events +{ + EVENT_PURSUE = 1, + EVENT_MISSILE, + EVENT_VENT, +}; + struct TRINITY_DLL_DECL boss_flame_leviathanAI : public BossAI { boss_flame_leviathanAI(Creature *c) : BossAI(c, BOSS_LEVIATHAN) @@ -40,17 +47,113 @@ struct TRINITY_DLL_DECL boss_flame_leviathanAI : public BossAI assert(c->isVehicle()); } + void EnterCombat(Unit *who) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_PURSUE, 0); + events.ScheduleEvent(EVENT_MISSILE, 1500); + events.ScheduleEvent(EVENT_VENT, 20000); + if(Creature *turret = CAST_CRE(CAST_VEH(me)->GetPassenger(7))) + turret->AI()->DoZoneInCombat(); + } + + // TODO: effect 0 and effect 1 may be on different target + void SpellHitTarget(Unit *target, const SpellEntry *spell) + { + if(spell->Id == SPELL_PURSUED) + AttackStart(target); + } + void UpdateAI(const uint32 diff) { - if(!UpdateVictim()) + if(!me->isInCombat()) return; + if(me->getThreatManager().isThreatListEmpty()) + { + EnterEvadeMode(); + return; + } + events.Update(diff); if(me->hasUnitState(UNIT_STAT_CASTING)) return; - DoMeleeAttackIfReady(); + uint32 eventId = events.GetEvent(); + if(!me->getVictim()) + eventId = EVENT_PURSUE; + + switch(eventId) + { + case 0: + return; + case EVENT_PURSUE: + DoCastAOE(SPELL_PURSUED); + events.RepeatEvent(35000); + return; + case EVENT_MISSILE: + //TODO: without unittarget no visual effect + //DoCastAOE(SPELL_MISSILE_BARRAGE); + DoCast(me->getVictim(), SPELL_MISSILE_BARRAGE); + events.RepeatEvent(1500); + return; + case EVENT_VENT: + DoCastAOE(SPELL_FLAME_VENTS); + events.RepeatEvent(20000); + return; + default: + events.PopEvent(); + break; + } + + DoSpellAttackIfReady(SPELL_BATTERING_RAM); + } +}; + + +struct TRINITY_DLL_DECL boss_flame_leviathan_turretAI : public ScriptedAI +{ + boss_flame_leviathan_turretAI(Creature *c) : ScriptedAI(c) + { + me->SetReactState(REACT_PASSIVE); + } + + void Reset() + { + events.Reset(); + } + + EventMap events; + + void EnterCombat(Unit *who) + { + events.ScheduleEvent(1, 5000); + } + + void UpdateAI(const uint32 diff) + { + if(!UpdateCombatState()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(uint32 eventId = events.GetEvent()) + { + switch(eventId) + { + case 1: + DoCast(SelectTarget(SELECT_TARGET_RANDOM), SPELL_CANNON); + events.RepeatEvent(10000); + return; + default: + events.PopEvent(); + break; + } + } } }; @@ -60,12 +163,55 @@ struct TRINITY_DLL_DECL boss_flame_leviathan_seatAI : public ScriptedAI boss_flame_leviathan_seatAI(Creature *c) : ScriptedAI(c) { assert(c->isVehicle()); + if(const CreatureInfo *cInfo = me->GetCreatureInfo()) + me->SetDisplayId(cInfo->DisplayID_A[0]); // 0 invisible, 1 visible } void Reset() { - if(const CreatureInfo *cInfo = me->GetCreatureInfo()) - me->SetDisplayId(cInfo->DisplayID_H[1]); // A for gm, H1 invisible + me->SetReactState(REACT_AGGRESSIVE); + } + + void MoveInLineOfSight(Unit *who) // for test + { + if(who->GetTypeId() == TYPEID_PLAYER && !who->m_Vehicle + && !CAST_VEH(me)->GetPassenger(0) && CAST_VEH(me)->GetPassenger(2)) + who->EnterVehicle(CAST_VEH(me), 0); + } + + void UpdateAI(const uint32 diff) + { + if(!CAST_VEH(me)->GetPassenger(2)) + if(Unit *who = CAST_VEH(me)->GetPassenger(0)) + who->ExitVehicle(); + } +}; + +struct TRINITY_DLL_DECL boss_flame_leviathan_defense_turretAI : public ScriptedAI +{ + boss_flame_leviathan_defense_turretAI(Creature *c) : ScriptedAI(c) + { + } + + void Reset() + { + } + + void DamageTaken(Unit *who, uint32 &damage) + { + if(!who->m_Vehicle || who->m_Vehicle->GetEntry() != 33114) + damage = 0; + } + + void MoveInLineOfSight(Unit *who) + { + if(me->getVictim()) + return; + + if(who->GetTypeId() != TYPEID_PLAYER || !who->m_Vehicle || who->m_Vehicle->GetEntry() != 33114) + return; + + AttackStart(who); } void UpdateAI(const uint32 diff) @@ -76,7 +222,30 @@ struct TRINITY_DLL_DECL boss_flame_leviathan_seatAI : public ScriptedAI if(me->hasUnitState(UNIT_STAT_CASTING)) return; - DoMeleeAttackIfReady(); + DoCast(me->getVictim(), SPELL_SEARING_FLAME); + } +}; + +struct TRINITY_DLL_DECL boss_flame_leviathan_overload_deviceAI : public ScriptedAI +{ + boss_flame_leviathan_overload_deviceAI(Creature *c) : ScriptedAI(c) + { + if(const CreatureInfo *cInfo = me->GetCreatureInfo()) + me->SetDisplayId(cInfo->DisplayID_H[0]); // A0 gm, H0 device + } + + void Reset() + { + } + + void DamageTaken(Unit *who, uint32 &damage) + { + if(damage >= me->GetHealth()) + { + damage = 0; + if(!me->hasUnitState(UNIT_STAT_CASTING)) + DoCastAOE(SPELL_OVERLOAD_CIRCUIT); + } } }; @@ -85,11 +254,26 @@ CreatureAI* GetAI_boss_flame_leviathan(Creature *_Creature) return new boss_flame_leviathanAI (_Creature); } +CreatureAI* GetAI_boss_flame_leviathan_turret(Creature *_Creature) +{ + return new boss_flame_leviathan_turretAI (_Creature); +} + CreatureAI* GetAI_boss_flame_leviathan_seat(Creature *_Creature) { return new boss_flame_leviathan_seatAI (_Creature); } +CreatureAI* GetAI_boss_flame_leviathan_defense_turret(Creature *_Creature) +{ + return new boss_flame_leviathan_defense_turretAI (_Creature); +} + +CreatureAI* GetAI_boss_flame_leviathan_overload_device(Creature *_Creature) +{ + return new boss_flame_leviathan_overload_deviceAI (_Creature); +} + void AddSC_boss_flame_leviathan() { Script *newscript; @@ -99,7 +283,22 @@ void AddSC_boss_flame_leviathan() newscript->RegisterSelf(); newscript = new Script; + newscript->Name="boss_flame_leviathan_turret"; + newscript->GetAI = &GetAI_boss_flame_leviathan_turret; + newscript->RegisterSelf(); + + newscript = new Script; newscript->Name="boss_flame_leviathan_seat"; newscript->GetAI = &GetAI_boss_flame_leviathan_seat; newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="boss_flame_leviathan_defense_turret"; + newscript->GetAI = &GetAI_boss_flame_leviathan_defense_turret; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="boss_flame_leviathan_overload_device"; + newscript->GetAI = &GetAI_boss_flame_leviathan_overload_device; + newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp index 2d8ce56428a..df9a01046a4 100644 --- a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp +++ b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_ingvar_the_plunderer.cpp @@ -26,44 +26,47 @@ EndScriptData */ #include "precompiled.h" #include "def_utgarde_keep.h" -//Yells Ingvar -#define YELL_AGGRO_1 -1574015 -#define YELL_AGGRO_2 -1574022 +enum +{ + //Yells Ingvar + YELL_AGGRO_1 = -1574005, + YELL_AGGRO_2 = -1574006, -#define YELL_DEAD_1 -1574017 -#define YELL_DEAD_2 -1574024 + YELL_DEAD_1 = -1574007, + YELL_DEAD_2 = -1574008, -#define YELL_KILL_1 -1574023 -#define YELL_KILL_2 -1574016 + YELL_KILL_1 = -1574009, + YELL_KILL_2 = -1574010, //Ingvar Spells human form -#define MOB_INGVAR_HUMAN 23954 -#define SPELL_CLEAVE 42724 -#define SPELL_SMASH 42669 -#define H_SPELL_SMASH 59706 -#define SPELL_STAGGERING_ROAR 42708 -#define H_SPELL_STAGGERING_ROAR 59708 -#define SPELL_ENRAGE 42705 -#define H_SPELL_ENRAGE 59707 - -#define MOB_ANNHYLDE_THE_CALLER 24068 -#define SPELL_INGVAR_FEIGN_DEATH 42795 -#define SPELL_SUMMON_BANSHEE 42912 -#define SPELL_SCOURG_RESURRECTION_EFFEKTSPAWN 42863 //Spawn resurrecteffekt around Ingvar - -#define MODEL_INGVAR_UNDEAD 26351 -#define MODEL_INGVAR_HUMAN 21953 + MOB_INGVAR_HUMAN = 23954, + SPELL_CLEAVE = 42724, + SPELL_SMASH = 42669, + H_SPELL_SMASH = 59706, + SPELL_STAGGERING_ROAR = 42708, + H_SPELL_STAGGERING_ROAR = 59708, + SPELL_ENRAGE = 42705, + H_SPELL_ENRAGE = 59707, + + MOB_ANNHYLDE_THE_CALLER = 24068, + SPELL_INGVAR_FEIGN_DEATH = 42795, + SPELL_SUMMON_BANSHEE = 42912, + SPELL_SCOURG_RESURRECTION_EFFEKTSPAWN = 42863, //Spawn resurrecteffekt around Ingvar + + MODEL_INGVAR_UNDEAD = 26351, + MODEL_INGVAR_HUMAN = 21953, //Ingvar Spells undead form -#define MOB_INGVAR_UNDEAD 23980 -#define SPELL_DARK_SMASH 42723 -#define SPELL_DREADFUL_ROAR 42729 -#define H_SPELL_DREADFUL_ROAR 59734 -#define SPELL_WOE_STRIKE 42730 -#define H_SPELL_WOE_STRIKE 59735 - -#define ENTRY_THROW_TARGET 23996 -#define SPELL_SHADOW_AXE_SUMMON 42749 + MOB_INGVAR_UNDEAD = 23980, + SPELL_DARK_SMASH = 42723, + SPELL_DREADFUL_ROAR = 42729, + H_SPELL_DREADFUL_ROAR = 59734, + SPELL_WOE_STRIKE = 42730, + H_SPELL_WOE_STRIKE = 59735, + + ENTRY_THROW_TARGET = 23996, + SPELL_SHADOW_AXE_SUMMON = 42749 +}; struct TRINITY_DLL_DECL boss_ingvar_the_plundererAI : public ScriptedAI { @@ -273,13 +276,17 @@ CreatureAI* GetAI_boss_ingvar_the_plunderer(Creature *_Creature) return new boss_ingvar_the_plundererAI (_Creature); } -#define YELL_RESSURECT -1574025 +enum +{ +//we don't have that text in db so comment it until we get this text +// YELL_RESSURECT = -1574025, //Spells for Annhylde -#define SPELL_SCOURG_RESURRECTION_HEAL 42704 //Heal Max + DummyAura -#define SPELL_SCOURG_RESURRECTION_BEAM 42857 //Channeling Beam of Annhylde -#define SPELL_SCOURG_RESURRECTION_DUMMY 42862 //Some Emote Dummy? -#define SPELL_INGVAR_TRANSFORM 42796 + SPELL_SCOURG_RESURRECTION_HEAL = 42704, //Heal Max + DummyAura + SPELL_SCOURG_RESURRECTION_BEAM = 42857, //Channeling Beam of Annhylde + SPELL_SCOURG_RESURRECTION_DUMMY = 42862, //Some Emote Dummy? + SPELL_INGVAR_TRANSFORM = 42796 +}; struct TRINITY_DLL_DECL mob_annhylde_the_callerAI : public ScriptedAI { @@ -309,7 +316,7 @@ struct TRINITY_DLL_DECL mob_annhylde_the_callerAI : public ScriptedAI { m_creature->GetMotionMaster()->MovePoint(1,x,y,z+15); - DoScriptText(YELL_RESSURECT,m_creature); +// DoScriptText(YELL_RESSURECT,m_creature); } } @@ -381,8 +388,11 @@ CreatureAI* GetAI_mob_annhylde_the_caller(Creature *_Creature) return new mob_annhylde_the_callerAI (_Creature); } -#define SPELL_SHADOW_AXE_DAMAGE 42750 -#define H_SPELL_SHADOW_AXE_DAMAGE 59719 +enum +{ + SPELL_SHADOW_AXE_DAMAGE = 42750, + H_SPELL_SHADOW_AXE_DAMAGE = 59719 +}; struct TRINITY_DLL_DECL mob_ingvar_throw_dummyAI : public ScriptedAI { diff --git a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_keleseth.cpp b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_keleseth.cpp index c05d28bc58b..ea3b829ef6a 100644 --- a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_keleseth.cpp +++ b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_keleseth.cpp @@ -26,20 +26,25 @@ EndScriptData */ #include "precompiled.h" #include "def_utgarde_keep.h" -#define SPELL_SHADOWBOLT 43667 -#define SPELL_SHADOWBOLT_HEROIC 59389 -#define SPELL_FROST_TOMB 48400 -#define SPELL_FROST_TOMB_SUMMON 42714 -#define SPELL_DECREPIFY 42702 -#define SPELL_SCOURGE_RESSURRECTION 42704 -#define CREATURE_FROSTTOMB 23965 -#define CREATURE_SKELETON 23970 - -#define SAY_AGGRO -1574000 -#define SAY_KILL -1574001 -#define SAY_DEATH -1574002 -#define SAY_FROST_TOMB -1574003 -#define SAY_SKELETONS -1574004 +enum +{ + ACHIEVEMENT_ON_THE_ROCKS = 1919, + + SPELL_SHADOWBOLT = 43667, + SPELL_SHADOWBOLT_HEROIC = 59389, + SPELL_FROST_TOMB = 48400, + SPELL_FROST_TOMB_SUMMON = 42714, + SPELL_DECREPIFY = 42702, + SPELL_SCOURGE_RESSURRECTION = 42704, + CREATURE_FROSTTOMB = 23965, + CREATURE_SKELETON = 23970, + + SAY_AGGRO = -1574000, + SAY_FROST_TOMB = -1574001, + SAY_SKELETONS = -1574002, + SAY_KILL = -1574003, + SAY_DEATH = -1574004 +}; #define SKELETONSPAWN_Z 42.8668 @@ -54,6 +59,8 @@ float SkeletonSpawnPoint[5][5]= float AttackLoc[3]={197.636, 194.046, 40.8164}; +bool ShatterFrostTomb; // needed for achievement: On The Rocks(1919) + struct TRINITY_DLL_DECL mob_frost_tombAI : public ScriptedAI { mob_frost_tombAI(Creature *c) : ScriptedAI(c) @@ -75,6 +82,9 @@ struct TRINITY_DLL_DECL mob_frost_tombAI : public ScriptedAI void JustDied(Unit *killer) { + if(killer->GetGUID() != m_creature->GetGUID()) + ShatterFrostTomb = true; + if(FrostTombGUID) { Unit* FrostTomb = Unit::GetUnit((*m_creature),FrostTombGUID); @@ -115,6 +125,8 @@ struct TRINITY_DLL_DECL boss_kelesethAI : public ScriptedAI ShadowboltTimer = 0; Skeletons = false; + ShatterFrostTomb = false; + ResetTimer(); if(pInstance) @@ -133,6 +145,21 @@ struct TRINITY_DLL_DECL boss_kelesethAI : public ScriptedAI { DoScriptText(SAY_DEATH, m_creature); + if(Heroic && !ShatterFrostTomb) + { + AchievementEntry const *AchievOnTheRocks = GetAchievementStore()->LookupEntry(ACHIEVEMENT_ON_THE_ROCKS); + if(AchievOnTheRocks) + { + Map *map = m_creature->GetMap(); + if(map && map->IsDungeon()) + { + Map::PlayerList const &players = map->GetPlayers(); + for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + itr->getSource()->CompletedAchievement(AchievOnTheRocks); + } + } + } + if(pInstance) pInstance->SetData(DATA_PRINCEKELESETH_EVENT, DONE); } diff --git a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp index 5c5a5ba2f16..8bbb871a0b2 100644 --- a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp +++ b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/boss_skarvald_dalronn.cpp @@ -26,34 +26,35 @@ EndScriptData */ #include "precompiled.h" #include "def_utgarde_keep.h" -#define YELL_SKARVALD_AGGRO -1574010 -#define YELL_DALRONN_AGGRO -1574005 - -#define YELL_SKARVALD_KILL -1574011 -#define YELL_DALRONN_KILL -1574006 - -#define YELL_DALRONN_DAL_DIEDFIRST -1574007 -#define YELL_SKARVALD_DAL_DIEDFIRST -1574014 -#define YELL_SKARVALD_DAL_DIED -1574013 - -#define YELL_SKARVALD_SKA_DIEDFIRST -1574012 -#define YELL_DALRONN_SKA_DIEDFIRST -1574009 -#define YELL_DALRONN_SKA_DIED -1574008 +enum +{ + YELL_SKARVALD_AGGRO = -1574011, + YELL_SKARVALD_DAL_DIED = -1574012, + YELL_SKARVALD_SKA_DIEDFIRST = -1574013, + YELL_SKARVALD_KILL = -1574014, + YELL_SKARVALD_DAL_DIEDFIRST = -1574015, + + YELL_DALRONN_AGGRO = -1574016, + YELL_DALRONN_SKA_DIED = -1574017, + YELL_DALRONN_DAL_DIEDFIRST = -1574018, + YELL_DALRONN_KILL = -1574019, + YELL_DALRONN_SKA_DIEDFIRST = -1574020, //Spells of Skarvald and his Ghost -#define MOB_SKARVALD_THE_CONSTRUCTOR 24200 -#define SPELL_CHARGE 43651 -#define SPELL_STONE_STRIKE 48583 -#define SPELL_SUMMON_SKARVALD_GHOST 48613 -#define MOB_SKARVALD_GHOST 27390 + MOB_SKARVALD_THE_CONSTRUCTOR = 24200, + SPELL_CHARGE = 43651, + SPELL_STONE_STRIKE = 48583, + SPELL_SUMMON_SKARVALD_GHOST = 48613, + MOB_SKARVALD_GHOST = 27390, //Spells of Dalronn and his Ghost -#define MOB_DALRONN_THE_CONTROLLER 24201 -#define SPELL_SHADOW_BOLT 43649 -#define H_SPELL_SHADOW_BOLT 59575 -#define H_SPELL_SUMMON_SKELETONS 52611 -#define SPELL_DEBILITATE 43650 -#define SPELL_SUMMON_DALRONN_GHOST 48612 -#define MOB_DALRONN_GHOST 27389 + MOB_DALRONN_THE_CONTROLLER = 24201, + SPELL_SHADOW_BOLT = 43649, + H_SPELL_SHADOW_BOLT = 59575, + H_SPELL_SUMMON_SKELETONS = 52611, + SPELL_DEBILITATE = 43650, + SPELL_SUMMON_DALRONN_GHOST = 48612, + MOB_DALRONN_GHOST = 27389 +}; struct TRINITY_DLL_DECL boss_skarvald_the_constructorAI : public ScriptedAI { diff --git a/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_archavon.cpp b/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_archavon.cpp index d963024d69e..51e6df5e023 100644 --- a/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_archavon.cpp +++ b/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_archavon.cpp @@ -3,77 +3,77 @@ UPDATE `creature_template` SET `ScriptName`='boss_archavon' WHERE `entry`='31125 UPDATE `creature_template` SET `ScriptName`='mob_archavon_warder' WHERE `entry`='32353'; *** SQL END ***/ #include "precompiled.h" +#include "def_vault_of_archavon.h" -//These are patchwerk's yell -#define SAY_AGGRO1 -1533017 -#define SAY_AGGRO2 -1533018 -#define SAY_SLAY -1533019 -#define SAY_DEATH -1533020 - -#define EMOTE_BERSERK -1533021 -#define EMOTE_ENRAGE -1533022 +#define EMOTE_BERSERK -1590002 //Spells Archavon -#define SPELL_ROCK_SHARDS 58678 -#define SPELL_CRUSHING_LEAP HEROIC(58960,60894)//Instant (10-80yr range) -- Leaps at an enemy, inflicting 8000 Physical damage, knocking all nearby enemies away, and creating a cloud of choking debris. -#define SPELL_STOMP HEROIC(58663,60880) -#define SPELL_IMPALE HEROIC(58666,60882) //Lifts an enemy off the ground with a spiked fist, inflicting 47125 to 52875 Physical damage and 9425 to 10575 additional damage each second for 8 sec. -#define SPELL_BERSERK 47008 +#define SPELL_ROCK_SHARDS 58678 +#define SPELL_CRUSHING_LEAP HEROIC(58960,60894)//Instant (10-80yr range) -- Leaps at an enemy, inflicting 8000 Physical damage, knocking all nearby enemies away, and creating a cloud of choking debris. +#define SPELL_STOMP HEROIC(58663,60880) +#define SPELL_IMPALE HEROIC(58666,60882) //Lifts an enemy off the ground with a spiked fist, inflicting 47125 to 52875 Physical damage and 9425 to 10575 additional damage each second for 8 sec. +#define SPELL_BERSERK 47008 //Spells Archavon Warders -#define SPELL_ROCK_SHOWER HEROIC(60919,60923) -#define SPELL_SHIELD_CRUSH HEROIC(60897,60899) -#define SPELL_WHIRL HEROIC(60902,60916) +#define SPELL_ROCK_SHOWER HEROIC(60919,60923) +#define SPELL_SHIELD_CRUSH HEROIC(60897,60899) +#define SPELL_WHIRL HEROIC(60902,60916) //4 Warders spawned -#define ARCHAVON_WARDER 32353 //npc 32353 +#define ARCHAVON_WARDER 32353 //npc 32353 //Yell #define SAY_LEAP "Archavon the Stone Watcher lunges for $N!" //$N should be the target -#define EVENT_ROCK_SHARDS 1 //15s cd -#define EVENT_CHOKING_CLOUD 2 //30s cd +#define EVENT_ROCK_SHARDS 1 //15s cd +#define EVENT_CHOKING_CLOUD 2 //30s cd #define EVENT_STOMP 3 //45s cd #define EVENT_IMPALE 4 #define EVENT_BERSERK 5 //300s cd //mob -#define EVENT_ROCK_SHOWER 5 //set = 20s cd,unkown cd -#define EVENT_SHIELD_CRUSH 6 //set = 30s cd -#define EVENT_WHIRL 8 //set= 10s cd +#define EVENT_ROCK_SHOWER 5 //set = 20s cd,unkown cd +#define EVENT_SHIELD_CRUSH 6 //set = 30s cd +#define EVENT_WHIRL 8 //set= 10s cd struct TRINITY_DLL_DECL boss_archavonAI : public ScriptedAI { - boss_archavonAI(Creature *c) : ScriptedAI(c) {} + boss_archavonAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + ScriptedInstance* pInstance; EventMap events; void Reset() { events.Reset(); - } - void KilledUnit(Unit* Victim) - { - if(!(rand()%5)) - DoScriptText(SAY_SLAY, me); + if(pInstance) + pInstance->SetData(DATA_ARCHAVON_EVENT, NOT_STARTED); } + void KilledUnit(Unit* Victim){} + void JustDied(Unit* Killer) { - DoScriptText(SAY_DEATH, me); + if (pInstance) + pInstance->SetData(DATA_ARCHAVON_EVENT, DONE); } void EnterCombat(Unit *who) { - DoScriptText((rand()%2) ? SAY_AGGRO1 : SAY_AGGRO2, me); DoZoneInCombat(); events.ScheduleEvent(EVENT_ROCK_SHARDS, 15000); events.ScheduleEvent(EVENT_CHOKING_CLOUD, 30000); events.ScheduleEvent(EVENT_STOMP, 45000); events.ScheduleEvent(EVENT_BERSERK, 300000); - } + if(pInstance) + pInstance->SetData(DATA_ARCHAVON_EVENT, IN_PROGRESS); + } + // Below UpdateAI may need review/debug. void UpdateAI(const uint32 diff) { //Return since we have no target diff --git a/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp b/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp new file mode 100644 index 00000000000..2cbe082c358 --- /dev/null +++ b/src/bindings/scripts/scripts/zone/vault_of_archavon/boss_emalon.cpp @@ -0,0 +1,284 @@ +#include "precompiled.h" +#include "def_vault_of_archavon.h" + +#define EMOTE_OVERCHARGE_TEMPEST_MINION -1590000 +#define EMOTE_MINION_RESPAWN -1590001 + +//Spells Emalon +#define SPELL_CHAIN_LIGHTNING HEROIC(64213,64215) +#define SPELL_LIGHTNING_NOVA HEROIC(64216,65279) +#define SPELL_OVERCHARGE 64218 +#define SPELL_BERSERK 47008 + +//Spells Tempest Minions +#define SPELL_OVERCHARGED 64217 +#define SPELL_OVERCHARGED_BLAST 64219 +#define SPELL_SHOCK 64363 + +//4 Warders spawned +#define TEMPEST_MINIONS 33998 + +#define EVENT_CHAIN_LIGHTNING 1 //5s cd +#define EVENT_OVERCHARGE 2 //45s cd +#define EVENT_LIGHTNING_NOVA 3 //40s cd +#define EVENT_BERSERK 4 //360s cd +#define EVENT_SHOCK 5 //20s cd + +struct Location +{ + float x, y, z, o; +}; + +static Location MinionLocation[]= +{ + -231.713,-281.96,91.466,1.53213, + -205.585,-281.549,91.4661,1.75204, + -205.651,-296.394,91.4661,1.69549, + -232.235,-296.433,91.4998,1.44417 +}; + +struct TRINITY_DLL_DECL boss_emalonAI : public ScriptedAI +{ + boss_emalonAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + } + + ScriptedInstance* pInstance; + EventMap events; + std::list<uint64> MinionList; + + void Reset() + { + events.Reset(); + DespawnAllMinions(); + SummonAllMinions(); + + if(pInstance) + pInstance->SetData(DATA_EMALON_EVENT, NOT_STARTED); + } + + void DespawnAllMinions() + { + if(!MinionList.empty()) + { + for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); itr++) + { + Unit *Minion = Unit::GetUnit(*m_creature, (*itr)); + if(Minion) + Minion->RemoveFromWorld(); + } + } + + MinionList.clear(); + } + + void JustSummoned(Creature *Summoned) + { + MinionList.push_back(Summoned->GetGUID()); + if(Unit* target = m_creature->getVictim()) + Summoned->AI()->AttackStart(target); + } + + void SummonAllMinions() + { + if(MinionList.empty()) + for(uint8 i = 0; i < 4; i++) + SummonMinion(m_creature, MinionLocation[i].x, MinionLocation[i].y, MinionLocation[i].z, MinionLocation[i].o); + } + + static void SummonMinion(Creature *Summoner, float x, float y, float z, float o) + { + Summoner->SummonCreature(TEMPEST_MINIONS, x, y, z, o, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + void KilledUnit(Unit* Victim){} + + void JustDied(Unit* Killer) + { + DespawnAllMinions(); + if (pInstance) + pInstance->SetData(DATA_EMALON_EVENT, DONE); + } + + void EnterCombat(Unit *who) + { + if(!MinionList.empty()) + { + for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) + { + Creature* Minion = (Unit::GetCreature(*m_creature, *itr)); + Minion->AI()->AttackStart(who); + } + } + + DoZoneInCombat(); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 5000); + events.ScheduleEvent(EVENT_OVERCHARGE, 45000); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 30000); + events.ScheduleEvent(EVENT_BERSERK, 360000); + events.ScheduleEvent(EVENT_SHOCK, 20000); + + if(pInstance) + pInstance->SetData(DATA_EMALON_EVENT, IN_PROGRESS); + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if(!UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_CHAIN_LIGHTNING: + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_CHAIN_LIGHTNING); + events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 20000); + return; + case EVENT_OVERCHARGE: + for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) + { + Creature* Minion = (Unit::GetCreature(*m_creature, *itr)); + if(Minion && Minion->isAlive() && !Minion->HasAura(SPELL_OVERCHARGED)) + { + Minion->CastSpell(me, SPELL_OVERCHARGED, true); + Minion->SetHealth(Minion->GetMaxHealth()); + DoScriptText(EMOTE_OVERCHARGE_TEMPEST_MINION, m_creature); + events.ScheduleEvent(EVENT_OVERCHARGE, 45000); + return; + } + } + case EVENT_LIGHTNING_NOVA: + DoCast(me->getVictim(), SPELL_LIGHTNING_NOVA); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 25000); + return; + case EVENT_SHOCK: + for(std::list<uint64>::const_iterator itr = MinionList.begin(); itr != MinionList.end(); ++itr) + { + Creature* Minion = (Unit::GetCreature(*m_creature, *itr)); + if(Minion && Minion->isAlive()) + { + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + { + Minion->CastSpell(target, SPELL_SHOCK, true); + events.ScheduleEvent(EVENT_SHOCK, 20000); + return; + } + } + } + case EVENT_BERSERK: + DoCast(m_creature, SPELL_BERSERK); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## Mob Tempest Minions +######*/ +struct TRINITY_DLL_DECL mob_tempest_minionAI : public ScriptedAI +{ + mob_tempest_minionAI(Creature *c) : ScriptedAI(c) + { + pInstance = c->GetInstanceData(); + EmalonGUID = pInstance ? pInstance->GetData64(DATA_EMALON) : 0; + Emalon = Unit::GetCreature(*m_creature, EmalonGUID); + } + + ScriptedInstance* pInstance; + EventMap events; + uint64 EmalonGUID; + std::list<Creature*> MinionList; + Creature* Emalon; + uint32 SPELL_OVERCHARGED_Timer; + bool AlreadyOvercharged; + + void Reset() + { + events.Reset(); + AlreadyOvercharged = false; + SPELL_OVERCHARGED_Timer = 0; + } + + void EnterCombat(Unit *who) + { + DoZoneInCombat(); + if(Emalon) + Emalon->AI()->AttackStart(who); + } + + void JustDied(Unit* Killer) + { + m_creature->RemoveCorpse(); + m_creature->RemoveFromWorld(); + if(Emalon) + { + boss_emalonAI::SummonMinion(Emalon, Emalon->GetPositionX(), Emalon->GetPositionY(), Emalon->GetPositionZ(), Emalon->GetOrientation()); + DoScriptText(EMOTE_MINION_RESPAWN, m_creature); + } + } + + void UpdateAI(const uint32 diff) + { + //Return since we have no target + if(!UpdateVictim()) + return; + + if(Aura *OverchargedAura = m_creature->GetAura(SPELL_OVERCHARGED)) + { + if(OverchargedAura->GetStackAmount() < 10) + { + if (SPELL_OVERCHARGED_Timer < diff) + { + DoCast(me, SPELL_OVERCHARGED); + SPELL_OVERCHARGED_Timer = 2000; + }else SPELL_OVERCHARGED_Timer -=diff; + } + else + { + if(OverchargedAura->GetStackAmount() == 10 && (AlreadyOvercharged == false)) + { + DoCast(me,SPELL_OVERCHARGED_BLAST); + AlreadyOvercharged = true; + } + } + } + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_tempest_minion(Creature *_Creature) +{ + return new mob_tempest_minionAI (_Creature); +} + +CreatureAI* GetAI_boss_emalon(Creature *_Creature) +{ + return new boss_emalonAI (_Creature); +} + +void AddSC_boss_emalon() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="boss_emalon"; + newscript->GetAI = &GetAI_boss_emalon; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="mob_tempest_minion"; + newscript->GetAI = &GetAI_mob_tempest_minion; + newscript->RegisterSelf(); +} diff --git a/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h b/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h index f46ba447945..5b11d5729eb 100644 --- a/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h +++ b/src/bindings/scripts/scripts/zone/vault_of_archavon/def_vault_of_archavon.h @@ -1,4 +1,13 @@ #ifndef DEF_ARCHAVON_H #define DEF_ARCHAVON_H +enum +{ + DATA_ARCHAVON = 1, + DATA_EMALON = 2, + + DATA_ARCHAVON_EVENT = 3, + DATA_EMALON_EVENT = 4 +}; + #endif diff --git a/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp b/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp index dc725b2be66..e7f6f572a77 100644 --- a/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp +++ b/src/bindings/scripts/scripts/zone/vault_of_archavon/instance_vault_of_archavon.cpp @@ -1,9 +1,112 @@ #include "precompiled.h" #include "def_vault_of_archavon.h" +#define NUMBER_OF_ENCOUNTERS 2 + struct TRINITY_DLL_DECL instance_archavon : public ScriptedInstance { instance_archavon(Map *Map) : ScriptedInstance(Map) {Initialize();}; + + std::string strInstData; + uint64 Archavon; + uint64 Emalon; + uint32 Encounters[NUMBER_OF_ENCOUNTERS]; + + void Initialize() + { + Archavon = 0; + Emalon = 0; + + for(uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; i++) + Encounters[i] = NOT_STARTED; + } + + bool IsEncounterInProgress() const + { + for(uint8 i = 0; i < NUMBER_OF_ENCOUNTERS; ++i) + if(Encounters[i] == IN_PROGRESS) + return true; + + return false; + } + + void OnCreatureCreate(Creature *creature, bool add) + { + switch(creature->GetEntry()) + { + case 31125: Archavon = creature->GetGUID(); break; + case 33993: Emalon = creature->GetGUID(); break; + } + } + + uint64 GetData64(uint32 identifier) + { + switch(identifier) + { + case DATA_ARCHAVON: return Archavon; + case DATA_EMALON: return Emalon; + } + return 0; + } + + uint32 GetData(uint32 identifier) + { + switch(identifier) + { + case DATA_ARCHAVON_EVENT: return Encounters[0]; + case DATA_EMALON_EVENT: return Encounters[1]; + } + return 0; + } + + void SetData(uint32 identifier, uint32 data) + { + switch(identifier) + { + case DATA_ARCHAVON_EVENT: Encounters[0] = data; break; + case DATA_EMALON_EVENT: Encounters[1] = data; break; + } + + if (data == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << Encounters[0] << " " << Encounters[1]; + + strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } + } + + std::string GetSaveData() + { + return strInstData; + } + + void Load(const char* chrIn) + { + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> Encounters[0] >> Encounters[1]; + + for(uint8 i = 1; i < NUMBER_OF_ENCOUNTERS; ++i) + { + if (Encounters[i] == IN_PROGRESS) + Encounters[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; + } }; InstanceData* GetInstanceData_instance_archavon(Map* map) diff --git a/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp b/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp index c6518d5f131..533480d1f6f 100644 --- a/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp +++ b/src/bindings/scripts/scripts/zone/western_plaguelands/western_plaguelands.cpp @@ -167,7 +167,7 @@ struct TRINITY_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI if( CAST_PLR(who)->GetQuestStatus(5216) == QUEST_STATUS_INCOMPLETE || CAST_PLR(who)->GetQuestStatus(5229) == QUEST_STATUS_INCOMPLETE ) { - DoSpawnCreature(11075,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + m_creature->SummonCreature(11075, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); DoDie(); } break; @@ -175,7 +175,7 @@ struct TRINITY_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI if( CAST_PLR(who)->GetQuestStatus(5219) == QUEST_STATUS_INCOMPLETE || CAST_PLR(who)->GetQuestStatus(5231) == QUEST_STATUS_INCOMPLETE ) { - DoSpawnCreature(11077,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + m_creature->SummonCreature(11077, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); DoDie(); } break; @@ -183,7 +183,7 @@ struct TRINITY_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI if( CAST_PLR(who)->GetQuestStatus(5225) == QUEST_STATUS_INCOMPLETE || CAST_PLR(who)->GetQuestStatus(5235) == QUEST_STATUS_INCOMPLETE ) { - DoSpawnCreature(11078,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + m_creature->SummonCreature(11078, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); DoDie(); } break; @@ -191,7 +191,7 @@ struct TRINITY_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI if( CAST_PLR(who)->GetQuestStatus(5222) == QUEST_STATUS_INCOMPLETE || CAST_PLR(who)->GetQuestStatus(5233) == QUEST_STATUS_INCOMPLETE ) { - DoSpawnCreature(11076,0,0,0,m_creature->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + m_creature->SummonCreature(11076, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); DoDie(); } break; diff --git a/src/bindings/scripts/scripts/zone/westfall/westfall.cpp b/src/bindings/scripts/scripts/zone/westfall/westfall.cpp index f9e04a5186f..3548e9ee089 100644 --- a/src/bindings/scripts/scripts/zone/westfall/westfall.cpp +++ b/src/bindings/scripts/scripts/zone/westfall/westfall.cpp @@ -84,24 +84,23 @@ struct TRINITY_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI { case 4: SetEquipmentSlots(false, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE, EQUIP_ID_RIFLE); - SetSheathState(SHEATH_STATE_RANGED); + m_creature->SetSheath(SHEATH_STATE_RANGED); m_creature->HandleEmoteCommand(EMOTE_STATE_USESTANDING_NOSHEATHE); break; - case 6: - SetCombatMovement(false); - break; case 7: m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836, 1569.755, 54.267, 4.230, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697, 1569.124, 54.421, 4.206, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237, 1568.307, 54.620, 4.206, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); break; case 8: + m_creature->SetSheath(SHEATH_STATE_RANGED); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836, 1569.755, 54.267, 4.230, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697, 1569.124, 54.421, 4.206, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237, 1568.307, 54.620, 4.206, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.037, 1570.213, 54.961, 4.283, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); break; case 9: + m_creature->SetSheath(SHEATH_STATE_RANGED); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836, 1569.755, 54.267, 4.230, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697, 1569.124, 54.421, 4.206, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237, 1568.307, 54.620, 4.206, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); @@ -115,9 +114,9 @@ struct TRINITY_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI DoScriptText(SAY_DS_PROLOGUE, m_creature); break; case 13: - SetSheathState(SHEATH_STATE_UNARMED); - m_creature->HandleEmoteCommand(EMOTE_STATE_USESTANDING_NOSHEATHE); SetEquipmentSlots(true); + m_creature->SetSheath(SHEATH_STATE_UNARMED); + m_creature->HandleEmoteCommand(EMOTE_STATE_USESTANDING_NOSHEATHE); break; case 17: pPlayer->GroupEventHappens(QUEST_TOME_VALOR, m_creature); @@ -125,6 +124,21 @@ struct TRINITY_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI } } + void AttackStart(Unit* pWho) + { + if (!pWho) + return; + + if (m_creature->Attack(pWho, false)) + { + m_creature->AddThreat(pWho, 0.0f); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + + m_creature->GetMotionMaster()->MoveChase(pWho, 30.0f); + } + } + void JustSummoned(Creature* pSummoned) { pSummoned->AI()->AttackStart(m_creature); @@ -148,14 +162,10 @@ struct TRINITY_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI if (uiShootTimer < diff) { - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE)) - SetCombatMovement(true); - else - SetCombatMovement(false); - uiShootTimer = 1500; - DoCast(m_creature->getVictim(), SPELL_SHOOT); + if (!m_creature->IsWithinDist(m_creature->getVictim(), ATTACK_DISTANCE)) + DoCast(m_creature->getVictim(), SPELL_SHOOT); }else uiShootTimer -= diff; } }; diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp index 926a751c7cd..7207e33e398 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp @@ -25,43 +25,46 @@ EndScriptData */ #include "def_zulaman.h" #include "GridNotifiers.h" -#define SAY_AGGRO -1568000 -#define SAY_FIRE_BOMBS -1568001 -#define SAY_SUMMON_HATCHER -1568002 -#define SAY_ALL_EGGS -1568003 -#define SAY_BERSERK -1568004 -#define SAY_SLAY_1 -1568005 -#define SAY_SLAY_2 -1568006 -#define SAY_DEATH -1568007 -#define SAY_EVENT_STRANGERS -1568008 -#define SAY_EVENT_FRIENDS -1568009 +enum +{ + SAY_AGGRO = -1568000, + SAY_FIRE_BOMBS = -1568001, + SAY_SUMMON_HATCHER = -1568002, + SAY_ALL_EGGS = -1568003, + SAY_BERSERK = -1568004, + SAY_SLAY_1 = -1568005, + SAY_SLAY_2 = -1568006, + SAY_DEATH = -1568007, + SAY_EVENT_STRANGERS = -1568008, + SAY_EVENT_FRIENDS = -1568009, // Jan'alai -// --Spell -#define SPELL_FLAME_BREATH 43140 -#define SPELL_FIRE_WALL 43113 -#define SPELL_ENRAGE 44779 -#define SPELL_SUMMON_PLAYERS 43097 -#define SPELL_TELE_TO_CENTER 43098 // coord -#define SPELL_HATCH_ALL 43144 -#define SPELL_BERSERK 45078 + SPELL_FLAME_BREATH = 43140, + SPELL_FIRE_WALL = 43113, + SPELL_ENRAGE = 44779, + SPELL_SUMMON_PLAYERS = 43097, + SPELL_TELE_TO_CENTER = 43098, // coord + SPELL_HATCH_ALL = 43144, + SPELL_BERSERK = 45078, + // -- Fire Bob Spells -#define SPELL_FIRE_BOMB_CHANNEL 42621 // last forever -#define SPELL_FIRE_BOMB_THROW 42628 // throw visual -#define SPELL_FIRE_BOMB_DUMMY 42629 // bomb visual -#define SPELL_FIRE_BOMB_DAMAGE 42630 + SPELL_FIRE_BOMB_CHANNEL = 42621, // last forever + SPELL_FIRE_BOMB_THROW = 42628, // throw visual + SPELL_FIRE_BOMB_DUMMY = 42629, // bomb visual + SPELL_FIRE_BOMB_DAMAGE = 42630, // --Summons -#define MOB_AMANI_HATCHER 23818 -#define MOB_HATCHLING 23598 // 42493 -#define MOB_EGG 23817 -#define MOB_FIRE_BOMB 23920 + MOB_AMANI_HATCHER = 23818, + MOB_HATCHLING = 23598, // 42493 + MOB_EGG = 23817, + MOB_FIRE_BOMB = 23920, // -- Hatcher Spells -#define SPELL_HATCH_EGG 43734 // 42471 + SPELL_HATCH_EGG = 43734, // 42471 // -- Hatchling Spells -#define SPELL_FLAMEBUFFET 43299 + SPELL_FLAMEBUFFET = 43299 +}; const int area_dx = 44; const int area_dy = 51; @@ -119,7 +122,6 @@ struct TRINITY_DLL_DECL boss_janalaiAI : public ScriptedAI uint32 BombCount; uint32 HatcherTimer; uint32 EnrageTimer; - uint32 ResetTimer; bool noeggs; bool enraged; @@ -139,8 +141,7 @@ struct TRINITY_DLL_DECL boss_janalaiAI : public ScriptedAI BombSequenceTimer = 1000; BombCount = 0; HatcherTimer = 10000; - EnrageTimer = 300000; - ResetTimer = 5000; + EnrageTimer = MINUTE*5*IN_MILISECONDS; noeggs = false; isBombing =false; @@ -417,17 +418,7 @@ struct TRINITY_DLL_DECL boss_janalaiAI : public ScriptedAI }else HatcherTimer -= diff; } - if(ResetTimer < diff) - { - float x, y, z, o; - m_creature->GetHomePosition(x, y, z, o); - if(m_creature->GetPositionZ() <= z-7) - { - EnterEvadeMode(); - return; - } - ResetTimer = 5000; - }else ResetTimer -= diff; + EnterEvadeIfOutOfCombatArea(diff); DoMeleeAttackIfReady(); diff --git a/src/bindings/scripts/scripts/zone/zuldrak/zuldrak.cpp b/src/bindings/scripts/scripts/zone/zuldrak/zuldrak.cpp new file mode 100644 index 00000000000..b1afaa9ed5e --- /dev/null +++ b/src/bindings/scripts/scripts/zone/zuldrak/zuldrak.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2009 Trinity <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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "precompiled.h" + +/*#### +## npc_drakuru_shackles +####*/ + +enum +{ + SPELL_LEFT_CHAIN = 59951, + SPELL_RIGHT_CHAIN = 59952, + SPELL_UNLOCK_SHACKLE = 55083, + SPELL_FREE_RAGECLAW = 55223, + + NPC_RAGECLAW = 29686 +}; + +struct TRINITY_DLL_DECL npc_drakuru_shacklesAI : public ScriptedAI +{ + npc_drakuru_shacklesAI(Creature *c) : ScriptedAI(c) {} + + Unit* Rageclaw; + + void Reset() + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + float x, y, z; + Rageclaw = NULL; + m_creature->GetClosePoint(x, y, z, m_creature->GetObjectSize()/3,0.1); + if (Unit* summon = m_creature->SummonCreature(NPC_RAGECLAW,x,y,z,0,TEMPSUMMON_DEAD_DESPAWN,1000)) + DoActionOnRageclaw(true,summon); + } + + void DoActionOnRageclaw(bool locking, Unit *who) + { + if (!who) + return; + + if (locking) + { + if (who) + { + Rageclaw = who; + + m_creature->SetInFront(Rageclaw); + Rageclaw->SetInFront(m_creature); + + m_creature->CastSpell(Rageclaw, SPELL_LEFT_CHAIN, true); + m_creature->CastSpell(Rageclaw, SPELL_RIGHT_CHAIN, true); + } + } + else + { + DoCast(Rageclaw, SPELL_FREE_RAGECLAW, true); + CAST_PLR(who)->KilledMonsterCredit(NPC_RAGECLAW, Rageclaw->GetGUID()); + m_creature->setDeathState(DEAD); + } + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (spell->Id == SPELL_UNLOCK_SHACKLE) + { + if (Rageclaw) + DoActionOnRageclaw(false,caster); + else + m_creature->setDeathState(JUST_DIED); + + } + } +}; + +CreatureAI* GetAI_npc_drakuru_shackles(Creature *_Creature) +{ + return new npc_drakuru_shacklesAI (_Creature); +} + + +/*#### +## npc_captured_rageclaw +####*/ + +enum +{ + SPELL_UNSHACKLED = 55085, + SPELL_KNEEL = 39656 +}; + +const char * SAY_RAGECLAW_1 = "I poop on you, trollses!"; +const char * SAY_RAGECLAW_2 = "ARRRROOOOGGGGAAAA!"; +const char * SAY_RAGECLAW_3 = "No more mister nice wolvar!"; +#define SAY_RAGECLAW RAND(SAY_RAGECLAW_1,SAY_RAGECLAW_2,SAY_RAGECLAW_3) + +struct TRINITY_DLL_DECL npc_captured_rageclawAI : public ScriptedAI +{ + npc_captured_rageclawAI(Creature *c) : ScriptedAI(c) {} + + uint32 DespawnTimer; + bool Despawn; + + void Reset() + { + Despawn = false; + DespawnTimer = 0; + m_creature->setFaction(35); + m_creature->CastSpell(m_creature, SPELL_KNEEL, true); // Little Hack for kneel - Thanks Illy :P + } + + void MoveInLineOfSight(Unit *who){} + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + if (spell->Id == SPELL_FREE_RAGECLAW) + { + m_creature->RemoveAurasDueToSpell(SPELL_LEFT_CHAIN); + + m_creature->RemoveAurasDueToSpell(SPELL_RIGHT_CHAIN); + + m_creature->RemoveAurasDueToSpell(SPELL_KNEEL); + + m_creature->setFaction(m_creature->GetCreatureInfo()->faction_H); + + DoCast(m_creature, SPELL_UNSHACKLED, true); + DoSay(SAY_RAGECLAW, LANG_UNIVERSAL, NULL); + m_creature->GetMotionMaster()->MoveRandom(10); + + DespawnTimer = 10000; + Despawn = true; + } + } + + void UpdateAI(const uint32 diff) + { + if (m_creature->getVictim()) + { + DoMeleeAttackIfReady(); + return; + } + + if (!Despawn) + return; + + if (DespawnTimer < diff) + m_creature->setDeathState(JUST_DIED); + else DespawnTimer-=diff; + } +}; + +CreatureAI* GetAI_npc_captured_rageclaw(Creature *_Creature) +{ + return new npc_captured_rageclawAI (_Creature); +} + +void AddSC_zuldrak() +{ + Script *newscript; + + newscript = new Script; + newscript->Name="npc_drakuru_shackles"; + newscript->GetAI = &GetAI_npc_drakuru_shackles; + newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="npc_captured_rageclaw"; + newscript->GetAI = &GetAI_npc_captured_rageclaw; + newscript->RegisterSelf(); +} diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp index b3b92cbc2c7..895e91c13c6 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_marli.cpp @@ -71,9 +71,6 @@ struct TRINITY_DLL_DECL boss_marliAI : public ScriptedAI Spawned = false; PhaseTwo = false; - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); } void EnterCombat(Unit *who) diff --git a/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp b/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp index 76d3d5268e9..5cd5fc61d8f 100644 --- a/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp +++ b/src/bindings/scripts/scripts/zone/zulgurub/boss_thekal.cpp @@ -117,8 +117,7 @@ struct TRINITY_DLL_DECL boss_thekalAI : public ScriptedAI if(pInstance->GetData(DATA_LORKHANISDEAD)) { //Resurrect LorKhan - Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN)); - if(pLorKhan) + if(Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN))) { pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); pLorKhan->setFaction(14); @@ -336,8 +335,7 @@ struct TRINITY_DLL_DECL mob_zealot_lorkhanAI : public ScriptedAI if(pInstance->GetData(DATA_THEKALISFAKEDEAD)) { //Resurrect Thekal - Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); - if(pThekal) + if(Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL))) { pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -349,8 +347,7 @@ struct TRINITY_DLL_DECL mob_zealot_lorkhanAI : public ScriptedAI if(pInstance->GetData(DATA_ZATHISDEAD)) { //Resurrect Zath - Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH)); - if(pZath) + if(Unit *pZath = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_ZATH))) { pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -473,8 +470,7 @@ struct TRINITY_DLL_DECL mob_zealot_zathAI : public ScriptedAI if(pInstance->GetData(DATA_LORKHANISDEAD)) { //Resurrect LorKhan - Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN)); - if(pLorKhan) + if(Unit *pLorKhan = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_LORKHAN))) { pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -486,8 +482,7 @@ struct TRINITY_DLL_DECL mob_zealot_zathAI : public ScriptedAI if(pInstance->GetData(DATA_THEKALISFAKEDEAD)) { //Resurrect Thekal - Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL)); - if(pThekal) + if(Unit *pThekal = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_THEKAL))) { pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); diff --git a/src/framework/Platform/Define.h b/src/framework/Platform/Define.h index 8f10fc20020..35bc07f5656 100644 --- a/src/framework/Platform/Define.h +++ b/src/framework/Platform/Define.h @@ -145,8 +145,17 @@ typedef uint64 OBJECT_HANDLE; #define MaNGOS Trinity #define MANGOS_DLL_DECL TRINITY_DLL_DECL #define MANGOS_DLL_SPEC TRINITY_DLL_SPEC -#define MANGOS_DEBUG TRINITY_DEBUG #define GetMangosString GetTrinityString +#if defined(MANGOS_DEBUG) || defined(TRINITY_DEBUG) +# ifndef TRINITY_DEBUG +# define TRINITY_DEBUG +# endif +# ifndef MANGOS_DEBUG +# define MANGOS_DEBUG +# endif +#endif + + #endif //TRINITY_DEFINE_H diff --git a/src/game/AccountMgr.cpp b/src/game/AccountMgr.cpp index 66660766dae..74bc4cd2dcc 100644 --- a/src/game/AccountMgr.cpp +++ b/src/game/AccountMgr.cpp @@ -26,7 +26,7 @@ #include "Player.h" #include "Util.h" -extern DatabaseType LoginDatabase; +extern DatabaseType loginDatabase; INSTANTIATE_SINGLETON_1(AccountMgr); @@ -44,26 +44,26 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass normalizeString(username); normalizeString(password); - LoginDatabase.escape_string(username); - LoginDatabase.escape_string(password); + loginDatabase.escape_string(username); + loginDatabase.escape_string(password); - QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'", username.c_str()); + QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'", username.c_str()); if(result) { delete result; return AOR_NAME_ALREDY_EXIST; // username does already exist } - if(!LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str())) + if(!loginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str())) return AOR_DB_INTERNAL_ERROR; // unexpected error - LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL"); + loginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL"); return AOR_OK; // everything's fine } AccountOpResult AccountMgr::DeleteAccount(uint32 accid) { - QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); + QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); if(!result) return AOR_NAME_NOT_EXIST; // account doesn't exist delete result; @@ -78,7 +78,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid) uint64 guid = MAKE_NEW_GUID(guidlo, 0, HIGHGUID_PLAYER); // kick if player currently - if(Player* p = ObjectAccessor::FindPlayer(guid)) + if(Player* p = ObjectAccessor::GetObjectInWorld(guid, (Player*)NULL)) { WorldSession* s = p->GetSession(); s->KickPlayer(); // mark session to remove at next session list update @@ -94,13 +94,13 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid) // table realm specific but common for all characters of account for realm CharacterDatabase.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid); - LoginDatabase.BeginTransaction(); + loginDatabase.BeginTransaction(); bool res = - LoginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) && - LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid); + loginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) && + loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid); - LoginDatabase.CommitTransaction(); + loginDatabase.CommitTransaction(); if(!res) return AOR_DB_INTERNAL_ERROR; // unexpected error; @@ -110,7 +110,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid) AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd) { - QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); + QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); if(!result) return AOR_NAME_NOT_EXIST; // account doesn't exist delete result; @@ -124,9 +124,9 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, normalizeString(new_uname); normalizeString(new_passwd); - LoginDatabase.escape_string(new_uname); - LoginDatabase.escape_string(new_passwd); - if(!LoginDatabase.PExecute("UPDATE account SET username='%s',sha_pass_hash=SHA1(CONCAT('%s',':','%s')) WHERE id='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid)) + loginDatabase.escape_string(new_uname); + loginDatabase.escape_string(new_passwd); + if(!loginDatabase.PExecute("UPDATE account SET username='%s',sha_pass_hash=SHA1(CONCAT('%s',':','%s')) WHERE id='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid)) return AOR_DB_INTERNAL_ERROR; // unexpected error return AOR_OK; @@ -134,7 +134,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd) { - QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); + QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid); if(!result) return AOR_NAME_NOT_EXIST; // account doesn't exist delete result; @@ -144,8 +144,8 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd) normalizeString(new_passwd); - LoginDatabase.escape_string(new_passwd); - if(!LoginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid)) + loginDatabase.escape_string(new_passwd); + if(!loginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid)) return AOR_DB_INTERNAL_ERROR; // unexpected error return AOR_OK; @@ -153,8 +153,8 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd) uint32 AccountMgr::GetId(std::string username) { - LoginDatabase.escape_string(username); - QueryResult *result = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str()); + loginDatabase.escape_string(username); + QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str()); if(!result) return 0; else @@ -167,7 +167,7 @@ uint32 AccountMgr::GetId(std::string username) uint32 AccountMgr::GetSecurity(uint32 acc_id) { - QueryResult *result = LoginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id); + QueryResult *result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id); if(result) { uint32 sec = (*result)[0].GetUInt32(); @@ -180,7 +180,7 @@ uint32 AccountMgr::GetSecurity(uint32 acc_id) bool AccountMgr::GetName(uint32 acc_id, std::string &name) { - QueryResult *result = LoginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id); + QueryResult *result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id); if(result) { name = (*result)[0].GetCppString(); @@ -194,9 +194,9 @@ bool AccountMgr::GetName(uint32 acc_id, std::string &name) bool AccountMgr::CheckPassword(uint32 accid, std::string passwd) { normalizeString(passwd); - LoginDatabase.escape_string(passwd); + loginDatabase.escape_string(passwd); - QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str()); + QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str()); if (result) { delete result; diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index e86fb543ed5..09ae58eea8d 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -35,6 +35,9 @@ #include "ProgressBar.h" #include "SpellMgr.h" +#include "MapManager.h" +#include "BattleGround.h" +#include "BattleGroundAB.h" INSTANTIATE_SINGLETON_1(AchievementGlobalMgr); @@ -81,11 +84,13 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) switch(criteria->requiredType) { case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: - case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: break; @@ -139,7 +144,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD: if (player_dead.own_team_flag > 1) { - sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong boolean value1 (%u).", + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD (%u) have wrong boolean value1 (%u).", criteria->ID, criteria->requiredType,dataType,player_dead.own_team_flag); return false; } @@ -228,10 +233,12 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) if (!sHolidaysStore.LookupEntry(holiday.id)) { sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) have unknown holiday in value1 (%u), ignore.", - criteria->ID, criteria->requiredType,dataType,drunk.state); + criteria->ID, criteria->requiredType,dataType,holiday.id); return false; } return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: + return true; // not check correctness node indexes default: sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) have data for not supported data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType); return false; @@ -300,6 +307,13 @@ bool AchievementCriteriaData::Meets(Player const* source, Unit const* target, ui return Player::GetDrunkenstateByValue(source->GetDrunkValue()) >= drunk.state; case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY: return IsHolidayActive(HolidayIds(holiday.id)); + case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE: + { + BattleGround* bg = source->GetBattleGround(); + if(!bg) + return false; + return bg->IsTeamScoreInRange(source->GetTeam()==ALLIANCE ? HORDE : ALLIANCE,bg_loss_team_score.min_score,bg_loss_team_score.max_score); + } } return false; } @@ -535,7 +549,7 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri if (!criteria) { // we will remove not existed criteria for all characters - sLog.outError("Not existed achievement creataria %u data removed from table `character_achievement_progress`.",id); + sLog.outError("Not existed achievement criteria %u data removed from table `character_achievement_progress`.",id); CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE criteria = %u",id); continue; } @@ -678,7 +692,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui // std. case: increment at 1 case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS: - case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL: case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED: case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED: @@ -719,6 +732,54 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui // specialized cases + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: + { + // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case + if (!miscvalue1) + continue; + if (achievementCriteria->win_bg.bgMapID != GetPlayer()->GetMapId()) + continue; + + if (achievementCriteria->win_bg.additionalRequirement1_type) + { + // those requirements couldn't be found in the dbc + AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria); + if (!data || !data->Meets(GetPlayer(),unit)) + continue; + } + // some hardcoded requirements + else + { + BattleGround* bg = GetPlayer()->GetBattleGround(); + if (!bg) + continue; + + switch(achievementCriteria->referredAchievement) + { + case 161: // AB, Overcome a 500 resource disadvantage + { + if (bg->GetTypeID() != BATTLEGROUND_AB) + continue; + if(!((BattleGroundAB*)bg)->IsTeamScores500disadvantage(GetPlayer()->GetTeam())) + continue; + break; + } + case 156: // AB, win while controlling all 5 flags (all nodes) + case 784: // EY, win while holding 4 bases (all nodes) + { + if(!bg->IsAllNodesConrolledByTeam(GetPlayer()->GetTeam())) + continue; + break; + } + case 1762: // SA, win without losing any siege vehicles + case 2192: // SA, win without losing any siege vehicles + continue; // not implemented + } + } + + SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_ACCUMULATE); + break; + } case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: { // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case @@ -827,8 +888,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if(!miscvalue1) continue; - Map const* map = GetPlayer()->GetMap(); - if(!map->IsDungeon()) + Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : MapManager::Instance().FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId()); + if(!map || !map->IsDungeon()) continue; // search case @@ -1194,6 +1255,24 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui SetCriteriaProgress(achievementCriteria, spellCount); break; } + case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: + // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case + if(!miscvalue1) + continue; + + if(achievementCriteria->win_duel.duelCount) + { + // those requirements couldn't be found in the dbc + AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria); + if(!data) + continue; + + if(!data->Meets(GetPlayer(),unit)) + continue; + } + + SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + break; case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION: SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetReveredFactionCount()); break; @@ -1270,7 +1349,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING: break; // FIXME: not triggered in code as result, need to implement - case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID: case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE: @@ -1298,7 +1376,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if(IsCompletedCriteria(achievementCriteria,achievement)) CompletedCriteriaFor(achievement); - // check again the completeness for SUMM and REQ COUNT achievements, + // check again the completeness for SUMM and REQ COUNT achievements, // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria if (achievement->flags & ACHIEVEMENT_FLAG_SUMM) { @@ -1339,6 +1417,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve switch(achievementCriteria->requiredType) { + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: + return progress->counter >= achievementCriteria->win_bg.winCount; case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: return progress->counter >= achievementCriteria->kill_creature.creatureCount; case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: @@ -1430,7 +1510,6 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return progress->counter >= achievementCriteria->learn_skill_line.spellCount; case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL: return progress->counter >= achievementCriteria->honorable_kill.killCount; - // handle all statistic-only criteria here case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: @@ -1514,7 +1593,7 @@ bool AchievementMgr::IsCompletedAchievement(AchievementEntry const* entry) return false; } - // Default case - need complete all or + // Default case - need complete all or bool completed_all = true; for(AchievementCriteriaEntryList::const_iterator itr = cList->begin(); itr != cList->end(); ++itr) { @@ -1844,6 +1923,10 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() switch(criteria->requiredType) { + case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG: + if(!criteria->win_bg.additionalRequirement1_type) + continue; + break; case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: break; // any cases case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: @@ -1878,6 +1961,10 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() if(criteria->do_emote.count==0) continue; break; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: // skip statistics + if(criteria->win_duel.duelCount==0) + continue; + break; case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: // any cases break; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: // need skip generic cases diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index 9a3ff496e7b..5020539bb5c 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -51,17 +51,18 @@ enum AchievementCriteriaDataType ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0 ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target - ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10,// gender 0=male; 1=female + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target + ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10,// gender 0=male; 1=female ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED = 11,// used to prevent achievement creteria complete if not all requirement implemented and listed in table ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12,// difficulty normal/heroic difficulty for current event map ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13,// count "with less than %u people in the zone" ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14,// team HORDE(67), ALLIANCE(469) ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK = 15,// drunken_state 0 (enum DrunkenState) of player ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16,// holiday_id 0 event in holiday time + ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE = 17,// min_score max_score player's team win bg and opposition team have team score in range }; -#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 17 // maximum value in AchievementCriteriaDataType enum +#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 18 // maximum value in AchievementCriteriaDataType enum class Player; class Unit; @@ -141,11 +142,17 @@ struct AchievementCriteriaData { uint32 state; } drunk; - // ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY + // ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16 struct { - uint16 id; + uint32 id; } holiday; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE= 17 + struct + { + uint32 min_score; + uint32 max_score; + } bg_loss_team_score; // ... struct { @@ -227,6 +234,7 @@ class AchievementMgr void SaveToDB(); void ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0); void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0); + void CompletedAchievement(AchievementEntry const* entry); void CheckAllAchievementCriteria(); void SendAllAchievementData(); void SendRespondInspectAchievements(Player* player); @@ -238,7 +246,6 @@ class AchievementMgr void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress); void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET); void CompletedCriteriaFor(AchievementEntry const* achievement); - void CompletedAchievement(AchievementEntry const* entry); bool IsCompletedCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement); bool IsCompletedAchievement(AchievementEntry const* entry); void CompleteAchievementsWithRefs(AchievementEntry const* entry); diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index d827e3e2672..3050c772e28 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -91,3 +91,58 @@ void SpellAI::UpdateAI(const uint32 diff) else DoMeleeAttackIfReady(); } + +void SpellCasterAI::InitializeAI() +{ + SpellAI::InitializeAI(); + float m_attackDist = 30.0f; + for(SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr) + { + if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange) + m_attackDist = GetAISpellInfo(*itr)->maxRange; + } + if (m_attackDist == 30.0f) + m_attackDist = MELEE_RANGE; +} + +void SpellCasterAI::EnterCombat(Unit *who) +{ + if (spells.empty()) + return; + + uint32 spell = rand() % spells.size(); + uint32 count = 0; + for(SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count) + { + if(AISpellInfo[*itr].condition == AICOND_AGGRO) + me->CastSpell(who, *itr, false); + else if (AISpellInfo[*itr].condition == AICOND_COMBAT) + { + uint32 cooldown = GetAISpellInfo(*itr)->realCooldown; + if (count == spell) + { + DoCast(spells[spell]); + cooldown += me->GetCurrentSpellCastTime(*itr); + } + events.ScheduleEvent(*itr, cooldown); + } + } +} + +void SpellCasterAI::UpdateAI(const uint32 diff) +{ + if(!UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(uint32 spellId = events.ExecuteEvent()) + { + DoCast(spellId); + uint32 casttime = me->GetCurrentSpellCastTime(spellId); + events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown); + } +} diff --git a/src/game/AggressorAI.h b/src/game/AggressorAI.h index 2c43ccf82b7..cec11c0fb22 100644 --- a/src/game/AggressorAI.h +++ b/src/game/AggressorAI.h @@ -48,9 +48,21 @@ class TRINITY_DLL_SPEC SpellAI : public CreatureAI void JustDied(Unit *killer); void UpdateAI(const uint32 diff); static int Permissible(const Creature *); - private: + protected: EventMap events; SpellVct spells; }; +class TRINITY_DLL_SPEC SpellCasterAI : public SpellAI +{ + public: + explicit SpellCasterAI(Creature *c) : SpellAI(c) {m_attackDist = MELEE_RANGE;} + void InitializeAI(); + void AttackStart(Unit * victim){SpellAI::AttackStartCaster(victim, m_attackDist);} + void UpdateAI(const uint32 diff); + void EnterCombat(Unit *who); + private: + float m_attackDist; +}; + #endif diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp index 23050dcf25c..22d121c38c1 100644 --- a/src/game/ArenaTeam.cpp +++ b/src/game/ArenaTeam.cpp @@ -20,6 +20,7 @@ #include "WorldPacket.h" #include "ArenaTeam.h" +#include "World.h" void ArenaTeamMember::ModifyPersonalRating(Player* plr, int32 mod, uint32 slot) { @@ -32,21 +33,24 @@ void ArenaTeamMember::ModifyPersonalRating(Player* plr, int32 mod, uint32 slot) ArenaTeam::ArenaTeam() { - Id = 0; - Type = 0; - Name = ""; - CaptainGuid = 0; - BackgroundColor = 0; // background - EmblemStyle = 0; // icon - EmblemColor = 0; // icon color - BorderStyle = 0; // border - BorderColor = 0; // border color - stats.games_week = 0; - stats.games_season = 0; - stats.rank = 0; - stats.rating = ARENA_NEW_TEAM_RATING; - stats.wins_week = 0; - stats.wins_season = 0; + m_TeamId = 0; + m_Type = 0; + m_Name = ""; + m_CaptainGuid = 0; + m_BackgroundColor = 0; // background + m_EmblemStyle = 0; // icon + m_EmblemColor = 0; // icon color + m_BorderStyle = 0; // border + m_BorderColor = 0; // border color + m_stats.games_week = 0; + m_stats.games_season = 0; + m_stats.rank = 0; + if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6) + m_stats.rating = 0; + else + m_stats.rating = 1500; + m_stats.wins_week = 0; + m_stats.wins_season = 0; } ArenaTeam::~ArenaTeam() @@ -62,27 +66,27 @@ bool ArenaTeam::Create(uint64 captainGuid, uint32 type, std::string ArenaTeamNam sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid)); - CaptainGuid = captainGuid; - Name = ArenaTeamName; - Type = type; + m_CaptainGuid = captainGuid; + m_Name = ArenaTeamName; + m_Type = type; - Id = objmgr.GenerateArenaTeamId(); + m_TeamId = objmgr.GenerateArenaTeamId(); // ArenaTeamName already assigned to ArenaTeam::name, use it to encode string for DB CharacterDatabase.escape_string(ArenaTeamName); CharacterDatabase.BeginTransaction(); - // CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", Id); - MAX(arenateam)+1 not exist - CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", Id); + // CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", m_TeamId); - MAX(arenateam)+1 not exist + CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", m_TeamId); CharacterDatabase.PExecute("INSERT INTO arena_team (arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor) " "VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')", - Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor); + m_TeamId, ArenaTeamName.c_str(), GUID_LOPART(m_CaptainGuid), m_Type, m_BackgroundColor, m_EmblemStyle, m_EmblemColor, m_BorderStyle, m_BorderColor); CharacterDatabase.PExecute("INSERT INTO arena_team_stats (arenateamid, rating, games, wins, played, wins2, rank) VALUES " - "('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id, stats.rating, stats.games_week, stats.wins_week, stats.games_season, stats.wins_season, stats.rank); + "('%u', '%u', '%u', '%u', '%u', '%u', '%u')", m_TeamId, m_stats.rating, m_stats.games_week, m_stats.wins_week, m_stats.games_season, m_stats.wins_season, m_stats.rank); CharacterDatabase.CommitTransaction(); - AddMember(CaptainGuid); + AddMember(m_CaptainGuid); sLog.outArena("New ArenaTeam created [Id: %u] [Type: %u] [Captain GUID: %u]", GetId(), GetType(), GetCaptain()); return true; } @@ -139,19 +143,29 @@ bool ArenaTeam::AddMember(const uint64& PlayerGuid) newmember.games_week = 0; newmember.wins_season = 0; newmember.wins_week = 0; - newmember.personal_rating = AREAN_NEW_PERSONAL_RATING; - members.push_back(newmember); + if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6) + { + if (m_stats.rating < 1000) + newmember.personal_rating = m_stats.rating; + else + newmember.personal_rating = 1000; + } + else + { + newmember.personal_rating = 1500; + } + m_members.push_back(newmember); - CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid, guid, personal_rating) VALUES ('%u', '%u', '%u')", Id, GUID_LOPART(newmember.guid), newmember.personal_rating ); + CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid, guid, personal_rating) VALUES ('%u', '%u', '%u')", m_TeamId, GUID_LOPART(newmember.guid), newmember.personal_rating ); if(pl) { - pl->SetInArenaTeam(Id, GetSlot()); + pl->SetInArenaTeam(m_TeamId, GetSlot()); pl->SetArenaTeamIdInvited(0); pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, newmember.personal_rating ); // hide promote/remove buttons - if(CaptainGuid != PlayerGuid) + if(m_CaptainGuid != PlayerGuid) pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 1, 1); sLog.outArena("Player: %s [GUID: %u] joined arena team type: %u [Id: %u].", pl->GetName(), pl->GetGUIDLow(), GetType(), GetId()); } @@ -167,15 +181,15 @@ bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId) Field *fields = result->Fetch(); - Id = fields[0].GetUInt32(); - Name = fields[1].GetCppString(); - CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); - Type = fields[3].GetUInt32(); - BackgroundColor = fields[4].GetUInt32(); - EmblemStyle = fields[5].GetUInt32(); - EmblemColor = fields[6].GetUInt32(); - BorderStyle = fields[7].GetUInt32(); - BorderColor = fields[8].GetUInt32(); + m_TeamId = fields[0].GetUInt32(); + m_Name = fields[1].GetCppString(); + m_CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); + m_Type = fields[3].GetUInt32(); + m_BackgroundColor = fields[4].GetUInt32(); + m_EmblemStyle = fields[5].GetUInt32(); + m_EmblemColor = fields[6].GetUInt32(); + m_BorderStyle = fields[7].GetUInt32(); + m_BorderColor = fields[8].GetUInt32(); delete result; @@ -207,12 +221,12 @@ void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId) Field *fields = result->Fetch(); - stats.rating = fields[0].GetUInt32(); - stats.games_week = fields[1].GetUInt32(); - stats.wins_week = fields[2].GetUInt32(); - stats.games_season = fields[3].GetUInt32(); - stats.wins_season = fields[4].GetUInt32(); - stats.rank = fields[5].GetUInt32(); + m_stats.rating = fields[0].GetUInt32(); + m_stats.games_week = fields[1].GetUInt32(); + m_stats.wins_week = fields[2].GetUInt32(); + m_stats.games_season = fields[3].GetUInt32(); + m_stats.wins_season = fields[4].GetUInt32(); + m_stats.rank = fields[5].GetUInt32(); delete result; } @@ -239,7 +253,7 @@ void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId) newmember.personal_rating = fields[5].GetUInt32(); newmember.name = fields[6].GetCppString(); newmember.Class = fields[7].GetUInt8(); - members.push_back(newmember); + m_members.push_back(newmember); }while( result->NextRow() ); delete result; } @@ -252,10 +266,10 @@ void ArenaTeam::SetCaptain(const uint64& guid) oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1); // set new captain - CaptainGuid = guid; + m_CaptainGuid = guid; // update database - CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), Id); + CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), m_TeamId); // enable remove/promote buttons Player *newcaptain = objmgr.GetPlayer(guid); @@ -268,11 +282,11 @@ void ArenaTeam::SetCaptain(const uint64& guid) void ArenaTeam::DelMember(uint64 guid) { - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + for (MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { if (itr->guid == guid) { - members.erase(itr); + m_members.erase(itr); break; } } @@ -300,21 +314,21 @@ void ArenaTeam::Disband(WorldSession *session) session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), ""); BroadcastPacket(&data); - while (!members.empty()) + while (!m_members.empty()) { // Removing from members is done in DelMember. - DelMember(members.front().guid); + DelMember(m_members.front().guid); } if(Player *player = session->GetPlayer()) sLog.outArena("Player: %s [GUID: %u] disbanded arena team type: %u [Id: %u].", player->GetName(), player->GetGUIDLow(), GetType(), GetId()); CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id); - CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id); //< this should be alredy done by calling DelMember(memberGuids[j]); for each member - CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id); + CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", m_TeamId); + CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", m_TeamId); //< this should be alredy done by calling DelMember(memberGuids[j]); for each member + CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", m_TeamId); CharacterDatabase.CommitTransaction(); - objmgr.RemoveArenaTeam(Id); + objmgr.RemoveArenaTeam(m_TeamId); } void ArenaTeam::Roster(WorldSession *session) @@ -324,12 +338,12 @@ void ArenaTeam::Roster(WorldSession *session) uint8 unk308 = 0; WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100); - data << uint32(GetId()); // arena team id + data << uint32(GetId()); // team id data << uint8(unk308); // 308 unknown value but affect packet structure data << uint32(GetMembersSize()); // members count data << uint32(GetType()); // arena team type? - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { pl = objmgr.GetPlayer(itr->guid); @@ -361,11 +375,11 @@ void ArenaTeam::Query(WorldSession *session) data << uint32(GetId()); // team id data << GetName(); // team name data << uint32(GetType()); // arena team type (2=2x2, 3=3x3 or 5=5x5) - data << uint32(BackgroundColor); // background color - data << uint32(EmblemStyle); // emblem style - data << uint32(EmblemColor); // emblem color - data << uint32(BorderStyle); // border style - data << uint32(BorderColor); // border color + data << uint32(m_BackgroundColor); // background color + data << uint32(m_EmblemStyle); // emblem style + data << uint32(m_EmblemColor); // emblem color + data << uint32(m_BorderStyle); // border style + data << uint32(m_BorderColor); // border color session->SendPacket(&data); sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_QUERY_RESPONSE"); } @@ -373,13 +387,13 @@ void ArenaTeam::Query(WorldSession *session) void ArenaTeam::Stats(WorldSession *session) { WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7); - data << uint32(GetId()); // arena team id - data << uint32(stats.rating); // rating - data << uint32(stats.games_week); // games this week - data << uint32(stats.wins_week); // wins this week - data << uint32(stats.games_season); // played this season - data << uint32(stats.wins_season); // wins this season - data << uint32(stats.rank); // rank + data << uint32(GetId()); // team id + data << uint32(m_stats.rating); // rating + data << uint32(m_stats.games_week); // games this week + data << uint32(m_stats.wins_week); // wins this week + data << uint32(m_stats.games_season); // played this season + data << uint32(m_stats.wins_season); // wins this season + data << uint32(m_stats.rank); // rank session->SendPacket(&data); } @@ -387,7 +401,7 @@ void ArenaTeam::NotifyStatsChanged() { // this is called after a rated match ended // updates arena team stats for every member of the team (not only the ones who participated!) - for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + for(MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { Player * plr = objmgr.GetPlayer(itr->guid); if(plr) @@ -405,9 +419,9 @@ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid) data << uint64(guid); // player guid data << uint8(GetSlot()); // slot (0...2) data << uint32(GetId()); // arena team id - data << uint32(stats.rating); // rating - data << uint32(stats.games_season); // season played - data << uint32(stats.wins_season); // season wins + data << uint32(m_stats.rating); // rating + data << uint32(m_stats.games_season); // season played + data << uint32(m_stats.wins_season); // season wins data << uint32(member->games_season); // played (count of all games, that the inspected member participated...) data << uint32(member->personal_rating); // personal rating session->SendPacket(&data); @@ -415,13 +429,13 @@ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid) void ArenaTeam::SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor) { - BackgroundColor = backgroundColor; - EmblemStyle = emblemStyle; - EmblemColor = emblemColor; - BorderStyle = borderStyle; - BorderColor = borderColor; + m_BackgroundColor = backgroundColor; + m_EmblemStyle = emblemStyle; + m_EmblemColor = emblemColor; + m_BorderStyle = borderStyle; + m_BorderColor = borderColor; - CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor, Id); + CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", m_BackgroundColor, m_EmblemStyle, m_EmblemColor, m_BorderStyle, m_BorderColor, m_TeamId); } void ArenaTeam::SetStats(uint32 stat_type, uint32 value) @@ -429,27 +443,27 @@ void ArenaTeam::SetStats(uint32 stat_type, uint32 value) switch(stat_type) { case STAT_TYPE_RATING: - stats.rating = value; + m_stats.rating = value; CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u' WHERE arenateamid = '%u'", value, GetId()); break; case STAT_TYPE_GAMES_WEEK: - stats.games_week = value; + m_stats.games_week = value; CharacterDatabase.PExecute("UPDATE arena_team_stats SET games = '%u' WHERE arenateamid = '%u'", value, GetId()); break; case STAT_TYPE_WINS_WEEK: - stats.wins_week = value; + m_stats.wins_week = value; CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins = '%u' WHERE arenateamid = '%u'", value, GetId()); break; case STAT_TYPE_GAMES_SEASON: - stats.games_season = value; + m_stats.games_season = value; CharacterDatabase.PExecute("UPDATE arena_team_stats SET played = '%u' WHERE arenateamid = '%u'", value, GetId()); break; case STAT_TYPE_WINS_SEASON: - stats.wins_season = value; + m_stats.wins_season = value; CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins2 = '%u' WHERE arenateamid = '%u'", value, GetId()); break; case STAT_TYPE_RANK: - stats.rank = value; + m_stats.rank = value; CharacterDatabase.PExecute("UPDATE arena_team_stats SET rank = '%u' WHERE arenateamid = '%u'", value, GetId()); break; default: @@ -460,7 +474,7 @@ void ArenaTeam::SetStats(uint32 stat_type, uint32 value) void ArenaTeam::BroadcastPacket(WorldPacket *packet) { - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { Player *player = objmgr.GetPlayer(itr->guid); if(player) @@ -484,7 +498,7 @@ uint8 ArenaTeam::GetSlotByType( uint32 type ) bool ArenaTeam::HaveMember( const uint64& guid ) const { - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if(itr->guid == guid) return true; @@ -496,17 +510,18 @@ uint32 ArenaTeam::GetPoints(uint32 MemberRating) // returns how many points would be awarded with this team type with this rating float points; - uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating; + uint32 rating = MemberRating + 150 < m_stats.rating ? MemberRating : m_stats.rating; if(rating<=1500) - points = (float)rating * 0.22f + 14.0f; + // points = (float)1500 * 0.22f + 14.0f; + points = 344.0f; // 3.1 change - teams with rating below 1500 get arena points for 1500 rating else points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating)); // type penalties for <5v5 teams - if(Type == ARENA_TEAM_2v2) + if(m_Type == ARENA_TEAM_2v2) points *= 0.76f; - else if(Type == ARENA_TEAM_3v3) + else if(m_Type == ARENA_TEAM_3v3) points *= 0.88f; return (uint32) points; @@ -516,31 +531,43 @@ float ArenaTeam::GetChanceAgainst(uint32 own_rating, uint32 enemy_rating) { // returns the chance to win against a team with the given rating, used in the rating adjustment calculation // ELO system + + if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6) + if (enemy_rating < 1300) + enemy_rating = 1300; return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)enemy_rating - (float)own_rating)/400.0f)); } +void ArenaTeam::FinishGame(int32 mod) +{ + if (int32(m_stats.rating) + mod < 0) + m_stats.rating = 0; + else + m_stats.rating += mod; + + m_stats.games_week += 1; + m_stats.games_season += 1; + // update team's rank + m_stats.rank = 1; + ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin(); + for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i) + { + if (i->second->GetType() == m_Type && i->second->GetStats().rating > m_stats.rating) + ++m_stats.rank; + } +} + int32 ArenaTeam::WonAgainst(uint32 againstRating) { // called when the team has won //'chance' calculation - to beat the opponent - float chance = GetChanceAgainst(stats.rating,againstRating); + float chance = GetChanceAgainst(m_stats.rating, againstRating); // calculate the rating modification (ELO system with k=32) int32 mod = (int32)floor(32.0f * (1.0f - chance)); // modify the team stats accordingly - int32 newTeamRating = (int32)stats.rating + mod; - stats.rating = newTeamRating > 0 ? newTeamRating : 0; - stats.games_week += 1; - stats.wins_week += 1; - stats.games_season += 1; - stats.wins_season += 1; - //update team's rank - stats.rank = 1; - ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin(); - for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i) - { - if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating) - ++stats.rank; - } + FinishGame(mod); + m_stats.wins_week += 1; + m_stats.wins_season += 1; // return the rating change, used to display it on the results screen return mod; @@ -550,23 +577,11 @@ int32 ArenaTeam::LostAgainst(uint32 againstRating) { // called when the team has lost //'chance' calculation - to loose to the opponent - float chance = GetChanceAgainst(stats.rating,againstRating); + float chance = GetChanceAgainst(m_stats.rating, againstRating); // calculate the rating modification (ELO system with k=32) int32 mod = (int32)ceil(32.0f * (0.0f - chance)); // modify the team stats accordingly - int32 newTeamRating = (int32)stats.rating + mod; - stats.rating = newTeamRating > 0 ? newTeamRating : 0; - stats.games_week += 1; - stats.games_season += 1; - //update team's rank - - stats.rank = 1; - ObjectMgr::ArenaTeamMap::const_iterator i = objmgr.GetArenaTeamMapBegin(); - for ( ; i != objmgr.GetArenaTeamMapEnd(); ++i) - { - if (i->second->GetType() == this->Type && i->second->GetStats().rating > stats.rating) - ++stats.rank; - } + FinishGame(mod); // return the rating change, used to display it on the results screen return mod; @@ -575,7 +590,7 @@ int32 ArenaTeam::LostAgainst(uint32 againstRating) void ArenaTeam::MemberLost(Player * plr, uint32 againstRating) { // called for each participant of a match after losing - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { if(itr->guid == plr->GetGUID()) { @@ -597,7 +612,7 @@ void ArenaTeam::MemberLost(Player * plr, uint32 againstRating) void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstRating) { // called for offline player after ending rated arena match! - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { if(itr->guid == guid) { @@ -619,7 +634,7 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstRating) void ArenaTeam::MemberWon(Player * plr, uint32 againstRating) { // called for each participant after winning a match - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { if(itr->guid == plr->GetGUID()) { @@ -645,17 +660,17 @@ void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& PlayerPoints) // called after a match has ended and the stats are already modified // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons) // 10 played games per week is a minimum - if (stats.games_week < 10) + if (m_stats.games_week < 10) return; // to get points, a player has to participate in at least 30% of the matches - uint32 min_plays = (uint32) ceil(stats.games_week * 0.3); - for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + uint32 min_plays = (uint32) ceil(m_stats.games_week * 0.3); + for(MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { // the player participated in enough games, update his points uint32 points_to_add = 0; if (itr->games_week >= min_plays) points_to_add = GetPoints(itr->personal_rating); - // OBSOLETE : CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid); + // OBSOLETE : CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, m_TeamId, itr->guid); std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.find(GUID_LOPART(itr->guid)); if (plr_itr != PlayerPoints.end()) @@ -674,19 +689,19 @@ void ArenaTeam::SaveToDB() // save team and member stats to db // called after a match has ended, or when calculating arena_points CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games_week, stats.games_season, stats.rank, stats.wins_week, stats.wins_season, GetId()); - for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", m_stats.rating, m_stats.games_week, m_stats.games_season, m_stats.rank, m_stats.wins_week, m_stats.wins_season, GetId()); + for(MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { - CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', personal_rating = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, itr->personal_rating, Id, GUID_LOPART(itr->guid)); + CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', personal_rating = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, itr->personal_rating, m_TeamId, GUID_LOPART(itr->guid)); } CharacterDatabase.CommitTransaction(); } void ArenaTeam::FinishWeek() { - stats.games_week = 0; // played this week - stats.wins_week = 0; // wins this week - for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + m_stats.games_week = 0; // played this week + m_stats.wins_week = 0; // wins this week + for(MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { itr->games_week = 0; itr->wins_week = 0; @@ -695,7 +710,7 @@ void ArenaTeam::FinishWeek() bool ArenaTeam::IsFighting() const { - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + for (MemberList::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { if (Player *p = objmgr.GetPlayer(itr->guid)) { diff --git a/src/game/ArenaTeam.h b/src/game/ArenaTeam.h index 2dc5b45e880..dbeac2f09f0 100644 --- a/src/game/ArenaTeam.h +++ b/src/game/ArenaTeam.h @@ -85,9 +85,6 @@ enum ArenaTeamTypes ARENA_TEAM_5v5 = 5 }; -#define ARENA_NEW_TEAM_RATING 0 -#define AREAN_NEW_PERSONAL_RATING 0 - struct ArenaTeamMember { uint64 guid; @@ -120,26 +117,26 @@ class ArenaTeam ArenaTeam(); ~ArenaTeam(); - bool Create(uint64 CaptainGuid, uint32 type, std::string ArenaTeamName); + bool Create(uint64 captainGuid, uint32 type, std::string ArenaTeamName); void Disband(WorldSession *session); typedef std::list<ArenaTeamMember> MemberList; - uint32 GetId() const { return Id; } - uint32 GetType() const { return Type; } + uint32 GetId() const { return m_TeamId; } + uint32 GetType() const { return m_Type; } uint8 GetSlot() const { return GetSlotByType(GetType()); } static uint8 GetSlotByType(uint32 type); - const uint64& GetCaptain() const { return CaptainGuid; } - std::string GetName() const { return Name; } - const ArenaTeamStats& GetStats() const { return stats; } + const uint64& GetCaptain() const { return m_CaptainGuid; } + std::string GetName() const { return m_Name; } + const ArenaTeamStats& GetStats() const { return m_stats; } void SetStats(uint32 stat_type, uint32 value); - uint32 GetRating() const { return stats.rating; } + uint32 GetRating() const { return m_stats.rating; } - uint32 GetEmblemStyle() const { return EmblemStyle; } - uint32 GetEmblemColor() const { return EmblemColor; } - uint32 GetBorderStyle() const { return BorderStyle; } - uint32 GetBorderColor() const { return BorderColor; } - uint32 GetBackgroundColor() const { return BackgroundColor; } + uint32 GetEmblemStyle() const { return m_EmblemStyle; } + uint32 GetEmblemColor() const { return m_EmblemColor; } + uint32 GetBorderStyle() const { return m_BorderStyle; } + uint32 GetBorderColor() const { return m_BorderColor; } + uint32 GetBackgroundColor() const { return m_BackgroundColor; } void SetCaptain(const uint64& guid); bool AddMember(const uint64& PlayerGuid); @@ -150,15 +147,15 @@ class ArenaTeam void SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor); - size_t GetMembersSize() const { return members.size(); } - bool Empty() const { return members.empty(); } - MemberList::iterator membersBegin() { return members.begin(); } - MemberList::iterator membersEnd() { return members.end(); } + size_t GetMembersSize() const { return m_members.size(); } + bool Empty() const { return m_members.empty(); } + MemberList::iterator m_membersBegin() { return m_members.begin(); } + MemberList::iterator m_membersEnd() { return m_members.end(); } bool HaveMember(const uint64& guid) const; ArenaTeamMember* GetMember(const uint64& guid) { - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + for (MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if(itr->guid == guid) return &(*itr); @@ -167,7 +164,7 @@ class ArenaTeam ArenaTeamMember* GetMember(const std::string& name) { - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + for (MemberList::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if(itr->name == name) return &(*itr); @@ -202,22 +199,23 @@ class ArenaTeam void NotifyStatsChanged(); void FinishWeek(); + void FinishGame(int32 mod); protected: - uint32 Id; - uint32 Type; - std::string Name; - uint64 CaptainGuid; + uint32 m_TeamId; + uint32 m_Type; + std::string m_Name; + uint64 m_CaptainGuid; - uint32 BackgroundColor; // ARGB format - uint32 EmblemStyle; // icon id - uint32 EmblemColor; // ARGB format - uint32 BorderStyle; // border image id - uint32 BorderColor; // ARGB format + uint32 m_BackgroundColor; // ARGB format + uint32 m_EmblemStyle; // icon id + uint32 m_EmblemColor; // ARGB format + uint32 m_BorderStyle; // border image id + uint32 m_BorderColor; // ARGB format - MemberList members; - ArenaTeamStats stats; + MemberList m_members; + ArenaTeamStats m_stats; }; #endif diff --git a/src/game/AuctionHouseBot.cpp b/src/game/AuctionHouseBot.cpp index c2af4c92c15..3e53f3f4e9b 100644 --- a/src/game/AuctionHouseBot.cpp +++ b/src/game/AuctionHouseBot.cpp @@ -1,73 +1,83 @@ -#include <vector> -#include <iostream> -#include "time.h" - -#include "ObjectMgr.h" -#include "World.h" -#include "WorldSession.h" -#include "Config/ConfigEnv.h" -#include "Database/DatabaseEnv.h" - #include "AuctionHouseBot.h" +#include "ObjectMgr.h" #include "AuctionHouseMgr.h" -#include "Bag.h" -#include "Item.h" -#include "Log.h" -#include "Player.h" + +#include "Policies/SingletonImp.h" +INSTANTIATE_SINGLETON_1(AuctionHouseBot); using namespace std; -static bool debug_Out = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG", false); - -static vector<uint32> npcItems; -static vector<uint32> lootItems; -static vector<uint32> greyTradeGoodsBin; -static vector<uint32> whiteTradeGoodsBin; -static vector<uint32> greenTradeGoodsBin; -static vector<uint32> blueTradeGoodsBin; -static vector<uint32> purpleTradeGoodsBin; -static vector<uint32> orangeTradeGoodsBin; -static vector<uint32> yellowTradeGoodsBin; -static vector<uint32> greyItemsBin; -static vector<uint32> whiteItemsBin; -static vector<uint32> greenItemsBin; -static vector<uint32> blueItemsBin; -static vector<uint32> purpleItemsBin; -static vector<uint32> orangeItemsBin; -static vector<uint32> yellowItemsBin; - -static bool AHBSeller = 0; -static bool AHBBuyer = 0; - -static bool Vendor_Items = 0; -static bool Loot_Items = 0; -static bool Other_Items = 0; - -static bool No_Bind = 0; -static bool Bind_When_Picked_Up = 0; -static bool Bind_When_Equipped = 0; -static bool Bind_When_Use = 0; -static bool Bind_Quest_Item = 0; - -static AHBConfig AllianceConfig = AHBConfig(2); -static AHBConfig HordeConfig = AHBConfig(6); -static AHBConfig NeutralConfig = AHBConfig(7); -time_t _lastrun_a; -time_t _lastrun_h; -time_t _lastrun_n; - -/////////////////////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////////////////////// -static inline uint32 minValue(uint32 a, uint32 b) +AuctionHouseBot::AuctionHouseBot() +{ + debug_Out = false; + + AHBSeller = false; + AHBBuyer = false; + + //Begin Filters + + Vendor_Items = false; + Loot_Items = false; + Other_Items = false; + + No_Bind = false; + Bind_When_Picked_Up = false; + Bind_When_Equipped = false; + Bind_When_Use = false; + Bind_Quest_Item = false; + + DisableBeta_PTR_Unused = false; + DisablePermEnchant = false; + DisableConjured = false; + DisableGems = false; + DisableMoney = false; + DisableMoneyLoot = false; + DisableLootable = false; + DisableKeys = false; + DisableDuration = false; + DisableBOP_Or_Quest_NoReqLevel = false; + + DisableWarriorItems = false; + DisablePaladinItems = false; + DisableHunterItems = false; + DisableRogueItems = false; + DisablePriestItems = false; + DisableDKItems = false; + DisableShamanItems = false; + DisableMageItems = false; + DisableWarlockItems = false; + DisableUnusedClassItems = false; + DisableDruidItems = false; + + DisableItemsBelowLevel = 0; + DisableItemsAboveLevel = 0; + DisableTGsBelowLevel = 0; + DisableTGsAboveLevel = 0; + DisableItemsBelowGUID = 0; + DisableItemsAboveGUID = 0; + DisableTGsBelowGUID = 0; + DisableTGsAboveGUID = 0; + DisableItemsBelowReqLevel = 0; + DisableItemsAboveReqLevel = 0; + DisableTGsBelowReqLevel = 0; + DisableTGsAboveReqLevel = 0; + DisableItemsBelowReqSkillRank = 0; + DisableItemsAboveReqSkillRank = 0; + DisableTGsBelowReqSkillRank = 0; + DisableTGsAboveReqSkillRank = 0; + + //End Filters + + AllianceConfig = AHBConfig(2); + HordeConfig = AHBConfig(6); + NeutralConfig = AHBConfig(7); +} + +AuctionHouseBot::~AuctionHouseBot() { - return a <= b ? a : b; } -/////////////////////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////////////////////// -static void addNewAuctions(Player *AHBplayer, AHBConfig *config) +void AuctionHouseBot::addNewAuctions(Player *AHBplayer, AHBConfig *config) { if (!AHBSeller) return; @@ -78,19 +88,26 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config) uint32 maxItems = config->GetMaxItems(); uint32 auctions = auctionHouse->Getcount(); uint32 AuctioneerGUID = 0; - switch (config->GetAHID()){ - case 2: - AuctioneerGUID = 79707; //Human in stormwind. - case 6: - AuctioneerGUID = 4656; //orc in Orgrimmar - case 7: - AuctioneerGUID = 23442; //goblin in GZ - default: - AuctioneerGUID = 23442; //default to neutral 7 + switch (config->GetAHID()) + { + case 2: + AuctioneerGUID = 79707; //Human in stormwind. + break; + case 6: + AuctioneerGUID = 4656; //orc in Orgrimmar + break; + case 7: + AuctioneerGUID = 23442; //goblin in GZ + break; + default: + if (debug_Out) sLog.outError("GetAHID() - Default switch reached"); + AuctioneerGUID = 23442; //default to neutral 7 + break; } if (auctions >= minItems) - return; + return; + if (auctions <= maxItems) { if ((maxItems - auctions) > ItemsPerCycle) @@ -113,9 +130,9 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config) uint32 orangeIcount = config->GetPercents(AHB_ORANGE_I); uint32 yellowIcount = config->GetPercents(AHB_YELLOW_I); uint32 total = greyTGcount + whiteTGcount + greenTGcount + blueTGcount - + purpleTGcount + orangeTGcount + yellowTGcount - + whiteIcount + greenIcount + blueIcount + purpleIcount - + orangeIcount + yellowIcount; + + purpleTGcount + orangeTGcount + yellowTGcount + + whiteIcount + greenIcount + blueIcount + purpleIcount + + orangeIcount + yellowIcount; uint32 greyTGoods = 0; uint32 whiteTGoods = 0; @@ -133,74 +150,71 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config) uint32 orangeItems = 0; uint32 yellowItems = 0; - for (AuctionHouseObject::AuctionEntryMap::iterator itr = auctionHouse->GetAuctionsBegin();itr != auctionHouse->GetAuctionsEnd();++itr) + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin();itr != auctionHouse->GetAuctionsEnd();++itr) { AuctionEntry *Aentry = itr->second; Item *item = auctionmgr.GetAItem(Aentry->item_guidlow); - if( item ) + if (item) { ItemPrototype const *prototype = item->GetProto(); - if( prototype ) + if (prototype) { switch (prototype->Quality) { - case 0: + case 0: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - ++greyTGoods; + ++greyTGoods; else - ++greyItems; + ++greyItems; break; - - case 1: + case 1: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - ++whiteTGoods; + ++whiteTGoods; else - ++whiteItems; + ++whiteItems; break; - - case 2: + case 2: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - ++greenTGoods; + ++greenTGoods; else - ++greenItems; + ++greenItems; break; - - case 3: + case 3: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - ++blueTGoods; + ++blueTGoods; else - ++blueItems; + ++blueItems; break; - - case 4: + case 4: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - ++purpleTGoods; + ++purpleTGoods; else - ++purpleItems; + ++purpleItems; break; - - case 5: + case 5: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - ++orangeTGoods; + ++orangeTGoods; else - ++orangeItems; + ++orangeItems; break; - - case 6: + case 6: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - ++yellowTGoods; + ++yellowTGoods; else - ++yellowItems; + ++yellowItems; break; } } } } + // only insert a few at a time, so as not to peg the processor for (uint32 cnt = 1;cnt <= items;cnt++) { uint32 itemID = 0; - while (itemID == 0) + uint32 loopBreaker = 0; + uint32 itemColor = 99; + while (itemID == 0 && loopBreaker < 50) { uint32 choice = urand(0, 13); switch (choice) @@ -208,269 +222,224 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config) case 0: { if ((greyItemsBin.size() > 0) && (greyItems < greyIcount)) - { - itemID = greyItemsBin[urand(0, greyItemsBin.size() - 1)]; - ++greyItems; - break; - } + itemID = greyItemsBin[urand(0, greyItemsBin.size() - 1)]; + else continue; + break; } case 1: { if ((whiteItemsBin.size() > 0) && (whiteItems < whiteIcount)) - { - itemID = whiteItemsBin[urand(0, whiteItemsBin.size() - 1)]; - ++whiteItems; - break; - } + itemID = whiteItemsBin[urand(0, whiteItemsBin.size() - 1)]; + else continue; + break; } case 2: { if ((greenItemsBin.size() > 0) && (greenItems < greenIcount)) - { - itemID = greenItemsBin[urand(0, greenItemsBin.size() - 1)]; - ++greenItems; - break; - } + itemID = greenItemsBin[urand(0, greenItemsBin.size() - 1)]; + else continue; + break; } case 3: { if ((blueItemsBin.size() > 0) && (blueItems < blueIcount)) - { - itemID = blueItemsBin[urand(0, blueItemsBin.size() - 1)]; - ++blueItems; - break; - } + itemID = blueItemsBin[urand(0, blueItemsBin.size() - 1)]; + else continue; + break; } case 4: { if ((purpleItemsBin.size() > 0) && (purpleItems < purpleIcount)) - { itemID = purpleItemsBin[urand(0, purpleItemsBin.size() - 1)]; - ++purpleItems; - break; - } + else continue; + break; } case 5: { if ((orangeItemsBin.size() > 0) && (orangeItems < orangeIcount)) - { itemID = orangeItemsBin[urand(0, orangeItemsBin.size() - 1)]; - ++orangeItems; - break; - } + else continue; + break; } case 6: { if ((yellowItemsBin.size() > 0) && (yellowItems < yellowIcount)) - { itemID = yellowItemsBin[urand(0, yellowItemsBin.size() - 1)]; - ++yellowItems; - break; - } + else continue; + break; } case 7: { if ((greyTradeGoodsBin.size() > 0) && (greyTGoods < greyTGcount)) - { - itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)]; - ++greyTGoods; - break; - } + itemID = greyTradeGoodsBin[urand(0, greyTradeGoodsBin.size() - 1)]; + else continue; + break; } case 8: { if ((whiteTradeGoodsBin.size() > 0) && (whiteTGoods < whiteTGcount)) - { - itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)]; - ++whiteTGoods; - break; - } + itemID = whiteTradeGoodsBin[urand(0, whiteTradeGoodsBin.size() - 1)]; + else continue; + break; } case 9: { if ((greenTradeGoodsBin.size() > 0) && (greenTGoods < greenTGcount)) - { - itemID = greenTradeGoodsBin[urand(0, greenTradeGoodsBin.size() - 1)]; - ++greenTGoods; - break; - } + itemID = greenTradeGoodsBin[urand(0, greenTradeGoodsBin.size() - 1)]; + else continue; + break; } case 10: { if ((blueTradeGoodsBin.size() > 0) && (blueTGoods < blueTGcount)) - { - itemID = blueTradeGoodsBin[urand(0, blueTradeGoodsBin.size() - 1)]; - ++blueTGoods; - break; - } + itemID = blueTradeGoodsBin[urand(0, blueTradeGoodsBin.size() - 1)]; + else continue; + break; } case 11: { if ((purpleTradeGoodsBin.size() > 0) && (purpleTGoods < purpleTGcount)) - { - itemID = purpleTradeGoodsBin[urand(0, purpleTradeGoodsBin.size() - 1)]; - ++purpleTGoods; - break; - } + itemID = purpleTradeGoodsBin[urand(0, purpleTradeGoodsBin.size() - 1)]; + else continue; + break; } case 12: { if ((orangeTradeGoodsBin.size() > 0) && (orangeTGoods < orangeTGcount)) - { - itemID = orangeTradeGoodsBin[urand(0, orangeTradeGoodsBin.size() - 1)]; - ++orangeTGoods; - break; - } + itemID = orangeTradeGoodsBin[urand(0, orangeTradeGoodsBin.size() - 1)]; + else continue; + break; } case 13: { if ((yellowTradeGoodsBin.size() > 0) && (yellowTGoods < yellowTGcount)) - { - itemID = yellowTradeGoodsBin[urand(0, yellowTradeGoodsBin.size() - 1)]; - ++yellowTGoods; - break; - } + itemID = yellowTradeGoodsBin[urand(0, yellowTradeGoodsBin.size() - 1)]; + else continue; + break; } default: { + if (debug_Out) sLog.outError("AuctionHouseBot: itemID Switch - Default Reached"); break; } + ++loopBreaker; } - } - - ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); - if (prototype == NULL) - { - sLog.outString("AuctionHouseBot: Huh?!?! prototype == NULL"); - continue; - } - - Item* item = Item::CreateItem(itemID, 1, AHBplayer); - item->AddToUpdateQueueOf(AHBplayer); - if (item == NULL) - { - sLog.outString("AuctionHouseBot: Item::CreateItem() returned NULL"); - break; - } - - uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); - if (randomPropertyId != 0) - item->SetItemRandomProperties(randomPropertyId); - - uint32 buyoutPrice; - uint32 bidPrice = 0; - uint32 stackCount = urand(1, item->GetMaxStackCount()); - - switch (SellMethod) - { - case 0: - buyoutPrice = prototype->SellPrice * item->GetCount(); - break; - case 1: - buyoutPrice = prototype->BuyPrice * item->GetCount(); - break; - default: - buyoutPrice = 0; - break; - } - - switch (prototype->Quality) - { - case 0: - if (config->GetMaxStack(AHB_GREY) != 0) + if (itemID == 0) { - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREY))); + if (debug_Out) sLog.outError("AuctionHouseBot: Item::CreateItem() - ItemID is 0"); + continue; } - buyoutPrice *= urand(config->GetMinPrice(AHB_GREY), config->GetMaxPrice(AHB_GREY)) * stackCount; - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREY), config->GetMaxBidPrice(AHB_GREY)); - bidPrice /= 100; - break; - case 1: - if (config->GetMaxStack(AHB_WHITE) != 0) + ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); + if (prototype == NULL) { - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_WHITE))); + if (debug_Out) sLog.outError("AuctionHouseBot: Huh?!?! prototype == NULL"); + continue; } - buyoutPrice *= urand(config->GetMinPrice(AHB_WHITE), config->GetMaxPrice(AHB_WHITE)) * stackCount; - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_WHITE), config->GetMaxBidPrice(AHB_WHITE)); - bidPrice /= 100; - break; - case 2: - if (config->GetMaxStack(AHB_GREEN) != 0) + Item* item = Item::CreateItem(itemID, 1, AHBplayer); + item->AddToUpdateQueueOf(AHBplayer); + if (item == NULL) { - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREEN))); + if (debug_Out) sLog.outError("AuctionHouseBot: Item::CreateItem() returned NULL"); + break; } - buyoutPrice *= urand(config->GetMinPrice(AHB_GREEN), config->GetMaxPrice(AHB_GREEN)) * stackCount; - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREEN), config->GetMaxBidPrice(AHB_GREEN)); - bidPrice /= 100; - break; - case 3: - if (config->GetMaxStack(AHB_BLUE) != 0) - { - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_BLUE))); - } - buyoutPrice *= urand(config->GetMinPrice(AHB_BLUE), config->GetMaxPrice(AHB_BLUE)) * stackCount; - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_BLUE), config->GetMaxBidPrice(AHB_BLUE)); - bidPrice /= 100; - break; + uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); + if (randomPropertyId != 0) + item->SetItemRandomProperties(randomPropertyId); - case 4: - if (config->GetMaxStack(AHB_PURPLE) != 0) - { - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_PURPLE))); - } - buyoutPrice *= urand(config->GetMinPrice(AHB_PURPLE), config->GetMaxPrice(AHB_PURPLE)) * stackCount; - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_PURPLE), config->GetMaxBidPrice(AHB_PURPLE)); - bidPrice /= 100; - break; - case 5: - if (config->GetMaxStack(AHB_ORANGE) != 0) + uint64 buyoutPrice = 0; + uint64 bidPrice = 0; + uint32 stackCount = 1; + + switch (SellMethod) { - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_ORANGE))); + case 0: + buyoutPrice = prototype->SellPrice; + break; + case 1: + buyoutPrice = prototype->BuyPrice; + break; } - buyoutPrice *= urand(config->GetMinPrice(AHB_ORANGE), config->GetMaxPrice(AHB_ORANGE)) * stackCount; - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_ORANGE), config->GetMaxBidPrice(AHB_ORANGE)); - bidPrice /= 100; - break; - case 6: - if (config->GetMaxStack(AHB_YELLOW) != 0) + + switch (prototype->Quality) { - stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_YELLOW))); + case AHB_GREY: + if (config->GetMaxStack(AHB_GREY) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREY))); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(AHB_GREY), config->GetMaxPrice(AHB_GREY)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREY), config->GetMaxBidPrice(AHB_GREY)); + bidPrice /= 100; + break; + case AHB_WHITE: + if (config->GetMaxStack(AHB_WHITE) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_WHITE))); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(AHB_WHITE), config->GetMaxPrice(AHB_WHITE)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_WHITE), config->GetMaxBidPrice(AHB_WHITE)); + bidPrice /= 100; + break; + case AHB_GREEN: + if (config->GetMaxStack(AHB_GREEN) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_GREEN))); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(AHB_GREEN), config->GetMaxPrice(AHB_GREEN)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_GREEN), config->GetMaxBidPrice(AHB_GREEN)); + bidPrice /= 100; + break; + case AHB_BLUE: + if (config->GetMaxStack(AHB_BLUE) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_BLUE))); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(AHB_BLUE), config->GetMaxPrice(AHB_BLUE)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_BLUE), config->GetMaxBidPrice(AHB_BLUE)); + bidPrice /= 100; + break; + case AHB_PURPLE: + if (config->GetMaxStack(AHB_PURPLE) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_PURPLE))); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(AHB_PURPLE), config->GetMaxPrice(AHB_PURPLE)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_PURPLE), config->GetMaxBidPrice(AHB_PURPLE)); + bidPrice /= 100; + break; + case AHB_ORANGE: + if (config->GetMaxStack(AHB_ORANGE) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_ORANGE))); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(AHB_ORANGE), config->GetMaxPrice(AHB_ORANGE)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_ORANGE), config->GetMaxBidPrice(AHB_ORANGE)); + bidPrice /= 100; + break; + case AHB_YELLOW: + if (config->GetMaxStack(AHB_YELLOW) > 1 && item->GetMaxStackCount() > 1) + stackCount = urand(1, minValue(item->GetMaxStackCount(), config->GetMaxStack(AHB_YELLOW))); + else + stackCount = 1; + buyoutPrice *= urand(config->GetMinPrice(AHB_YELLOW), config->GetMaxPrice(AHB_YELLOW)); + buyoutPrice /= 100; + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_YELLOW), config->GetMaxBidPrice(AHB_YELLOW)); + bidPrice /= 100; + break; } - buyoutPrice *= urand(config->GetMinPrice(AHB_YELLOW), config->GetMaxPrice(AHB_YELLOW)) * stackCount; - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(AHB_YELLOW), config->GetMaxBidPrice(AHB_YELLOW)); - bidPrice /= 100; - break; - } - - if(auctionmgr.GetAItem(GUID_LOPART(item->GetGUID()))) - { - sLog.outError("Item %u not found", item->GetEntry()); - break; - } - if(!item->CanBeTraded()) - { - sLog.outError("Item %u can't be traded", item->GetEntry()); - break; - } - if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION)) - { - sLog.outError("Item %u is conjured or has a duration", item->GetEntry()); - break; - } - uint32 etime = urand(1,3); - switch(etime) - { + uint32 etime = urand(1,3); + switch(etime) + { case 1: etime = 43200; break; @@ -483,91 +452,144 @@ static void addNewAuctions(Player *AHBplayer, AHBConfig *config) default: etime = 86400; break; + } + item->SetCount(stackCount); + + uint32 dep = auctionmgr.GetAuctionDeposit(ahEntry, etime, item); + + AuctionEntry* auctionEntry = new AuctionEntry; + auctionEntry->Id = objmgr.GenerateAuctionID(); + auctionEntry->auctioneer = AuctioneerGUID; + auctionEntry->item_guidlow = item->GetGUIDLow(); + auctionEntry->item_template = item->GetEntry(); + auctionEntry->owner = AHBplayer->GetGUIDLow(); + auctionEntry->startbid = bidPrice * stackCount; + auctionEntry->buyout = buyoutPrice * stackCount; + auctionEntry->bidder = 0; + auctionEntry->bid = 0; + auctionEntry->deposit = dep; + auctionEntry->expire_time = (time_t) etime + time(NULL); + auctionEntry->auctionHouseEntry = ahEntry; + item->SaveToDB(); + item->RemoveFromUpdateQueueOf(AHBplayer); + auctionmgr.AddAItem(item); + auctionHouse->AddAuction(auctionEntry); + auctionEntry->SaveToDB(); + + switch(itemColor) + { + case 0: + ++greyItems; + break; + case 1: + ++whiteItems; + break; + case 2: + ++greenItems; + break; + case 3: + ++blueItems; + break; + case 4: + ++purpleItems; + break; + case 5: + ++orangeItems; + break; + case 6: + ++yellowItems; + break; + case 7: + ++greyTGoods; + break; + case 8: + ++whiteTGoods; + break; + case 9: + ++greenTGoods; + break; + case 10: + ++blueTGoods; + break; + case 11: + ++purpleTGoods; + break; + case 12: + ++orangeTGoods; + break; + case 13: + ++yellowTGoods; + break; + default: + break; + } } - uint32 dep = auctionmgr.GetAuctionDeposit( ahEntry, etime, item ); - - item->SetCount(stackCount); - - AuctionEntry* auctionEntry = new AuctionEntry; - auctionEntry->Id = objmgr.GenerateAuctionID(); - auctionEntry->auctioneer = AuctioneerGUID; - auctionEntry->item_guidlow = item->GetGUIDLow(); - auctionEntry->item_template = item->GetEntry(); - auctionEntry->owner = AHBplayer->GetGUIDLow(); - auctionEntry->startbid = bidPrice; - auctionEntry->buyout = buyoutPrice; - auctionEntry->bidder = 0; - auctionEntry->bid = 0; - auctionEntry->deposit = dep; - auctionEntry->expire_time = (time_t) etime + time(NULL); - auctionEntry->auctionHouseEntry = ahEntry; - item->SaveToDB(); - item->RemoveFromUpdateQueueOf(AHBplayer); - auctionmgr.AddAItem(item); - auctionHouse->AddAuction(auctionEntry); - auctionEntry->SaveToDB(); } } - -static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session) +void AuctionHouseBot::addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session) { if (!AHBBuyer) return; // Fetches content of selected AH AuctionHouseObject* auctionHouse = auctionmgr.GetAuctionsMap(config->GetAHFID()); - AuctionHouseObject::AuctionEntryMap::iterator itr; - - itr = auctionHouse->GetAuctionsBegin(); vector<uint32> possibleBids; - while (itr != auctionHouse->GetAuctionsEnd()) + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin();itr != auctionHouse->GetAuctionsEnd();++itr) { - AuctionHouseObject::AuctionEntryMap::iterator tmp = itr; - ++itr; // Check if the auction is ours // if it is, we skip this iteration. - if(tmp->second->owner == AHBplayerGUID) + if (itr->second->owner == AHBplayerGUID) { continue; } // Check that we haven't bidded in this auction already. - if(tmp->second->bidder != AHBplayerGUID) + if (itr->second->bidder != AHBplayerGUID) { - uint32 tmpdata = tmp->second->Id; + uint32 tmpdata = itr->second->Id; possibleBids.push_back(tmpdata); } } - uint32 bids = config->GetBidsPerInterval(); - for (uint32 count = 0; count < bids; ++count) + for (uint32 count = 1;count < config->GetBidsPerInterval();++count) { // Do we have anything to bid? If not, stop here. - if(possibleBids.empty()) - return; + if (possibleBids.empty()) + { + count = config->GetBidsPerInterval(); + continue; + } // Choose random auction from possible auctions uint32 vectorPos = urand(0, possibleBids.size() - 1); vector<uint32>::iterator iter = possibleBids.begin(); advance(iter, vectorPos); + // from auctionhousehandler.cpp, creates auction pointer & player pointer AuctionEntry* auction = auctionHouse->GetAuction(*iter); - // Erase the auction from the vector to prevent bidding on item in next itteration. + + // Erase the auction from the vector to prevent bidding on item in next iteration. possibleBids.erase(iter); + if (!auction) + { + if (debug_Out) sLog.outError("Item doesn't exist, perhaps bought already?"); + continue; + } + // get exact item information Item *pItem = auctionmgr.GetAItem(auction->item_guidlow); if (!pItem) { - sLog.outError("Item doesn't exists, perhaps bought already?"); - return; + if (debug_Out) sLog.outError("Item doesn't exist, perhaps bought already?"); + continue; } // get item prototype ItemPrototype const* prototype = objmgr.GetItemPrototype(auction->item_template); // check which price we have to use, startbid or if it is bidded already - if(debug_Out) + if (debug_Out) { sLog.outError("Auction Number: %u", auction->Id); sLog.outError("Item Template: %u", auction->item_template); @@ -577,17 +599,15 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World } uint32 currentprice; - if(auction->bid) + if (auction->bid) { currentprice = auction->bid; - if(debug_Out) - {sLog.outError("Current Price: %u", auction->bid);} + if (debug_Out) sLog.outError("Current Price: %u", auction->bid); } else { currentprice = auction->startbid; - if(debug_Out) - {sLog.outError("Current Price: %u", auction->startbid);} + if (debug_Out) sLog.outError("Current Price: %u", auction->startbid); } // Prepare portion from maximum bid @@ -595,7 +615,7 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World double tmprate = static_cast<double>(tmprate2); double bidrate = tmprate / 100; long double bidMax = 0; - if(debug_Out) + if (debug_Out) { sLog.outError("tmprate: %f", tmprate); sLog.outError("bidrate: %f", bidrate); @@ -604,140 +624,135 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World // check that bid has acceptable value and take bid based on vendorprice, stacksize and quality switch (BuyMethod) { - case 0: + case 0: { switch (prototype->Quality) { - case 0: - if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY); - break; - case 1: - if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE); - break; - case 2: - if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN); - break; - case 3: - if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE); - break; - case 4: - if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE); - case 5: - if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE); - case 6: - if(currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW)) - bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW); - break; - default: - // quality is something it shouldn't be, let's get out of here - if(debug_Out) - sLog.outError("bidMax(fail): %f", bidMax); - return; + case 0: + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY); + break; + case 1: + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE); + break; + case 2: + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN); + break; + case 3: + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE); + break; + case 4: + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE); + case 5: + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE); + case 6: + if (currentprice < prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW)) + bidMax = prototype->SellPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW); + break; + default: + // quality is something it shouldn't be, let's get out of here + if (debug_Out) sLog.outError("bidMax(fail): %f", bidMax); + continue; + break; } break; } - case 1: + case 1: { switch (prototype->Quality) { - case 0: - if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY); - break; - case 1: - if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE); - break; - case 2: - if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN); - break; - case 3: - if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE); - break; - case 4: - if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE); - case 5: - if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE); - case 6: - if(currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW)) - bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW); - break; - default: - // quality is something it shouldn't be, let's get out of here - if(debug_Out) - sLog.outError("bidMax(fail): %f", bidMax); - return; + case 0: + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREY); + break; + case 1: + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_WHITE); + break; + case 2: + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_GREEN); + break; + case 3: + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_BLUE); + break; + case 4: + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_PURPLE); + case 5: + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_ORANGE); + case 6: + if (currentprice < prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW)) + bidMax = prototype->BuyPrice * pItem->GetCount() * config->GetBuyerPrice(AHB_YELLOW); + break; + default: + // quality is something it shouldn't be, let's get out of here + if (debug_Out) sLog.outError("bidMax(fail): %f", bidMax); + continue; + break; } break; } - default: - bidMax = 0; - break; } - if(debug_Out) - sLog.outError("bidMax(succeed): %f", bidMax); + if (debug_Out) sLog.outError("bidMax(succeed): %f", bidMax); // check some special items, and do recalculating to their prices switch (prototype->Class) { // ammo - case 6: - bidMax = 0; - break; - default: - break; + case 6: + bidMax = 0; + break; + default: + break; } - if(bidMax == 0) + if (bidMax == 0) { // quality check failed to get bidmax, let's get out of here - return; + continue; } // Calculate our bid - long double bidvalue = currentprice + ( (bidMax - currentprice) * bidrate); + long double bidvalue = currentprice + ((bidMax - currentprice) * bidrate); // Convert to uint32 uint32 bidprice = static_cast<uint32>(bidvalue); - if(debug_Out) + if (debug_Out) { sLog.outError("bidprice: %u", bidprice); sLog.outError("bidvalue: %f", bidvalue); } // Check our bid is high enough to be valid. If not, correct it to minimum. - if((currentprice + auction->GetAuctionOutBid()) > bidprice) + if ((currentprice + auction->GetAuctionOutBid()) > bidprice) { bidprice = currentprice + auction->GetAuctionOutBid(); - if(debug_Out) - sLog.outError("bidprice(>): %u", bidprice); + if (debug_Out) sLog.outError("bidprice(>): %u", bidprice); } - // Check wether we do normal bid, or buyout + // Check whether we do normal bid, or buyout if ((bidprice < auction->buyout) || (auction->buyout == 0)) { if (auction->bidder > 0) { - if ( auction->bidder == AHBplayer->GetGUIDLow() ) + if (auction->bidder == AHBplayer->GetGUIDLow()) { - //pl->ModifyMoney( -int32(price - auction->bid)); + //pl->ModifyMoney(-int32(price - auction->bid)); } else { // mail to last bidder and return money - session->SendAuctionOutbiddedMail( auction , bidprice ); - //pl->ModifyMoney( -int32(price) ); + session->SendAuctionOutbiddedMail(auction , bidprice); + //pl->ModifyMoney(-int32(price)); } } @@ -750,24 +765,24 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World else { //buyout - if (AHBplayer->GetGUIDLow() == auction->bidder ) + if (AHBplayer->GetGUIDLow() == auction->bidder) { //pl->ModifyMoney(-int32(auction->buyout - auction->bid)); } else { //pl->ModifyMoney(-int32(auction->buyout)); - if ( auction->bidder ) + if (auction->bidder) { - session->SendAuctionOutbiddedMail( auction, auction->buyout ); + session->SendAuctionOutbiddedMail(auction, auction->buyout); } } auction->bidder = AHBplayer->GetGUIDLow(); auction->bid = auction->buyout; // Send mails to buyer & seller - auctionmgr.SendAuctionSuccessfulMail( auction ); - auctionmgr.SendAuctionWonMail( auction ); + auctionmgr.SendAuctionSuccessfulMail(auction); + auctionmgr.SendAuctionWonMail(auction); // Remove item from auctionhouse auctionmgr.RemoveAItem(auction->item_guidlow); @@ -779,21 +794,20 @@ static void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, World } } } -/////////////////////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////////////////////// -void AuctionHouseBot() + +void AuctionHouseBot::Update() { time_t _newrun = time(NULL); if ((!AHBSeller) && (!AHBBuyer)) - return; + return; WorldSession _session(AHBplayerAccount, NULL, SEC_PLAYER, true, 0, LOCALE_enUS); Player _AHBplayer(&_session); _AHBplayer.MinimalLoadFromDB(NULL, AHBplayerGUID); ObjectAccessor::Instance().AddObject(&_AHBplayer); - if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + // Add New Bids + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) { addNewAuctions(&_AHBplayer, &AllianceConfig); if (((_newrun - _lastrun_a) > (AllianceConfig.GetBiddingInterval() * 60)) && (AllianceConfig.GetBidsPerInterval() > 0)) @@ -801,6 +815,7 @@ void AuctionHouseBot() addNewAuctionBuyerBotBid(&_AHBplayer, &AllianceConfig, &_session); _lastrun_a = _newrun; } + addNewAuctions(&_AHBplayer, &HordeConfig); if (((_newrun - _lastrun_h) > (HordeConfig.GetBiddingInterval() *60)) && (HordeConfig.GetBidsPerInterval() > 0)) { @@ -808,6 +823,7 @@ void AuctionHouseBot() _lastrun_h = _newrun; } } + addNewAuctions(&_AHBplayer, &NeutralConfig); if (((_newrun - _lastrun_n) > (NeutralConfig.GetBiddingInterval() * 60)) && (NeutralConfig.GetBidsPerInterval() > 0)) { @@ -816,75 +832,128 @@ void AuctionHouseBot() } ObjectAccessor::Instance().RemoveObject(&_AHBplayer); } -/////////////////////////////////////////////////////////////////////////////// -// -/////////////////////////////////////////////////////////////////////////////// -void AuctionHouseBotInit() + +void AuctionHouseBot::Initialize() { + debug_Out = sConfig.GetBoolDefault("AuctionHouseBot.DEBUG", false); + AHBSeller = sConfig.GetBoolDefault("AuctionHouseBot.EnableSeller", false); AHBBuyer = sConfig.GetBoolDefault("AuctionHouseBot.EnableBuyer", false); + SellMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForSeller", false); + BuyMethod = sConfig.GetBoolDefault("AuctionHouseBot.UseBuyPriceForBuyer", false); + + AHBplayerAccount = sConfig.GetIntDefault("AuctionHouseBot.Account", 0); + AHBplayerGUID = sConfig.GetIntDefault("AuctionHouseBot.GUID", 0); + ItemsPerCycle = sConfig.GetIntDefault("AuctionHouseBot.ItemsPerCycle", 200); + + + //Begin Filters + + Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", false); + Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", true); + Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", false); + No_Bind = sConfig.GetBoolDefault("AuctionHouseBot.No_Bind", true); Bind_When_Picked_Up = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Picked_Up", false); Bind_When_Equipped = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Equipped", true); Bind_When_Use = sConfig.GetBoolDefault("AuctionHouseBot.Bind_When_Use", true); Bind_Quest_Item = sConfig.GetBoolDefault("AuctionHouseBot.Bind_Quest_Item", false); - if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) + DisableBeta_PTR_Unused = sConfig.GetBoolDefault("AuctionHouseBot.DisableBeta_PTR_Unused", false); + DisablePermEnchant = sConfig.GetBoolDefault("AuctionHouseBot.DisablePermEnchant", false); + DisableConjured = sConfig.GetBoolDefault("AuctionHouseBot.DisableConjured", false); + DisableGems = sConfig.GetBoolDefault("AuctionHouseBot.DisableGems", false); + DisableMoney = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoney", false); + DisableMoneyLoot = sConfig.GetBoolDefault("AuctionHouseBot.DisableMoneyLoot", false); + DisableLootable = sConfig.GetBoolDefault("AuctionHouseBot.DisableLootable", false); + DisableKeys = sConfig.GetBoolDefault("AuctionHouseBot.DisableKeys", false); + DisableDuration = sConfig.GetBoolDefault("AuctionHouseBot.DisableDuration", false); + DisableBOP_Or_Quest_NoReqLevel = sConfig.GetBoolDefault("AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel", false); + + DisableWarriorItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarriorItems", false); + DisablePaladinItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePaladinItems", false); + DisableHunterItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableHunterItems", false); + DisableRogueItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableRogueItems", false); + DisablePriestItems = sConfig.GetBoolDefault("AuctionHouseBot.DisablePriestItems", false); + DisableDKItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDKItems", false); + DisableShamanItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableShamanItems", false); + DisableMageItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableMageItems", false); + DisableWarlockItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableWarlockItems", false); + DisableUnusedClassItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableUnusedClassItems", false); + DisableDruidItems = sConfig.GetBoolDefault("AuctionHouseBot.DisableDruidItems", false); + + DisableItemsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowLevel", 0); + DisableItemsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveLevel", 0); + DisableTGsBelowLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowLevel", 0); + DisableTGsAboveLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveLevel", 0); + DisableItemsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowGUID", 0); + DisableItemsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveGUID", 0); + DisableTGsBelowGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowGUID", 0); + DisableTGsAboveGUID = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveGUID", 0); + DisableItemsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqLevel", 0); + DisableItemsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqLevel", 0); + DisableTGsBelowReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqLevel", 0); + DisableTGsAboveReqLevel = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqLevel", 0); + DisableItemsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsBelowReqSkillRank", 0); + DisableItemsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableItemsAboveReqSkillRank", 0); + DisableTGsBelowReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsBelowReqSkillRank", 0); + DisableTGsAboveReqSkillRank = sConfig.GetIntDefault("AuctionHouseBot.DisableTGsAboveReqSkillRank", 0); + + //End Filters + + if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) { - AuctionHouseBotLoadValues(&AllianceConfig); - AuctionHouseBotLoadValues(&HordeConfig); + LoadValues(&AllianceConfig); + LoadValues(&HordeConfig); } - AuctionHouseBotLoadValues(&NeutralConfig); + LoadValues(&NeutralConfig); if (AHBSeller) { - Vendor_Items = sConfig.GetBoolDefault("AuctionHouseBot.VendorItems", false); - Loot_Items = sConfig.GetBoolDefault("AuctionHouseBot.LootItems", true); - Other_Items = sConfig.GetBoolDefault("AuctionHouseBot.OtherItems", false); - QueryResult* results = (QueryResult*) NULL; char npcQuery[] = "SELECT distinct `item` FROM `npc_vendor`"; results = WorldDatabase.PQuery(npcQuery); if (results != NULL) { - do - { - Field* fields = results->Fetch(); - npcItems.push_back(fields[0].GetUInt32()); + do + { + Field* fields = results->Fetch(); + npcItems.push_back(fields[0].GetUInt32()); - } while (results->NextRow()); + } while (results->NextRow()); - delete results; + delete results; } else { - sLog.outString("AuctionHouseBot: \"%s\" failed", npcQuery); + if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", npcQuery); } char lootQuery[] = "SELECT `item` FROM `creature_loot_template` UNION " - "SELECT `item` FROM `disenchant_loot_template` UNION " - "SELECT `item` FROM `fishing_loot_template` UNION " - "SELECT `item` FROM `gameobject_loot_template` UNION " - "SELECT `item` FROM `item_loot_template` UNION " - "SELECT `item` FROM `pickpocketing_loot_template` UNION " - "SELECT `item` FROM `prospecting_loot_template` UNION " - "SELECT `item` FROM `skinning_loot_template`"; + "SELECT `item` FROM `disenchant_loot_template` UNION " + "SELECT `item` FROM `fishing_loot_template` UNION " + "SELECT `item` FROM `gameobject_loot_template` UNION " + "SELECT `item` FROM `item_loot_template` UNION " + "SELECT `item` FROM `milling_loot_template` UNION " + "SELECT `item` FROM `pickpocketing_loot_template` UNION " + "SELECT `item` FROM `prospecting_loot_template` UNION " + "SELECT `item` FROM `skinning_loot_template`"; results = WorldDatabase.PQuery(lootQuery); if (results != NULL) { - do - { - Field* fields = results->Fetch(); - lootItems.push_back(fields[0].GetUInt32()); + do + { + Field* fields = results->Fetch(); + lootItems.push_back(fields[0].GetUInt32()); - } while (results->NextRow()); + } while (results->NextRow()); - delete results; + delete results; } else { - sLog.outString("AuctionHouseBot: \"%s\" failed", lootQuery); + if (debug_Out) sLog.outString("AuctionHouseBot: \"%s\" failed", lootQuery); } for (uint32 itemID = 0; itemID < sItemStorage.MaxEntry; itemID++) @@ -892,7 +961,7 @@ void AuctionHouseBotInit() ItemPrototype const* prototype = objmgr.GetItemPrototype(itemID); if (prototype == NULL) - continue; + continue; switch (prototype->Bonding) { @@ -931,13 +1000,10 @@ void AuctionHouseBotInit() if (prototype->BuyPrice == 0) continue; break; - default: - continue; - break; } if ((prototype->Quality < 0) || (prototype->Quality > 6)) - continue; + continue; if (Vendor_Items == 0) { @@ -945,12 +1011,12 @@ void AuctionHouseBotInit() for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) { - if (itemID == npcItems[i]) - isVendorItem = true; + if (itemID == npcItems[i]) + isVendorItem = true; } if (isVendorItem) - continue; + continue; } if (Loot_Items == 0) @@ -959,12 +1025,12 @@ void AuctionHouseBotInit() for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) { - if (itemID == lootItems[i]) - isLootItem = true; + if (itemID == lootItems[i]) + isLootItem = true; } if (isLootItem) - continue; + continue; } if (Other_Items == 0) @@ -974,92 +1040,349 @@ void AuctionHouseBotInit() for (unsigned int i = 0; (i < npcItems.size()) && (!isVendorItem); i++) { - if (itemID == npcItems[i]) - isVendorItem = true; + if (itemID == npcItems[i]) + isVendorItem = true; } for (unsigned int i = 0; (i < lootItems.size()) && (!isLootItem); i++) { - if (itemID == lootItems[i]) - isLootItem = true; + if (itemID == lootItems[i]) + isLootItem = true; } if ((!isLootItem) && (!isVendorItem)) continue; } + //TODO:Make list of items and create a vector + // Disable PTR/Beta/Unused items + if ((DisableBeta_PTR_Unused) && ((prototype->ItemId == 21878) || (prototype->ItemId == 27774) || (prototype->ItemId == 27811) || (prototype->ItemId == 28117) || (prototype->ItemId == 28112))) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (PTR/Beta/Unused Item)", prototype->ItemId); + continue; + } + + // Disable permanent enchants items + if ((DisablePermEnchant) && (prototype->Class == ITEM_CLASS_PERMANENT)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Permanent Enchant Item)", prototype->ItemId); + continue; + } + + // Disable conjured items + if ((DisableConjured) && (prototype->IsConjuredConsumable())) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Conjured Consumable)", prototype->ItemId); + continue; + } + + // Disable gems + if ((DisableGems) && (prototype->Class == ITEM_CLASS_GEM)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Gem)", prototype->ItemId); + continue; + } + + // Disable money + if ((DisableMoney) && (prototype->Class == ITEM_CLASS_MONEY)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Money)", prototype->ItemId); + continue; + } + + // Disable moneyloot + if ((DisableMoneyLoot) && (prototype->MinMoneyLoot > 0)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (MoneyLoot)", prototype->ItemId); + continue; + } + + // Disable lootable items + if ((DisableLootable) && (prototype->Flags & 4)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Lootable Item)", prototype->ItemId); + continue; + } + + // Disable Keys + if ((DisableKeys) && (prototype->Class == ITEM_CLASS_KEY)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Quest Item)", prototype->ItemId); + continue; + } + + // Disable items with duration + if ((DisableDuration) && (prototype->Duration > 0)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Has a Duration)", prototype->ItemId); + continue; + } + + // Disable items which are BOP or Quest Items and have a required level lower than the item level + if ((DisableBOP_Or_Quest_NoReqLevel) && ((prototype->Bonding == BIND_WHEN_PICKED_UP || prototype->Bonding == BIND_QUEST_ITEM) && (prototype->RequiredLevel < prototype->ItemLevel))) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (BOP or BQI and Required Level is less than Item Level)", prototype->ItemId); + continue; + } + + // Disable items specifically for Warrior + if ((DisableWarriorItems) && (prototype->AllowableClass == 1)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Warrior Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Paladin + if ((DisablePaladinItems) && (prototype->AllowableClass == 2)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Paladin Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Hunter + if ((DisableHunterItems) && (prototype->AllowableClass == 4)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Hunter Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Rogue + if ((DisableRogueItems) && (prototype->AllowableClass == 8)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Rogue Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Priest + if ((DisablePriestItems) && (prototype->AllowableClass == 16)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Priest Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for DK + if ((DisableDKItems) && (prototype->AllowableClass == 32)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (DK Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Shaman + if ((DisableShamanItems) && (prototype->AllowableClass == 64)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Shaman Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Mage + if ((DisableMageItems) && (prototype->AllowableClass == 128)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Mage Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Warlock + if ((DisableWarlockItems) && (prototype->AllowableClass == 256)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Warlock Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Unused Class + if ((DisableUnusedClassItems) && (prototype->AllowableClass == 512)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Unused Item)", prototype->ItemId); + continue; + } + + // Disable items specifically for Druid + if ((DisableDruidItems) && (prototype->AllowableClass == 1024)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Druid Item)", prototype->ItemId); + continue; + } + + // Disable Items below level X + if ((DisableItemsBelowLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableItemsBelowLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items above level X + if ((DisableItemsAboveLevel) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableItemsAboveLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods below level X + if ((DisableTGsBelowLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel < DisableTGsBelowLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods above level X + if ((DisableTGsAboveLevel) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemLevel > DisableTGsAboveLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items below GUID X + if ((DisableItemsBelowGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableItemsBelowGUID)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items above GUID X + if ((DisableItemsAboveGUID) && (prototype->Class != ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableItemsAboveGUID)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Item Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods below GUID X + if ((DisableTGsBelowGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId < DisableTGsBelowGUID)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Trade Goods above GUID X + if ((DisableTGsAboveGUID) && (prototype->Class == ITEM_CLASS_TRADE_GOODS) && (prototype->ItemId > DisableTGsAboveGUID)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (Trade Good Level = %u)", prototype->ItemId, prototype->ItemLevel); + continue; + } + + // Disable Items for level lower than X + if ((DisableItemsBelowReqLevel) && (prototype->RequiredLevel < DisableItemsBelowReqLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Items for level higher than X + if ((DisableItemsAboveReqLevel) && (prototype->RequiredLevel > DisableItemsAboveReqLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Trade Goods for level lower than X + if ((DisableTGsBelowReqLevel) && (prototype->RequiredLevel < DisableTGsBelowReqLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Trade Goods for level higher than X + if ((DisableTGsAboveReqLevel) && (prototype->RequiredLevel > DisableTGsAboveReqLevel)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Trade Good %u disabled (RequiredLevel = %u)", prototype->ItemId, prototype->RequiredLevel); + continue; + } + + // Disable Items that require skill lower than X + if ((DisableItemsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableItemsBelowReqSkillRank)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + + // Disable Items that require skill higher than X + if ((DisableItemsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableItemsAboveReqSkillRank)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + + // Disable Trade Goods that require skill lower than X + if ((DisableTGsBelowReqSkillRank) && (prototype->RequiredSkillRank < DisableTGsBelowReqSkillRank)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + + // Disable Trade Goods that require skill higher than X + if ((DisableTGsAboveReqSkillRank) && (prototype->RequiredSkillRank > DisableTGsAboveReqSkillRank)) + { + if (debug_Out) sLog.outError("AuctionHouseBot: Item %u disabled (RequiredSkillRank = %u)", prototype->ItemId, prototype->RequiredSkillRank); + continue; + } + switch (prototype->Quality) { - case 0: + case 0: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - greyTradeGoodsBin.push_back(itemID); + greyTradeGoodsBin.push_back(itemID); else - greyItemsBin.push_back(itemID); + greyItemsBin.push_back(itemID); break; - case 1: + case 1: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - whiteTradeGoodsBin.push_back(itemID); + whiteTradeGoodsBin.push_back(itemID); else - whiteItemsBin.push_back(itemID); + whiteItemsBin.push_back(itemID); break; - case 2: + case 2: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - greenTradeGoodsBin.push_back(itemID); + greenTradeGoodsBin.push_back(itemID); else - greenItemsBin.push_back(itemID); + greenItemsBin.push_back(itemID); break; - case 3: + case 3: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - blueTradeGoodsBin.push_back(itemID); + blueTradeGoodsBin.push_back(itemID); else - blueItemsBin.push_back(itemID); + blueItemsBin.push_back(itemID); break; - case 4: + case 4: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - purpleTradeGoodsBin.push_back(itemID); + purpleTradeGoodsBin.push_back(itemID); else - purpleItemsBin.push_back(itemID); + purpleItemsBin.push_back(itemID); break; - case 5: + case 5: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - orangeTradeGoodsBin.push_back(itemID); + orangeTradeGoodsBin.push_back(itemID); else - orangeItemsBin.push_back(itemID); + orangeItemsBin.push_back(itemID); break; - case 6: + case 6: if (prototype->Class == ITEM_CLASS_TRADE_GOODS) - yellowTradeGoodsBin.push_back(itemID); + yellowTradeGoodsBin.push_back(itemID); else - yellowItemsBin.push_back(itemID); + yellowItemsBin.push_back(itemID); break; } } - if ( - (greyTradeGoodsBin.size() == 0) && - (whiteTradeGoodsBin.size() == 0) && - (greenTradeGoodsBin.size() == 0) && - (blueTradeGoodsBin.size() == 0) && - (purpleTradeGoodsBin.size() == 0) && - (orangeTradeGoodsBin.size() == 0) && - (yellowTradeGoodsBin.size() == 0) && - (greyItemsBin.size() == 0) && - (whiteItemsBin.size() == 0) && - (greenItemsBin.size() == 0) && - (blueItemsBin.size() == 0) && - (purpleItemsBin.size() == 0) && - (orangeItemsBin.size() == 0) && - (yellowItemsBin.size() == 0) - ) + if ((greyTradeGoodsBin.size() == 0) && + (whiteTradeGoodsBin.size() == 0) && + (greenTradeGoodsBin.size() == 0) && + (blueTradeGoodsBin.size() == 0) && + (purpleTradeGoodsBin.size() == 0) && + (orangeTradeGoodsBin.size() == 0) && + (yellowTradeGoodsBin.size() == 0) && + (greyItemsBin.size() == 0) && + (whiteItemsBin.size() == 0) && + (greenItemsBin.size() == 0) && + (blueItemsBin.size() == 0) && + (purpleItemsBin.size() == 0) && + (orangeItemsBin.size() == 0) && + (yellowItemsBin.size() == 0)) { - sLog.outString("AuctionHouseBot: No items"); - AHBSeller = 0; + sLog.outString("AuctionHouseBot: No items"); + AHBSeller = 0; } - sLog.outString("AuctionHouseBot:"); sLog.outString("loaded %u grey trade goods", greyTradeGoodsBin.size()); sLog.outString("loaded %u white trade goods", whiteTradeGoodsBin.size()); @@ -1078,9 +1401,9 @@ void AuctionHouseBotInit() } sLog.outString("AuctionHouseBot by Paradox (original by ChrisK) has been loaded."); sLog.outString("AuctionHouseBot now includes AHBuyer by Kerbe and Paradox"); - } -void AuctionHouseBotCommands(uint32 command, uint32 ahMapID, uint32 col, char* args) + +void AuctionHouseBot::Commands(uint32 command, uint32 ahMapID, uint32 col, char* args) { AHBConfig *config; switch (ahMapID) @@ -1133,32 +1456,33 @@ void AuctionHouseBotCommands(uint32 command, uint32 ahMapID, uint32 col, char* a while (itr != auctionHouse->GetAuctionsEnd()) { - if (itr->second->owner == AHBplayerGUID) - itr->second->expire_time = sWorld.GetGameTime(); + if (itr->second->owner == AHBplayerGUID) + itr->second->expire_time = sWorld.GetGameTime(); - ++itr; + ++itr; } - }break; + } + break; case 1: //min items { char * param1 = strtok(args, " "); uint32 minItems = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET minitems = '%u' WHERE auctionhouse = '%u'", minItems, ahMapID); config->SetMinItems(minItems); - }break; + } + break; case 2: //max items { char * param1 = strtok(args, " "); uint32 maxItems = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxitems = '%u' WHERE auctionhouse = '%u'", maxItems, ahMapID); config->SetMaxItems(maxItems); - }break; + } + break; case 3: //min time Deprecated (Place holder for future commands) - { - }break; + break; case 4: //max time Deprecated (Place holder for future commands) - { - }break; + break; case 5: //percentages { char * param1 = strtok(args, " "); @@ -1207,77 +1531,89 @@ void AuctionHouseBotCommands(uint32 command, uint32 ahMapID, uint32 col, char* a CharacterDatabase.PExecute("UPDATE auctionhousebot SET percentyellowitems = '%u' WHERE auctionhouse = '%u'", yellowi, ahMapID); CharacterDatabase.CommitTransaction(); config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); - }break; + } + break; case 6: //min prices { char * param1 = strtok(args, " "); uint32 minPrice = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET minprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minPrice, ahMapID); config->SetMinPrice(col, minPrice); - }break; + } + break; case 7: //max prices { char * param1 = strtok(args, " "); uint32 maxPrice = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxPrice, ahMapID); config->SetMaxPrice(col, maxPrice); - }break; + } + break; case 8: //min bid price { char * param1 = strtok(args, " "); uint32 minBidPrice = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET minbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), minBidPrice, ahMapID); config->SetMinBidPrice(col, minBidPrice); - }break; + } + break; case 9: //max bid price { char * param1 = strtok(args, " "); uint32 maxBidPrice = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxbidprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxBidPrice, ahMapID); config->SetMaxBidPrice(col, maxBidPrice); - }break; + } + break; case 10: //max stacks { char * param1 = strtok(args, " "); uint32 maxStack = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET maxstack%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), maxStack, ahMapID); config->SetMaxStack(col, maxStack); - }break; + } + break; case 11: //buyer bid prices { char * param1 = strtok(args, " "); uint32 buyerPrice = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerprice%s = '%u' WHERE auctionhouse = '%u'",color.c_str(), buyerPrice, ahMapID); config->SetBuyerPrice(col, buyerPrice); - }break; + } + break; case 12: //buyer bidding interval { char * param1 = strtok(args, " "); uint32 bidInterval = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbiddinginterval = '%u' WHERE auctionhouse = '%u'", bidInterval, ahMapID); config->SetBiddingInterval(bidInterval); - }break; + } + break; case 13: //buyer bids per interval { char * param1 = strtok(args, " "); uint32 bidsPerInterval = (uint32) strtoul(param1, NULL, 0); CharacterDatabase.PExecute("UPDATE auctionhousebot SET buyerbidsperinterval = '%u' WHERE auctionhouse = '%u'", bidsPerInterval, ahMapID); config->SetBidsPerInterval(bidsPerInterval); - }break; + } + break; default: break; } } -void AuctionHouseBotLoadValues(AHBConfig *config) + +void AuctionHouseBot::LoadValues(AHBConfig *config) { if (AHBSeller) { //load min and max items config->SetMinItems(CharacterDatabase.PQuery("SELECT minitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxItems(CharacterDatabase.PQuery("SELECT maxitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minItems = %u", config->GetMinItems()); - sLog.outError("maxItems = %u", config->GetMaxItems());} + if (debug_Out) + { + sLog.outError("minItems = %u", config->GetMinItems()); + sLog.outError("maxItems = %u", config->GetMaxItems()); + } //load percentages uint32 greytg = CharacterDatabase.PQuery("SELECT percentgreytradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); uint32 whitetg = CharacterDatabase.PQuery("SELECT percentwhitetradegoods FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); @@ -1294,7 +1630,7 @@ void AuctionHouseBotLoadValues(AHBConfig *config) uint32 orangei = CharacterDatabase.PQuery("SELECT percentorangeitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); uint32 yellowi = CharacterDatabase.PQuery("SELECT percentyellowitems FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32(); config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); - if(debug_Out) + if (debug_Out) { sLog.outError("percentGreyTradeGoods = %u", config->GetPercentages(AHB_GREY_TG)); sLog.outError("percentWhiteTradeGoods = %u", config->GetPercentages(AHB_WHITE_TG)); @@ -1314,104 +1650,160 @@ void AuctionHouseBotLoadValues(AHBConfig *config) //load min and max prices config->SetMinPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minPriceGrey = %u", config->GetMinPrice(AHB_GREY)); - sLog.outError("maxPriceGrey = %u", config->GetMaxPrice(AHB_GREY));} + if (debug_Out) + { + sLog.outError("minPriceGrey = %u", config->GetMinPrice(AHB_GREY)); + sLog.outError("maxPriceGrey = %u", config->GetMaxPrice(AHB_GREY)); + } config->SetMinPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minPriceWhite = %u", config->GetMinPrice(AHB_WHITE)); - sLog.outError("maxPriceWhite = %u", config->GetMaxPrice(AHB_WHITE));} + if (debug_Out) + { + sLog.outError("minPriceWhite = %u", config->GetMinPrice(AHB_WHITE)); + sLog.outError("maxPriceWhite = %u", config->GetMaxPrice(AHB_WHITE)); + } config->SetMinPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minPriceGreen = %u", config->GetMinPrice(AHB_GREEN)); - sLog.outError("maxPriceGreen = %u", config->GetMaxPrice(AHB_GREEN));} + if (debug_Out) + { + sLog.outError("minPriceGreen = %u", config->GetMinPrice(AHB_GREEN)); + sLog.outError("maxPriceGreen = %u", config->GetMaxPrice(AHB_GREEN)); + } config->SetMinPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minPriceBlue = %u", config->GetMinPrice(AHB_BLUE)); - sLog.outError("maxPriceBlue = %u", config->GetMaxPrice(AHB_BLUE));} + if (debug_Out) + { + sLog.outError("minPriceBlue = %u", config->GetMinPrice(AHB_BLUE)); + sLog.outError("maxPriceBlue = %u", config->GetMaxPrice(AHB_BLUE)); + } config->SetMinPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minPricePurple = %u", config->GetMinPrice(AHB_PURPLE)); - sLog.outError("maxPricePurple = %u", config->GetMaxPrice(AHB_PURPLE));} + if (debug_Out) + { + sLog.outError("minPricePurple = %u", config->GetMinPrice(AHB_PURPLE)); + sLog.outError("maxPricePurple = %u", config->GetMaxPrice(AHB_PURPLE)); + } config->SetMinPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minPriceOrange = %u", config->GetMinPrice(AHB_ORANGE)); - sLog.outError("maxPriceOrange = %u", config->GetMaxPrice(AHB_ORANGE));} + if (debug_Out) + { + sLog.outError("minPriceOrange = %u", config->GetMinPrice(AHB_ORANGE)); + sLog.outError("maxPriceOrange = %u", config->GetMaxPrice(AHB_ORANGE)); + } config->SetMinPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetMaxPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minPriceYellow = %u", config->GetMinPrice(AHB_YELLOW)); - sLog.outError("maxPriceYellow = %u", config->GetMaxPrice(AHB_YELLOW));} + if (debug_Out) + { + sLog.outError("minPriceYellow = %u", config->GetMinPrice(AHB_YELLOW)); + sLog.outError("maxPriceYellow = %u", config->GetMaxPrice(AHB_YELLOW)); + } //load min and max bid prices config->SetMinBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT minbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError(",minBidPriceGrey = %u", config->GetMinBidPrice(AHB_GREY));} + if (debug_Out) + { + sLog.outError("minBidPriceGrey = %u", config->GetMinBidPrice(AHB_GREY)); + } config->SetMaxBidPrice(AHB_GREY, CharacterDatabase.PQuery("SELECT maxbidpricegrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxBidPriceGrey = %u", config->GetMaxBidPrice(AHB_GREY));} + if (debug_Out) + { + sLog.outError("maxBidPriceGrey = %u", config->GetMaxBidPrice(AHB_GREY)); + } config->SetMinBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT minbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError(",minBidPriceWhite = %u", config->GetMinBidPrice(AHB_WHITE));} + if (debug_Out) + { + sLog.outError("minBidPriceWhite = %u", config->GetMinBidPrice(AHB_WHITE)); + } config->SetMaxBidPrice(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxbidpricewhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxBidPriceWhite = %u", config->GetMaxBidPrice(AHB_WHITE));} + if (debug_Out) + { + sLog.outError("maxBidPriceWhite = %u", config->GetMaxBidPrice(AHB_WHITE)); + } config->SetMinBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT minbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minBidPriceGreen = %u", config->GetMinBidPrice(AHB_GREEN));} + if (debug_Out) + { + sLog.outError("minBidPriceGreen = %u", config->GetMinBidPrice(AHB_GREEN)); + } config->SetMaxBidPrice(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxbidpricegreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxBidPriceGreen = %u", config->GetMaxBidPrice(AHB_GREEN));} + if (debug_Out) + { + sLog.outError("maxBidPriceGreen = %u", config->GetMaxBidPrice(AHB_GREEN)); + } config->SetMinBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT minbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE));} + if (debug_Out) + { + sLog.outError("minBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE)); + } config->SetMaxBidPrice(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxbidpriceblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE));} + if (debug_Out) + { + sLog.outError("maxBidPriceBlue = %u", config->GetMinBidPrice(AHB_BLUE)); + } config->SetMinBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT minbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minBidPricePurple = %u", config->GetMinBidPrice(AHB_PURPLE));} + if (debug_Out) + { + sLog.outError("minBidPricePurple = %u", config->GetMinBidPrice(AHB_PURPLE)); + } config->SetMaxBidPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxbidpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxBidPricePurple = %u", config->GetMaxBidPrice(AHB_PURPLE));} + if (debug_Out) + { + sLog.outError("maxBidPricePurple = %u", config->GetMaxBidPrice(AHB_PURPLE)); + } config->SetMinBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT minbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minBidPriceOrange = %u", config->GetMinBidPrice(AHB_ORANGE));} + if (debug_Out) + { + sLog.outError("minBidPriceOrange = %u", config->GetMinBidPrice(AHB_ORANGE)); + } config->SetMaxBidPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxbidpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxBidPriceOrange = %u", config->GetMaxBidPrice(AHB_ORANGE));} + if (debug_Out) + { + sLog.outError("maxBidPriceOrange = %u", config->GetMaxBidPrice(AHB_ORANGE)); + } config->SetMinBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT minbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("minBidPriceYellow = %u", config->GetMinBidPrice(AHB_YELLOW));} + if (debug_Out) + { + sLog.outError("minBidPriceYellow = %u", config->GetMinBidPrice(AHB_YELLOW)); + } config->SetMaxBidPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxbidpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxBidPriceYellow = %u", config->GetMaxBidPrice(AHB_YELLOW));} + if (debug_Out) + { + sLog.outError("maxBidPriceYellow = %u", config->GetMaxBidPrice(AHB_YELLOW)); + } //load max stacks config->SetMaxStack(AHB_GREY, CharacterDatabase.PQuery("SELECT maxstackgrey FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxStackGrey = %u", config->GetMaxStack(AHB_GREY));} + if (debug_Out) + { + sLog.outError("maxStackGrey = %u", config->GetMaxStack(AHB_GREY)); + } config->SetMaxStack(AHB_WHITE, CharacterDatabase.PQuery("SELECT maxstackwhite FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxStackWhite = %u", config->GetMaxStack(AHB_WHITE));} + if (debug_Out) + { + sLog.outError("maxStackWhite = %u", config->GetMaxStack(AHB_WHITE)); + } config->SetMaxStack(AHB_GREEN, CharacterDatabase.PQuery("SELECT maxstackgreen FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxStackGreen = %u", config->GetMaxStack(AHB_GREEN));} + if (debug_Out) + { + sLog.outError("maxStackGreen = %u", config->GetMaxStack(AHB_GREEN)); + } config->SetMaxStack(AHB_BLUE, CharacterDatabase.PQuery("SELECT maxstackblue FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxStackBlue = %u", config->GetMaxStack(AHB_BLUE));} + if (debug_Out) + { + sLog.outError("maxStackBlue = %u", config->GetMaxStack(AHB_BLUE)); + } config->SetMaxStack(AHB_PURPLE, CharacterDatabase.PQuery("SELECT maxstackpurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxStackPurple = %u", config->GetMaxStack(AHB_PURPLE));} + if (debug_Out) + { + sLog.outError("maxStackPurple = %u", config->GetMaxStack(AHB_PURPLE)); + } config->SetMaxStack(AHB_ORANGE, CharacterDatabase.PQuery("SELECT maxstackorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxStackOrange = %u", config->GetMaxStack(AHB_ORANGE));} + if (debug_Out) + { + sLog.outError("maxStackOrange = %u", config->GetMaxStack(AHB_ORANGE)); + } config->SetMaxStack(AHB_YELLOW, CharacterDatabase.PQuery("SELECT maxstackyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("maxStackYellow = %u", config->GetMaxStack(AHB_YELLOW));} + if (debug_Out) + { + sLog.outError("maxStackYellow = %u", config->GetMaxStack(AHB_YELLOW)); + } } if (AHBBuyer) { @@ -1423,7 +1815,7 @@ void AuctionHouseBotLoadValues(AHBConfig *config) config->SetBuyerPrice(AHB_PURPLE, CharacterDatabase.PQuery("SELECT buyerpricepurple FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetBuyerPrice(AHB_ORANGE, CharacterDatabase.PQuery("SELECT buyerpriceorange FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); config->SetBuyerPrice(AHB_YELLOW, CharacterDatabase.PQuery("SELECT buyerpriceyellow FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) + if (debug_Out) { sLog.outError("buyerPriceGrey = %u", config->GetBuyerPrice(AHB_GREY)); sLog.outError("buyerPriceWhite = %u", config->GetBuyerPrice(AHB_WHITE)); @@ -1435,11 +1827,15 @@ void AuctionHouseBotLoadValues(AHBConfig *config) } //load bidding interval config->SetBiddingInterval(CharacterDatabase.PQuery("SELECT buyerbiddinginterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("buyerBiddingInterval = %u", config->GetBiddingInterval());} + if (debug_Out) + { + sLog.outError("buyerBiddingInterval = %u", config->GetBiddingInterval()); + } //load bids per interval config->SetBidsPerInterval(CharacterDatabase.PQuery("SELECT buyerbidsperinterval FROM auctionhousebot WHERE auctionhouse = %u",config->GetAHID())->Fetch()->GetUInt32()); - if(debug_Out) - {sLog.outError("buyerBidsPerInterval = %u", config->GetBidsPerInterval());} + if (debug_Out) + { + sLog.outError("buyerBidsPerInterval = %u", config->GetBidsPerInterval()); + } } } diff --git a/src/game/AuctionHouseBot.h b/src/game/AuctionHouseBot.h index 906a857d206..df7e842ad4f 100644 --- a/src/game/AuctionHouseBot.h +++ b/src/game/AuctionHouseBot.h @@ -1,10 +1,9 @@ #ifndef AUCTION_HOUSE_BOT_H #define AUCTION_HOUSE_BOT_H -#include "Common.h" +#include "World.h" #include "Config/ConfigEnv.h" - -#include "Log.h" +#include "ace/Vector_T.h" #define AHB_GREY 0 #define AHB_WHITE 1 @@ -27,153 +26,149 @@ #define AHB_PURPLE_I 11 #define AHB_ORANGE_I 12 #define AHB_YELLOW_I 13 -#define AHBplayerAccount sConfig.GetIntDefault("AuctionHouseBot.Account", 0) -#define AHBplayerGUID sConfig.GetIntDefault("AuctionHouseBot.GUID", 0) -#define ItemsPerCycle sConfig.GetIntDefault("AuctionHouseBot.ItemsPerCycle", 200) -#define SellMethod sConfig.GetIntDefault("AuctionHouseBot.UseBuyPriceForSeller", 1) -#define BuyMethod sConfig.GetIntDefault("AuctionHouseBot.UseBuyPriceForBuyer", 0) class AHBConfig { - private: - uint32 AHID; - uint32 AHFID; - uint32 minItems; - uint32 maxItems; - uint32 percentGreyTradeGoods; - uint32 percentWhiteTradeGoods; - uint32 percentGreenTradeGoods; - uint32 percentBlueTradeGoods; - uint32 percentPurpleTradeGoods; - uint32 percentOrangeTradeGoods; - uint32 percentYellowTradeGoods; - uint32 percentGreyItems; - uint32 percentWhiteItems; - uint32 percentGreenItems; - uint32 percentBlueItems; - uint32 percentPurpleItems; - uint32 percentOrangeItems; - uint32 percentYellowItems; - uint32 minPriceGrey; - uint32 maxPriceGrey; - uint32 minBidPriceGrey; - uint32 maxBidPriceGrey; - uint32 maxStackGrey; - uint32 minPriceWhite; - uint32 maxPriceWhite; - uint32 minBidPriceWhite; - uint32 maxBidPriceWhite; - uint32 maxStackWhite; - uint32 minPriceGreen; - uint32 maxPriceGreen; - uint32 minBidPriceGreen; - uint32 maxBidPriceGreen; - uint32 maxStackGreen; - uint32 minPriceBlue; - uint32 maxPriceBlue; - uint32 minBidPriceBlue; - uint32 maxBidPriceBlue; - uint32 maxStackBlue; - uint32 minPricePurple; - uint32 maxPricePurple; - uint32 minBidPricePurple; - uint32 maxBidPricePurple; - uint32 maxStackPurple; - uint32 minPriceOrange; - uint32 maxPriceOrange; - uint32 minBidPriceOrange; - uint32 maxBidPriceOrange; - uint32 maxStackOrange; - uint32 minPriceYellow; - uint32 maxPriceYellow; - uint32 minBidPriceYellow; - uint32 maxBidPriceYellow; - uint32 maxStackYellow; +private: + uint32 AHID; + uint32 AHFID; + uint32 minItems; + uint32 maxItems; + uint32 percentGreyTradeGoods; + uint32 percentWhiteTradeGoods; + uint32 percentGreenTradeGoods; + uint32 percentBlueTradeGoods; + uint32 percentPurpleTradeGoods; + uint32 percentOrangeTradeGoods; + uint32 percentYellowTradeGoods; + uint32 percentGreyItems; + uint32 percentWhiteItems; + uint32 percentGreenItems; + uint32 percentBlueItems; + uint32 percentPurpleItems; + uint32 percentOrangeItems; + uint32 percentYellowItems; + uint32 minPriceGrey; + uint32 maxPriceGrey; + uint32 minBidPriceGrey; + uint32 maxBidPriceGrey; + uint32 maxStackGrey; + uint32 minPriceWhite; + uint32 maxPriceWhite; + uint32 minBidPriceWhite; + uint32 maxBidPriceWhite; + uint32 maxStackWhite; + uint32 minPriceGreen; + uint32 maxPriceGreen; + uint32 minBidPriceGreen; + uint32 maxBidPriceGreen; + uint32 maxStackGreen; + uint32 minPriceBlue; + uint32 maxPriceBlue; + uint32 minBidPriceBlue; + uint32 maxBidPriceBlue; + uint32 maxStackBlue; + uint32 minPricePurple; + uint32 maxPricePurple; + uint32 minBidPricePurple; + uint32 maxBidPricePurple; + uint32 maxStackPurple; + uint32 minPriceOrange; + uint32 maxPriceOrange; + uint32 minBidPriceOrange; + uint32 maxBidPriceOrange; + uint32 maxStackOrange; + uint32 minPriceYellow; + uint32 maxPriceYellow; + uint32 minBidPriceYellow; + uint32 maxBidPriceYellow; + uint32 maxStackYellow; + + uint32 buyerPriceGrey; + uint32 buyerPriceWhite; + uint32 buyerPriceGreen; + uint32 buyerPriceBlue; + uint32 buyerPricePurple; + uint32 buyerPriceOrange; + uint32 buyerPriceYellow; + uint32 buyerBiddingInterval; + uint32 buyerBidsPerInterval; - uint32 buyerPriceGrey; - uint32 buyerPriceWhite; - uint32 buyerPriceGreen; - uint32 buyerPriceBlue; - uint32 buyerPricePurple; - uint32 buyerPriceOrange; - uint32 buyerPriceYellow; - uint32 buyerBiddingInterval; - uint32 buyerBidsPerInterval; + uint32 greytgp; + uint32 whitetgp; + uint32 greentgp; + uint32 bluetgp; + uint32 purpletgp; + uint32 orangetgp; + uint32 yellowtgp; + uint32 greyip; + uint32 whiteip; + uint32 greenip; + uint32 blueip; + uint32 purpleip; + uint32 orangeip; + uint32 yellowip; - uint32 greytgp; - uint32 whitetgp; - uint32 greentgp; - uint32 bluetgp; - uint32 purpletgp; - uint32 orangetgp; - uint32 yellowtgp; - uint32 greyip; - uint32 whiteip; - uint32 greenip; - uint32 blueip; - uint32 purpleip; - uint32 orangeip; - uint32 yellowip; - public: +public: AHBConfig(uint32 ahid) - { - AHID = ahid; - switch(ahid) - { - case 2: - AHFID = 55; - break; - case 6: + { + AHID = ahid; + switch(ahid) + { + case 2: + AHFID = 55; + break; + case 6: AHFID = 29; - break; - case 7: + break; + case 7: AHFID = 120; - break; - default: + break; + default: AHFID = 120; - break; - } - } - AHBConfig() - { - } - uint32 GetAHID() - { - return AHID; - } - uint32 GetAHFID() - { - return AHFID; - } - void SetMinItems(uint32 value) - { - minItems = value; - } - uint32 GetMinItems() - { + break; + } + } + AHBConfig() + { + } + uint32 GetAHID() + { + return AHID; + } + uint32 GetAHFID() + { + return AHFID; + } + void SetMinItems(uint32 value) + { + minItems = value; + } + uint32 GetMinItems() + { if ((minItems == 0) && (maxItems)) return maxItems; else if ((maxItems) && (minItems > maxItems)) return maxItems; else return minItems; - } - void SetMaxItems(uint32 value) - { - maxItems = value; - CalculatePercents(); - } - uint32 GetMaxItems() - { + } + void SetMaxItems(uint32 value) + { + maxItems = value; + CalculatePercents(); + } + uint32 GetMaxItems() + { return maxItems; - } - void SetPercentages(uint32 greytg, uint32 whitetg, uint32 greentg, uint32 bluetg, uint32 purpletg, uint32 orangetg, uint32 yellowtg, uint32 greyi, uint32 whitei, uint32 greeni, uint32 bluei, uint32 purplei, uint32 orangei, uint32 yellowi) - { + } + void SetPercentages(uint32 greytg, uint32 whitetg, uint32 greentg, uint32 bluetg, uint32 purpletg, uint32 orangetg, uint32 yellowtg, uint32 greyi, uint32 whitei, uint32 greeni, uint32 bluei, uint32 purplei, uint32 orangei, uint32 yellowi) + { uint32 totalPercent = greytg + whitetg + greentg + bluetg + purpletg + orangetg + yellowtg + greyi + whitei + greeni + bluei + purplei + orangei + yellowi; if (totalPercent == 0) { - maxItems = 0; + maxItems = 0; } else if (totalPercent != 100) { @@ -207,92 +202,92 @@ class AHBConfig percentOrangeItems = orangei; percentYellowItems = yellowi; CalculatePercents(); - } - uint32 GetPercentages(uint32 color) - { - switch(color) - { - case AHB_GREY_TG: + } + uint32 GetPercentages(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: return percentGreyTradeGoods; - break; - case AHB_WHITE_TG: + break; + case AHB_WHITE_TG: return percentWhiteTradeGoods; - break; - case AHB_GREEN_TG: + break; + case AHB_GREEN_TG: return percentGreenTradeGoods; - break; - case AHB_BLUE_TG: + break; + case AHB_BLUE_TG: return percentBlueTradeGoods; - break; - case AHB_PURPLE_TG: + break; + case AHB_PURPLE_TG: return percentPurpleTradeGoods; - break; - case AHB_ORANGE_TG: + break; + case AHB_ORANGE_TG: return percentOrangeTradeGoods; - break; - case AHB_YELLOW_TG: + break; + case AHB_YELLOW_TG: return percentYellowTradeGoods; - break; - case AHB_GREY_I: + break; + case AHB_GREY_I: return percentGreyItems; - break; - case AHB_WHITE_I: + break; + case AHB_WHITE_I: return percentWhiteItems; - break; - case AHB_GREEN_I: + break; + case AHB_GREEN_I: return percentGreenItems; - break; - case AHB_BLUE_I: + break; + case AHB_BLUE_I: return percentBlueItems; - break; - case AHB_PURPLE_I: + break; + case AHB_PURPLE_I: return percentPurpleItems; - break; - case AHB_ORANGE_I: + break; + case AHB_ORANGE_I: return percentOrangeItems; - break; - case AHB_YELLOW_I: + break; + case AHB_YELLOW_I: return percentYellowItems; - break; - default: + break; + default: return 0; - break; - } - } - void SetMinPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: + break; + } + } + void SetMinPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: minPriceGrey = value; - break; - case AHB_WHITE: + break; + case AHB_WHITE: minPriceWhite = value; - break; - case AHB_GREEN: + break; + case AHB_GREEN: minPriceGreen = value; - break; - case AHB_BLUE: + break; + case AHB_BLUE: minPriceBlue = value; - break; - case AHB_PURPLE: + break; + case AHB_PURPLE: minPricePurple = value; - break; - case AHB_ORANGE: + break; + case AHB_ORANGE: minPriceOrange = value; - break; - case AHB_YELLOW: + break; + case AHB_YELLOW: minPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMinPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: + break; + default: + break; + } + } + uint32 GetMinPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: { if (minPriceGrey == 0) return 100; @@ -302,7 +297,7 @@ class AHBConfig return minPriceGrey; break; } - case AHB_WHITE: + case AHB_WHITE: { if (minPriceWhite == 0) return 150; @@ -312,7 +307,7 @@ class AHBConfig return minPriceWhite; break; } - case AHB_GREEN: + case AHB_GREEN: { if (minPriceGreen == 0) return 200; @@ -322,7 +317,7 @@ class AHBConfig return minPriceGreen; break; } - case AHB_BLUE: + case AHB_BLUE: { if (minPriceBlue == 0) return 250; @@ -332,7 +327,7 @@ class AHBConfig return minPriceBlue; break; } - case AHB_PURPLE: + case AHB_PURPLE: { if (minPricePurple == 0) return 300; @@ -342,7 +337,7 @@ class AHBConfig return minPricePurple; break; } - case AHB_ORANGE: + case AHB_ORANGE: { if (minPriceOrange == 0) return 400; @@ -352,7 +347,7 @@ class AHBConfig return minPriceOrange; break; } - case AHB_YELLOW: + case AHB_YELLOW: { if (minPriceYellow == 0) return 500; @@ -362,47 +357,47 @@ class AHBConfig return minPriceYellow; break; } - default: - { - return 0; - break; - } + default: + { + return 0; + break; + } } - } - void SetMaxPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: + } + void SetMaxPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: maxPriceGrey = value; - break; - case AHB_WHITE: + break; + case AHB_WHITE: maxPriceWhite = value; - break; - case AHB_GREEN: + break; + case AHB_GREEN: maxPriceGreen = value; - break; - case AHB_BLUE: + break; + case AHB_BLUE: maxPriceBlue = value; - break; - case AHB_PURPLE: + break; + case AHB_PURPLE: maxPricePurple = value; - break; - case AHB_ORANGE: + break; + case AHB_ORANGE: maxPriceOrange = value; - break; - case AHB_YELLOW: + break; + case AHB_YELLOW: maxPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMaxPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: + break; + default: + break; + } + } + uint32 GetMaxPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: { if (maxPriceGrey == 0) return 150; @@ -410,7 +405,7 @@ class AHBConfig return maxPriceGrey; break; } - case AHB_WHITE: + case AHB_WHITE: { if (maxPriceWhite == 0) return 250; @@ -418,7 +413,7 @@ class AHBConfig return maxPriceWhite; break; } - case AHB_GREEN: + case AHB_GREEN: { if (maxPriceGreen == 0) return 300; @@ -426,7 +421,7 @@ class AHBConfig return maxPriceGreen; break; } - case AHB_BLUE: + case AHB_BLUE: { if (maxPriceBlue == 0) return 350; @@ -434,7 +429,7 @@ class AHBConfig return maxPriceBlue; break; } - case AHB_PURPLE: + case AHB_PURPLE: { if (maxPricePurple == 0) return 450; @@ -442,7 +437,7 @@ class AHBConfig return maxPricePurple; break; } - case AHB_ORANGE: + case AHB_ORANGE: { if (maxPriceOrange == 0) return 550; @@ -450,7 +445,7 @@ class AHBConfig return maxPriceOrange; break; } - case AHB_YELLOW: + case AHB_YELLOW: { if (maxPriceYellow == 0) return 650; @@ -458,47 +453,47 @@ class AHBConfig return maxPriceYellow; break; } - default: - { - return 0; - break; - } + default: + { + return 0; + break; + } } - } - void SetMinBidPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: + } + void SetMinBidPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: minBidPriceGrey = value; - break; - case AHB_WHITE: + break; + case AHB_WHITE: minBidPriceWhite = value; - break; - case AHB_GREEN: + break; + case AHB_GREEN: minBidPriceGreen = value; - break; - case AHB_BLUE: + break; + case AHB_BLUE: minBidPriceBlue = value; - break; - case AHB_PURPLE: + break; + case AHB_PURPLE: minBidPricePurple = value; - break; - case AHB_ORANGE: + break; + case AHB_ORANGE: minBidPriceOrange = value; - break; - case AHB_YELLOW: + break; + case AHB_YELLOW: minBidPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMinBidPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: + break; + default: + break; + } + } + uint32 GetMinBidPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: { if (minBidPriceGrey > 100) return 100; @@ -506,7 +501,7 @@ class AHBConfig return minBidPriceGrey; break; } - case AHB_WHITE: + case AHB_WHITE: { if (minBidPriceWhite > 100) return 100; @@ -514,7 +509,7 @@ class AHBConfig return minBidPriceWhite; break; } - case AHB_GREEN: + case AHB_GREEN: { if (minBidPriceGreen > 100) return 100; @@ -522,7 +517,7 @@ class AHBConfig return minBidPriceGreen; break; } - case AHB_BLUE: + case AHB_BLUE: { if (minBidPriceBlue > 100) return 100; @@ -530,7 +525,7 @@ class AHBConfig return minBidPriceBlue; break; } - case AHB_PURPLE: + case AHB_PURPLE: { if (minBidPricePurple > 100) return 100; @@ -538,7 +533,7 @@ class AHBConfig return minBidPricePurple; break; } - case AHB_ORANGE: + case AHB_ORANGE: { if (minBidPriceOrange > 100) return 100; @@ -546,7 +541,7 @@ class AHBConfig return minBidPriceOrange; break; } - case AHB_YELLOW: + case AHB_YELLOW: { if (minBidPriceYellow > 100) return 100; @@ -554,47 +549,47 @@ class AHBConfig return minBidPriceYellow; break; } - default: - { - return 0; - break; - } - } - } - void SetMaxBidPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: + default: + { + return 0; + break; + } + } + } + void SetMaxBidPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: maxBidPriceGrey = value; - break; - case AHB_WHITE: + break; + case AHB_WHITE: maxBidPriceWhite = value; - break; - case AHB_GREEN: + break; + case AHB_GREEN: maxBidPriceGreen = value; - break; - case AHB_BLUE: + break; + case AHB_BLUE: maxBidPriceBlue = value; - break; - case AHB_PURPLE: + break; + case AHB_PURPLE: maxBidPricePurple = value; - break; - case AHB_ORANGE: + break; + case AHB_ORANGE: maxBidPriceOrange = value; - break; - case AHB_YELLOW: + break; + case AHB_YELLOW: maxBidPriceYellow = value; - break; - default: - break; - } - } - uint32 GetMaxBidPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: + break; + default: + break; + } + } + uint32 GetMaxBidPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: { if (maxBidPriceGrey > 100) return 100; @@ -602,7 +597,7 @@ class AHBConfig return maxBidPriceGrey; break; } - case AHB_WHITE: + case AHB_WHITE: { if (maxBidPriceWhite > 100) return 100; @@ -610,7 +605,7 @@ class AHBConfig return maxBidPriceWhite; break; } - case AHB_GREEN: + case AHB_GREEN: { if (maxBidPriceGreen > 100) return 100; @@ -618,7 +613,7 @@ class AHBConfig return maxBidPriceGreen; break; } - case AHB_BLUE: + case AHB_BLUE: { if (maxBidPriceBlue > 100) return 100; @@ -626,7 +621,7 @@ class AHBConfig return maxBidPriceBlue; break; } - case AHB_PURPLE: + case AHB_PURPLE: { if (maxBidPricePurple > 100) return 100; @@ -634,7 +629,7 @@ class AHBConfig return maxBidPricePurple; break; } - case AHB_ORANGE: + case AHB_ORANGE: { if (maxBidPriceOrange > 100) return 100; @@ -642,7 +637,7 @@ class AHBConfig return maxBidPriceOrange; break; } - case AHB_YELLOW: + case AHB_YELLOW: { if (maxBidPriceYellow > 100) return 100; @@ -650,157 +645,157 @@ class AHBConfig return maxBidPriceYellow; break; } - default: - { - return 0; - break; - } - } - } - void SetMaxStack(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: + default: + { + return 0; + break; + } + } + } + void SetMaxStack(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: maxStackGrey = value; - break; - case AHB_WHITE: + break; + case AHB_WHITE: maxStackWhite = value; - break; - case AHB_GREEN: + break; + case AHB_GREEN: maxStackGreen = value; - break; - case AHB_BLUE: + break; + case AHB_BLUE: maxStackBlue = value; - break; - case AHB_PURPLE: + break; + case AHB_PURPLE: maxStackPurple = value; - break; - case AHB_ORANGE: + break; + case AHB_ORANGE: maxStackOrange = value; - break; - case AHB_YELLOW: + break; + case AHB_YELLOW: maxStackYellow = value; - break; - default: - break; - } - } - uint32 GetMaxStack(uint32 color) - { - switch(color) - { - case AHB_GREY: + break; + default: + break; + } + } + uint32 GetMaxStack(uint32 color) + { + switch(color) + { + case AHB_GREY: { return maxStackGrey; break; } - case AHB_WHITE: + case AHB_WHITE: { return maxStackWhite; break; } - case AHB_GREEN: + case AHB_GREEN: { return maxStackGreen; break; } - case AHB_BLUE: + case AHB_BLUE: { return maxStackBlue; break; } - case AHB_PURPLE: + case AHB_PURPLE: { return maxStackPurple; break; } - case AHB_ORANGE: + case AHB_ORANGE: { return maxStackOrange; break; } - case AHB_YELLOW: + case AHB_YELLOW: { return maxStackYellow; break; } - default: - { - return 0; - break; - } - } - } - void SetBuyerPrice(uint32 color, uint32 value) - { - switch(color) - { - case AHB_GREY: + default: + { + return 0; + break; + } + } + } + void SetBuyerPrice(uint32 color, uint32 value) + { + switch(color) + { + case AHB_GREY: buyerPriceGrey = value; - break; - case AHB_WHITE: + break; + case AHB_WHITE: buyerPriceWhite = value; - break; - case AHB_GREEN: + break; + case AHB_GREEN: buyerPriceGreen = value; - break; - case AHB_BLUE: + break; + case AHB_BLUE: buyerPriceBlue = value; - break; - case AHB_PURPLE: + break; + case AHB_PURPLE: buyerPricePurple = value; - break; - case AHB_ORANGE: + break; + case AHB_ORANGE: buyerPriceOrange = value; - break; - case AHB_YELLOW: + break; + case AHB_YELLOW: buyerPriceYellow = value; - break; - default: - break; - } - } - uint32 GetBuyerPrice(uint32 color) - { - switch(color) - { - case AHB_GREY: + break; + default: + break; + } + } + uint32 GetBuyerPrice(uint32 color) + { + switch(color) + { + case AHB_GREY: return buyerPriceGrey; - break; - case AHB_WHITE: + break; + case AHB_WHITE: return buyerPriceWhite; - break; - case AHB_GREEN: + break; + case AHB_GREEN: return buyerPriceGreen; - break; - case AHB_BLUE: + break; + case AHB_BLUE: return buyerPriceBlue; - break; - case AHB_PURPLE: + break; + case AHB_PURPLE: return buyerPricePurple; - break; - case AHB_ORANGE: + break; + case AHB_ORANGE: return buyerPriceOrange; - break; - case AHB_YELLOW: + break; + case AHB_YELLOW: return buyerPriceYellow; - break; - default: - return 0; - break; - } - } - void SetBiddingInterval(uint32 value) - { - buyerBiddingInterval = value; - } - uint32 GetBiddingInterval() - { - return buyerBiddingInterval; - } - void CalculatePercents() - { + break; + default: + return 0; + break; + } + } + void SetBiddingInterval(uint32 value) + { + buyerBiddingInterval = value; + } + uint32 GetBiddingInterval() + { + return buyerBiddingInterval; + } + void CalculatePercents() + { greytgp = (uint32) (((double)percentGreyTradeGoods / 100.0) * maxItems); whitetgp = (uint32) (((double)percentWhiteTradeGoods / 100.0) * maxItems); greentgp = (uint32) (((double)percentGreenTradeGoods / 100.0) * maxItems); @@ -828,72 +823,177 @@ class AHBConfig { whiteip += diff; } - } - uint32 GetPercents(uint32 color) - { - switch(color) - { - case AHB_GREY_TG: + } + uint32 GetPercents(uint32 color) + { + switch(color) + { + case AHB_GREY_TG: return greytgp; - break; - case AHB_WHITE_TG: + break; + case AHB_WHITE_TG: return whitetgp; - break; - case AHB_GREEN_TG: + break; + case AHB_GREEN_TG: return greentgp; - break; - case AHB_BLUE_TG: + break; + case AHB_BLUE_TG: return bluetgp; - break; - case AHB_PURPLE_TG: + break; + case AHB_PURPLE_TG: return purpletgp; - break; - case AHB_ORANGE_TG: + break; + case AHB_ORANGE_TG: return orangetgp; - break; - case AHB_YELLOW_TG: + break; + case AHB_YELLOW_TG: return yellowtgp; - break; - case AHB_GREY_I: - return greyip; - break; - case AHB_WHITE_I: + break; + case AHB_GREY_I: + return greyip; + break; + case AHB_WHITE_I: return whiteip; - break; - case AHB_GREEN_I: + break; + case AHB_GREEN_I: return greenip; - break; - case AHB_BLUE_I: + break; + case AHB_BLUE_I: return blueip; - break; - case AHB_PURPLE_I: + break; + case AHB_PURPLE_I: return purpleip; - break; - case AHB_ORANGE_I: + break; + case AHB_ORANGE_I: return orangeip; - break; - case AHB_YELLOW_I: + break; + case AHB_YELLOW_I: return yellowip; - break; - default: - return 0; - break; - } - } - void SetBidsPerInterval(uint32 value) - { - buyerBidsPerInterval = value; - } - uint32 GetBidsPerInterval() - { - return buyerBidsPerInterval; - } - ~AHBConfig() - { - } + break; + default: + return 0; + break; + } + } + void SetBidsPerInterval(uint32 value) + { + buyerBidsPerInterval = value; + } + uint32 GetBidsPerInterval() + { + return buyerBidsPerInterval; + } + ~AHBConfig() + { + } }; -void AuctionHouseBot(); -void AuctionHouseBotInit(); -void AuctionHouseBotLoadValues(AHBConfig*); -void AuctionHouseBotCommands(uint32, uint32, uint32, char*); +class AuctionHouseBot +{ +private: + ACE_Vector<uint32> npcItems; + ACE_Vector<uint32> lootItems; + ACE_Vector<uint32> greyTradeGoodsBin; + ACE_Vector<uint32> whiteTradeGoodsBin; + ACE_Vector<uint32> greenTradeGoodsBin; + ACE_Vector<uint32> blueTradeGoodsBin; + ACE_Vector<uint32> purpleTradeGoodsBin; + ACE_Vector<uint32> orangeTradeGoodsBin; + ACE_Vector<uint32> yellowTradeGoodsBin; + ACE_Vector<uint32> greyItemsBin; + ACE_Vector<uint32> whiteItemsBin; + ACE_Vector<uint32> greenItemsBin; + ACE_Vector<uint32> blueItemsBin; + ACE_Vector<uint32> purpleItemsBin; + ACE_Vector<uint32> orangeItemsBin; + ACE_Vector<uint32> yellowItemsBin; + + bool debug_Out; + + bool AHBSeller; + bool AHBBuyer; + bool BuyMethod; + bool SellMethod; + + uint32 AHBplayerAccount; + uint32 AHBplayerGUID; + uint32 ItemsPerCycle; + + //Begin Filters + + bool Vendor_Items; + bool Loot_Items; + bool Other_Items; + + bool No_Bind; + bool Bind_When_Picked_Up; + bool Bind_When_Equipped; + bool Bind_When_Use; + bool Bind_Quest_Item; + + bool DisableBeta_PTR_Unused; + bool DisablePermEnchant; + bool DisableConjured; + bool DisableGems; + bool DisableMoney; + bool DisableMoneyLoot; + bool DisableLootable; + bool DisableKeys; + bool DisableDuration; + bool DisableBOP_Or_Quest_NoReqLevel; + + bool DisableWarriorItems; + bool DisablePaladinItems; + bool DisableHunterItems; + bool DisableRogueItems; + bool DisablePriestItems; + bool DisableDKItems; + bool DisableShamanItems; + bool DisableMageItems; + bool DisableWarlockItems; + bool DisableUnusedClassItems; + bool DisableDruidItems; + + uint32 DisableItemsBelowLevel; + uint32 DisableItemsAboveLevel; + uint32 DisableTGsBelowLevel; + uint32 DisableTGsAboveLevel; + uint32 DisableItemsBelowGUID; + uint32 DisableItemsAboveGUID; + uint32 DisableTGsBelowGUID; + uint32 DisableTGsAboveGUID; + uint32 DisableItemsBelowReqLevel; + uint32 DisableItemsAboveReqLevel; + uint32 DisableTGsBelowReqLevel; + uint32 DisableTGsAboveReqLevel; + uint32 DisableItemsBelowReqSkillRank; + uint32 DisableItemsAboveReqSkillRank; + uint32 DisableTGsBelowReqSkillRank; + uint32 DisableTGsAboveReqSkillRank; + + //End Filters + + AHBConfig AllianceConfig; + AHBConfig HordeConfig; + AHBConfig NeutralConfig; + + time_t _lastrun_a; + time_t _lastrun_h; + time_t _lastrun_n; + + inline uint32 minValue(uint32 a, uint32 b) { return a <= b ? a : b; }; + void addNewAuctions(Player *AHBplayer, AHBConfig *config); + void addNewAuctionBuyerBotBid(Player *AHBplayer, AHBConfig *config, WorldSession *session); + +public: + AuctionHouseBot(); + ~AuctionHouseBot(); + void Update(); + void Initialize(); + void LoadValues(AHBConfig*); + void Commands(uint32, uint32, uint32, char*); + uint32 GetAHBplayerGUID() { return AHBplayerGUID; }; +}; + +#define auctionbot Trinity::Singleton<AuctionHouseBot>::Instance() + #endif diff --git a/src/game/AuctionHouseHandler.cpp b/src/game/AuctionHouseHandler.cpp index d1f399bf570..9962a16bc77 100644 --- a/src/game/AuctionHouseHandler.cpp +++ b/src/game/AuctionHouseHandler.cpp @@ -127,7 +127,7 @@ void WorldSession::SendAuctionOutbiddedMail(AuctionEntry *auction, uint32 newPri msgAuctionOutbiddedSubject << auction->item_template << ":0:" << AUCTION_OUTBIDDED; if (oldBidder && !_player) - oldBidder->GetSession()->SendAuctionBidderNotification( auction->GetHouseId(), auction->Id, AHBplayerGUID, newPrice, auction->GetAuctionOutBid(), auction->item_template); + oldBidder->GetSession()->SendAuctionBidderNotification( auction->GetHouseId(), auction->Id, auctionbot.GetAHBplayerGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template); if (oldBidder && _player) oldBidder->GetSession()->SendAuctionBidderNotification( auction->GetHouseId(), auction->Id, _player->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template); diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 71062657c0b..709cac492d5 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -182,6 +182,9 @@ BattleGround::BattleGround() m_PlayersCount[BG_TEAM_ALLIANCE] = 0; m_PlayersCount[BG_TEAM_HORDE] = 0; + m_TeamScores[BG_TEAM_ALLIANCE] = 0; + m_TeamScores[BG_TEAM_HORDE] = 0; + m_PrematureCountDown = false; m_PrematureCountDown = 0; @@ -204,16 +207,13 @@ BattleGround::~BattleGround() // (this is done automatically in mapmanager update, when the instance is reset after the reset time) int size = m_BgCreatures.size(); for(int i = 0; i < size; ++i) - { DelCreature(i); - } + size = m_BgObjects.size(); for(int i = 0; i < size; ++i) - { DelObject(i); - } - if(GetInstanceID()) // not spam by useless queries in case BG templates + if (GetInstanceID()) // not spam by useless queries in case BG templates { // delete creature and go respawn times WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID()); @@ -230,6 +230,9 @@ BattleGround::~BattleGround() ((BattleGroundMap*)map)->SetUnload(); // remove from bg free slot queue this->RemoveFromBGFreeSlotQueue(); + + for(BattleGroundScoreMap::const_iterator itr = m_PlayerScores.begin(); itr != m_PlayerScores.end(); ++itr) + delete itr->second; } void BattleGround::Update(uint32 diff) @@ -473,7 +476,7 @@ void BattleGround::Update(uint32 diff) void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O) { - uint8 idx = GetTeamIndexByTeamId(TeamID); + BattleGroundTeamId idx = GetTeamIndexByTeamId(TeamID); m_TeamStartLocX[idx] = X; m_TeamStartLocY[idx] = Y; m_TeamStartLocZ[idx] = Z; @@ -759,6 +762,7 @@ void BattleGround::EndBattleGround(uint32 winner) { RewardMark(plr,ITEM_WINNER_COUNT); RewardQuestComplete(plr); + plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, 1); } else if(winner) RewardMark(plr,ITEM_LOSER_COUNT); @@ -843,7 +847,7 @@ void BattleGround::RewardMark(Player *plr,uint32 count) void BattleGround::RewardSpellCast(Player *plr, uint32 spell_id) { // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) + if (plr->HasAura(SPELL_AURA_PLAYER_INACTIVE)) return; SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); @@ -859,7 +863,7 @@ void BattleGround::RewardSpellCast(Player *plr, uint32 spell_id) void BattleGround::RewardItem(Player *plr, uint32 item_id, uint32 count) { // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) + if (plr->HasAura(SPELL_AURA_PLAYER_INACTIVE)) return; ItemPosCountVec dest; @@ -963,7 +967,7 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac participant = true; } - std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid); + BattleGroundScoreMap::iterator itr2 = m_PlayerScores.find(guid); if (itr2 != m_PlayerScores.end()) { delete itr2->second; // delete player's score @@ -1105,7 +1109,12 @@ void BattleGround::Reset() m_InBGFreeSlotQueue = false; m_Players.clear(); + + for(BattleGroundScoreMap::const_iterator itr = m_PlayerScores.begin(); itr != m_PlayerScores.end(); ++itr) + delete itr->second; m_PlayerScores.clear(); + + ResetBGSubclass(); } void BattleGround::StartBattleGround() @@ -1342,7 +1351,7 @@ bool BattleGround::HasFreeSlots() const void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value) { //this procedure is called from virtual function implemented in bg subclass - std::map<uint64, BattleGroundScore*>::const_iterator itr = m_PlayerScores.find(Source->GetGUID()); + BattleGroundScoreMap::const_iterator itr = m_PlayerScores.find(Source->GetGUID()); if(itr == m_PlayerScores.end()) // player not found... return; @@ -1609,8 +1618,6 @@ bool BattleGround::DelCreature(uint32 type) sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type])); return false; } - //TODO: only delete creature after not in combat - cr->CleanupsBeforeDelete(); cr->AddObjectToRemoveList(); m_BgCreatures[type] = 0; return true; @@ -1876,3 +1883,9 @@ WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player ) { return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() ); } + +bool BattleGround::IsTeamScoreInRange(uint32 team, uint32 minScore, uint32 maxScore) const +{ + BattleGroundTeamId team_idx = GetTeamIndexByTeamId(team); + return m_TeamScores[team_idx] >= minScore && m_TeamScores[team_idx] <= maxScore; +} diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index 509ba6eb972..4ed660a3595 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -297,6 +297,13 @@ class BattleGround virtual void Reset(); // resets all common properties for battlegrounds, must be implemented and called in BG subclass virtual void StartingEventCloseDoors() {} virtual void StartingEventOpenDoors() {} + virtual void ResetBGSubclass() // must be implemented in BG subclass + { + } + + /* achievement req. */ + virtual bool IsAllNodesConrolledByTeam(uint32 /*team*/) const { return false; } + bool IsTeamScoreInRange(uint32 team, uint32 minScore, uint32 maxScore) const; /* Battleground */ // Get methods: @@ -377,8 +384,9 @@ class BattleGround BattleGroundPlayerMap const& GetPlayers() const { return m_Players; } uint32 GetPlayersSize() const { return m_Players.size(); } - std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresBegin() const { return m_PlayerScores.begin(); } - std::map<uint64, BattleGroundScore*>::const_iterator GetPlayerScoresEnd() const { return m_PlayerScores.end(); } + typedef std::map<uint64, BattleGroundScore*> BattleGroundScoreMap; + BattleGroundScoreMap::const_iterator GetPlayerScoresBegin() const { return m_PlayerScores.begin(); } + BattleGroundScoreMap::const_iterator GetPlayerScoresEnd() const { return m_PlayerScores.end(); } uint32 GetPlayerScoresSize() const { return m_PlayerScores.size(); } uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); } @@ -397,7 +405,7 @@ class BattleGround void SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O); void GetTeamStartLoc(uint32 TeamID, float &X, float &Y, float &Z, float &O) const { - uint8 idx = GetTeamIndexByTeamId(TeamID); + BattleGroundTeamId idx = GetTeamIndexByTeamId(TeamID); X = m_TeamStartLocX[idx]; Y = m_TeamStartLocY[idx]; Z = m_TeamStartLocZ[idx]; @@ -441,7 +449,7 @@ class BattleGround virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value); - uint8 GetTeamIndexByTeamId(uint32 Team) const { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; } + static BattleGroundTeamId GetTeamIndexByTeamId(uint32 Team) { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; } uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; } uint32 GetAlivePlayersCountByTeam(uint32 Team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases void UpdatePlayersCountByTeam(uint32 Team, bool remove) @@ -514,14 +522,17 @@ class BattleGround void SetDeleteThis() {m_SetDeleteThis = true;} + /* virtual score-array - get's used in bg-subclasses */ + int32 m_TeamScores[BG_TEAMS_COUNT]; + protected: //this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround void EndNow(); void PlayerAddedToBGCheckIfBGIsRunning(Player* plr); /* Scorekeeping */ - // Player scores - std::map<uint64, BattleGroundScore*> m_PlayerScores; + + BattleGroundScoreMap m_PlayerScores; // Player scores // must be implemented in BG subclass virtual void RemovePlayer(Player * /*player*/, uint64 /*guid*/) {} diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp index f5fba6f4186..70709af42ad 100644 --- a/src/game/BattleGroundAB.cpp +++ b/src/game/BattleGroundAB.cpp @@ -161,6 +161,18 @@ void BattleGroundAB::Update(uint32 diff) } } + // achievements flags + if (m_TeamScores[BG_TEAM_ALLIANCE] > m_TeamScores[BG_TEAM_HORDE]) + { + if (m_TeamScores[BG_TEAM_ALLIANCE] - m_TeamScores[BG_TEAM_HORDE] >= 500) + m_TeamScores500disadvantage[BG_TEAM_HORDE] = true; + } + else + { + if (m_TeamScores[BG_TEAM_HORDE] - m_TeamScores[BG_TEAM_ALLIANCE] >= 500) + m_TeamScores500disadvantage[BG_TEAM_ALLIANCE] = true; + } + // Test win condition if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE) EndBattleGround(ALLIANCE); @@ -428,7 +440,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ return; } - uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam()); + BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(source->GetTeam()); // Check if player really could use this banner, not cheated if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2)) @@ -474,7 +486,7 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; // FIXME: node names not localized - if (teamIndex == 0) + if (teamIndex == BG_TEAM_ALLIANCE) SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); @@ -491,15 +503,15 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true); _SendNodeUpdate(node); m_NodeTimers[node] = 0; - _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE); + _NodeOccupied(node,(teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE:HORDE); // FIXME: node names not localized - if (teamIndex == 0) + if (teamIndex == BG_TEAM_ALLIANCE) SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); } - sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; + sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; } // If node is occupied, change to enemy-contested else @@ -516,19 +528,19 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; // FIXME: node names not localized - if (teamIndex == 0) + if (teamIndex == BG_TEAM_ALLIANCE) SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); - sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; + sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE; } // If node is occupied again, send "X has taken the Y" msg. if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED) { // FIXME: team and node names not localized - if (teamIndex == 0) + if (teamIndex == BG_TEAM_ALLIANCE) SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node)); else SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node)); @@ -591,6 +603,8 @@ void BattleGroundAB::Reset() bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call! m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks; m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks; + m_TeamScores500disadvantage[BG_TEAM_ALLIANCE] = false; + m_TeamScores500disadvantage[BG_TEAM_HORDE] = false; for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) { @@ -621,7 +635,7 @@ void BattleGroundAB::EndBattleGround(uint32 winner) WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) { - uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam()); + BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(player->GetTeam()); // Is there any occupied node for this team? std::vector<uint8> nodes; @@ -660,8 +674,7 @@ WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value) { - std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); - + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); if( itr == m_PlayerScores.end() ) // player not found... return; @@ -679,3 +692,13 @@ void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value } } +bool BattleGroundAB::IsAllNodesConrolledByTeam(uint32 team) const +{ + uint32 count = 0; + for(int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + if (team == ALLIANCE && m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED || + team == HORDE && m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) + ++count; + + return count == BG_AB_DYNAMIC_NODES_COUNT; +} diff --git a/src/game/BattleGroundAB.h b/src/game/BattleGroundAB.h index 1c4a6d3b738..1a940a041d4 100644 --- a/src/game/BattleGroundAB.h +++ b/src/game/BattleGroundAB.h @@ -262,6 +262,9 @@ class BattleGroundAB : public BattleGround /* Nodes occupying */ virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj); + /* achievement req. */ + bool IsAllNodesConrolledByTeam(uint32 team) const; // overwrited + bool IsTeamScores500disadvantage(uint32 team) const { return m_TeamScores500disadvantage[GetTeamIndexByTeamId(team)]; } private: /* Gameobject spawning/despawning */ void _CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay); @@ -285,15 +288,14 @@ class BattleGroundAB : public BattleGround uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT]; BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT]; uint32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT]; - uint32 m_TeamScores[BG_TEAMS_COUNT]; uint32 m_lastTick[BG_TEAMS_COUNT]; uint32 m_HonorScoreTics[BG_TEAMS_COUNT]; uint32 m_ReputationScoreTics[BG_TEAMS_COUNT]; bool m_IsInformedNearVictory; uint32 m_HonorTics; uint32 m_ReputationTics; - - + // need for achievements + bool m_TeamScores500disadvantage[BG_TEAMS_COUNT]; }; #endif diff --git a/src/game/BattleGroundAV.cpp b/src/game/BattleGroundAV.cpp index a93b304e2b9..4778bdb2384 100644 --- a/src/game/BattleGroundAV.cpp +++ b/src/game/BattleGroundAV.cpp @@ -34,11 +34,10 @@ BattleGroundAV::BattleGroundAV() m_BgObjects.resize(BG_AV_OBJECT_MAX); m_BgCreatures.resize(AV_CPLACE_MAX+AV_STATICCPLACE_MAX); - //TODO FIX ME! - m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES; - m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE; - m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN; + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AV_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AV_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AV_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AV_HAS_BEGUN; } BattleGroundAV::~BattleGroundAV() @@ -300,117 +299,8 @@ Creature* BattleGroundAV::AddAVCreature(uint16 cinfoid, uint16 type ) void BattleGroundAV::Update(uint32 diff) { BattleGround::Update(diff); - if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) - { - ModifyStartDelayTime(diff); - - if (!(m_Events & 0x01)) - { - m_Events |= 0x01; - - if(!SetupBattleGround()) - { - EndNow(); - return; - } - uint16 i; - sLog.outDebug("Alterac Valley: entering state STATUS_WAIT_JOIN ..."); - // Initial Nodes - for(i = 0; i < BG_AV_OBJECT_MAX; i++) - SpawnBGObject(i, RESPAWN_ONE_DAY); - for(i = BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE ; i++){ - SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+3*i,RESPAWN_IMMEDIATELY); - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - } - for(i = BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER ; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - for(i = BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE; i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER ; i++){ - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - if(i<=BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT) - SpawnBGObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+3*GetNodeThroughObject(i),RESPAWN_IMMEDIATELY); - } - for(i = BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER; i+=2) - { - SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag - SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura - } - for(i = BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER; i <= BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER; i+=2) - { - SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag - SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura - } - //snowfall and the doors - for(i = BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; i <= BG_AV_OBJECT_DOOR_A; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE,RESPAWN_IMMEDIATELY); - - //creatures - sLog.outDebug("BG_AV start poputlating nodes"); - for(BG_AV_Nodes i= BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i ) - { - if(m_Nodes[i].Owner) - PopulateNode(i); - } - //all creatures which don't get despawned through the script are static - sLog.outDebug("BG_AV: start spawning static creatures"); - for(i=0; i < AV_STATICCPLACE_MAX; i++ ) - AddAVCreature(0,i+AV_CPLACE_MAX); - //mainspiritguides: - sLog.outDebug("BG_AV: start spawning spiritguides creatures"); - AddSpiritGuide(7, BG_AV_CreaturePos[7][0], BG_AV_CreaturePos[7][1], BG_AV_CreaturePos[7][2], BG_AV_CreaturePos[7][3], ALLIANCE); - AddSpiritGuide(8, BG_AV_CreaturePos[8][0], BG_AV_CreaturePos[8][1], BG_AV_CreaturePos[8][2], BG_AV_CreaturePos[8][3], HORDE); - //spawn the marshals (those who get deleted, if a tower gets destroyed) - sLog.outDebug("BG_AV: start spawning marshal creatures"); - for(i=AV_NPC_A_MARSHAL_SOUTH; i<= AV_NPC_H_MARSHAL_WTOWER; i++) - AddAVCreature(i,AV_CPLACE_A_MARSHAL_SOUTH+(i-AV_NPC_A_MARSHAL_SOUTH)); - - AddAVCreature(AV_NPC_HERALD,AV_CPLACE_HERALD); - DoorClose(BG_AV_OBJECT_DOOR_A); - DoorClose(BG_AV_OBJECT_DOOR_H); - - SetStartDelayTime(BG_START_DELAY_2M); - } - // After 1 minute, warning is signalled - else if (GetStartDelayTime() <= BG_START_DELAY_1M && !(m_Events & 0x04)) - { - m_Events |= 0x04; - SendMessageToAll(LANG_BG_AV_ONEMINTOSTART, CHAT_MSG_BG_SYSTEM_NEUTRAL); - } - // After 1,5 minute, warning is signalled - else if (GetStartDelayTime() <= BG_START_DELAY_1M + BG_START_DELAY_30S && !(m_Events & 0x08)) - { - m_Events |= 0x08; - SendMessageToAll(LANG_BG_AV_HALFMINTOSTART, CHAT_MSG_BG_SYSTEM_NEUTRAL); - } - // After 2 minutes, gates OPEN ! x) - else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10)) - { - UpdateWorldState(AV_SHOW_H_SCORE, 1); - UpdateWorldState(AV_SHOW_A_SCORE, 1); - m_Events |= 0x10; - - SendMessageToAll(LANG_BG_AV_STARTED, CHAT_MSG_BG_SYSTEM_NEUTRAL); - PlaySoundToAll(SOUND_BG_START); - SetStatus(STATUS_IN_PROGRESS); - - sLog.outDebug("BG_AV: start spawning mine stuff"); - for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_N_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_N_MAX;i++) - SpawnBGObject(i,RESPAWN_IMMEDIATELY); - for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_S_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_S_MAX;i++) - SpawnBGObject(i,RESPAWN_IMMEDIATELY); - for(uint8 mine = AV_NORTH_MINE; mine <= AV_SOUTH_MINE; mine++) //mine population - ChangeMineOwner(mine, AV_NEUTRAL_TEAM,true); - DoorOpen(BG_AV_OBJECT_DOOR_H); - DoorOpen(BG_AV_OBJECT_DOOR_A); - - - for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player* plr = objmgr.GetPlayer(itr->first)) - plr->RemoveAurasDueToSpell(SPELL_PREPARATION); - } - } - else if(GetStatus() == STATUS_IN_PROGRESS) + if(GetStatus() == STATUS_IN_PROGRESS) { for(uint8 i=0; i<=1;i++)//0=alliance, 1=horde { @@ -470,10 +360,25 @@ void BattleGroundAV::Update(uint32 diff) void BattleGroundAV::StartingEventCloseDoors() { + DoorClose(BG_AV_OBJECT_DOOR_A); + DoorClose(BG_AV_OBJECT_DOOR_H); } void BattleGroundAV::StartingEventOpenDoors() { + sLog.outDebug("BG_AV: start spawning mine stuff"); + for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_N_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_N_MAX;i++) + SpawnBGObject(i,RESPAWN_IMMEDIATELY); + for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_S_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_S_MAX;i++) + SpawnBGObject(i,RESPAWN_IMMEDIATELY); + for(uint8 mine = AV_NORTH_MINE; mine <= AV_SOUTH_MINE; mine++) //mine population + ChangeMineOwner(mine, AV_NEUTRAL_TEAM,true); + + UpdateWorldState(AV_SHOW_H_SCORE, 1); + UpdateWorldState(AV_SHOW_A_SCORE, 1); + + DoorOpen(BG_AV_OBJECT_DOOR_H); + DoorOpen(BG_AV_OBJECT_DOOR_A); } void BattleGroundAV::AddPlayer(Player *plr) @@ -584,8 +489,7 @@ void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger) void BattleGroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value) { - std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); - + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); if(itr == m_PlayerScores.end()) // player not found... return; @@ -1234,7 +1138,7 @@ bool BattleGroundAV::SetupBattleGround() return false; } -//spawn node-objects + //spawn node-objects for (uint8 i = BG_AV_NODES_FIRSTAID_STATION ; i < BG_AV_NODES_MAX; ++i) { if( i <= BG_AV_NODES_FROSTWOLF_HUT ) @@ -1345,6 +1249,58 @@ bool BattleGroundAV::SetupBattleGround() return false; } } + + uint16 i; + sLog.outDebug("Alterac Valley: entering state STATUS_WAIT_JOIN ..."); + // Initial Nodes + for(i = 0; i < BG_AV_OBJECT_MAX; i++) + SpawnBGObject(i, RESPAWN_ONE_DAY); + for(i = BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE ; i++){ + SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+3*i,RESPAWN_IMMEDIATELY); + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + } + for(i = BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER ; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + for(i = BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE; i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER ; i++){ + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + if(i<=BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT) + SpawnBGObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+3*GetNodeThroughObject(i),RESPAWN_IMMEDIATELY); + } + for(i = BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER; i+=2) + { + SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag + SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura + } + for(i = BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER; i <= BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER; i+=2) + { + SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag + SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura + } + //snowfall and the doors + for(i = BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; i <= BG_AV_OBJECT_DOOR_A; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE,RESPAWN_IMMEDIATELY); + + //creatures + sLog.outDebug("BG_AV start poputlating nodes"); + for(BG_AV_Nodes i= BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i ) + { + if(m_Nodes[i].Owner) + PopulateNode(i); + } + //all creatures which don't get despawned through the script are static + sLog.outDebug("BG_AV: start spawning static creatures"); + for(i=0; i < AV_STATICCPLACE_MAX; i++ ) + AddAVCreature(0,i+AV_CPLACE_MAX); + //mainspiritguides: + sLog.outDebug("BG_AV: start spawning spiritguides creatures"); + AddSpiritGuide(7, BG_AV_CreaturePos[7][0], BG_AV_CreaturePos[7][1], BG_AV_CreaturePos[7][2], BG_AV_CreaturePos[7][3], ALLIANCE); + AddSpiritGuide(8, BG_AV_CreaturePos[8][0], BG_AV_CreaturePos[8][1], BG_AV_CreaturePos[8][2], BG_AV_CreaturePos[8][3], HORDE); + //spawn the marshals (those who get deleted, if a tower gets destroyed) + sLog.outDebug("BG_AV: start spawning marshal creatures"); + for(i=AV_NPC_A_MARSHAL_SOUTH; i<= AV_NPC_H_MARSHAL_WTOWER; i++) + AddAVCreature(i,AV_CPLACE_A_MARSHAL_SOUTH+(i-AV_NPC_A_MARSHAL_SOUTH)); + AddAVCreature(AV_NPC_HERALD,AV_CPLACE_HERALD); return true; } @@ -1378,10 +1334,26 @@ const char* BattleGroundAV::GetNodeName(BG_AV_Nodes node) void BattleGroundAV::AssaultNode(BG_AV_Nodes node, uint16 team) { - assert(m_Nodes[node].TotalOwner != team); - assert(m_Nodes[node].Owner != team); - assert(m_Nodes[node].State != POINT_DESTROYED); - assert(m_Nodes[node].State != POINT_ASSAULTED || !m_Nodes[node].TotalOwner ); //only assault an assaulted node if no totalowner exists + if (m_Nodes[node].TotalOwner == team) + { + sLog.outCrash("Assaulting team is TotalOwner of node"); + assert (false); + } + if (m_Nodes[node].Owner == team) + { + sLog.outCrash("Assaulting team is owner of node"); + assert (false); + } + if (m_Nodes[node].State == POINT_DESTROYED) + { + sLog.outCrash("Destroyed node is being assaulted"); + assert (false); + } + if (m_Nodes[node].State == POINT_ASSAULTED && m_Nodes[node].TotalOwner) //only assault an assaulted node if no totalowner exists + { + sLog.outCrash("Assault on an not assaulted node with total owner"); + assert (false); + } //the timer gets another time, if the previous owner was 0==Neutral m_Nodes[node].Timer = (m_Nodes[node].PrevOwner)? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP; m_Nodes[node].PrevOwner = m_Nodes[node].Owner; diff --git a/src/game/BattleGroundBE.cpp b/src/game/BattleGroundBE.cpp index d58c2250948..05475328b01 100644 --- a/src/game/BattleGroundBE.cpp +++ b/src/game/BattleGroundBE.cpp @@ -182,8 +182,7 @@ bool BattleGroundBE::SetupBattleGround() void BattleGroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value) { - std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); - + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); if(itr == m_PlayerScores.end()) // player not found... return; diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp index 9b54ecce643..78654677230 100644 --- a/src/game/BattleGroundEY.cpp +++ b/src/game/BattleGroundEY.cpp @@ -128,7 +128,7 @@ void BattleGroundEY::StartingEventOpenDoors() void BattleGroundEY::AddPoints(uint32 Team, uint32 Points) { - uint8 team_index = GetTeamIndexByTeamId(Team); + BattleGroundTeamId team_index = GetTeamIndexByTeamId(Team); m_TeamScores[team_index] += Points; m_HonorScoreTics[team_index] += Points; if (m_HonorScoreTics[team_index] >= m_HonorTics ) @@ -788,8 +788,7 @@ void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType void BattleGroundEY::UpdatePlayerScore(Player *Source, uint32 type, uint32 value) { - std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); - + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); if(itr == m_PlayerScores.end()) // player not found return; @@ -908,3 +907,12 @@ WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player) return nearestEntry; } +bool BattleGroundEY::IsAllNodesConrolledByTeam(uint32 team) const +{ + uint32 count = 0; + for(int i = 0; i < EY_POINTS_MAX; ++i) + if (m_PointOwnedByTeam[i] == team && m_PointState[i] == EY_POINT_UNDER_CONTROL) + ++count; + + return count == EY_POINTS_MAX; +} diff --git a/src/game/BattleGroundEY.h b/src/game/BattleGroundEY.h index a22d6ecc6db..3385a06bfb0 100644 --- a/src/game/BattleGroundEY.h +++ b/src/game/BattleGroundEY.h @@ -350,6 +350,8 @@ class BattleGroundEY : public BattleGround virtual void EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj); virtual void EventPlayerDroppedFlag(Player *Source); + /* achievement req. */ + bool IsAllNodesConrolledByTeam(uint32 team) const; private: void EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType); void EventTeamCapturedPoint(Player *Source, uint32 Point); @@ -369,7 +371,6 @@ class BattleGroundEY : public BattleGround void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; } void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; } - uint32 m_TeamScores[2]; uint32 m_HonorScoreTics[2]; uint32 m_TeamPointsCount[2]; diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index c8bc2bc4ecf..497db2ceadd 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -448,7 +448,8 @@ void WorldSession::HandleBattleFieldPortOpcode( WorldPacket &recv_data ) if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); + } sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index 371c204717d..d70aa52a018 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -1349,7 +1349,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) *data << (int32)(bg->GetPlayerScoresSize()); - for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr) + for(BattleGround::BattleGroundScoreMap::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr) { *data << (uint64)itr->first; *data << (int32)itr->second->KillingBlows; @@ -1474,6 +1474,8 @@ BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 inst BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId) { + if (!InstanceID) + return NULL; //search if needed BattleGroundSet::iterator itr; if (bgTypeId == BATTLEGROUND_TYPE_NONE) diff --git a/src/game/BattleGroundSA.cpp b/src/game/BattleGroundSA.cpp index 5f20950070d..acf16ad3af0 100644 --- a/src/game/BattleGroundSA.cpp +++ b/src/game/BattleGroundSA.cpp @@ -72,8 +72,7 @@ void BattleGroundSA::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) void BattleGroundSA::UpdatePlayerScore(Player* Source, uint32 type, uint32 value) { - std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); - + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); if(itr == m_PlayerScores.end()) // player not found... return; diff --git a/src/game/BattleGroundWS.cpp b/src/game/BattleGroundWS.cpp index c4a2402ad67..81080284b9d 100644 --- a/src/game/BattleGroundWS.cpp +++ b/src/game/BattleGroundWS.cpp @@ -719,8 +719,7 @@ void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer) void BattleGroundWS::UpdatePlayerScore(Player *Source, uint32 type, uint32 value) { - std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); - + BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID()); if(itr == m_PlayerScores.end()) // player not found return; diff --git a/src/game/BattleGroundWS.h b/src/game/BattleGroundWS.h index 7395c3a5bb9..16631afecdc 100644 --- a/src/game/BattleGroundWS.h +++ b/src/game/BattleGroundWS.h @@ -200,12 +200,10 @@ class BattleGroundWS : public BattleGround void AddPoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] += Points; } void SetTeamPoint(uint32 TeamID, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] = Points; } void RemovePoint(uint32 TeamID, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(TeamID)] -= Points; } - private: uint64 m_FlagKeepers[2]; // 0 - alliance, 1 - horde uint64 m_DroppedFlagGUID[2]; uint8 m_FlagState[2]; // for checking flag state - uint32 m_TeamScores[2]; int32 m_FlagsTimer[2]; int32 m_FlagsDropTimer[2]; diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index bb05b4d6076..7132d89d983 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -56,8 +56,9 @@ SET(game_STAT_SRCS Channel.cpp Channel.h ChannelHandler.cpp - ChannelMgr.h CharacterHandler.cpp + ChannelMgr.h + ChannelMgr.cpp Chat.cpp Chat.h ChatHandler.cpp diff --git a/src/game/Channel.cpp b/src/game/Channel.cpp index 9bb3463dbdb..ae7e4d17352 100644 --- a/src/game/Channel.cpp +++ b/src/game/Channel.cpp @@ -23,9 +23,10 @@ #include "SocialMgr.h" #include "World.h" -Channel::Channel(const std::string& name, uint32 channel_id) -: m_announce(true), m_moderate(false), m_name(name), m_flags(0), m_channelId(channel_id), m_ownerGUID(0) +Channel::Channel(const std::string& name, uint32 channel_id, uint32 Team) + : m_name(name), m_announce(true), m_moderate(false), m_channelId(channel_id), m_ownerGUID(0), m_password(""), m_flags(0) { + m_Team = Team; // set special flags if built-in channel ChatChannelsEntry const* ch = GetChannelEntryFor(channel_id); if(ch) // it's built-in channel @@ -45,10 +46,54 @@ Channel::Channel(const std::string& name, uint32 channel_id) m_flags |= CHANNEL_FLAG_LFG; else // for all other channels m_flags |= CHANNEL_FLAG_NOT_LFG; + m_IsSaved = false; } else // it's custom channel { m_flags |= CHANNEL_FLAG_CUSTOM; + //load not built in channel if saved + QueryResult *result = CharacterDatabase.PQuery("SELECT m_name, m_team, m_ownerGUID, m_announce, m_moderate, m_password, BannedList FROM channels WHERE m_name = '%s' AND m_team = '%u'", name.c_str(), m_Team); + if (result)//load + { + Field *fields = result->Fetch(); + const char* db_name = fields[0].GetString(); + uint32 db_team = fields[1].GetUInt32(); + uint64 db_owner = fields[2].GetUInt64(); + bool db_announce = fields[3].GetBool(); + bool db_moderate = fields[4].GetBool(); + const char* db_password = fields[5].GetString(); + const char* db_BannedList = fields[6].GetString(); + + m_ownerGUID = db_owner; + m_announce = db_announce; + m_moderate = db_moderate; + m_password = db_password; + m_IsSaved = true; + + if(db_BannedList) + { + Tokens tokens = StrSplit(db_BannedList, " "); + Tokens::iterator iter; + for (iter = tokens.begin();iter != tokens.end(); ++iter) + { + uint64 banned_guid = atol((*iter).c_str()); + if(banned_guid) + { + sLog.outDebug("Channel(%s) loaded banned guid: %u",name.c_str(), banned_guid); + banned.insert(banned_guid); + } + } + } + }else{//save + std::ostringstream ss; + ss << "INSERT INTO channels (m_name,m_team,m_ownerGUID,m_announce,m_moderate,m_password) VALUES ('" + << name.c_str() << "','" << m_Team << "','0','1','0','')"; + if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) + { + sLog.outDebug("New Channel(%s) saved", name.c_str()); + m_IsSaved = true; + } + } } } @@ -120,6 +165,10 @@ void Channel::Join(uint64 p, const char *pass) if(!IsConstant() && !m_ownerGUID) { SetOwner(p, (players.size() > 1 ? true : false)); + players[p].SetModerator(true); + }else if(!IsConstant() && m_ownerGUID && plr && m_ownerGUID == plr->GetGUID()) + { + SetOwner(p, (players.size() > 1 ? true : false)); players[p].SetModerator(true); } } @@ -161,7 +210,7 @@ void Channel::Leave(uint64 p, bool send) LeaveNotify(p); - if(changeowner) + if(changeowner && !m_IsSaved) { uint64 newowner = !players.empty() ? players.begin()->second.player : 0; SetOwner(newowner); @@ -213,6 +262,23 @@ void Channel::KickOrBan(uint64 good, const char *badname, bool ban) { banned.insert(bad->GetGUID()); MakePlayerBanned(&data, bad->GetGUID(), good); + //save banlist + if(m_IsSaved) + { + std::ostringstream banlist; + BannedList::iterator iter; + for (iter = banned.begin();iter != banned.end(); ++iter) + { + banlist << (*iter) << " "; + } + std::ostringstream ss; + ss << "UPDATE channels SET BannedList = '" << banlist.str().c_str() << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'"; + if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) + { + sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str()); + } + } + } else MakePlayerKicked(&data, bad->GetGUID(), good); @@ -265,6 +331,22 @@ void Channel::UnBan(uint64 good, const char *badname) WorldPacket data; MakePlayerUnbanned(&data, bad->GetGUID(), good); SendToAll(&data); + //save banlist + if(m_IsSaved) + { + std::ostringstream banlist; + BannedList::iterator iter; + for (iter = banned.begin();iter != banned.end(); ++iter) + { + banlist << (*iter) << " "; + } + std::ostringstream ss; + ss << "UPDATE channels SET BannedList = '" << banlist.str().c_str() << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'"; + if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) + { + sLog.outDebug("Channel(%s) BannedList saved", m_name.c_str()); + } + } } } } @@ -295,6 +377,15 @@ void Channel::Password(uint64 p, const char *pass) WorldPacket data; MakePasswordChanged(&data, p); SendToAll(&data); + if(m_IsSaved) + { + std::ostringstream ss; + ss << "UPDATE channels SET m_password = '" << pass << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'"; + if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) + { + sLog.outDebug("Channel(%s) password saved", m_name.c_str()); + } + } } } @@ -448,7 +539,7 @@ void Channel::List(Player* player) size_t pos = data.wpos(); data << uint32(0); // size of list, placeholder - bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || player->GetSession()->GetSecurity() > SEC_PLAYER; + uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); uint32 count = 0; for(PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) @@ -457,7 +548,8 @@ void Channel::List(Player* player) // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if (plr && ( plr->GetSession()->GetSecurity() == SEC_PLAYER || (gmInWhoList && plr->IsVisibleGloballyFor(player)))) + if (plr && (player->GetSession()->GetSecurity() > SEC_PLAYER || plr->GetSession()->GetSecurity() <= gmLevelInWhoList) && + plr->IsVisibleGloballyFor(player)) { data << uint64(i->first); data << uint8(i->second.flags); // flags seems to be changed... @@ -500,6 +592,16 @@ void Channel::Announce(uint64 p) else MakeAnnouncementsOff(&data, p); SendToAll(&data); + if(m_IsSaved) + { + std::ostringstream ss; + ss << "UPDATE channels SET m_announce = '" << m_announce << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'"; + if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) + { + sLog.outDebug("Channel(%s) announce saved", m_name.c_str()); + } + } + } } @@ -532,6 +634,15 @@ void Channel::Moderate(uint64 p) else MakeModerationOff(&data, p); SendToAll(&data); + if(m_IsSaved) + { + std::ostringstream ss; + ss << "UPDATE channels SET m_moderate = '" << m_moderate << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'"; + if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) + { + sLog.outDebug("Channel(%s) moderate saved", m_name.c_str()); + } + } } } @@ -659,6 +770,16 @@ void Channel::SetOwner(uint64 guid, bool exclaim) MakeOwnerChanged(&data, m_ownerGUID); SendToAll(&data); } + if(m_IsSaved) + { + std::ostringstream ss; + ss << "UPDATE channels SET m_ownerGUID = '" << guid << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'"; + if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) + { + sLog.outDebug("Channel(%s) owner saved", m_name.c_str()); + } + } + } } diff --git a/src/game/Channel.h b/src/game/Channel.h index c2dd5ecd3ac..69a1e2f66f6 100644 --- a/src/game/Channel.h +++ b/src/game/Channel.h @@ -158,6 +158,7 @@ class Channel uint8 m_flags; uint32 m_channelId; uint64 m_ownerGUID; + bool m_IsSaved; private: // initial packet data (notify type and channel name) @@ -243,7 +244,8 @@ class Channel } public: - Channel(const std::string& name, uint32 channel_id); + uint32 m_Team; + Channel(const std::string& name, uint32 channel_id, uint32 Team = 0); std::string GetName() const { return m_name; } uint32 GetChannelId() const { return m_channelId; } bool IsConstant() const { return m_channelId != 0; } diff --git a/src/game/ChannelHandler.cpp b/src/game/ChannelHandler.cpp index 45cdf8c20b2..e3c10afe81f 100644 --- a/src/game/ChannelHandler.cpp +++ b/src/game/ChannelHandler.cpp @@ -24,9 +24,6 @@ #include "ObjectMgr.h" // for normalizePlayerName #include "ChannelMgr.h" -INSTANTIATE_SINGLETON_1( AllianceChannelMgr ); -INSTANTIATE_SINGLETON_1( HordeChannelMgr ); - void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) { sLog.outDebug("Opcode %u", recvPacket.GetOpcode()); @@ -48,8 +45,11 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) recvPacket >> pass; if(ChannelMgr* cMgr = channelMgr(_player->GetTeam())) + { + cMgr->team = _player->GetTeam(); if(Channel *chn = cMgr->GetJoinChannel(channelname, channel_id)) chn->Join(_player->GetGUID(), pass.c_str()); + } } void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket) diff --git a/src/game/ChannelMgr.cpp b/src/game/ChannelMgr.cpp new file mode 100644 index 00000000000..09d172155cc --- /dev/null +++ b/src/game/ChannelMgr.cpp @@ -0,0 +1,97 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ChannelMgr.h" +#include "Policies/SingletonImp.h" +#include "World.h" + +INSTANTIATE_SINGLETON_1( AllianceChannelMgr ); +INSTANTIATE_SINGLETON_1( HordeChannelMgr ); + +ChannelMgr* channelMgr(uint32 team) +{ + if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + return &MaNGOS::Singleton<AllianceChannelMgr>::Instance(); // cross-faction + + if(team == ALLIANCE) + return &MaNGOS::Singleton<AllianceChannelMgr>::Instance(); + if(team == HORDE) + return &MaNGOS::Singleton<HordeChannelMgr>::Instance(); + + return NULL; +} + +ChannelMgr::~ChannelMgr() +{ + for(ChannelMap::iterator itr = channels.begin();itr!=channels.end(); ++itr) + delete itr->second; + + channels.clear(); +} + +Channel *ChannelMgr::GetJoinChannel(std::string name, uint32 channel_id) +{ + if (channels.find(name) == channels.end()) + { + Channel *nchan = new Channel(name,channel_id, team); + channels[name] = nchan; + } + + return channels[name]; +} + +Channel *ChannelMgr::GetChannel(std::string name, Player *p, bool pkt) +{ + ChannelMap::const_iterator i = channels.find(name); + + if(i == channels.end()) + { + if(pkt) + { + WorldPacket data; + MakeNotOnPacket(&data,name); + p->GetSession()->SendPacket(&data); + } + + return NULL; + } + else + return i->second; +} + +void ChannelMgr::LeftChannel(std::string name) +{ + ChannelMap::const_iterator i = channels.find(name); + + if(i == channels.end()) + return; + + Channel* channel = i->second; + + if(channel->GetNumPlayers() == 0 && !channel->IsConstant()) + { + channels.erase(name); + delete channel; + } +} + +void ChannelMgr::MakeNotOnPacket(WorldPacket *data, std::string name) +{ + data->Initialize(SMSG_CHANNEL_NOTIFY, (1+10)); // we guess size + (*data) << (uint8)0x05 << name; +} diff --git a/src/game/ChannelMgr.h b/src/game/ChannelMgr.h index aeecfbfa541..f65a8520648 100644 --- a/src/game/ChannelMgr.h +++ b/src/game/ChannelMgr.h @@ -17,8 +17,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef TRINITYCORE_CHANNELMGR_H -#define TRINITYCORE_CHANNELMGR_H +#ifndef MANGOSSERVER_CHANNELMGR_H +#define MANGOSSERVER_CHANNELMGR_H + +#include "Common.h" +#include "Channel.h" +#include "Policies/Singleton.h" #include <map> #include <string> @@ -31,75 +35,23 @@ class ChannelMgr { public: + uint32 team; typedef std::map<std::string,Channel *> ChannelMap; - ChannelMgr() {} - ~ChannelMgr() - { - for(ChannelMap::const_iterator itr = channels.begin();itr!=channels.end(); ++itr) - delete itr->second; - channels.clear(); - } - Channel *GetJoinChannel(const std::string& name, uint32 channel_id) - { - if (channels.find(name) == channels.end()) - { - Channel *nchan = new Channel(name,channel_id); - channels[name] = nchan; - } - return channels[name]; - } - Channel *GetChannel(const std::string& name, Player *p) - { - ChannelMap::const_iterator i = channels.find(name); - - if(i == channels.end()) - { - WorldPacket data; - MakeNotOnPacket(&data,name); - p->GetSession()->SendPacket(&data); - return NULL; - } - else - return i->second; - } - void LeftChannel(const std::string& name) - { - ChannelMap::const_iterator i = channels.find(name); + ChannelMgr() {team = 0;} + ~ChannelMgr(); - if(i == channels.end()) - return; - - Channel* channel = i->second; - - if(channel->GetNumPlayers() == 0 && !channel->IsConstant()) - { - channels.erase(name); - delete channel; - } - } + Channel *GetJoinChannel(std::string name, uint32 channel_id); + Channel *GetChannel(std::string name, Player *p, bool pkt = true); + void LeftChannel(std::string name); private: ChannelMap channels; - void MakeNotOnPacket(WorldPacket *data, const std::string& name) - { - data->Initialize(SMSG_CHANNEL_NOTIFY, (1+10)); // we guess size - (*data) << (uint8)0x05 << name; - } + void MakeNotOnPacket(WorldPacket *data, std::string name); }; class AllianceChannelMgr : public ChannelMgr {}; class HordeChannelMgr : public ChannelMgr {}; -inline ChannelMgr* channelMgr(uint32 team) -{ - if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - //For Test,No Seprate Faction - return &Trinity::Singleton<AllianceChannelMgr>::Instance(); +ChannelMgr* channelMgr(uint32 team); - if(team==ALLIANCE) - return &Trinity::Singleton<AllianceChannelMgr>::Instance(); - if(team==HORDE) - return &Trinity::Singleton<HordeChannelMgr>::Instance(); - return NULL; -} #endif diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 84b830651e7..056bcd816e0 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -64,7 +64,7 @@ bool LoginQueryHolder::Initialize() // NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure. // !!! NOTE: including unused `zone`,`online` - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo,instance_id FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,instance_id,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2 ,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid)); @@ -73,7 +73,7 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT button,action,type FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" UI64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid)); @@ -123,7 +123,7 @@ class CharacterHandler void WorldSession::HandleCharEnum(QueryResult * result) { // keys can be non cleared if player open realm list and close it by 'cancel' - LoginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId()); + loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId()); WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size @@ -133,21 +133,15 @@ void WorldSession::HandleCharEnum(QueryResult * result) if( result ) { - Player *plr = new Player(this); do { uint32 guidlow = (*result)[0].GetUInt32(); sLog.outDetail("Loading char guid %u from account %u.",guidlow,GetAccountId()); - - if(plr->MinimalLoadFromDB( result, guidlow )) - { - plr->BuildEnumData( result, &data ); + if(Player::BuildEnumData(result, &data)) ++num; - } } while( result->NextRow() ); - delete plr; delete result; } @@ -162,19 +156,23 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ ) CharacterDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnumCallback, GetAccountId(), !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ? // ------- Query Without Declined Names -------- - // 0 1 2 3 4 5 6 7 8 - "SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, " - // 9 10 11 12 13 14 - "characters.at_login, characters.zone, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid " + // 0 1 2 3 4 5 6 7 + "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " + // 8 9 10 11 12 13 14 + "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " + // 15 16 17 18 19 + "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data " "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' " "LEFT JOIN guild_member ON characters.guid = guild_member.guid " "WHERE characters.account = '%u' ORDER BY characters.guid" : // --------- Query With Declined Names --------- - // 0 1 2 3 4 5 6 7 8 - "SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, " - // 9 10 11 12 13 14 15 - "characters.at_login, characters.zone, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, character_declinedname.genitive " + // 0 1 2 3 4 5 6 7 + "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " + // 8 9 10 11 12 13 14 + "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " + // 15 16 17 18 19 20 + "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_declinedname.genitive " "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' " "LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid " "LEFT JOIN guild_member ON characters.guid = guild_member.guid " @@ -251,38 +249,39 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) } // prevent character creating with invalid name - if(!normalizePlayerName(name)) + if (!normalizePlayerName(name)) { - data << (uint8)CHAR_NAME_INVALID_CHARACTER; + data << (uint8)CHAR_NAME_NO_NAME; SendPacket( &data ); sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId()); return; } // check name limitations - if(!ObjectMgr::IsValidName(name,true)) + uint8 res = ObjectMgr::CheckPlayerName(name,true); + if (res != CHAR_NAME_SUCCESS) { - data << (uint8)CHAR_NAME_INVALID_CHARACTER; + data << uint8(res); SendPacket( &data ); return; } - if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name)) + if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name)) { data << (uint8)CHAR_NAME_RESERVED; SendPacket( &data ); return; } - if(objmgr.GetPlayerGUIDByName(name)) + if (objmgr.GetPlayerGUIDByName(name)) { data << (uint8)CHAR_CREATE_NAME_IN_USE; SendPacket( &data ); return; } - QueryResult *resultacct = LoginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId()); - if ( resultacct ) + QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId()); + if (resultacct) { Field *fields=resultacct->Fetch(); uint32 acctcharcount = fields[0].GetUInt32(); @@ -340,7 +339,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) if(!AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) { - QueryResult *result2 = CharacterDatabase.PQuery("SELECT guid,race,class FROM characters WHERE account = '%u' %s", + QueryResult *result2 = CharacterDatabase.PQuery("SELECT level,race,class FROM characters WHERE account = '%u' %s", GetAccountId(), (skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT) ? "" : "LIMIT 1"); if(result2) { @@ -367,8 +366,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) if(!have_req_level_for_heroic) { - uint32 acc_guid = field[0].GetUInt32(); - uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid); + uint32 acc_level = field[0].GetUInt32(); if(acc_level >= req_level_for_heroic) have_req_level_for_heroic = true; } @@ -422,8 +420,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) if(!have_req_level_for_heroic) { - uint32 acc_guid = field[0].GetUInt32(); - uint32 acc_level = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,acc_guid); + uint32 acc_level = field[0].GetUInt32(); if(acc_level >= req_level_for_heroic) have_req_level_for_heroic = true; } @@ -464,8 +461,8 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) pNewChar->SaveToDB(); charcount+=1; - LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID); - LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID); + loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID); + loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID); delete pNewChar; // created only to call SaveToDB() @@ -739,7 +736,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) pCurrChar->SendInitialPacketsAfterAddToMap(); CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow()); - LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId()); + loginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId()); pCurrChar->SetInGameTime( getMSTime() ); // announce group about member online (must be after add to player list to receive announce to self) @@ -815,6 +812,10 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) SendDoFlight( mountDisplayId, path, startNode ); } + // reset for all pets before pet loading + if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) + Pet::resetTalentsForAllPetsOf(pCurrChar); + // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned) pCurrChar->LoadPet(); @@ -835,6 +836,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) { pCurrChar->resetTalents(true); + pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state SendNotification(LANG_RESET_TALENTS); } @@ -852,6 +854,9 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid:%u)", GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUIDLow()); + if(!pCurrChar->IsStandState() && !pCurrChar->hasUnitState(UNIT_STAT_STUNNED)) + pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); + m_playerLoading = false; delete holder; } @@ -985,7 +990,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) recv_data >> newname; // prevent character rename to invalid name - if(!normalizePlayerName(newname)) + if (!normalizePlayerName(newname)) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << uint8(CHAR_NAME_NO_NAME); @@ -993,16 +998,17 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) return; } - if(!ObjectMgr::IsValidName(newname, true)) + uint8 res = ObjectMgr::CheckPlayerName(newname,true); + if (res != CHAR_NAME_SUCCESS) { WorldPacket data(SMSG_CHAR_RENAME, 1); - data << uint8(CHAR_NAME_INVALID_CHARACTER); + data << uint8(res); SendPacket( &data ); return; } // check name limitations - if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) + if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << uint8(CHAR_NAME_RESERVED); @@ -1258,7 +1264,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data) } // prevent character rename to invalid name - if(!normalizePlayerName(newname)) + if (!normalizePlayerName(newname)) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_NAME_NO_NAME); @@ -1266,16 +1272,17 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data) return; } - if(!ObjectMgr::IsValidName(newname,true)) + uint8 res = ObjectMgr::CheckPlayerName(newname,true); + if (res != CHAR_NAME_SUCCESS) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); - data << uint8(CHAR_NAME_INVALID_CHARACTER); + data << uint8(res); SendPacket( &data ); return; } // check name limitations - if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) + if (GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname)) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_NAME_RESERVED); @@ -1284,9 +1291,9 @@ void WorldSession::HandleCharCustomize(WorldPacket& recv_data) } // character with this name already exist - if(uint64 newguid = objmgr.GetPlayerGUIDByName(newname)) + if (uint64 newguid = objmgr.GetPlayerGUIDByName(newname)) { - if(newguid != guid) + if (newguid != guid) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_CREATE_NAME_IN_USE); diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index d1e85f6baa0..06822627460 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -154,19 +154,21 @@ ChatCommand * ChatHandler::getCommandTable() { "anim", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugAnimCommand, "", NULL }, { "arena", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugArenaCommand, "", NULL }, { "bg", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugBattlegroundCommand, "", NULL }, - { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemState, "", NULL }, - { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipient, "", NULL }, - { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValue, "", NULL }, - { "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugMod32Value, "", NULL }, + { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemStateCommand, "", NULL }, + { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipientCommand, "", NULL }, + { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValueCommand, "", NULL }, + { "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugMod32ValueCommand, "", NULL }, { "play", SEC_MODERATOR, false, NULL, "", debugPlayCommandTable }, { "send", SEC_ADMINISTRATOR, false, NULL, "", debugSendCommandTable }, + { "setaurastate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetAuraStateCommand, "", NULL }, { "setitemflag", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemFlagCommand, "", NULL }, - { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValue, "", NULL }, + { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValueCommand, "", NULL }, { "spawnvehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpawnVehicle, "", NULL }, { "setvid", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetVehicleId, "", NULL }, { "entervehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugEnterVehicle, "", NULL }, { "uws", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdateWorldStateCommand, "", NULL }, - { "update", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdate, "", NULL }, + { "update", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugUpdateCommand, "", NULL }, + { "itemexpire", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugItemExpireCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; @@ -371,6 +373,7 @@ ChatCommand * ChatHandler::getCommandTable() { "tame", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcTameCommand, "", NULL }, { "setdeathstate", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetDeathStateCommand, "", NULL }, { "addformation", SEC_MODERATOR, false, &ChatHandler::HandleNpcAddFormationCommand, "", NULL }, + { "setlink", SEC_MODERATOR, false, &ChatHandler::HandleNpcSetLinkCommand, "", NULL }, //{ TODO: fix or remove this commands { "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAddWeaponCommand, "", NULL }, @@ -477,7 +480,6 @@ ChatCommand * ChatHandler::getCommandTable() { "skill_extra_item_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillExtraItemTemplateCommand, "", NULL }, { "skill_fishing_base_level", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSkillFishingBaseLevelCommand, "", NULL }, { "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL }, - { "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL }, { "spell_required", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellRequiredCommand, "", NULL }, { "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL }, { "spell_bonus_data", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellBonusesCommand, "", NULL }, @@ -546,7 +548,6 @@ ChatCommand * ChatHandler::getCommandTable() { { "cancel", SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCancelCommand,"", NULL }, { "" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleServerShutDownCommand, "", NULL }, - { "setlink", SEC_MODERATOR, false, &ChatHandler::HandleNpcSetLinkCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; @@ -627,7 +628,7 @@ ChatCommand * ChatHandler::getCommandTable() { "go", SEC_MODERATOR, false, NULL, "", goCommandTable }, { "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable }, { "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable }, - { "debug", SEC_MODERATOR, false, NULL, "", debugCommandTable }, + { "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable }, { "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable }, { "character", SEC_GAMEMASTER, false, NULL, "", characterCommandTable}, { "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable }, diff --git a/src/game/Chat.h b/src/game/Chat.h index b970628f94f..ee01b7b61f4 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -138,16 +138,19 @@ class ChatHandler bool HandleDebugAnimCommand(const char* args); bool HandleDebugArenaCommand(const char * args); bool HandleDebugBattlegroundCommand(const char * args); - bool HandleDebugGetItemState(const char * args); - bool HandleDebugGetLootRecipient(const char * args); - bool HandleDebugGetValue(const char* args); - bool HandleDebugMod32Value(const char* args); - bool HandleDebugSetValue(const char* args); + bool HandleDebugGetItemStateCommand(const char * args); + bool HandleDebugGetLootRecipientCommand(const char * args); + bool HandleDebugGetValueCommand(const char* args); + bool HandleDebugMod32ValueCommand(const char* args); + bool HandleDebugSetAuraStateCommand(const char * args); bool HandleDebugSetItemFlagCommand(const char * args); + bool HandleDebugItemExpireCommand(const char * args); bool HandleDebugSetVehicleId(const char * args); - bool HandleDebugSpawnVehicle(const char * args); bool HandleDebugEnterVehicle(const char * args); - bool HandleDebugUpdate(const char* args); + bool HandleDebugSetValueCommand(const char* args); + bool HandleDebugSpawnVehicle(const char * args); + bool HandleDebugSpellCheckCommand(const char* args); + bool HandleDebugUpdateCommand(const char* args); bool HandleDebugUpdateWorldStateCommand(const char* args); bool HandleDebugSet32Bit(const char* args); @@ -397,7 +400,6 @@ class ChatHandler bool HandleReloadSkillDiscoveryTemplateCommand(const char* args); bool HandleReloadSkillExtraItemTemplateCommand(const char* args); bool HandleReloadSkillFishingBaseLevelCommand(const char* args); - bool HandleReloadSpellAffectCommand(const char* args); bool HandleReloadSpellRequiredCommand(const char* args); bool HandleReloadSpellAreaCommand(const char* args); bool HandleReloadSpellElixirCommand(const char* args); @@ -562,7 +564,7 @@ class ChatHandler bool HandleQuestRemove(const char * args); bool HandleQuestComplete(const char * args);*/ - bool HandleSet32Bit(const char* args); + //bool HandleSet32Bit(const char* args); bool HandleSaveAllCommand(const char* args); Player* getSelectedPlayer(); diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index ae9da2d9fe5..6fdf9f0b222 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -155,6 +155,15 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) GetPlayer()->UpdateSpeakTime(); } + if (GetPlayer()->HasAura(1852) && type != CHAT_MSG_WHISPER) + { + std::string msg=""; + recv_data >> msg; + + SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); + return; + } + switch(type) { case CHAT_MSG_SAY: @@ -231,6 +240,12 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) } } + if (GetPlayer()->HasAura(1852) && !player->isGameMaster()) + { + SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName()); + return; + } + GetPlayer()->Whisper(msg, lang,player->GetGUID()); } break; diff --git a/src/game/Corpse.cpp b/src/game/Corpse.cpp index 9fe54be1bec..83d21bb3b14 100644 --- a/src/game/Corpse.cpp +++ b/src/game/Corpse.cpp @@ -39,6 +39,8 @@ Corpse::Corpse(CorpseType type) : WorldObject() m_type = type; + m_mapId = 0; + m_time = time(NULL); lootForBody = false; @@ -74,9 +76,11 @@ bool Corpse::Create( uint32 guidlow ) bool Corpse::Create( uint32 guidlow, Player *owner) { - SetInstanceId(owner->GetInstanceId()); + ASSERT(owner); - WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetMapId(), owner->GetPhaseMask()); + //we need to assign owner's map for corpse + //in other way we will get a crash in Corpse::SaveToDB() + SetMap(owner->GetMap()); Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation()); @@ -87,6 +91,8 @@ bool Corpse::Create( uint32 guidlow, Player *owner) return false; } + WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetPhaseMask()); + SetFloatValue( OBJECT_FIELD_SCALE_X, 1 ); SetUInt64Value( CORPSE_FIELD_OWNER, owner->GetGUID() ); @@ -146,6 +152,7 @@ void Corpse::DeleteFromDB() CharacterDatabase.PExecute("DELETE FROM corpse WHERE player = '%d' AND corpse_type <> '0'", GUID_LOPART(GetOwnerGUID())); } +/* bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId) { bool external = (result != NULL); @@ -173,7 +180,7 @@ bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId) delete result; return true; -} +}*/ bool Corpse::LoadFromDB(uint32 guid, Field *fields) { @@ -183,7 +190,6 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields) float positionY = fields[1].GetFloat(); float positionZ = fields[2].GetFloat(); float ort = fields[3].GetFloat(); - uint32 mapid = fields[4].GetUInt32(); Object::_Create(guid, 0, HIGHGUID_CORPSE); @@ -193,6 +199,9 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields) return false; } + SetMapId(fields[4].GetUInt32()); + SetInstanceId(fields[8].GetUInt32()); + m_time = time_t(fields[6].GetUInt64()); m_type = CorpseType(fields[7].GetUInt32()); @@ -202,15 +211,11 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields) return false; } - uint32 instanceid = fields[8].GetUInt32(); uint32 phaseMask = fields[9].GetUInt32(); // overwrite possible wrong/corrupted guid SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE)); - // place - SetInstanceId(instanceid); - SetMapId(mapid); SetPhaseMask(phaseMask, false); Relocate(positionX, positionY, positionZ, ort); diff --git a/src/game/Corpse.h b/src/game/Corpse.h index da3511abfbb..ee6556e3436 100644 --- a/src/game/Corpse.h +++ b/src/game/Corpse.h @@ -61,12 +61,19 @@ class Corpse : public WorldObject bool Create( uint32 guidlow, Player *owner ); void SaveToDB(); - bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId); + //bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId); bool LoadFromDB(uint32 guid, Field *fields); void DeleteBonesFromWorld(); void DeleteFromDB(); + void SetMap (Map * map) {WorldObject::SetMap(map); m_mapId = map->GetId(); SetInstanceId(map->GetInstanceId());} + // Used to check object existence in unloaded grids + uint32 GetMapId() const {return m_mapId;} + void SetMapId (uint32 id) {m_mapId = id;} + uint32 GetInstanceId() const {return m_instanceId;} + void SetInstanceId (uint32 id) {m_instanceId = id;} + uint64 const& GetOwnerGUID() const { return GetUInt64Value(CORPSE_FIELD_OWNER); } time_t const& GetGhostTime() const { return m_time; } @@ -95,6 +102,8 @@ class Corpse : public WorldObject CorpseType m_type; time_t m_time; GridPair m_grid; // gride for corpse position for fast search + uint32 m_mapId; // map id for fast corpse check at packet requests and in other situations with unloaded map of corpse. + uint32 m_instanceId; }; #endif diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 50fa95337f6..fc2185bb5a8 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -691,17 +691,18 @@ void Creature::Motion_Initialize() bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 team, float x, float y, float z, float ang, const CreatureData *data) { + ASSERT(map); + SetMap(map); + SetPhaseMask(phaseMask,false); + Relocate(x, y, z, ang); + if(!IsPositionValid()) { sLog.outError("Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,Entry,x,y); return false; } - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); - SetPhaseMask(phaseMask,false); - //oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0; const bool bResult = CreateFromProto(guidlow, Entry, team, data); @@ -1392,7 +1393,7 @@ void Creature::SelectLevel(const CreatureInfo *cinfo) //damage - float damagemod = _GetDamageMod(rank); + float damagemod = 1.0f;//_GetDamageMod(rank); SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); @@ -2055,7 +2056,7 @@ void Creature::CallAssistance() TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyAssistCreatureInRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher); CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(GetMapId(), this)); + cell_lock->Visit(cell_lock, grid_creature_searcher, *GetMap()); } if (!assistList.empty()) @@ -2102,6 +2103,10 @@ bool Creature::CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction / if (!isAlive()) return false; + // we don't need help from non-combatant ;) + if (isCivilian()) + return false; + // skip fighting creature if (isInCombat()) return false; @@ -2262,6 +2267,43 @@ void Creature::SendZoneUnderAttackMessage(Player* attacker) sWorld.SendGlobalMessage(&data,NULL,(enemy_team==ALLIANCE ? HORDE : ALLIANCE)); } +void Creature::SetInCombatWithZone() +{ + if (!CanHaveThreatList()) + { + sLog.outError("Creature entry %u call SetInCombatWithZone but creature cannot have threat list.", GetEntry()); + return; + } + + Map* pMap = GetMap(); + + if (!pMap->IsDungeon()) + { + sLog.outError("Creature entry %u call SetInCombatWithZone for map (id: %u) that isn't an instance.", GetEntry(), pMap->GetId()); + return; + } + + Map::PlayerList const &PlList = pMap->GetPlayers(); + + if (PlList.isEmpty()) + return; + + for(Map::PlayerList::const_iterator i = PlList.begin(); i != PlList.end(); ++i) + { + if (Player* pPlayer = i->getSource()) + { + if (pPlayer->isGameMaster()) + continue; + + if (pPlayer->isAlive()) + { + pPlayer->SetInCombatWith(this); + AddThreat(pPlayer, 0.0f); + } + } + } +} + void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time) { m_CreatureSpellCooldowns[spell_id] = end_time; @@ -2540,3 +2582,4 @@ time_t Creature::GetLinkedCreatureRespawnTime() const return 0; } + diff --git a/src/game/Creature.h b/src/game/Creature.h index f29982436d5..d291aaf9db0 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -150,6 +150,7 @@ enum CreatureFlagsExtra CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging) //CREATURE_FLAG_EXTRA_CHARM_AI = 0x00008000, // use ai when charmed CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes + CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills }; enum SummonMask @@ -163,6 +164,7 @@ enum SummonMask SUMMON_MASK_VEHICLE = 0x00000020, SUMMON_MASK_PUPPET = 0x00000040, SUMMON_MASK_HUNTER_PET = 0x00000080, + SUMMON_MASK_CONTROLABLE_GUARDIAN = 0x00000100, }; // 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 @@ -172,13 +174,14 @@ enum SummonMask #pragma pack(push,1) #endif +#define MAX_KILL_CREDIT 2 + // from `creature_template` table struct CreatureInfo { uint32 Entry; uint32 HeroicEntry; - uint32 unk1; - uint32 unk2; + uint32 KillCredit[MAX_KILL_CREDIT]; uint32 DisplayID_A[2]; uint32 DisplayID_H[2]; char* Name; @@ -319,7 +322,7 @@ struct CreatureData struct CreatureDataAddonAura { - uint16 spell_id; + uint32 spell_id; uint8 effect_idx; }; @@ -692,6 +695,8 @@ class TRINITY_DLL_SPEC Creature : public Unit void SendZoneUnderAttackMessage(Player* attacker); + void SetInCombatWithZone(); + bool hasQuest(uint32 quest_id) const; bool hasInvolvedQuest(uint32 quest_id) const; @@ -700,10 +705,10 @@ class TRINITY_DLL_SPEC Creature : public Unit virtual uint8 GetPetAutoSpellSize() const { return CREATURE_MAX_SPELLS; } virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const { - if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->active != ACT_ENABLED) + if (pos >= CREATURE_MAX_SPELLS || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED) return 0; else - return m_charmInfo->GetCharmSpell(pos)->spellId; + return m_charmInfo->GetCharmSpell(pos)->GetAction(); } void SetHomePosition(float x, float y, float z, float ori) { mHome_X = x; mHome_Y = y; mHome_Z = z; mHome_O = ori;} @@ -734,10 +739,11 @@ class TRINITY_DLL_SPEC Creature : public Unit } void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; } uint32 m_PlayerDamageReq; - + void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; } static float _GetDamageMod(int32 Rank); + protected: bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); @@ -751,7 +757,6 @@ class TRINITY_DLL_SPEC Creature : public Unit uint32 m_lootMoney; uint64 m_lootRecipient; - uint32 m_unDamageByPlayers; /// Timers uint32 m_deathTimer; // (msecs)timer for death or corpse disappearance diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index 9f06ca38b56..165bb2411ec 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -91,6 +91,13 @@ void CreatureAI::DoZoneInCombat(Creature* creature) pPlayer->SetInCombatWith(creature); creature->AddThreat(pPlayer, 0.0f); } + + for(Unit::ControlList::const_iterator itr = pPlayer->m_Controlled.begin(); itr != pPlayer->m_Controlled.end(); ++itr) + { + creature->SetInCombatWith(*itr); + (*itr)->SetInCombatWith(creature); + creature->AddThreat(*itr, 0.0f); + } } } } @@ -148,7 +155,6 @@ bool CreatureAI::UpdateVictim() { if(!me->isInCombat()) return false; - if(Unit *victim = me->SelectVictim()) AttackStart(victim); return me->getVictim(); @@ -194,10 +200,16 @@ void CreatureAI::EnterEvadeMode() if(!_EnterEvadeMode()) return; - if(Unit *owner = me->GetCharmerOrOwner()) - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE); - else - me->GetMotionMaster()->MoveTargetedHome(); + if(!me->m_Vehicle) // otherwise me will be in evade mode forever + { + if(Unit *owner = me->GetCharmerOrOwner()) + { + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, m_creature->GetFollowAngle(), MOTION_SLOT_ACTIVE); + } + else + me->GetMotionMaster()->MoveTargetedHome(); + } Reset(); } diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h index 91fabe30448..061b3d273c2 100644 --- a/src/game/CreatureAI.h +++ b/src/game/CreatureAI.h @@ -115,6 +115,7 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc) //virtual void AttackedBy(Unit* attacker); + virtual bool IsEscorted () {return false;} // Called when creature is spawned or respawned (for reseting variables) virtual void JustRespawned() { Reset(); } diff --git a/src/game/CreatureAIImpl.h b/src/game/CreatureAIImpl.h index f6653ce40f7..bcedd108d44 100644 --- a/src/game/CreatureAIImpl.h +++ b/src/game/CreatureAIImpl.h @@ -246,10 +246,13 @@ enum AICondition struct AISpellInfoType { - AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT), cooldown(AI_DEFAULT_COOLDOWN) {} + AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT) + , cooldown(AI_DEFAULT_COOLDOWN), realCooldown(0), maxRange(0.0f){} AITarget target; AICondition condition; uint32 cooldown; + uint32 realCooldown; + float maxRange; }; TRINITY_DLL_SPEC AISpellInfoType * GetAISpellInfo(uint32 i); diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index 65e50a2e41b..68055bcddd3 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -54,13 +54,13 @@ namespace FactorySelector // select by NPC flags if(!ai_factory) { - if(creature->isGuardian() && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) + if(creature->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER) ai_factory = ai_registry.GetRegistryItem("PetAI"); else if(creature->isVehicle() || creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) ai_factory = ai_registry.GetRegistryItem("NullCreatureAI"); else if(creature->isGuard()) ai_factory = ai_registry.GetRegistryItem("GuardAI"); - else if(creature->isGuardian()) + else if(creature->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN)) ai_factory = ai_registry.GetRegistryItem("PetAI"); else if(creature->isTotem()) ai_factory = ai_registry.GetRegistryItem("TotemAI"); @@ -71,7 +71,7 @@ namespace FactorySelector else ai_factory = ai_registry.GetRegistryItem("NullCreatureAI"); } - else if(creature->GetCreatureType() == CREATURE_TYPE_CRITTER) + else if(creature->GetCreatureType() == CREATURE_TYPE_CRITTER && !creature->HasSummonMask(SUMMON_MASK_GUARDIAN)) ai_factory = ai_registry.GetRegistryItem("CritterAI"); } diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index 0393c30e7d3..5c425217844 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -30,6 +30,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "InstanceData.h" +#include "SpellMgr.h" bool CreatureEventAIHolder::UpdateRepeatTimer( Creature* creature, uint32 repeatMin, uint32 repeatMax ) { @@ -95,6 +96,8 @@ CreatureEventAI::CreatureEventAI(Creature *c ) : CreatureAI(c) AttackDistance = 0.0f; AttackAngle = 0.0f; + InvinceabilityHpLevel = 0; + //Handle Spawned Events if (!bEmptyList) { @@ -113,13 +116,6 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction if (pHolder.Event.event_inverse_phase_mask & (1 << Phase)) return false; - //Store random here so that all random actions match up - uint32 rnd = rand(); - - //Return if chance for event is not met - if (pHolder.Event.event_chance <= rnd % 100) - return false; - CreatureEventAI_Event const& event = pHolder.Event; //Check event conditions based on the event type, also reset events @@ -331,6 +327,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE)) pHolder.Enabled = false; + //Store random here so that all random actions match up + uint32 rnd = rand(); + + //Return if chance for event is not met + if (pHolder.Event.event_chance <= rnd % 100) + return false; + //Process actions for (uint32 j = 0; j < MAX_ACTIONS; j++) ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker); @@ -746,15 +749,10 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(),NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); break; case ACTION_T_ZONE_COMBAT_PULSE: - if (!m_creature->isInCombat() || !m_creature->GetMap()->IsDungeon()) - { - - sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_ZONE_COMBAT_PULSE on creature out of combat or in non-dungeon map. Creature %d", EventId, m_creature->GetEntry()); - return; - } - - DoZoneInCombat(m_creature); + { + m_creature->SetInCombatWithZone(); break; + } case ACTION_T_CALL_FOR_HELP: { m_creature->CallForHelp(action.call_for_help.radius); @@ -796,6 +794,14 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 m_creature->ForcedDespawn(); break; } + case ACTION_T_SET_INVINCIBILITY_HP_LEVEL: + { + if(action.invincibility_hp_level.is_percent) + InvinceabilityHpLevel = m_creature->GetMaxHealth()*action.invincibility_hp_level.hp_level/100; + else + InvinceabilityHpLevel = action.invincibility_hp_level.hp_level; + break; + } } } @@ -1302,7 +1308,7 @@ bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Trigge return false; //Check for power - if (!Triggered && me->GetPower((Powers)Spell->powerType) < Spell->manaCost) + if (!Triggered && me->GetPower((Powers)Spell->powerType) < CalculatePowerCost(Spell, me, GetSpellSchoolMask(Spell))) return false; SpellRangeEntry const *TempRange = NULL; @@ -1342,6 +1348,17 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote) } } +void CreatureEventAI::DamageTaken( Unit* done_by, uint32& damage ) +{ + if(InvinceabilityHpLevel > 0 && m_creature->GetHealth() < InvinceabilityHpLevel+damage) + { + if(m_creature->GetHealth() <= InvinceabilityHpLevel) + damage = 0; + else + damage = m_creature->GetHealth() - InvinceabilityHpLevel; + } +} + bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& event) { if(event.event_type != EVENT_T_SPAWNED) diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h index ad3827ef75d..7882e7542ec 100644 --- a/src/game/CreatureEventAI.h +++ b/src/game/CreatureEventAI.h @@ -113,6 +113,7 @@ enum EventAI_ActionType ACTION_T_FORCE_DESPAWN = 41, // No Params ACTION_T_END = 105, + ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health) }; enum Target @@ -379,6 +380,12 @@ struct CreatureEventAI_Action { uint32 sheath; } set_sheath; + // ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42 + struct + { + uint32 hp_level; + uint32 is_percent; + } invincibility_hp_level; // RAW struct { @@ -581,6 +588,7 @@ class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI void AttackStart(Unit *who); void MoveInLineOfSight(Unit *who); void SpellHit(Unit* pUnit, const SpellEntry* pSpell); + void DamageTaken(Unit* done_by, uint32& damage); void UpdateAI(const uint32 diff); void ReceiveEmote(Player* pPlayer, uint32 text_emote); static int Permissible(const Creature *); @@ -608,10 +616,11 @@ class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI bool bEmptyList; //Variables used by Events themselves - uint8 Phase; //Current phase, max 32 phases - bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat) - bool MeleeEnabled; //If we allow melee auto attack - float AttackDistance; //Distance to attack from - float AttackAngle; //Angle of attack + uint8 Phase; // Current phase, max 32 phases + bool CombatMovementEnabled; // If we allow targeted movment gen (movement twoards top threat) + bool MeleeEnabled; // If we allow melee auto attack + float AttackDistance; // Distance to attack from + float AttackAngle; // Angle of attack + uint32 InvinceabilityHpLevel; // Minimal health level allowed at damage apply }; #endif diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp index 38cc84177e4..901ec541455 100644 --- a/src/game/CreatureEventAIMgr.cpp +++ b/src/game/CreatureEventAIMgr.cpp @@ -39,7 +39,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Texts() objmgr.LoadTrinityStrings(WorldDatabase,"creature_ai_texts",MIN_CREATURE_AI_TEXT_STRING_ID,MAX_CREATURE_AI_TEXT_STRING_ID); // Gather Additional data from EventAI Texts - QueryResult *result = WorldDatabase.PQuery("SELECT entry, sound, type, language, emote FROM creature_ai_texts"); + QueryResult *result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM creature_ai_texts"); sLog.outString("Loading EventAI Texts additional data..."); if (result) @@ -117,8 +117,8 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Summons() //Drop Existing EventSummon Map m_CreatureEventAI_Summon_Map.clear(); - //Gather additional data for EventAI - QueryResult *result = WorldDatabase.PQuery("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons"); + // Gather additional data for EventAI + QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons"); if (result) { barGoLink bar(result->GetRowCount()); @@ -169,8 +169,8 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() //Drop Existing EventAI List m_CreatureEventAI_Event_Map.clear(); - //Gather event data - QueryResult *result = WorldDatabase.PQuery("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, " + // Gather event data + QueryResult *result = WorldDatabase.Query("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, " "event_param1, event_param2, event_param3, event_param4, " "action1_type, action1_param1, action1_param2, action1_param3, " "action2_type, action2_param1, action2_param2, action2_param3, " @@ -473,9 +473,8 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() action.morph.modelId = 0; } } - - break; } + break; case ACTION_T_SOUND: if (!sSoundEntriesStore.LookupEntry(action.sound.soundId)) sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, action.sound.soundId); @@ -662,6 +661,16 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() action.set_sheath.sheath = SHEATH_STATE_UNARMED; } break; + case ACTION_T_SET_INVINCIBILITY_HP_LEVEL: + if(action.invincibility_hp_level.is_percent) + { + if(action.invincibility_hp_level.hp_level > 100) + { + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses wrong percent value %u.", i, j+1, action.invincibility_hp_level.hp_level); + action.invincibility_hp_level.hp_level = 100; + } + } + break; case ACTION_T_EVADE: //No Params case ACTION_T_FLEE_FOR_ASSIST: //No Params case ACTION_T_DIE: //No Params diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp index f618b8cfb8c..42780870499 100644 --- a/src/game/DBCStores.cpp +++ b/src/game/DBCStores.cpp @@ -191,7 +191,7 @@ inline void LoadDBC(uint32& availableDbcLocales,barGoLink& bar, StoreProblemList if(f) { char buf[100]; - snprintf(buf,100," (exist, but have %d fields instead %d) Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat())); + snprintf(buf,100," (exist, but have %d fields instead " SIZEFMTD ") Wrong client version DBC file?",storage.GetFieldCount(),strlen(storage.GetFormat())); errlist.push_back(dbc_filename + buf); fclose(f); } @@ -696,3 +696,4 @@ TRINITY_DLL_SPEC DBCStorage <ItemEntry> const* GetItemDisplayStore() TRINITY_DLL_SPEC DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore() { return &sCreatureDisplayInfoStore; } TRINITY_DLL_SPEC DBCStorage <EmotesEntry> const* GetEmotesStore() { return &sEmotesStore; } TRINITY_DLL_SPEC DBCStorage <EmotesTextEntry> const* GetEmotesTextStore() { return &sEmotesTextStore; } +TRINITY_DLL_SPEC DBCStorage <AchievementEntry> const* GetAchievementStore() { return &sAchievementStore; } diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h index a423cd0bfc8..fc47568e6a5 100644 --- a/src/game/DBCStores.h +++ b/src/game/DBCStores.h @@ -158,4 +158,5 @@ TRINITY_DLL_SPEC DBCStorage <ItemEntry> const* GetItemDisplaySt TRINITY_DLL_SPEC DBCStorage <CreatureDisplayInfoEntry> const* GetCreatureDisplayStore(); TRINITY_DLL_SPEC DBCStorage <EmotesEntry> const* GetEmotesStore(); TRINITY_DLL_SPEC DBCStorage <EmotesTextEntry> const* GetEmotesTextStore(); +TRINITY_DLL_SPEC DBCStorage <AchievementEntry> const* GetAchievementStore(); #endif diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index 686c43fc355..a8b5d3ef177 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -84,11 +84,14 @@ struct AchievementCriteriaEntry } kill_creature; // ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1 - // TODO: there are further criterias instead just winning struct { uint32 bgMapID; // 3 uint32 winCount; // 4 + uint32 additionalRequirement1_type; // 5 additional requirement 1 type + uint32 additionalRequirement1_value; // 6 additional requirement 1 value + uint32 additionalRequirement2_type; // 7 additional requirement 2 type + uint32 additionalRequirement2_value; // 8 additional requirement 1 value } win_bg; // ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5 @@ -490,7 +493,9 @@ struct AchievementCriteriaEntry //uint32 name_flags; // 25 uint32 completionFlag; // 26 uint32 groupFlag; // 27 - //uint32 unk1; // 28 + //uint32 unk1; // 28 Alway appears with timed events + // for timed spells it is spell id for + // timed kills it is creature id uint32 timeLimit; // 29 time limit in seconds //uint32 showOrder; // 30 show order }; @@ -507,6 +512,14 @@ struct AreaTableEntry char* area_name[16]; // 11-26 // 27, string flags, unused uint32 team; // 28 + + // helpers + bool IsSanctuary() const + { + if (mapid == 609) + return true; + return (flags & AREA_FLAG_SANCTUARY); + } }; struct AreaGroupEntry @@ -1423,7 +1436,7 @@ struct SpellEntry uint32 SchoolMask; // 228 m_schoolMask uint32 runeCostID; // 229 m_runeCostID //uint32 spellMissileID; // 230 m_spellMissileID not used - //uint32 PowerDisplayId; // 231 PowerDisplay.dbc, new in 3.1 + //uint32 PowerDisplayId; // 231 PowerDisplay.dbc, new in 3.1 // helpers int32 CalculateSimpleValue(uint8 eff) const { return EffectBasePoints[eff]+int32(EffectBaseDice[eff]); } @@ -1453,13 +1466,6 @@ struct SpellFocusObjectEntry // 16 string flags, unused }; -// stored in SQL table -struct SpellThreatEntry -{ - uint32 spellId; - int32 threat; -}; - struct SpellRadiusEntry { uint32 ID; diff --git a/src/game/Debugcmds.cpp b/src/game/Debugcmds.cpp index d8b94df4e10..69b3bcb1284 100644 --- a/src/game/Debugcmds.cpp +++ b/src/game/Debugcmds.cpp @@ -36,10 +36,12 @@ #include "CellImpl.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" +#include "SpellMgr.h" +#include "ScriptCalls.h" bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args) { - if(!args) + if (!*args) return false; char* px = strtok((char*)args, " "); @@ -47,7 +49,7 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args) return false; uint8 failnum = (uint8)atoi(px); - if(failnum==0 && *px!='0') + if (failnum==0 && *px!='0') return false; char* p1 = strtok(NULL, " "); @@ -72,20 +74,20 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args) bool ChatHandler::HandleDebugSendPoiCommand(const char* args) { + if (!*args) + return false; + Player *pPlayer = m_session->GetPlayer(); Unit* target = getSelectedUnit(); - if(!target) + if (!target) { SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); return true; } - if(!args) - return false; - char* icon_text = strtok((char*)args, " "); char* flags_text = strtok(NULL, " "); - if(!icon_text || !flags_text) + if (!icon_text || !flags_text) return false; uint32 icon = atol(icon_text); @@ -98,7 +100,7 @@ bool ChatHandler::HandleDebugSendPoiCommand(const char* args) bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args) { - if(!args) + if (!*args) return false; uint8 msg = atoi(args); @@ -108,7 +110,7 @@ bool ChatHandler::HandleDebugSendEquipErrorCommand(const char* args) bool ChatHandler::HandleDebugSendSellErrorCommand(const char* args) { - if(!args) + if (!*args) return false; uint8 msg = atoi(args); @@ -118,7 +120,7 @@ bool ChatHandler::HandleDebugSendSellErrorCommand(const char* args) bool ChatHandler::HandleDebugSendBuyErrorCommand(const char* args) { - if(!args) + if (!*args) return false; uint8 msg = atoi(args); @@ -137,7 +139,7 @@ bool ChatHandler::HandleDebugSendOpcodeCommand(const char* /*args*/) if(!unit) unit = player; std::ifstream ifs("opcode.txt"); - if(ifs.bad()) + if (ifs.bad()) return false; uint32 opcode; @@ -273,7 +275,7 @@ bool ChatHandler::HandleDebugPlayCinematicCommand(const char* args) { // USAGE: .debug play cinematic #cinematicid // #cinematicid - ID decimal number from CinemaicSequences.dbc (1st column) - if( !*args ) + if (!*args) { SendSysMessage(LANG_BAD_VALUE); SetSentErrorMessage(true); @@ -282,7 +284,7 @@ bool ChatHandler::HandleDebugPlayCinematicCommand(const char* args) uint32 dwId = atoi((char*)args); - if(!sCinematicSequencesStore.LookupEntry(dwId)) + if (!sCinematicSequencesStore.LookupEntry(dwId)) { PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, dwId); SetSentErrorMessage(true); @@ -297,7 +299,7 @@ bool ChatHandler::HandleDebugPlayMovieCommand(const char* args) { // USAGE: .debug play movie #movieid // #movieid - ID decimal number from Movie.dbc (1st column) - if( !*args ) + if (!*args) { SendSysMessage(LANG_BAD_VALUE); SetSentErrorMessage(true); @@ -306,7 +308,7 @@ bool ChatHandler::HandleDebugPlayMovieCommand(const char* args) uint32 dwId = atoi((char*)args); - if(!sMovieStore.LookupEntry(dwId)) + if (!sMovieStore.LookupEntry(dwId)) { PSendSysMessage(LANG_MOVIE_NOT_EXIST, dwId); SetSentErrorMessage(true); @@ -322,7 +324,7 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args) { // USAGE: .debug playsound #soundid // #soundid - ID decimal number from SoundEntries.dbc (1st column) - if( !*args ) + if (!*args) { SendSysMessage(LANG_BAD_VALUE); SetSentErrorMessage(true); @@ -331,7 +333,7 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args) uint32 dwSoundId = atoi((char*)args); - if(!sSoundEntriesStore.LookupEntry(dwSoundId)) + if (!sSoundEntriesStore.LookupEntry(dwSoundId)) { PSendSysMessage(LANG_SOUND_NOT_EXIST, dwSoundId); SetSentErrorMessage(true); @@ -339,14 +341,14 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args) } Unit* unit = getSelectedUnit(); - if(!unit) + if (!unit) { SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); SetSentErrorMessage(true); return false; } - if(m_session->GetPlayer()->GetSelection()) + if (m_session->GetPlayer()->GetSelection()) unit->PlayDistanceSound(dwSoundId,m_session->GetPlayer()); else unit->PlayDirectSound(dwSoundId,m_session->GetPlayer()); @@ -358,7 +360,7 @@ bool ChatHandler::HandleDebugPlaySoundCommand(const char* args) //Send notification in channel bool ChatHandler::HandleDebugSendChannelNotifyCommand(const char* args) { - if(!args) + if (!*args) return false; const char *name = "test"; @@ -376,7 +378,7 @@ bool ChatHandler::HandleDebugSendChannelNotifyCommand(const char* args) //Send notification in chat bool ChatHandler::HandleDebugSendChatMsgCommand(const char* args) { - if(!args) + if (!*args) return false; const char *msg = "testtest"; @@ -394,10 +396,10 @@ bool ChatHandler::HandleDebugSendQuestPartyMsgCommand(const char* args) return true; } -bool ChatHandler::HandleDebugGetLootRecipient(const char* /*args*/) +bool ChatHandler::HandleDebugGetLootRecipientCommand(const char* /*args*/) { Creature* target = getSelectedCreature(); - if(!target) + if (!target) return false; PSendSysMessage("loot recipient: %s", target->hasLootRecipient()?(target->GetLootRecipient()?target->GetLootRecipient()->GetName():"offline"):"no loot recipient"); @@ -411,9 +413,9 @@ bool ChatHandler::HandleDebugSendQuestInvalidMsgCommand(const char* args) return true; } -bool ChatHandler::HandleDebugGetItemState(const char* args) +bool ChatHandler::HandleDebugGetItemStateCommand(const char* args) { - if (!args) + if (!*args) return false; std::string state_str = args; @@ -613,13 +615,13 @@ bool ChatHandler::HandleDebugGetItemState(const char* args) if (item->GetOwnerGUID() != player->GetGUID()) { - PSendSysMessage("queue(%d): for the an item (guid %d), the owner's guid (%d) and player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); + PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the owner's guid (%d) and player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); error = true; continue; } if (item->GetQueuePos() != i) { - PSendSysMessage("queue(%d): for the an item (guid %d), the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow()); + PSendSysMessage("queue(" SIZEFMTD "): for the an item (guid %d), the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow()); error = true; continue; } @@ -628,13 +630,13 @@ bool ChatHandler::HandleDebugGetItemState(const char* args) if (test == NULL) { - PSendSysMessage("queue(%d): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); + PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); error = true; continue; } if (test != item) { - PSendSysMessage("queue(%d): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); + PSendSysMessage("queue(" SIZEFMTD "): the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); error = true; continue; } } @@ -757,7 +759,7 @@ bool ChatHandler::HandleDebugEnterVehicle(const char * args) bool ChatHandler::HandleDebugSpawnVehicle(const char* args) { - if(!args) + if (!*args) return false; char* e = strtok((char*)args, " "); @@ -778,12 +780,12 @@ bool ChatHandler::HandleDebugSpawnVehicle(const char* args) CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry); - if(!ci) + if (!ci) return false; VehicleEntry const *ve = sVehicleStore.LookupEntry(id); - if(!ve) + if (!ve) return false; Vehicle *v = new Vehicle; @@ -812,7 +814,7 @@ bool ChatHandler::HandleDebugSendLargePacketCommand(const char* /*args*/) bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args) { - if(!args) + if (!*args) return false; uint32 PhaseShift = atoi(args); @@ -822,7 +824,7 @@ bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args) bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args) { - if(!args) + if (!*args) return false; char* e = strtok((char*)args, " "); @@ -836,7 +838,7 @@ bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args) Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); - if(!i) + if (!i) return false; i->SetUInt32Value(ITEM_FIELD_FLAGS, flag); @@ -844,6 +846,28 @@ bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args) return true; } +bool ChatHandler::HandleDebugItemExpireCommand(const char* args) +{ + if (!*args) + return false; + + char* e = strtok((char*)args, " "); + if (!e) + return false; + + uint32 guid = (uint32)atoi(e); + + Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); + + if (!i) + return false; + + m_session->GetPlayer()->DestroyItem( i->GetBagSlot(),i->GetSlot(), true); + Script->ItemExpire(m_session->GetPlayer(),i->GetProto()); + + return true; +} + //show animation bool ChatHandler::HandleDebugAnimCommand(const char* args) { @@ -854,3 +878,216 @@ bool ChatHandler::HandleDebugAnimCommand(const char* args) m_session->GetPlayer()->HandleEmoteCommand(anim_id); return true; } + +bool ChatHandler::HandleDebugSetAuraStateCommand(const char* args) +{ + if (!*args) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Unit* unit = getSelectedUnit(); + if (!unit) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + int32 state = atoi((char*)args); + if (!state) + { + // reset all states + for(int i = 1; i <= 32; ++i) + unit->ModifyAuraState(AuraState(i),false); + return true; + } + + unit->ModifyAuraState(AuraState(abs(state)),state > 0); + return true; +} + +bool ChatHandler::HandleDebugSetValueCommand(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + + if (!px || !py) + return false; + + WorldObject* target = getSelectedObject(); + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = target->GetGUID(); + + uint32 Opcode = (uint32)atoi(px); + if(Opcode >= target->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); + return false; + } + uint32 iValue; + float fValue; + bool isint32 = true; + if(pz) + isint32 = (bool)atoi(pz); + if(isint32) + { + iValue = (uint32)atoi(py); + sLog.outDebug(GetTrinityString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue); + target->SetUInt32Value( Opcode , iValue ); + PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue); + } + else + { + fValue = (float)atof(py); + sLog.outDebug(GetTrinityString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue); + target->SetFloatValue( Opcode , fValue ); + PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue); + } + + return true; +} + +bool ChatHandler::HandleDebugGetValueCommand(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + char* pz = strtok(NULL, " "); + + if (!px) + return false; + + Unit* target = getSelectedUnit(); + if(!target) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + uint64 guid = target->GetGUID(); + + uint32 Opcode = (uint32)atoi(px); + if(Opcode >= target->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); + return false; + } + uint32 iValue; + float fValue; + bool isint32 = true; + if(pz) + isint32 = (bool)atoi(pz); + + if(isint32) + { + iValue = target->GetUInt32Value( Opcode ); + sLog.outDebug(GetTrinityString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue); + PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue); + } + else + { + fValue = target->GetFloatValue( Opcode ); + sLog.outDebug(GetTrinityString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue); + PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue); + } + + return true; +} + +bool ChatHandler::HandleDebugMod32ValueCommand(const char* args) +{ + if(!*args) + return false; + + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + + if (!px || !py) + return false; + + uint32 Opcode = (uint32)atoi(px); + int Value = atoi(py); + + if(Opcode >= m_session->GetPlayer()->GetValuesCount()) + { + PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer( )->GetValuesCount()); + return false; + } + + sLog.outDebug(GetTrinityString(LANG_CHANGE_32BIT), Opcode, Value); + + int CurrentValue = (int)m_session->GetPlayer( )->GetUInt32Value( Opcode ); + + CurrentValue += Value; + m_session->GetPlayer( )->SetUInt32Value( Opcode , (uint32)CurrentValue ); + + PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue); + + return true; +} + +bool ChatHandler::HandleDebugUpdateCommand(const char* args) +{ + if(!*args) + return false; + + uint32 updateIndex; + uint32 value; + + char* pUpdateIndex = strtok((char*)args, " "); + + Unit* chr = getSelectedUnit(); + if (chr == NULL) + { + SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if(!pUpdateIndex) + { + return true; + } + updateIndex = atoi(pUpdateIndex); + //check updateIndex + if(chr->GetTypeId() == TYPEID_PLAYER) + { + if (updateIndex>=PLAYER_END) return true; + } + else + { + if (updateIndex>=UNIT_END) return true; + } + + char* pvalue = strtok(NULL, " "); + if (!pvalue) + { + value=chr->GetUInt32Value(updateIndex); + + PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value); + return true; + } + + value=atoi(pvalue); + + PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value); + + chr->SetUInt32Value(updateIndex,value); + + return true; +} diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h index d50d8c3e727..c84ce19a96d 100644 --- a/src/game/DestinationHolderImp.h +++ b/src/game/DestinationHolderImp.h @@ -142,7 +142,7 @@ DestinationHolder<TRAVELLER>::UpdateTraveller(TRAVELLER &traveller, uint32 diff, i_fromZ = z; } - if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y ) + if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y || traveller.GetTraveller().GetPositionZ() != z) { float ori = traveller.GetTraveller().GetAngle(x, y); traveller.Relocation(x, y, z, ori); diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index dc2b05e8d6a..80b0d91a1b8 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -72,9 +72,8 @@ void DynamicObject::RemoveFromWorld() bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32 effIndex, float x, float y, float z, int32 duration, float radius ) { - SetInstanceId(caster->GetInstanceId()); + SetMap(caster->GetMap()); - WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetMapId(), caster->GetPhaseMask()); Relocate(x, y, z, 0); if(!IsPositionValid()) @@ -83,6 +82,8 @@ bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32 return false; } + WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask()); + SetEntry(spellId); SetFloatValue( OBJECT_FIELD_SCALE_X, 1 ); SetUInt64Value( DYNAMICOBJECT_CASTER, caster->GetGUID() ); diff --git a/src/game/FleeingMovementGenerator.cpp b/src/game/FleeingMovementGenerator.cpp index 2eddd2a128c..eef98b705cc 100644 --- a/src/game/FleeingMovementGenerator.cpp +++ b/src/game/FleeingMovementGenerator.cpp @@ -413,6 +413,7 @@ template bool FleeingMovementGenerator<Creature>::Update(Creature &, const uint3 void TimedFleeingMovementGenerator::Finalize(Unit &owner) { + owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); owner.clearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_ROAMING); if (Unit* victim = owner.getVictim()) { diff --git a/src/game/Formulas.h b/src/game/Formulas.h index 041c0621c74..2ec175f95be 100644 --- a/src/game/Formulas.h +++ b/src/game/Formulas.h @@ -117,7 +117,7 @@ namespace Trinity (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) )) return 0; - uint32 xp_gain= BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(),pl->GetZoneId())); + uint32 xp_gain= BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(),u->GetZoneId())); if( xp_gain == 0 ) return 0; diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 0984c896eac..5b7aa737bc0 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -1215,7 +1215,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size()) { - sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size()); + sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventCreatureGuids.size()); return; } @@ -1248,7 +1248,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size()) { - sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size()); + sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventGameobjectGuids.size()); return; } @@ -1282,7 +1282,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size()) { - sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size()); + sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size()); return; } @@ -1298,7 +1298,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size()) { - sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size()); + sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventCreatureGuids.size()); return; } @@ -1313,16 +1313,13 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) objmgr.RemoveCreatureFromGrid(*itr, data); if( Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_UNIT), (Creature*)NULL) ) - { - pCreature->CleanupsBeforeDelete(); pCreature->AddObjectToRemoveList(); - } } } if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size()) { - sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size()); + sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventGameobjectGuids.size()); return; } @@ -1342,7 +1339,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) } if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size()) { - sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size()); + sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size()); return; } diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index d6aa162b50a..c3bfc1d77b9 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -54,7 +54,6 @@ GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue) m_spawnedByDefault = true; m_usetimes = 0; m_spellId = 0; - m_charges = 5; m_cooldownTime = 0; m_goInfo = NULL; m_goData = NULL; @@ -65,28 +64,39 @@ GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue) GameObject::~GameObject() { - /*if(m_uint32Values) // field array can be not exist if GameOBject not loaded + //if(m_uint32Values) // field array can be not exist if GameOBject not loaded + // CleanupsBeforeDelete(); +} + +void GameObject::CleanupsBeforeDelete() +{ + if(m_uint32Values) // field array can be not exist if GameOBject not loaded { // Possible crash at access to deleted GO in Unit::m_gameobj - uint64 owner_guid = GetOwnerGUID(); - if(owner_guid) + if(uint64 owner_guid = GetOwnerGUID()) { - Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid); + Unit* owner = NULL; + // Object may be deleted while player is not in world, skip this check for now. + /*if(IS_PLAYER_GUID(owner_guid)) + owner = ObjectAccessor::GetObjectInWorld(owner_guid, (Player*)NULL); + else*/ + owner = ObjectAccessor::GetUnit(*this,owner_guid); + if(owner) owner->RemoveGameObject(this,false); else { - char * ownerType = "creature"; + const char * ownerType = "creature"; if(IS_PLAYER_GUID(owner_guid)) ownerType = "player"; else if(IS_PET_GUID(owner_guid)) ownerType = "pet"; sLog.outError("Delete GameObject (GUID: %u Entry: %u SpellId %u LinkedGO %u) that lost references to owner (GUID %u Type '%s') GO list. Crash possible later.", - GetGUIDLow(), GetGOInfo()->id, m_spellId, GetLinkedGameObjectEntry(), GUID_LOPART(owner_guid), ownerType); + GetGUIDLow(), GetGOInfo()->id, m_spellId, GetGOInfo()->GetLinkedGameObjectEntry(), GUID_LOPART(owner_guid), ownerType); } } - }*/ + } } void GameObject::AddToWorld() @@ -113,8 +123,7 @@ void GameObject::RemoveFromWorld() // Possible crash at access to deleted GO in Unit::m_gameobj if(uint64 owner_guid = GetOwnerGUID()) { - Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid); - if(owner) + if(Unit * owner = GetOwner(false)) owner->RemoveGameObject(this,false); else if(!IS_PLAYER_GUID(owner_guid)) sLog.outError("Delete GameObject (GUID: %u Entry: %u ) that have references in not found creature %u GO list. Crash possible later.",GetGUIDLow(),GetGOInfo()->id,GUID_LOPART(owner_guid)); @@ -126,17 +135,18 @@ void GameObject::RemoveFromWorld() bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 ArtKit) { - Relocate(x,y,z,ang); - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); - SetPhaseMask(phaseMask,false); + ASSERT(map); + SetMap(map); + Relocate(x,y,z,ang); if(!IsPositionValid()) { sLog.outError("Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y); return false; } + SetPhaseMask(phaseMask,false); + GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id); if (!goinfo) { @@ -177,9 +187,6 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa switch(goinfo->type) { - case GAMEOBJECT_TYPE_SPELLCASTER: - m_charges = goinfo->spellcaster.charges; - break; case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING: m_goValue->building.health = goinfo->building.intactNumHits + goinfo->building.damagedNumHits; break; @@ -298,87 +305,94 @@ void GameObject::Update(uint32 /*p_time*/) } } - // traps can have time and can not have - GameObjectInfo const* goInfo = GetGOInfo(); - if(goInfo->type == GAMEOBJECT_TYPE_TRAP) + if(isSpawned()) { - // traps - Unit* owner = GetOwner(); - Unit* ok = NULL; // pointer to appropriate target if found any + // traps can have time and can not have + GameObjectInfo const* goInfo = GetGOInfo(); + if(goInfo->type == GAMEOBJECT_TYPE_TRAP) + { + if(m_cooldownTime >= time(NULL)) + return; - if(m_cooldownTime >= time(NULL)) - return; + // traps + Unit* owner = GetOwner(); + Unit* ok = NULL; // pointer to appropriate target if found any - bool IsBattleGroundTrap = false; - //FIXME: this is activation radius (in different casting radius that must be selected from spell data) - //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state - float radius = goInfo->trap.radius; - if(!radius) // i think this is a hack, spell radius is determined by trap radius (spell itself does not have radius) - if(const SpellEntry *spellEntry = sSpellStore.LookupEntry(m_spellId)) - radius = goInfo->trap.radius; - if(!radius) - { - if(goInfo->trap.cooldown == 3) // cast in other case (at some triggering/linked go/etc explicit call) + bool IsBattleGroundTrap = false; + //FIXME: this is activation radius (in different casting radius that must be selected from spell data) + //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state + float radius = goInfo->trap.radius; + if(!radius) { - if(m_respawnTime > 0) - break; + if(goInfo->trap.cooldown != 3) // cast in other case (at some triggering/linked go/etc explicit call) + return; + else + { + if(m_respawnTime > 0) + break; + + radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3 + IsBattleGroundTrap = true; - radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3 - IsBattleGroundTrap = true; + if(!radius) + return; + } } - if(!radius) - return; - } - // Note: this hack with search required until GO casting not implemented - // search unfriendly creature - if(owner) // hunter trap - { - Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius); - Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, ok, checker); - VisitNearbyGridObject(radius, searcher); - if(!ok) VisitNearbyWorldObject(radius, searcher); - } - else // environmental trap - { - // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support - // affect only players - Player* player = NULL; - MaNGOS::AnyPlayerInObjectRangeCheck checker(this, radius); - MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> searcher(this, player, checker); - VisitNearbyWorldObject(radius, searcher); - ok = player; - } + // Note: this hack with search required until GO casting not implemented + // search unfriendly creature + if(owner) // hunter trap + { + Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius); + Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, ok, checker); + VisitNearbyGridObject(radius, searcher); + if(!ok) VisitNearbyWorldObject(radius, searcher); + } + else // environmental trap + { + // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support + // affect only players + Player* player = NULL; + MaNGOS::AnyPlayerInObjectRangeCheck checker(this, radius); + MaNGOS::PlayerSearcher<MaNGOS::AnyPlayerInObjectRangeCheck> searcher(this, player, checker); + VisitNearbyWorldObject(radius, searcher); + ok = player; + } + + if (ok) + { + // some traps do not have spell but should be triggered + if(goInfo->trap.spellId) + CastSpell(ok, goInfo->trap.spellId); - if (ok) - { - // some traps do not have spell but should be triggered - if(goInfo->trap.spellId) - CastSpell(ok, goInfo->trap.spellId); - //Unit *caster = owner ? owner : ok; - //caster->CastSpell(ok, goInfo->trap.spellId, true, 0, 0, GetGUID()); - - if(goInfo->trap.cooldown) - m_cooldownTime = time(NULL) + goInfo->trap.cooldown; - else m_cooldownTime = time(NULL) + 4; // 4 seconds - if(owner) - SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed + // count charges + //if(goInfo->trap.charges > 0) + // AddUse(); + + if(owner) + SetLootState(GO_JUST_DEACTIVATED); - if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER) + if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER) + { + //BattleGround gameobjects case + if(((Player*)ok)->InBattleGround()) + if(BattleGround *bg = ((Player*)ok)->GetBattleGround()) + bg->HandleTriggerBuff(GetGUID()); + } + } + } + else if(uint32 max_charges = goInfo->GetCharges()) + { + if (m_usetimes >= max_charges) { - //BattleGround gameobjects case - if(((Player*)ok)->InBattleGround()) - if(BattleGround *bg = ((Player*)ok)->GetBattleGround()) - bg->HandleTriggerBuff(GetGUID()); + m_usetimes = 0; + SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed } } } - if (m_charges && m_usetimes >= m_charges) - SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed - break; } case GO_ACTIVATED: @@ -387,7 +401,7 @@ void GameObject::Update(uint32 /*p_time*/) { case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: - if (GetAutoCloseTime() && (m_cooldownTime < time(NULL))) + if (GetGOInfo()->GetAutoCloseTime() && (m_cooldownTime < time(NULL))) ResetDoorOrButton(); break; } @@ -420,16 +434,17 @@ void GameObject::Update(uint32 /*p_time*/) if(GetOwnerGUID()) { - if(Unit* owner = GetOwner()) + if(Unit* owner = GetOwner(false)) + { owner->RemoveGameObject(this, false); - - SetRespawnTime(0); - Delete(); + SetRespawnTime(0); + Delete(); + } return; } //burning flags in some battlegrounds, if you find better condition, just add it - if (GetGoAnimProgress() > 0) + if (GetGOInfo()->IsDespawnAtAction() || GetGoAnimProgress() > 0) { SendObjectDeSpawnAnim(GetGUID()); //reset flags @@ -477,8 +492,18 @@ void GameObject::AddUniqueUse(Player* player) m_unique_users.insert(player->GetGUIDLow()); } +void GameObject::DeleteObjectWithOwner() +{ + SetLootState(GO_NOT_READY); + if (GetOwnerGUID()) + if (Unit * owner = GetOwner(false)) + owner->RemoveGameObject(this, false); + Delete(); +} + void GameObject::Delete() { + assert (!GetOwnerGUID()); SendObjectDeSpawnAnim(GetGUID()); SetGoState(GO_STATE_READY); @@ -609,7 +634,7 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map) if (!Create(guid,entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) ) return false; - if(!GetDespawnPossibility()) + if(!GetGOInfo()->GetDespawnPossibility() && !GetGOInfo()->IsDespawnAtAction()) { SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); m_spawnedByDefault = true; @@ -657,22 +682,6 @@ GameObject* GameObject::GetGameObject(WorldObject& object, uint64 guid) return object.GetMap()->GetGameObject(guid); } -uint32 GameObject::GetLootId(GameObjectInfo const* ginfo) -{ - if (!ginfo) - return 0; - - switch(ginfo->type) - { - case GAMEOBJECT_TYPE_CHEST: - return ginfo->chest.lootId; - case GAMEOBJECT_TYPE_FISHINGHOLE: - return ginfo->fishinghole.lootId; - default: - return 0; - } -} - /*********************************************************/ /*** QUEST SYSTEM ***/ /*********************************************************/ @@ -706,9 +715,11 @@ bool GameObject::IsTransport() const return gInfo->type == GAMEOBJECT_TYPE_TRANSPORT || gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT; } -Unit* GameObject::GetOwner() const +Unit* GameObject::GetOwner(bool inWorld) const { - return ObjectAccessor::GetUnit(*this, GetOwnerGUID()); + if (inWorld) + return ObjectAccessor::GetUnit(*this, GetOwnerGUID()); + return ObjectAccessor::GetUnitInOrOutOfWorld(*this, GetOwnerGUID()); } void GameObject::SaveRespawnTime() @@ -788,7 +799,7 @@ bool GameObject::ActivateToQuest( Player *pTarget)const // scan GO chest with loot including quest items case GAMEOBJECT_TYPE_CHEST: { - if(LootTemplates_Gameobject.HaveQuestLootForPlayer(GetLootId(), pTarget)) + if(LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->GetLootId(), pTarget)) { //TODO: fix this hack //look for battlegroundAV for some objects which are only activated after mine gots captured by own team @@ -894,7 +905,7 @@ void GameObject::UseDoorOrButton(uint32 time_to_restore, bool alternative /* = f return; if(!time_to_restore) - time_to_restore = GetAutoCloseTime(); + time_to_restore = GetGOInfo()->GetAutoCloseTime(); SwitchDoorOrButton(true,alternative); SetLootState(GO_ACTIVATED); @@ -938,7 +949,7 @@ void GameObject::Use(Unit* user) UseDoorOrButton(); // activate script - sWorld.ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this); + GetMap()->ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this); return; case GAMEOBJECT_TYPE_QUESTGIVER: //2 @@ -1034,7 +1045,7 @@ void GameObject::Use(Unit* user) player->CastedCreatureOrGO(info->id, GetGUID(), 0); if (info->goober.eventId) - sWorld.ScriptsStart(sEventScripts, info->goober.eventId, player, this); + GetMap()->ScriptsStart(sEventScripts, info->goober.eventId, player, this); } // cast this spell later if provided @@ -1057,7 +1068,7 @@ void GameObject::Use(Unit* user) player->SendCinematicStart(info->camera.cinematicId); if (info->camera.eventID) - sWorld.ScriptsStart(sEventScripts, info->camera.eventID, player, this); + GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this); return; } @@ -1358,6 +1369,7 @@ void GameObject::Use(Unit* user) } Spell *spell = new Spell(spellCaster, spellInfo, triggered); + //Spell *spell = new Spell(spellCaster, spellInfo, triggered,GetGUID()); // spell target is user of GO SpellCastTargets targets; diff --git a/src/game/GameObject.h b/src/game/GameObject.h index 43f8fb0ea5f..43441e2fb9c 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -399,6 +399,98 @@ struct GameObjectInfo } raw; }; uint32 ScriptId; + + // helpers + bool IsDespawnAtAction() const + { + switch(type) + { + case GAMEOBJECT_TYPE_CHEST: return chest.consumable; + case GAMEOBJECT_TYPE_GOOBER: return goober.consumable; + default: return false; + } + } + + uint32 GetLockId() const + { + switch(type) + { + case GAMEOBJECT_TYPE_DOOR: return door.lockId; + case GAMEOBJECT_TYPE_BUTTON: return button.lockId; + case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.lockId; + case GAMEOBJECT_TYPE_CHEST: return chest.lockId; + case GAMEOBJECT_TYPE_TRAP: return trap.lockId; + case GAMEOBJECT_TYPE_GOOBER: return goober.lockId; + case GAMEOBJECT_TYPE_AREADAMAGE: return areadamage.lockId; + case GAMEOBJECT_TYPE_CAMERA: return camera.lockId; + case GAMEOBJECT_TYPE_FLAGSTAND: return flagstand.lockId; + case GAMEOBJECT_TYPE_FISHINGHOLE:return fishinghole.lockId; + case GAMEOBJECT_TYPE_FLAGDROP: return flagdrop.lockId; + default: return 0; + } + } + + bool GetDespawnPossibility() const // despawn at targeting of cast? + { + switch(type) + { + case GAMEOBJECT_TYPE_DOOR: return door.noDamageImmune; + case GAMEOBJECT_TYPE_BUTTON: return button.noDamageImmune; + case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.noDamageImmune; + case GAMEOBJECT_TYPE_GOOBER: return goober.noDamageImmune; + case GAMEOBJECT_TYPE_FLAGSTAND: return flagstand.noDamageImmune; + case GAMEOBJECT_TYPE_FLAGDROP: return flagdrop.noDamageImmune; + default: return true; + } + } + + uint32 GetCharges() const // despawn at uses amount + { + switch(type) + { + //case GAMEOBJECT_TYPE_TRAP: return trap.charges; + case GAMEOBJECT_TYPE_GUARDPOST: return guardpost.charges; + case GAMEOBJECT_TYPE_SPELLCASTER: return spellcaster.charges; + default: return 0; + } + } + + uint32 GetLinkedGameObjectEntry() const + { + switch(type) + { + case GAMEOBJECT_TYPE_CHEST: return chest.linkedTrapId; + case GAMEOBJECT_TYPE_SPELL_FOCUS: return spellFocus.linkedTrapId; + case GAMEOBJECT_TYPE_GOOBER: return goober.linkedTrapId; + default: return 0; + } + } + + uint32 GetAutoCloseTime() const + { + uint32 autoCloseTime = 0; + switch(type) + { + case GAMEOBJECT_TYPE_DOOR: autoCloseTime = door.autoCloseTime; break; + case GAMEOBJECT_TYPE_BUTTON: autoCloseTime = button.autoCloseTime; break; + case GAMEOBJECT_TYPE_TRAP: autoCloseTime = trap.autoCloseTime; break; + case GAMEOBJECT_TYPE_GOOBER: autoCloseTime = goober.autoCloseTime; break; + case GAMEOBJECT_TYPE_TRANSPORT: autoCloseTime = transport.autoCloseTime; break; + case GAMEOBJECT_TYPE_AREADAMAGE: autoCloseTime = areadamage.autoCloseTime; break; + default: break; + } + return autoCloseTime / 0x10000; + } + + uint32 GetLootId() const + { + switch(type) + { + case GAMEOBJECT_TYPE_CHEST: return chest.lootId; + case GAMEOBJECT_TYPE_FISHINGHOLE: return fishinghole.lootId; + default: return 0; + } + } }; class OPvPCapturePoint; @@ -488,6 +580,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject void AddToWorld(); void RemoveFromWorld(); + void CleanupsBeforeDelete(); bool Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 ArtKit = 0); void Update(uint32 p_time); @@ -498,14 +591,6 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject bool IsTransport() const; - void SetOwnerGUID(uint64 owner) - { - m_spawnedByDefault = false; // all object with owner is despawned after delay - SetUInt64Value(OBJECT_FIELD_CREATED_BY, owner); - } - uint64 GetOwnerGUID() const { return GetUInt64Value(OBJECT_FIELD_CREATED_BY); } - Unit* GetOwner() const; - uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; } void UpdateRotationFields(float rotation2 = 0.0f, float rotation3 = 0.0f); @@ -523,40 +608,26 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask); bool LoadFromDB(uint32 guid, Map *map); void DeleteFromDB(); - static uint32 GetLootId(GameObjectInfo const* info); - uint32 GetLootId() const { return GetLootId(GetGOInfo()); } - uint32 GetLockId() const + + void SetOwnerGUID(uint64 owner) { - switch(GetGoType()) + // Owner already found and different than expected owner - remove object from old owner + if (owner && GetOwnerGUID() && GetOwnerGUID() != owner) { - case GAMEOBJECT_TYPE_DOOR: return GetGOInfo()->door.lockId; - case GAMEOBJECT_TYPE_BUTTON: return GetGOInfo()->button.lockId; - case GAMEOBJECT_TYPE_QUESTGIVER: return GetGOInfo()->questgiver.lockId; - case GAMEOBJECT_TYPE_CHEST: return GetGOInfo()->chest.lockId; - case GAMEOBJECT_TYPE_TRAP: return GetGOInfo()->trap.lockId; - case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.lockId; - case GAMEOBJECT_TYPE_AREADAMAGE: return GetGOInfo()->areadamage.lockId; - case GAMEOBJECT_TYPE_CAMERA: return GetGOInfo()->camera.lockId; - case GAMEOBJECT_TYPE_FLAGSTAND: return GetGOInfo()->flagstand.lockId; - case GAMEOBJECT_TYPE_FISHINGHOLE:return GetGOInfo()->fishinghole.lockId; - case GAMEOBJECT_TYPE_FLAGDROP: return GetGOInfo()->flagdrop.lockId; - default: return 0; + assert(false); } + m_spawnedByDefault = false; // all object with owner is despawned after delay + SetUInt64Value(OBJECT_FIELD_CREATED_BY, owner); } + uint64 GetOwnerGUID() const { return GetUInt64Value(OBJECT_FIELD_CREATED_BY); } + Unit* GetOwner(bool inWorld = true) const; - bool GetDespawnPossibility() const + void SetSpellId(uint32 id) { - switch(GetGoType()) - { - case GAMEOBJECT_TYPE_DOOR: return GetGOInfo()->door.noDamageImmune; - case GAMEOBJECT_TYPE_BUTTON: return GetGOInfo()->button.noDamageImmune; - case GAMEOBJECT_TYPE_QUESTGIVER: return GetGOInfo()->questgiver.noDamageImmune; - case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.noDamageImmune; - case GAMEOBJECT_TYPE_FLAGSTAND: return GetGOInfo()->flagstand.noDamageImmune; - case GAMEOBJECT_TYPE_FLAGDROP: return GetGOInfo()->flagdrop.noDamageImmune; - default: return true; - } + m_spawnedByDefault = false; // all summoned object is despawned after delay + m_spellId = id; } + uint32 GetSpellId() const { return m_spellId;} time_t GetRespawnTime() const { return m_respawnTime; } time_t GetRespawnTimeEx() const @@ -585,8 +656,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject uint32 GetRespawnDelay() const { return m_respawnDelayTime; } void Refresh(); void Delete(); - void SetSpellId(uint32 id) { m_spellId = id;} - uint32 GetSpellId() const { return m_spellId;} + void DeleteObjectWithOwner(); void getFishLoot(Loot *loot, Player* loot_owner); GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); } void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); } @@ -627,34 +697,7 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject void UseDoorOrButton(uint32 time_to_restore = 0, bool alternative = false); // 0 = use `gameobject`.`spawntimesecs` void ResetDoorOrButton(); - // 0 = use `gameobject`.`spawntimesecs` - - uint32 GetLinkedGameObjectEntry() const - { - switch(GetGoType()) - { - case GAMEOBJECT_TYPE_CHEST: return GetGOInfo()->chest.linkedTrapId; - case GAMEOBJECT_TYPE_SPELL_FOCUS: return GetGOInfo()->spellFocus.linkedTrapId; - case GAMEOBJECT_TYPE_GOOBER: return GetGOInfo()->goober.linkedTrapId; - default: return 0; - } - } - uint32 GetAutoCloseTime() const - { - uint32 autoCloseTime = 0; - switch(GetGoType()) - { - case GAMEOBJECT_TYPE_DOOR: autoCloseTime = GetGOInfo()->door.autoCloseTime; break; - case GAMEOBJECT_TYPE_BUTTON: autoCloseTime = GetGOInfo()->button.autoCloseTime; break; - case GAMEOBJECT_TYPE_TRAP: autoCloseTime = GetGOInfo()->trap.autoCloseTime; break; - case GAMEOBJECT_TYPE_GOOBER: autoCloseTime = GetGOInfo()->goober.autoCloseTime; break; - case GAMEOBJECT_TYPE_TRANSPORT: autoCloseTime = GetGOInfo()->transport.autoCloseTime; break; - case GAMEOBJECT_TYPE_AREADAMAGE: autoCloseTime = GetGOInfo()->areadamage.autoCloseTime; break; - default: break; - } - return autoCloseTime / 0x10000; - } void TriggeringLinkedGameObject( uint32 trapEntry, Unit* target); @@ -675,7 +718,6 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject uint64 GetRotation() const { return m_rotation; } protected: - uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22) uint32 m_spellId; time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()), uint32 m_respawnDelayTime; // (secs) if 0 then current GO state no dependent from timer diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h index a3fe011f402..05080521f58 100644 --- a/src/game/GridDefines.h +++ b/src/game/GridDefines.h @@ -35,10 +35,8 @@ class Player; #ifdef LARGE_CELL #define MAX_NUMBER_OF_CELLS 4 -#define CENTER_GRID_CELL_ID 128 #else #define MAX_NUMBER_OF_CELLS 8 -#define CENTER_GRID_CELL_ID 256 #endif #define MAX_NUMBER_OF_GRIDS 64 @@ -53,6 +51,7 @@ class Player; #define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS) +#define CENTER_GRID_CELL_ID (MAX_NUMBER_OF_CELLS*MAX_NUMBER_OF_GRIDS/2) #define CENTER_GRID_CELL_OFFSET (SIZE_OF_GRID_CELL/2) #define TOTAL_NUMBER_OF_CELLS_PER_MAP (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS) @@ -73,7 +72,7 @@ typedef GridRefManager<GameObject> GameObjectMapType; typedef GridRefManager<Player> PlayerMapType; typedef Grid<Player, AllWorldObjectTypes,AllGridObjectTypes> GridType; -typedef NGrid<8, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType; +typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType; typedef TypeMapContainer<AllGridObjectTypes> GridTypeMapContainer; typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer; diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index 64deb0d3123..997f0806369 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -1135,48 +1135,69 @@ namespace Trinity Unit const* pUnit; }; - class AllGameObjectsWithEntryInGrid + class AllGameObjectsWithEntryInRange { public: - AllGameObjectsWithEntryInGrid(uint32 ent) : entry(ent) {} - bool operator() (GameObject* g) + AllGameObjectsWithEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} + bool operator() (GameObject* pGo) { - if(g->GetEntry() == entry) + if (pGo->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pGo,m_fRange,false)) return true; return false; } private: - uint32 entry; + const WorldObject* m_pObject; + uint32 m_uiEntry; + float m_fRange; }; - class GameObjectInRangeCheck + class AllCreaturesOfEntryInRange { - public: - GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {} - bool operator() (GameObject* go) - { - return go->IsInRange(x, y, z, range); - } - private: - float x, y, z, range; + public: + AllCreaturesOfEntryInRange(const WorldObject* pObject, uint32 uiEntry, float fMaxRange) : m_pObject(pObject), m_uiEntry(uiEntry), m_fRange(fMaxRange) {} + bool operator() (Unit* pUnit) + { + if (pUnit->GetEntry() == m_uiEntry && m_pObject->IsWithinDist(pUnit,m_fRange,false)) + return true; + + return false; + } + + private: + const WorldObject* m_pObject; + uint32 m_uiEntry; + float m_fRange; }; - class AllCreaturesOfEntryInRange + class PlayerAtMinimumRangeAway { public: - AllCreaturesOfEntryInRange(Unit const* obj, uint32 ent, float ran) : pUnit(obj), entry(ent), range(ran) {} - bool operator() (Unit* u) + PlayerAtMinimumRangeAway(Unit const* unit, float fMinRange) : pUnit(unit), fRange(fMinRange) {} + bool operator() (Player* pPlayer) { - if(u->GetEntry() == entry && pUnit->IsWithinDistInMap(u, range)) + //No threat list check, must be done explicit if expected to be in combat with creature + if (!pPlayer->isGameMaster() && pPlayer->isAlive() && !pUnit->IsWithinDist(pPlayer,fRange,false)) return true; return false; } + private: Unit const* pUnit; - uint32 entry; - float range; + float fRange; + }; + + class GameObjectInRangeCheck + { + public: + GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {} + bool operator() (GameObject* go) + { + return go->IsInRange(x, y, z, range); + } + private: + float x, y, z, range; }; // Player checks and do diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h index 6502c2ea7c8..211bca9cd3c 100644 --- a/src/game/GridNotifiersImpl.h +++ b/src/game/GridNotifiersImpl.h @@ -631,4 +631,28 @@ void MaNGOS::LocalizedPacketListDo<Builder>::operator()( Player* p ) p->SendDirectMessage((*data_list)[i]); } +struct ObjectDistanceOrder : public std::binary_function<const WorldObject, const WorldObject, bool> +{ + const Unit* m_pSource; + + ObjectDistanceOrder(const Unit* pSource) : m_pSource(pSource) {}; + + bool operator()(const WorldObject* pLeft, const WorldObject* pRight) const + { + return m_pSource->GetDistanceOrder(pLeft, pRight); + } +}; + +struct ObjectDistanceOrderReversed : public std::binary_function<const WorldObject, const WorldObject, bool> +{ + const Unit* m_pSource; + + ObjectDistanceOrderReversed(const Unit* pSource) : m_pSource(pSource) {}; + + bool operator()(const WorldObject* pLeft, const WorldObject* pRight) const + { + return !m_pSource->GetDistanceOrder(pLeft, pRight); + } +}; + #endif // MANGOS_GRIDNOTIFIERSIMPL_H diff --git a/src/game/Group.cpp b/src/game/Group.cpp index c08d1236c32..8a02afa25d2 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -967,7 +967,7 @@ void Group::SendUpdate() void Group::UpdatePlayerOutOfRange(Player* pPlayer) { - if(!pPlayer) + if(!pPlayer || !pPlayer->IsInWorld()) return; Player *player; @@ -1510,7 +1510,7 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) bool isEmpty = true; // if the map is loaded, reset it Map *map = MapManager::Instance().FindMap(p->GetMapId(), p->GetInstanceId()); - if(map && map->IsDungeon()) + if(map && map->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !p->CanReset())) { if(p->CanReset()) isEmpty = ((InstanceMap*)map)->Reset(method); diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp index 84271f08d04..7efc92c2fe0 100644 --- a/src/game/Guild.cpp +++ b/src/game/Guild.cpp @@ -283,7 +283,7 @@ bool Guild::LoadRanksFromDB(uint32 GuildId) std::string name = m_ranks[i].name; uint32 rights = m_ranks[i].rights; CharacterDatabase.escape_string(name); - CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, i+1, name.c_str(), rights); + CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, uint32(i+1), name.c_str(), rights); } CharacterDatabase.CommitTransaction(); } @@ -369,20 +369,17 @@ bool Guild::FillPlayerData(uint64 guid, MemberSlot* memslot) } else { - QueryResult *result = CharacterDatabase.PQuery("SELECT name,data,zone,class FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); - if(!result) - return false; // player doesn't exist + QueryResult *result = CharacterDatabase.PQuery("SELECT name,level,zone,class FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + if(!result) + return false; // player doesn't exist Field *fields = result->Fetch(); - plName = fields[0].GetCppString(); - - Tokens data = StrSplit(fields[1].GetCppString(), " "); - plLevel = Player::GetUInt32ValueFromArray(data,UNIT_FIELD_LEVEL); - - plZone = fields[2].GetUInt32(); - plClass = fields[3].GetUInt32(); - delete result; + plName = fields[0].GetCppString(); + plLevel = fields[1].GetUInt32(); + plZone = fields[2].GetUInt32(); + plClass = fields[3].GetUInt32(); + delete result; if(plLevel<1||plLevel>STRONG_MAX_LEVEL) // can be at broken `data` field { @@ -716,40 +713,40 @@ void Guild::Roster(WorldSession *session) data << (uint32)m_ranks.size(); for (RankList::const_iterator ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr) { - data << (uint32)ritr->rights; - data << (uint32)ritr->BankMoneyPerDay; // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze. - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) + data << uint32(ritr->rights); + data << uint32(ritr->BankMoneyPerDay); // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze. + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) { - data << (uint32)ritr->TabRight[i]; // for TAB_i rights: view tabs = 0x01, deposit items =0x02 - data << (uint32)ritr->TabSlotPerDay[i]; // for TAB_i count of: withdraw items(stack/day) + data << uint32(ritr->TabRight[i]); // for TAB_i rights: view tabs = 0x01, deposit items =0x02 + data << uint32(ritr->TabSlotPerDay[i]); // for TAB_i count of: withdraw items(stack/day) } } for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) { if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) { - data << (uint64)pl->GetGUID(); - data << (uint8)1; - data << (std::string)pl->GetName(); - data << (uint32)itr->second.RankId; - data << (uint8)pl->getLevel(); - data << (uint8)pl->getClass(); - data << (uint8)0; // new 2.4.0 - data << (uint32)pl->GetZoneId(); + data << uint64(pl->GetGUID()); + data << uint8(1); + data << pl->GetName(); + data << uint32(itr->second.RankId); + data << uint8(pl->getLevel()); + data << uint8(pl->getClass()); + data << uint8(0); // new 2.4.0 + data << uint32(pl->GetZoneId()); data << itr->second.Pnote; data << itr->second.OFFnote; } else { data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - data << (uint8)0; + data << uint8(0); data << itr->second.name; - data << (uint32)itr->second.RankId; - data << (uint8)itr->second.level; - data << (uint8)itr->second.Class; - data << (uint8)0; // new 2.4.0 - data << (uint32)itr->second.zoneId; - data << (float(time(NULL)-itr->second.logout_time) / DAY); + data << uint32(itr->second.RankId); + data << uint8(itr->second.level); + data << uint8(itr->second.Class); + data << uint8(0); // new 2.4.0 + data << uint32(itr->second.zoneId); + data << float(float(time(NULL)-itr->second.logout_time) / DAY); data << itr->second.Pnote; data << itr->second.OFFnote; } @@ -829,17 +826,17 @@ void Guild::DisplayGuildEventlog(WorldSession *session) for (GuildEventlog::const_iterator itr = m_GuildEventlog.begin(); itr != m_GuildEventlog.end(); ++itr) { // Event type - data << uint8((*itr)->EventType); + data << uint8(itr->EventType); // Player 1 - data << uint64((*itr)->PlayerGuid1); + data << uint64(itr->PlayerGuid1); // Player 2 not for left/join guild events - if( (*itr)->EventType != GUILD_EVENT_LOG_JOIN_GUILD && (*itr)->EventType != GUILD_EVENT_LOG_LEAVE_GUILD ) - data << uint64((*itr)->PlayerGuid2); + if (itr->EventType != GUILD_EVENT_LOG_JOIN_GUILD && itr->EventType != GUILD_EVENT_LOG_LEAVE_GUILD) + data << uint64(itr->PlayerGuid2); // New Rank - only for promote/demote guild events - if( (*itr)->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || (*itr)->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER ) - data << uint8((*itr)->NewRank); + if (itr->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || itr->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER) + data << uint8(itr->NewRank); // Event timestamp - data << uint32(time(NULL)-(*itr)->TimeStamp); + data << uint32(time(NULL)-itr->TimeStamp); } session->SendPacket(&data); sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)"); @@ -858,14 +855,14 @@ void Guild::LoadGuildEventLogFromDB() do { Field *fields = result->Fetch(); - GuildEventlogEntry *NewEvent = new GuildEventlogEntry; + GuildEventlogEntry NewEvent; // Fill entry - NewEvent->LogGuid = fields[0].GetUInt32(); - NewEvent->EventType = fields[1].GetUInt8(); - NewEvent->PlayerGuid1 = fields[2].GetUInt32(); - NewEvent->PlayerGuid2 = fields[3].GetUInt32(); - NewEvent->NewRank = fields[4].GetUInt8(); - NewEvent->TimeStamp = fields[5].GetUInt64(); + NewEvent.LogGuid = fields[0].GetUInt32(); + NewEvent.EventType = fields[1].GetUInt8(); + NewEvent.PlayerGuid1 = fields[2].GetUInt32(); + NewEvent.PlayerGuid2 = fields[3].GetUInt32(); + NewEvent.NewRank = fields[4].GetUInt8(); + NewEvent.TimeStamp = fields[5].GetUInt64(); // Add entry to map m_GuildEventlog.push_front(NewEvent); @@ -875,9 +872,8 @@ void Guild::LoadGuildEventLogFromDB() // Check lists size in case to many event entries in db // This cases can happen only if a crash occured somewhere and table has too many log entries if (!m_GuildEventlog.empty()) - { - CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id, m_GuildEventlog.front()->LogGuid); - } + CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id, m_GuildEventlog.front().LogGuid); + m_eventlogloaded = true; } @@ -886,16 +882,8 @@ void Guild::UnloadGuildEventlog() { if (!m_eventlogloaded) return; - GuildEventlogEntry *EventLogEntry; - if( !m_GuildEventlog.empty() ) - { - do - { - EventLogEntry = *(m_GuildEventlog.begin()); - m_GuildEventlog.pop_front(); - delete EventLogEntry; - }while( !m_GuildEventlog.empty() ); - } + + m_GuildEventlog.clear(); m_eventlogloaded = false; } @@ -915,27 +903,25 @@ void Guild::RenumGuildEventlog() // Add entry to guild eventlog void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank) { - GuildEventlogEntry *NewEvent = new GuildEventlogEntry; + GuildEventlogEntry NewEvent; // Fill entry - NewEvent->LogGuid = GuildEventlogMaxGuid++; - NewEvent->EventType = EventType; - NewEvent->PlayerGuid1 = PlayerGuid1; - NewEvent->PlayerGuid2 = PlayerGuid2; - NewEvent->NewRank = NewRank; - NewEvent->TimeStamp = uint32(time(NULL)); + NewEvent.LogGuid = GuildEventlogMaxGuid++; + NewEvent.EventType = EventType; + NewEvent.PlayerGuid1 = PlayerGuid1; + NewEvent.PlayerGuid2 = PlayerGuid2; + NewEvent.NewRank = NewRank; + NewEvent.TimeStamp = uint32(time(NULL)); // Check max entry limit and delete from db if needed if (m_GuildEventlog.size() > GUILD_EVENTLOG_MAX_ENTRIES) { - GuildEventlogEntry *OldEvent = *(m_GuildEventlog.begin()); + CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, m_GuildEventlog.front().LogGuid); m_GuildEventlog.pop_front(); - CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); - delete OldEvent; } // Add entry to map m_GuildEventlog.push_back(NewEvent); // Add new eventlog entry into DB CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "')", - Id, NewEvent->LogGuid, uint32(NewEvent->EventType), NewEvent->PlayerGuid1, NewEvent->PlayerGuid2, uint32(NewEvent->NewRank), NewEvent->TimeStamp); + Id, NewEvent.LogGuid, uint32(NewEvent.EventType), NewEvent.PlayerGuid1, NewEvent.PlayerGuid2, uint32(NewEvent.NewRank), NewEvent.TimeStamp); } // ************************************************* @@ -1507,30 +1493,28 @@ void Guild::LoadGuildBankEventLogFromDB() do { Field *fields = result->Fetch(); - GuildBankEvent *NewEvent = new GuildBankEvent; + GuildBankEvent NewEvent; - NewEvent->LogGuid = fields[0].GetUInt32(); - NewEvent->LogEntry = fields[1].GetUInt8(); + NewEvent.LogGuid = fields[0].GetUInt32(); + NewEvent.LogEntry = fields[1].GetUInt8(); uint8 TabId = fields[2].GetUInt8(); - NewEvent->PlayerGuid = fields[3].GetUInt32(); - NewEvent->ItemOrMoney = fields[4].GetUInt32(); - NewEvent->ItemStackCount = fields[5].GetUInt8(); - NewEvent->DestTabId = fields[6].GetUInt8(); - NewEvent->TimeStamp = fields[7].GetUInt64(); + NewEvent.PlayerGuid = fields[3].GetUInt32(); + NewEvent.ItemOrMoney = fields[4].GetUInt32(); + NewEvent.ItemStackCount = fields[5].GetUInt8(); + NewEvent.DestTabId = fields[6].GetUInt8(); + NewEvent.TimeStamp = fields[7].GetUInt64(); if (TabId >= GUILD_BANK_MAX_TABS) { - sLog.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId, GetName().c_str(), NewEvent->LogGuid); - delete NewEvent; + sLog.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId, GetName().c_str(), NewEvent.LogGuid); continue; } - if (NewEvent->isMoneyEvent() && m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS - || m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS) - { - delete NewEvent; + + if (NewEvent.isMoneyEvent() && m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS || + m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS) continue; - } - if (NewEvent->isMoneyEvent()) + + if (NewEvent.isMoneyEvent()) m_GuildBankEventLog_Money.push_front(NewEvent); else m_GuildBankEventLog_Item[TabId].push_front(NewEvent); @@ -1543,43 +1527,24 @@ void Guild::LoadGuildBankEventLogFromDB() if (!m_GuildBankEventLog_Money.empty()) { CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u", - Id, m_GuildBankEventLog_Money.front()->LogGuid); + Id, m_GuildBankEventLog_Money.front().LogGuid); } for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) { if (!m_GuildBankEventLog_Item[i].empty()) { CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u", - Id, m_GuildBankEventLog_Item[i].front()->LogGuid); + Id, m_GuildBankEventLog_Item[i].front().LogGuid); } } } void Guild::UnloadGuildBankEventLog() { - GuildBankEvent *EventLogEntry; - if( !m_GuildBankEventLog_Money.empty() ) - { - do - { - EventLogEntry = *(m_GuildBankEventLog_Money.begin()); - m_GuildBankEventLog_Money.pop_front(); - delete EventLogEntry; - }while( !m_GuildBankEventLog_Money.empty() ); - } + m_GuildBankEventLog_Money.clear(); - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - if( !m_GuildBankEventLog_Item[i].empty() ) - { - do - { - EventLogEntry = *(m_GuildBankEventLog_Item[i].begin()); - m_GuildBankEventLog_Item[i].pop_front(); - delete EventLogEntry; - }while( !m_GuildBankEventLog_Item[i].empty() ); - } - } + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + m_GuildBankEventLog_Item[i].clear(); } void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) @@ -1595,24 +1560,24 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr) { - data << uint8((*itr)->LogEntry); - data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER)); - if ((*itr)->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY || - (*itr)->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY || - (*itr)->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY || - (*itr)->LogEntry == GUILD_BANK_LOG_UNK1 || - (*itr)->LogEntry == GUILD_BANK_LOG_UNK2) + data << uint8(itr->LogEntry); + data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER)); + if (itr->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY || + itr->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY || + itr->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY || + itr->LogEntry == GUILD_BANK_LOG_UNK1 || + itr->LogEntry == GUILD_BANK_LOG_UNK2) { - data << uint32((*itr)->ItemOrMoney); + data << uint32(itr->ItemOrMoney); } else { - data << uint32((*itr)->ItemOrMoney); - data << uint32((*itr)->ItemStackCount); - if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2) - data << uint8((*itr)->DestTabId); // moved tab + data << uint32(itr->ItemOrMoney); + data << uint32(itr->ItemStackCount); + if (itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2) + data << uint8(itr->DestTabId); // moved tab } - data << uint32(time(NULL)-(*itr)->TimeStamp); + data << uint32(time(NULL) - itr->TimeStamp); } session->SendPacket(&data); } @@ -1625,24 +1590,24 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) data << uint8(m_GuildBankEventLog_Item[TabId].size()); for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr) { - data << uint8((*itr)->LogEntry); - data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER)); - if ((*itr)->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY || - (*itr)->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY || - (*itr)->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY || - (*itr)->LogEntry == GUILD_BANK_LOG_UNK1 || - (*itr)->LogEntry == GUILD_BANK_LOG_UNK2) + data << uint8(itr->LogEntry); + data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER)); + if (itr->LogEntry == GUILD_BANK_LOG_DEPOSIT_MONEY || + itr->LogEntry == GUILD_BANK_LOG_WITHDRAW_MONEY || + itr->LogEntry == GUILD_BANK_LOG_REPAIR_MONEY || + itr->LogEntry == GUILD_BANK_LOG_UNK1 || + itr->LogEntry == GUILD_BANK_LOG_UNK2) { - data << uint32((*itr)->ItemOrMoney); + data << uint32(itr->ItemOrMoney); } else { - data << uint32((*itr)->ItemOrMoney); - data << uint32((*itr)->ItemStackCount); - if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2) - data << uint8((*itr)->DestTabId); // moved tab + data << uint32(itr->ItemOrMoney); + data << uint32(itr->ItemStackCount); + if (itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || itr->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2) + data << uint8(itr->DestTabId); // moved tab } - data << uint32(time(NULL)-(*itr)->TimeStamp); + data << uint32(time(NULL) - itr->TimeStamp); } session->SendPacket(&data); } @@ -1651,24 +1616,23 @@ void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) void Guild::LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId) { - GuildBankEvent *NewEvent = new GuildBankEvent; + GuildBankEvent NewEvent; - NewEvent->LogGuid = LogMaxGuid++; - NewEvent->LogEntry = LogEntry; - NewEvent->PlayerGuid = PlayerGuidLow; - NewEvent->ItemOrMoney = ItemOrMoney; - NewEvent->ItemStackCount = ItemStackCount; - NewEvent->DestTabId = DestTabId; - NewEvent->TimeStamp = uint32(time(NULL)); + NewEvent.LogGuid = LogMaxGuid++; + NewEvent.LogEntry = LogEntry; + NewEvent.PlayerGuid = PlayerGuidLow; + NewEvent.ItemOrMoney = ItemOrMoney; + NewEvent.ItemStackCount = ItemStackCount; + NewEvent.DestTabId = DestTabId; + NewEvent.TimeStamp = uint32(time(NULL)); - if (NewEvent->isMoneyEvent()) + if (NewEvent.isMoneyEvent()) { if (m_GuildBankEventLog_Money.size() > GUILD_BANK_MAX_LOGS) { - GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Money.begin()); + CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", + Id, m_GuildBankEventLog_Money.front().LogGuid); m_GuildBankEventLog_Money.pop_front(); - CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); - delete OldEvent; } m_GuildBankEventLog_Money.push_back(NewEvent); } @@ -1676,15 +1640,14 @@ void Guild::LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint { if (m_GuildBankEventLog_Item[TabId].size() > GUILD_BANK_MAX_LOGS) { - GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Item[TabId].begin()); + CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", + Id, m_GuildBankEventLog_Item[TabId].front().LogGuid); m_GuildBankEventLog_Item[TabId].pop_front(); - CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid); - delete OldEvent; } m_GuildBankEventLog_Item[TabId].push_back(NewEvent); } CharacterDatabase.PExecute("INSERT INTO guild_bank_eventlog (guildid,LogGuid,LogEntry,TabId,PlayerGuid,ItemOrMoney,ItemStackCount,DestTabId,TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','%u','%u','" UI64FMTD "')", - Id, NewEvent->LogGuid, uint32(NewEvent->LogEntry), uint32(TabId), NewEvent->PlayerGuid, NewEvent->ItemOrMoney, uint32(NewEvent->ItemStackCount), uint32(NewEvent->DestTabId), NewEvent->TimeStamp); + Id, NewEvent.LogGuid, uint32(NewEvent.LogEntry), uint32(TabId), NewEvent.PlayerGuid, NewEvent.ItemOrMoney, uint32(NewEvent.ItemStackCount), uint32(NewEvent.DestTabId), NewEvent.TimeStamp); } // This will renum guids used at load to prevent always going up until infinit @@ -2013,4 +1976,3 @@ bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const return false; } - diff --git a/src/game/Guild.h b/src/game/Guild.h index 9f832260f14..6e2441416c6 100644 --- a/src/game/Guild.h +++ b/src/game/Guild.h @@ -460,8 +460,8 @@ class Guild TabListMap m_TabListMap; /** These are actually ordered lists. The first element is the oldest entry.*/ - typedef std::list<GuildEventlogEntry*> GuildEventlog; - typedef std::list<GuildBankEvent*> GuildBankEventLog; + typedef std::list<GuildEventlogEntry> GuildEventlog; + typedef std::list<GuildBankEvent> GuildBankEventLog; GuildEventlog m_GuildEventlog; GuildBankEventLog m_GuildBankEventLog_Money; GuildBankEventLog m_GuildBankEventLog_Item[GUILD_BANK_MAX_TABS]; diff --git a/src/game/GuildHandler.cpp b/src/game/GuildHandler.cpp index f3f9c6c6758..a8eba52dee0 100644 --- a/src/game/GuildHandler.cpp +++ b/src/game/GuildHandler.cpp @@ -976,7 +976,7 @@ void WorldSession::HandleGuildBankDepositMoney( WorldPacket & recv_data ) pGuild->SetBankMoney(pGuild->GetGuildBankMoney()+money); GetPlayer()->ModifyMoney(-int(money)); - GetPlayer()->SaveDataFieldToDB(); //contains money + GetPlayer()->SaveGoldToDB(); CharacterDatabase.CommitTransaction(); @@ -1032,7 +1032,7 @@ void WorldSession::HandleGuildBankWithdrawMoney( WorldPacket & recv_data ) } GetPlayer()->ModifyMoney(money); - GetPlayer()->SaveDataFieldToDB(); // contains money + GetPlayer()->SaveGoldToDB(); CharacterDatabase.CommitTransaction(); diff --git a/src/game/Item.cpp b/src/game/Item.cpp index bc1c1eeeaab..484fa766da0 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -25,6 +25,7 @@ #include "Database/DatabaseEnv.h" #include "ItemEnchantmentMgr.h" #include "SpellMgr.h" +#include "ScriptCalls.h" void AddItemsSetItem(Player*player,Item *item) { @@ -285,6 +286,7 @@ void Item::UpdateDuration(Player* owner, uint32 diff) if (GetUInt32Value(ITEM_FIELD_DURATION)<=diff) { owner->DestroyItem(GetBagSlot(), GetSlot(), true); + Script->ItemExpire(owner, GetProto()); return; } @@ -380,6 +382,16 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, QueryResult *result) if(!proto) return false; + // update max durability (and durability) if need + if(proto->MaxDurability!= GetUInt32Value(ITEM_FIELD_MAXDURABILITY)) + { + SetUInt32Value(ITEM_FIELD_MAXDURABILITY,proto->MaxDurability); + if(GetUInt32Value(ITEM_FIELD_DURABILITY) > proto->MaxDurability) + SetUInt32Value(ITEM_FIELD_DURABILITY,proto->MaxDurability); + + need_save = true; + } + // recalculate suffix factor if(GetItemRandomPropertyId() < 0) { diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp index cf762dd0cb2..114393f4287 100644 --- a/src/game/ItemHandler.cpp +++ b/src/game/ItemHandler.cpp @@ -674,7 +674,31 @@ void WorldSession::HandleBuyItemInSlotOpcode( WorldPacket & recv_data ) recv_data >> vendorguid >> item >> slot >> bagguid >> bagslot >> count; - GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bagguid,bagslot); + uint8 bag = NULL_BAG; // init for case invalid bagGUID + + // find bag slot by bag guid + if (bagguid == _player->GetGUID()) + bag = INVENTORY_SLOT_BAG_0; + else + { + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;++i) + { + if (Bag *pBag = (Bag*)_player->GetItemByPos(INVENTORY_SLOT_BAG_0,i)) + { + if (bagguid == pBag->GetGUID()) + { + bag = i; + break; + } + } + } + } + + // bag not found, cheating? + if (bag == NULL_BAG) + return; + + GetPlayer()->BuyItemFromVendor(vendorguid,item,count,bag,bagslot); } void WorldSession::HandleBuyItemOpcode( WorldPacket & recv_data ) @@ -838,12 +862,14 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& recvPacket) recvPacket >> guid; // cheating protection + /* not critical if "cheated", and check skip allow by slots in bank windows open by .bank command. Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_BANKER); if(!pCreature) { sLog.outDebug( "WORLD: HandleBuyBankSlotOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)) ); return; } + */ uint32 slot = _player->GetBankBagSlotCount(); diff --git a/src/game/LFGHandler.cpp b/src/game/LFGHandler.cpp index 51735c01e02..09653ccb0bc 100644 --- a/src/game/LFGHandler.cpp +++ b/src/game/LFGHandler.cpp @@ -42,6 +42,10 @@ static void AttemptJoin(Player* _player) if(!plr || plr==_player || plr->GetTeam() != _player->GetTeam()) continue; + //skip players not in world + if(!plr->IsInWorld()) + continue; + // skip not auto add, not group leader cases if(!plr->GetSession()->LookingForGroup_auto_add || plr->GetGroup() && plr->GetGroup()->GetLeaderGUID()!=plr->GetGUID()) continue; @@ -98,6 +102,9 @@ static void AttemptAddMore(Player* _player) if(!plr || plr==_player || plr->GetTeam() != _player->GetTeam()) continue; + if(!plr->IsInWorld()) + continue; + // skip not auto join or in group if(!plr->GetSession()->LookingForGroup_auto_join || plr->GetGroup() ) continue; @@ -311,6 +318,9 @@ void WorldSession::SendLfgResult(uint32 type, uint32 entry, uint8 lfg_type) if(!plr || plr->GetTeam() != _player->GetTeam()) continue; + if(!plr->IsInWorld()) + continue; + if(!plr->m_lookingForGroup.HaveInSlot(entry, type)) continue; diff --git a/src/game/Language.h b/src/game/Language.h index c16393eba1c..bd74333c45a 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -85,7 +85,8 @@ enum TrinityStrings LANG_USING_WORLD_DB = 57, LANG_USING_SCRIPT_LIB = 58, LANG_USING_EVENT_AI = 59, - // Room for more level 0 60-99 not used + LANG_CONNECTED_PLAYERS = 60, + // Room for more level 0 61-99 not used // level 1 chat LANG_GLOBAL_NOTIFY = 100, @@ -804,14 +805,15 @@ enum TrinityStrings LANG_BG_AV_NODE_TOWER_FROST_W = 1324, LANG_BG_AV_NODE_GRAVE_FROST_HUT = 1325, - LANG_BG_AV_ONEMINTOSTART = 1326, - LANG_BG_AV_HALFMINTOSTART = 1327, - LANG_BG_AV_STARTED = 1328, + LANG_BG_AV_START_ONE_MINUTE = 1326, + LANG_BG_AV_START_HALF_MINUTE = 1327, + LANG_BG_AV_HAS_BEGUN = 1328, LANG_BG_AV_A_NEAR_LOSE = 1329, LANG_BG_AV_H_NEAR_LOSE = 1330, LANG_BG_AV_H_CAPTAIN_DEAD = 1331, LANG_BG_AV_A_CAPTAIN_DEAD = 1332, - // FREE IDS 1333-1999 + LANG_BG_AV_START_TWO_MINUTES = 1333, + // FREE IDS 1334-1999 // Ticket Strings 2000-2029 LANG_COMMAND_TICKETNEW = 2000, @@ -868,7 +870,8 @@ enum TrinityStrings LANG_GM_BROADCAST = 6613, LANG_GM_NOTIFY = 6614, LANG_GM_ANNOUNCE_COLOR = 6615, - LANG_RESETALL_PET_SPELLS = 6616, + + LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852 LANG_WORLD_CLOSED = 7523, LANG_WORLD_OPENED = 7524, @@ -940,6 +943,7 @@ enum TrinityStrings LANG_OPVP_ZM_GOSSIP_HORDE = 10055, // Use for custom patches 11000-11999 + LANG_AUTO_BROADCAST = 11000, // NOT RESERVED IDS 12000-1999999999 // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp index c4f6935bced..efc09494d1d 100644 --- a/src/game/Level0.cpp +++ b/src/game/Level0.cpp @@ -86,11 +86,13 @@ bool ChatHandler::HandleStartCommand(const char* /*args*/) bool ChatHandler::HandleServerInfoCommand(const char* /*args*/) { + uint32 PlayersNum = sWorld.GetPlayerCount(); + uint32 MaxPlayersNum = sWorld.GetMaxPlayerCount(); uint32 activeClientsNum = sWorld.GetActiveSessionCount(); uint32 queuedClientsNum = sWorld.GetQueuedSessionCount(); uint32 maxActiveClientsNum = sWorld.GetMaxActiveSessionCount(); uint32 maxQueuedClientsNum = sWorld.GetMaxQueuedSessionCount(); - std::string str = secsToTimeString(sWorld.GetUptime()); + std::string uptime = secsToTimeString(sWorld.GetUptime()); uint32 updateTime = sWorld.GetUpdateTime(); PSendSysMessage(_FULLVERSION); @@ -103,8 +105,9 @@ bool ChatHandler::HandleServerInfoCommand(const char* /*args*/) //PSendSysMessage(LANG_USING_SCRIPT_LIB,sWorld.GetScriptsVersion()); //PSendSysMessage(LANG_USING_WORLD_DB,sWorld.GetDBVersion()); //PSendSysMessage(LANG_USING_EVENT_AI,sWorld.GetCreatureEventAIVersion()); + PSendSysMessage(LANG_CONNECTED_PLAYERS, PlayersNum, MaxPlayersNum); PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum); - PSendSysMessage(LANG_UPTIME, str.c_str()); + PSendSysMessage(LANG_UPTIME, uptime.c_str()); PSendSysMessage("Update time diff: %u.", updateTime); return true; @@ -160,9 +163,9 @@ bool ChatHandler::HandleGMListIngameCommand(const char* /*args*/) HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); for(; itr != m.end(); ++itr) { - if (itr->second->GetSession()->GetSecurity() > SEC_PLAYER && - (itr->second->isGameMaster() || sWorld.getConfig(CONFIG_GM_IN_GM_LIST)) && - (!m_session || itr->second->IsVisibleGloballyFor(m_session->GetPlayer())) ) + AccountTypes itr_sec = itr->second->GetSession()->GetSecurity(); + if ((itr->second->isGameMaster() || itr_sec > SEC_PLAYER && itr_sec <= sWorld.getConfig(CONFIG_GM_LEVEL_IN_GM_LIST)) && + (!m_session || itr->second->IsVisibleGloballyFor(m_session->GetPlayer()))) { if(first) { @@ -242,14 +245,14 @@ bool ChatHandler::HandleAccountLockCommand(const char* args) std::string argstr = (char*)args; if (argstr == "on") { - LoginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId()); + loginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId()); PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); return true; } if (argstr == "off") { - LoginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId()); + loginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId()); PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); return true; } diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index cb06b2fe273..275dd5b1e8c 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -370,7 +370,7 @@ bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args) uint64 tguid = atoi(args); GM_Ticket *ticket = objmgr.GetGMTicket(tguid); - if(!ticket) + if(!ticket || ticket->closed != 0) { SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); return true; @@ -400,7 +400,10 @@ bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args) if(!*args) return false; - Player *plr = objmgr.GetPlayer(args); + std::string name = (char*)args; + normalizePlayerName(name); + + Player *plr = objmgr.GetPlayer(name.c_str()); if(!plr) { SendSysMessage(LANG_NO_PLAYERS_FOUND); @@ -496,7 +499,7 @@ bool ChatHandler::HandleGMTicketAssignToCommand(const char* args) } uint64 tarGUID = objmgr.GetPlayerGUIDByName(targm.c_str()); uint64 accid = objmgr.GetPlayerAccountIdByGUID(tarGUID); - QueryResult *result = LoginDatabase.PQuery("SELECT `gmlevel` FROM `account` WHERE `id` = '%u'", accid); + QueryResult *result = loginDatabase.PQuery("SELECT `gmlevel` FROM `account` WHERE `id` = '%u'", accid); if(!tarGUID|| !result || result->Fetch()->GetUInt32() < SEC_MODERATOR) { SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); @@ -846,13 +849,13 @@ bool ChatHandler::HandleNamegoCommand(const char* args) PSendSysMessage(LANG_SUMMONING, nameLink.c_str(),""); if (needReportToTarget(target)) - ChatHandler(target).PSendSysMessage(LANG_SUMMONED_BY, nameLink.c_str()); + ChatHandler(target).PSendSysMessage(LANG_SUMMONED_BY, _player->GetName()); // stop flight if need if (target->isInFlight()) { target->GetMotionMaster()->MovementExpired(); - target->m_taxi.ClearTaxiDestinations(); + target->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -937,7 +940,7 @@ bool ChatHandler::HandleGonameCommand(const char* args) } else if(cMap->IsDungeon()) { - Map* pMap = MapManager::Instance().GetMap(_player->GetMapId(),_player); + Map* pMap = _player->GetMap(); // we have to go to instance, and can go to player only if: // 1) we are in his group (either as leader or as member) @@ -988,7 +991,7 @@ bool ChatHandler::HandleGonameCommand(const char* args) if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -1021,7 +1024,7 @@ bool ChatHandler::HandleGonameCommand(const char* args) if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -1055,7 +1058,7 @@ bool ChatHandler::HandleRecallCommand(const char* args) if(target->isInFlight()) { target->GetMotionMaster()->MovementExpired(); - target->m_taxi.ClearTaxiDestinations(); + target->CleanupAfterTaxiFlight(); } target->TeleportTo(target->m_recallMap, target->m_recallX, target->m_recallY, target->m_recallZ, target->m_recallO); @@ -1468,23 +1471,42 @@ bool ChatHandler::HandleModifyTalentCommand (const char* args) return false; int tp = atoi((char*)args); - if (tp>0) + if (tp < 0) + return false; + + Unit* target = getSelectedUnit(); + if(!target) { - Player* player = getSelectedPlayer(); - if(!player) - { - SendSysMessage(LANG_NO_CHAR_SELECTED); - SetSentErrorMessage(true); - return false; - } + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); + return false; + } + if(target->GetTypeId()==TYPEID_PLAYER) + { // check online security - if (HasLowerSecurity(player, 0)) + if (HasLowerSecurity((Player*)target, 0)) return false; - - player->SetFreeTalentPoints(tp); + ((Player*)target)->SetFreeTalentPoints(tp); + ((Player*)target)->SendTalentsInfoData(false); return true; } + else if(((Creature*)target)->isPet()) + { + Unit *owner = target->GetOwner(); + if(owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)target)->IsPermanentPetFor((Player*)owner)) + { + // check online security + if (HasLowerSecurity((Player*)owner, 0)) + return false; + ((Pet *)target)->SetFreeTalentPoints(tp); + ((Player*)owner)->SendTalentsInfoData(true); + return true; + } + } + + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); return false; } @@ -2222,7 +2244,7 @@ bool ChatHandler::HandleTeleCommand(const char * args) if(_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2243,7 +2265,7 @@ bool ChatHandler::HandleLookupAreaCommand(const char* args) if (!Utf8toWStr (namepart,wnamepart)) return false; - uint32 counter = 0; // Counter for figure out that we found smth. + bool found = false; // converting string that we try to find to lower case wstrToLower (wnamepart); @@ -2287,12 +2309,13 @@ bool ChatHandler::HandleLookupAreaCommand(const char* args) SendSysMessage (ss.str ().c_str()); - ++counter; + if(!found) + found = true; } } } - if (counter == 0) // if counter == 0 then we found nth + if (!found) SendSysMessage (LANG_COMMAND_NOAREAFOUND); return true; @@ -2485,7 +2508,7 @@ bool ChatHandler::HandleTeleNameCommand(const char * args) if(target->isInFlight()) { target->GetMotionMaster()->MovementExpired(); - target->m_taxi.ClearTaxiDestinations(); + target->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2581,7 +2604,7 @@ bool ChatHandler::HandleTeleGroupCommand(const char * args) if(pl->isInFlight()) { pl->GetMotionMaster()->MovementExpired(); - pl->m_taxi.ClearTaxiDestinations(); + pl->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2670,7 +2693,7 @@ bool ChatHandler::HandleGroupgoCommand(const char* args) if(pl->isInFlight()) { pl->GetMotionMaster()->MovementExpired(); - pl->m_taxi.ClearTaxiDestinations(); + pl->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2720,7 +2743,7 @@ bool ChatHandler::HandleGoTaxinodeCommand(const char* args) if (_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2763,7 +2786,7 @@ bool ChatHandler::HandleGoXYCommand(const char* args) if(_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2813,7 +2836,7 @@ bool ChatHandler::HandleGoXYZCommand(const char* args) if(_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2884,7 +2907,7 @@ bool ChatHandler::HandleGoZoneXYCommand(const char* args) if(_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else @@ -2931,7 +2954,7 @@ bool ChatHandler::HandleGoGridCommand(const char* args) if(_player->isInFlight()) { _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); + _player->CleanupAfterTaxiFlight(); } // save only in non-flight case else diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 63d8943469d..e3f3bbce6e6 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -44,12 +44,6 @@ #include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand #include "CreatureGroups.h" -static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] = -{ - LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL, - LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED -}; - //mute player for some times bool ChatHandler::HandleMuteCommand(const char* args) { @@ -59,6 +53,11 @@ bool ChatHandler::HandleMuteCommand(const char* args) if(!delayStr) return false; + char *mutereason = strtok(NULL, "\r"); + std::string mutereasonstr = "No reason"; + if(mutereason != NULL) + mutereasonstr = mutereason; + Player* target; uint64 target_guid; std::string target_name; @@ -85,14 +84,15 @@ bool ChatHandler::HandleMuteCommand(const char* args) if (target) target->GetSession()->m_muteTime = mutetime; - LoginDatabase.PExecute("UPDATE account SET mutetime = " UI64FMTD " WHERE id = '%u'",uint64(mutetime), account_id ); + loginDatabase.PExecute("UPDATE account SET mutetime = " UI64FMTD " WHERE id = '%u'",uint64(mutetime), account_id ); if(target) - ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime); + ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime, mutereasonstr.c_str()); std::string nameLink = playerLink(target_name); - PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime); + PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime, mutereasonstr.c_str()); + return true; } @@ -130,7 +130,7 @@ bool ChatHandler::HandleUnmuteCommand(const char* args) target->GetSession()->m_muteTime = 0; } - LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id ); + loginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id ); if(target) ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); @@ -891,98 +891,6 @@ bool ChatHandler::HandleGUIDCommand(const char* /*args*/) return true; } -bool ChatHandler::HandleLookupFactionCommand(const char* args) -{ - if (!*args) - return false; - - // Can be NULL at console call - Player *target = getSelectedPlayer (); - - std::string namepart = args; - std::wstring wnamepart; - - if (!Utf8toWStr (namepart,wnamepart)) - return false; - - // converting string that we try to find to lower case - wstrToLower (wnamepart); - - uint32 counter = 0; // Counter for figure out that we found smth. - - for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id) - { - FactionEntry const *factionEntry = sFactionStore.LookupEntry (id); - if (factionEntry) - { - FactionState const* repState = target ? target->GetReputationMgr().GetState(factionEntry) : NULL; - - int loc = GetSessionDbcLocale(); - std::string name = factionEntry->name[loc]; - if(name.empty()) - continue; - - if (!Utf8FitTo(name, wnamepart)) - { - loc = 0; - for(; loc < MAX_LOCALE; ++loc) - { - if(loc==GetSessionDbcLocale()) - continue; - - name = factionEntry->name[loc]; - if(name.empty()) - continue; - - if (Utf8FitTo(name, wnamepart)) - break; - } - } - - if(loc < MAX_LOCALE) - { - // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format - // or "id - [faction] [no reputation]" format - std::ostringstream ss; - if (m_session) - ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r"; - else - ss << id << " - " << name << " " << localeNames[loc]; - - if (repState) // and then target!=NULL also - { - ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); - std::string rankName = GetMangosString(ReputationRankStrIndex[rank]); - - ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")"; - - if(repState->Flags & FACTION_FLAG_VISIBLE) - ss << GetTrinityString(LANG_FACTION_VISIBLE); - if(repState->Flags & FACTION_FLAG_AT_WAR) - ss << GetTrinityString(LANG_FACTION_ATWAR); - if(repState->Flags & FACTION_FLAG_PEACE_FORCED) - ss << GetTrinityString(LANG_FACTION_PEACE_FORCED); - if(repState->Flags & FACTION_FLAG_HIDDEN) - ss << GetTrinityString(LANG_FACTION_HIDDEN); - if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED) - ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED); - if(repState->Flags & FACTION_FLAG_INACTIVE) - ss << GetTrinityString(LANG_FACTION_INACTIVE); - } - else - ss << GetTrinityString(LANG_FACTION_NOREPUTATION); - - SendSysMessage(ss.str().c_str()); - counter++; - } - } - } - - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND); - return true; -} - bool ChatHandler::HandleModifyRepCommand(const char * args) { if (!*args) return false; @@ -1371,7 +1279,6 @@ bool ChatHandler::HandleNpcDeleteCommand(const char* args) // Delete the creature unit->CombatStop(); unit->DeleteFromDB(); - unit->CleanupsBeforeDelete(); unit->AddObjectToRemoveList(); SendSysMessage(LANG_COMMAND_DELCREATMESSAGE); @@ -1754,7 +1661,7 @@ bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/) } // Follow player - Using pet's default dist and angle - creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, creature->GetFollowAngle()); PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName()); return true; @@ -2263,40 +2170,40 @@ bool ChatHandler::HandlePInfoCommand(const char* args) if (HasLowerSecurity(NULL, target_guid)) return false; - // 0 - QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime FROM characters WHERE guid = '%u'", GUID_LOPART(target_guid)); + // 0 1 2 3 + QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime, level, money, account FROM characters WHERE guid = '%u'", GUID_LOPART(target_guid)); if (!result) return false; Field *fields = result->Fetch(); total_player_time = fields[0].GetUInt32(); + level = fields[1].GetUInt32(); + money = fields[2].GetUInt32(); + accId = fields[3].GetUInt32(); delete result; - - Tokens data; - if (!Player::LoadValuesArrayFromDB(data,target_guid)) - return false; - - money = Player::GetUInt32ValueFromArray(data, PLAYER_FIELD_COINAGE); - level = Player::GetUInt32ValueFromArray(data, UNIT_FIELD_LEVEL); - accId = objmgr.GetPlayerAccountIdByGUID(target_guid); } std::string username = GetTrinityString(LANG_ERROR); + std::string email = GetTrinityString(LANG_ERROR); std::string last_ip = GetTrinityString(LANG_ERROR); uint32 security = 0; std::string last_login = GetTrinityString(LANG_ERROR); - QueryResult* result = LoginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId); + QueryResult* result = loginDatabase.PQuery("SELECT username,gmlevel,email,last_ip,last_login FROM account WHERE id = '%u'",accId); if(result) { Field* fields = result->Fetch(); username = fields[0].GetCppString(); security = fields[1].GetUInt32(); + email = fields[2].GetCppString(); + + if(email.empty()) + email = "-"; if(!m_session || m_session->GetSecurity() >= security) { - last_ip = fields[2].GetCppString(); - last_login = fields[3].GetCppString(); + last_ip = fields[3].GetCppString(); + last_login = fields[4].GetCppString(); } else { @@ -2309,7 +2216,7 @@ bool ChatHandler::HandlePInfoCommand(const char* args) std::string nameLink = playerLink(target_name); - PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetMangosString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(target_guid), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency); + PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetTrinityString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(target_guid), username.c_str(), accId, email.c_str(), security, last_ip.c_str(), last_login.c_str(), latency); std::string timeStr = secsToTimeString(total_player_time,true,true); uint32 gold = money /GOLD; @@ -3448,7 +3355,6 @@ bool ChatHandler::HandleWpShowCommand(const char* args) Field *fields = result->Fetch(); uint32 guid = fields[0].GetUInt32(); Creature* pCreature = m_session->GetPlayer()->GetMap()->GetCreature(MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT)); - if(!pCreature) { PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid); @@ -3673,7 +3579,7 @@ bool ChatHandler::HandleLookupEventCommand(const char* args) wstrToLower(wnamepart); - uint32 counter = 0; + bool found = false; GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); @@ -3695,11 +3601,12 @@ bool ChatHandler::HandleLookupEventCommand(const char* args) else PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,id,eventData.description.c_str(),active ); - ++counter; + if(!found) + found = true; } } - if (counter==0) + if (!found) SendSysMessage(LANG_NOEVENTFOUND); return true; @@ -4026,9 +3933,9 @@ bool ChatHandler::HandleLookupPlayerIpCommand(const char* args) char* limit_str = strtok (NULL, " "); int32 limit = limit_str ? atoi (limit_str) : -1; - LoginDatabase.escape_string (ip); + loginDatabase.escape_string (ip); - QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ()); + QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ()); return LookupPlayerSearchCommand (result,limit); } @@ -4045,9 +3952,9 @@ bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args) if (!AccountMgr::normalizeString (account)) return false; - LoginDatabase.escape_string (account); + loginDatabase.escape_string (account); - QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ()); + QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ()); return LookupPlayerSearchCommand (result,limit); } @@ -4062,9 +3969,9 @@ bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args) char* limit_str = strtok (NULL, " "); int32 limit = limit_str ? atoi (limit_str) : -1; - LoginDatabase.escape_string (email); + loginDatabase.escape_string (email); - QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ()); + QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ()); return LookupPlayerSearchCommand (result,limit); } diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index adb904dbbbe..c1b8b56f043 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -108,7 +108,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) PSendSysMessage("Syntax is: ahbotoptions ahexpire $ahMapID (2, 6 or 7)"); return false; } - AuctionHouseBotCommands(0, ahMapID, NULL, NULL); + auctionbot.Commands(0, ahMapID, NULL, NULL); } else if (strncmp(opt,"minitems",l) == 0) { @@ -118,21 +118,17 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) PSendSysMessage("Syntax is: ahbotoptions minitems $ahMapID (2, 6 or 7) $minItems"); return false; } - AuctionHouseBotCommands(1, ahMapID, NULL, param1); + auctionbot.Commands(1, ahMapID, NULL, param1); } else if (strncmp(opt,"maxitems",l) == 0) { - PSendSysMessage("ahbotoptions mintime has been deprecated"); - return false; - /* char * param1 = strtok(NULL, " "); if ((!ahMapIdStr) || (!param1)) { PSendSysMessage("Syntax is: ahbotoptions maxitems $ahMapID (2, 6 or 7) $maxItems"); return false; } - AuctionHouseBotCommands(2, ahMapID, NULL, param1); - */ + auctionbot.Commands(2, ahMapID, NULL, param1); } else if (strncmp(opt,"mintime",l) == 0) { @@ -145,7 +141,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) PSendSysMessage("Syntax is: ahbotoptions mintime $ahMapID (2, 6 or 7) $mintime"); return false; } - AuctionHouseBotCommands(3, ahMapID, NULL, param1); + auctionbot.Commands(3, ahMapID, NULL, param1); */ } else if (strncmp(opt,"maxtime",l) == 0) @@ -159,7 +155,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) PSendSysMessage("Syntax is: ahbotoptions maxtime $ahMapID (2, 6 or 7) $maxtime"); return false; } - AuctionHouseBotCommands(4, ahMapID, NULL, param1); + auctionbot.Commands(4, ahMapID, NULL, param1); */ } else if (strncmp(opt,"percentages",l) == 0) @@ -240,7 +236,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) strcat(param, param13); strcat(param, " "); strcat(param, param14); - AuctionHouseBotCommands(5, ahMapID, NULL, param); + auctionbot.Commands(5, ahMapID, NULL, param); } else if (strncmp(opt,"minprice",l) == 0) { @@ -253,31 +249,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) } if (strncmp(param1,"grey",l) == 0) { - AuctionHouseBotCommands(6, ahMapID, AHB_GREY, param2); + auctionbot.Commands(6, ahMapID, AHB_GREY, param2); } else if (strncmp(param1,"white",l) == 0) { - AuctionHouseBotCommands(6, ahMapID, AHB_WHITE, param2); + auctionbot.Commands(6, ahMapID, AHB_WHITE, param2); } else if (strncmp(param1,"green",l) == 0) { - AuctionHouseBotCommands(6, ahMapID, AHB_GREEN, param2); + auctionbot.Commands(6, ahMapID, AHB_GREEN, param2); } else if (strncmp(param1,"blue",l) == 0) { - AuctionHouseBotCommands(6, ahMapID, AHB_BLUE, param2); + auctionbot.Commands(6, ahMapID, AHB_BLUE, param2); } else if (strncmp(param1,"purple",l) == 0) { - AuctionHouseBotCommands(6, ahMapID, AHB_PURPLE, param2); + auctionbot.Commands(6, ahMapID, AHB_PURPLE, param2); } else if (strncmp(param1,"orange",l) == 0) { - AuctionHouseBotCommands(6, ahMapID, AHB_ORANGE, param2); + auctionbot.Commands(6, ahMapID, AHB_ORANGE, param2); } else if (strncmp(param1,"yellow",l) == 0) { - AuctionHouseBotCommands(6, ahMapID, AHB_YELLOW, param2); + auctionbot.Commands(6, ahMapID, AHB_YELLOW, param2); } else { @@ -296,31 +292,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) } if (strncmp(param1,"grey",l) == 0) { - AuctionHouseBotCommands(7, ahMapID, AHB_GREY, param2); + auctionbot.Commands(7, ahMapID, AHB_GREY, param2); } else if (strncmp(param1,"white",l) == 0) { - AuctionHouseBotCommands(7, ahMapID, AHB_WHITE, param2); + auctionbot.Commands(7, ahMapID, AHB_WHITE, param2); } else if (strncmp(param1,"green",l) == 0) { - AuctionHouseBotCommands(7, ahMapID, AHB_GREEN, param2); + auctionbot.Commands(7, ahMapID, AHB_GREEN, param2); } else if (strncmp(param1,"blue",l) == 0) { - AuctionHouseBotCommands(7, ahMapID, AHB_BLUE, param2); + auctionbot.Commands(7, ahMapID, AHB_BLUE, param2); } else if (strncmp(param1,"purple",l) == 0) { - AuctionHouseBotCommands(7, ahMapID, AHB_PURPLE, param2); + auctionbot.Commands(7, ahMapID, AHB_PURPLE, param2); } else if (strncmp(param1,"orange",l) == 0) { - AuctionHouseBotCommands(7, ahMapID, AHB_ORANGE, param2); + auctionbot.Commands(7, ahMapID, AHB_ORANGE, param2); } else if (strncmp(param1,"yellow",l) == 0) { - AuctionHouseBotCommands(7, ahMapID, AHB_YELLOW, param2); + auctionbot.Commands(7, ahMapID, AHB_YELLOW, param2); } else { @@ -345,31 +341,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) } if (strncmp(param1,"grey",l) == 0) { - AuctionHouseBotCommands(8, ahMapID, AHB_GREY, param2); + auctionbot.Commands(8, ahMapID, AHB_GREY, param2); } else if (strncmp(param1,"white",l) == 0) { - AuctionHouseBotCommands(8, ahMapID, AHB_WHITE, param2); + auctionbot.Commands(8, ahMapID, AHB_WHITE, param2); } else if (strncmp(param1,"green",l) == 0) { - AuctionHouseBotCommands(8, ahMapID, AHB_GREEN, param2); + auctionbot.Commands(8, ahMapID, AHB_GREEN, param2); } else if (strncmp(param1,"blue",l) == 0) { - AuctionHouseBotCommands(8, ahMapID, AHB_BLUE, param2); + auctionbot.Commands(8, ahMapID, AHB_BLUE, param2); } else if (strncmp(param1,"purple",l) == 0) { - AuctionHouseBotCommands(8, ahMapID, AHB_PURPLE, param2); + auctionbot.Commands(8, ahMapID, AHB_PURPLE, param2); } else if (strncmp(param1,"orange",l) == 0) { - AuctionHouseBotCommands(8, ahMapID, AHB_ORANGE, param2); + auctionbot.Commands(8, ahMapID, AHB_ORANGE, param2); } else if (strncmp(param1,"yellow",l) == 0) { - AuctionHouseBotCommands(8, ahMapID, AHB_YELLOW, param2); + auctionbot.Commands(8, ahMapID, AHB_YELLOW, param2); } else { @@ -394,31 +390,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) } if (strncmp(param1,"grey",l) == 0) { - AuctionHouseBotCommands(9, ahMapID, AHB_GREY, param2); + auctionbot.Commands(9, ahMapID, AHB_GREY, param2); } else if (strncmp(param1,"white",l) == 0) { - AuctionHouseBotCommands(9, ahMapID, AHB_WHITE, param2); + auctionbot.Commands(9, ahMapID, AHB_WHITE, param2); } else if (strncmp(param1,"green",l) == 0) { - AuctionHouseBotCommands(9, ahMapID, AHB_GREEN, param2); + auctionbot.Commands(9, ahMapID, AHB_GREEN, param2); } else if (strncmp(param1,"blue",l) == 0) { - AuctionHouseBotCommands(9, ahMapID, AHB_BLUE, param2); + auctionbot.Commands(9, ahMapID, AHB_BLUE, param2); } else if (strncmp(param1,"purple",l) == 0) { - AuctionHouseBotCommands(9, ahMapID, AHB_PURPLE, param2); + auctionbot.Commands(9, ahMapID, AHB_PURPLE, param2); } else if (strncmp(param1,"orange",l) == 0) { - AuctionHouseBotCommands(9, ahMapID, AHB_ORANGE, param2); + auctionbot.Commands(9, ahMapID, AHB_ORANGE, param2); } else if (strncmp(param1,"yellow",l) == 0) { - AuctionHouseBotCommands(9, ahMapID, AHB_YELLOW, param2); + auctionbot.Commands(9, ahMapID, AHB_YELLOW, param2); } else { @@ -443,31 +439,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) } if (strncmp(param1,"grey",l) == 0) { - AuctionHouseBotCommands(10, ahMapID, AHB_GREY, param2); + auctionbot.Commands(10, ahMapID, AHB_GREY, param2); } else if (strncmp(param1,"white",l) == 0) { - AuctionHouseBotCommands(10, ahMapID, AHB_WHITE, param2); + auctionbot.Commands(10, ahMapID, AHB_WHITE, param2); } else if (strncmp(param1,"green",l) == 0) { - AuctionHouseBotCommands(10, ahMapID, AHB_GREEN, param2); + auctionbot.Commands(10, ahMapID, AHB_GREEN, param2); } else if (strncmp(param1,"blue",l) == 0) { - AuctionHouseBotCommands(10, ahMapID, AHB_BLUE, param2); + auctionbot.Commands(10, ahMapID, AHB_BLUE, param2); } else if (strncmp(param1,"purple",l) == 0) { - AuctionHouseBotCommands(10, ahMapID, AHB_PURPLE, param2); + auctionbot.Commands(10, ahMapID, AHB_PURPLE, param2); } else if (strncmp(param1,"orange",l) == 0) { - AuctionHouseBotCommands(10, ahMapID, AHB_ORANGE, param2); + auctionbot.Commands(10, ahMapID, AHB_ORANGE, param2); } else if (strncmp(param1,"yellow",l) == 0) { - AuctionHouseBotCommands(10, ahMapID, AHB_YELLOW, param2); + auctionbot.Commands(10, ahMapID, AHB_YELLOW, param2); } else { @@ -486,31 +482,31 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) } if (strncmp(param1,"grey",l) == 0) { - AuctionHouseBotCommands(11, ahMapID, AHB_GREY, param2); + auctionbot.Commands(11, ahMapID, AHB_GREY, param2); } else if (strncmp(param1,"white",l) == 0) { - AuctionHouseBotCommands(11, ahMapID, AHB_WHITE, param2); + auctionbot.Commands(11, ahMapID, AHB_WHITE, param2); } else if (strncmp(param1,"green",l) == 0) { - AuctionHouseBotCommands(11, ahMapID, AHB_GREEN, param2); + auctionbot.Commands(11, ahMapID, AHB_GREEN, param2); } else if (strncmp(param1,"blue",l) == 0) { - AuctionHouseBotCommands(11, ahMapID, AHB_BLUE, param2); + auctionbot.Commands(11, ahMapID, AHB_BLUE, param2); } else if (strncmp(param1,"purple",l) == 0) { - AuctionHouseBotCommands(11, ahMapID, AHB_PURPLE, param2); + auctionbot.Commands(11, ahMapID, AHB_PURPLE, param2); } else if (strncmp(param1,"orange",l) == 0) { - AuctionHouseBotCommands(11, ahMapID, AHB_ORANGE, param2); + auctionbot.Commands(11, ahMapID, AHB_ORANGE, param2); } else if (strncmp(param1,"yellow",l) == 0) { - AuctionHouseBotCommands(11, ahMapID, AHB_YELLOW, param2); + auctionbot.Commands(11, ahMapID, AHB_YELLOW, param2); } else { @@ -526,7 +522,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) PSendSysMessage("Syntax is: ahbotoptions bidinterval $ahMapID (2, 6 or 7) $interval(in minutes)"); return false; } - AuctionHouseBotCommands(12, ahMapID, NULL, param1); + auctionbot.Commands(12, ahMapID, NULL, param1); } else if (strncmp(opt,"bidsperinterval",l) == 0) { @@ -536,7 +532,7 @@ bool ChatHandler::HandleAHBotOptionsCommand(const char* args) PSendSysMessage("Syntax is: ahbotoptions bidsperinterval $ahMapID (2, 6 or 7) $bids"); return false; } - AuctionHouseBotCommands(13, ahMapID, NULL, param1); + auctionbot.Commands(13, ahMapID, NULL, param1); } else { @@ -648,7 +644,6 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*) { HandleReloadSkillDiscoveryTemplateCommand("a"); HandleReloadSkillExtraItemTemplateCommand("a"); - HandleReloadSpellAffectCommand("a"); HandleReloadSpellRequiredCommand("a"); HandleReloadSpellAreaCommand("a"); HandleReloadSpellElixirCommand("a"); @@ -996,14 +991,6 @@ bool ChatHandler::HandleReloadSkillFishingBaseLevelCommand(const char* /*args*/) return true; } -bool ChatHandler::HandleReloadSpellAffectCommand(const char*) -{ - sLog.outString( "Re-Loading SpellAffect definitions..." ); - spellmgr.LoadSpellAffects(); - SendGlobalGMSysMessage("DB table `spell_affect` (spell mods apply requirements) reloaded."); - return true; -} - bool ChatHandler::HandleReloadSpellAreaCommand(const char*) { sLog.outString( "Re-Loading SpellArea Data..." ); @@ -1428,7 +1415,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args) PSendSysMessage(LANG_YOURS_SECURITY_CHANGED, m_session->GetPlayer()->GetName(), gm); } - LoginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId); + loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId); return true; }else { @@ -1469,7 +1456,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args) } PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm); - LoginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId); + loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId); return true; } } @@ -1644,6 +1631,9 @@ bool ChatHandler::HandleUnLearnCommand(const char* args) else SendSysMessage(LANG_FORGET_SPELL); + if(GetTalentSpellCost(spell_id)) + target->SendTalentsInfoData(false); + return true; } @@ -2134,7 +2124,6 @@ bool ChatHandler::HandleLearnAllCommand(const char* /*args*/) "1180", "201", "12593", - "12842", "16770", "6057", "12051", @@ -2161,9 +2150,7 @@ bool ChatHandler::HandleLearnAllCommand(const char* /*args*/) "11129", "16766", "12573", - "15053", "12580", - "12475", "12472", "12953", "12488", @@ -2586,6 +2573,10 @@ bool ChatHandler::HandleLearnCommand(const char* args) else targetPlayer->learnSpell(spell,false); + uint32 first_spell = spellmgr.GetFirstSpellInChain(spell); + if(GetTalentSpellCost(first_spell)) + targetPlayer->SendTalentsInfoData(false); + return true; } @@ -3215,7 +3206,7 @@ bool ChatHandler::HandleLookupItemCommand(const char* args) wstrToLower(wnamepart); - uint32 counter = 0; + bool found = false; // Search in `item_template` for (uint32 id = 0; id < sItemStorage.MaxEntry; id++) @@ -3240,7 +3231,10 @@ bool ChatHandler::HandleLookupItemCommand(const char* args) PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str()); else PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str()); - ++counter; + + if(!found) + found = true; + continue; } } @@ -3257,11 +3251,13 @@ bool ChatHandler::HandleLookupItemCommand(const char* args) PSendSysMessage(LANG_ITEM_LIST_CHAT, id, id, name.c_str()); else PSendSysMessage(LANG_ITEM_LIST_CONSOLE, id, name.c_str()); - ++counter; + + if(!found) + found = true; } } - if (counter==0) + if (!found) SendSysMessage(LANG_COMMAND_NOITEMFOUND); return true; @@ -3281,7 +3277,7 @@ bool ChatHandler::HandleLookupItemSetCommand(const char* args) // converting string that we try to find to lower case wstrToLower( wnamepart ); - uint32 counter = 0; // Counter for figure out that we found smth. + bool found = false; // Search in ItemSet.dbc for (uint32 id = 0; id < sItemSetStore.GetNumRows(); id++) @@ -3318,11 +3314,13 @@ bool ChatHandler::HandleLookupItemSetCommand(const char* args) PSendSysMessage(LANG_ITEMSET_LIST_CHAT,id,id,name.c_str(),localeNames[loc]); else PSendSysMessage(LANG_ITEMSET_LIST_CONSOLE,id,name.c_str(),localeNames[loc]); - ++counter; + + if(!found) + found = true; } } } - if (counter == 0) // if counter == 0 then we found nth + if (!found) SendSysMessage(LANG_COMMAND_NOITEMSETFOUND); return true; } @@ -3344,7 +3342,7 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args) // converting string that we try to find to lower case wstrToLower( wnamepart ); - uint32 counter = 0; // Counter for figure out that we found smth. + bool found = false; // Search in SkillLine.dbc for (uint32 id = 0; id < sSkillLineStore.GetNumRows(); id++) @@ -3396,11 +3394,12 @@ bool ChatHandler::HandleLookupSkillCommand(const char* args) else PSendSysMessage(LANG_SKILL_LIST_CONSOLE,id,name.c_str(),localeNames[loc],knownStr,valStr); - ++counter; + if(!found) + found = true; } } } - if (counter == 0) // if counter == 0 then we found nth + if (!found) SendSysMessage(LANG_COMMAND_NOSKILLFOUND); return true; } @@ -3422,7 +3421,7 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args) // converting string that we try to find to lower case wstrToLower( wnamepart ); - uint32 counter = 0; // Counter for figure out that we found smth. + bool found = false; // Search in Spell.dbc for (uint32 id = 0; id < sSpellStore.GetNumRows(); id++) @@ -3496,11 +3495,12 @@ bool ChatHandler::HandleLookupSpellCommand(const char* args) SendSysMessage(ss.str().c_str()); - ++counter; + if(!found) + found = true; } } } - if (counter == 0) // if counter == 0 then we found nth + if (!found) SendSysMessage(LANG_COMMAND_NOSPELLFOUND); return true; } @@ -3522,7 +3522,7 @@ bool ChatHandler::HandleLookupQuestCommand(const char* args) wstrToLower(wnamepart); - uint32 counter = 0 ; + bool found = false; ObjectMgr::QuestMap const& qTemplates = objmgr.GetQuestTemplates(); for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) @@ -3562,7 +3562,10 @@ bool ChatHandler::HandleLookupQuestCommand(const char* args) PSendSysMessage(LANG_QUEST_LIST_CHAT,qinfo->GetQuestId(),qinfo->GetQuestId(),title.c_str(),statusStr); else PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr); - ++counter; + + if(!found) + found = true; + continue; } } @@ -3597,11 +3600,12 @@ bool ChatHandler::HandleLookupQuestCommand(const char* args) else PSendSysMessage(LANG_QUEST_LIST_CONSOLE,qinfo->GetQuestId(),title.c_str(),statusStr); - ++counter; + if(!found) + found = true; } } - if (counter==0) + if (!found) SendSysMessage(LANG_COMMAND_NOQUESTFOUND); return true; @@ -3621,7 +3625,7 @@ bool ChatHandler::HandleLookupCreatureCommand(const char* args) wstrToLower (wnamepart); - uint32 counter = 0; + bool found = false; for (uint32 id = 0; id< sCreatureStorage.MaxEntry; ++id) { @@ -3645,7 +3649,10 @@ bool ChatHandler::HandleLookupCreatureCommand(const char* args) PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ()); else PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ()); - ++counter; + + if(!found) + found = true; + continue; } } @@ -3662,11 +3669,13 @@ bool ChatHandler::HandleLookupCreatureCommand(const char* args) PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CHAT, id, id, name.c_str ()); else PSendSysMessage (LANG_CREATURE_ENTRY_LIST_CONSOLE, id, name.c_str ()); - ++counter; + + if(!found) + found = true; } } - if (counter==0) + if (!found) SendSysMessage (LANG_COMMAND_NOCREATUREFOUND); return true; @@ -3686,7 +3695,7 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args) wstrToLower(wnamepart); - uint32 counter = 0; + bool found = false; for (uint32 id = 0; id< sGOStorage.MaxEntry; id++ ) { @@ -3710,7 +3719,10 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args) PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str()); else PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str()); - ++counter; + + if(!found) + found = true; + continue; } } @@ -3727,16 +3739,112 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args) PSendSysMessage(LANG_GO_ENTRY_LIST_CHAT, id, id, name.c_str()); else PSendSysMessage(LANG_GO_ENTRY_LIST_CONSOLE, id, name.c_str()); - ++counter; + + if(!found) + found = true; } } - if(counter==0) + if(!found) SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND); return true; } +bool ChatHandler::HandleLookupFactionCommand(const char* args) +{ + if (!*args) + return false; + + // Can be NULL at console call + Player *target = getSelectedPlayer (); + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr (namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower (wnamepart); + + bool found = false; + + for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry (id); + if (factionEntry) + { + FactionState const* repState = target ? target->GetReputationMgr().GetState(factionEntry) : NULL; + + int loc = GetSessionDbcLocale(); + std::string name = factionEntry->name[loc]; + if(name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for(; loc < MAX_LOCALE; ++loc) + { + if(loc==GetSessionDbcLocale()) + continue; + + name = factionEntry->name[loc]; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if(loc < MAX_LOCALE) + { + // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format + // or "id - [faction] [no reputation]" format + std::ostringstream ss; + if (m_session) + ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r"; + else + ss << id << " - " << name << " " << localeNames[loc]; + + if (repState) // and then target!=NULL also + { + ReputationRank rank = target->GetReputationMgr().GetRank(factionEntry); + std::string rankName = GetMangosString(ReputationRankStrIndex[rank]); + + ss << " " << rankName << "|h|r (" << target->GetReputationMgr().GetReputation(factionEntry) << ")"; + + if(repState->Flags & FACTION_FLAG_VISIBLE) + ss << GetTrinityString(LANG_FACTION_VISIBLE); + if(repState->Flags & FACTION_FLAG_AT_WAR) + ss << GetTrinityString(LANG_FACTION_ATWAR); + if(repState->Flags & FACTION_FLAG_PEACE_FORCED) + ss << GetTrinityString(LANG_FACTION_PEACE_FORCED); + if(repState->Flags & FACTION_FLAG_HIDDEN) + ss << GetTrinityString(LANG_FACTION_HIDDEN); + if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED) + ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED); + if(repState->Flags & FACTION_FLAG_INACTIVE) + ss << GetTrinityString(LANG_FACTION_INACTIVE); + } + else + ss << GetTrinityString(LANG_FACTION_NOREPUTATION); + + SendSysMessage(ss.str().c_str()); + + if(!found) + found = true; + } + } + } + + if (!found) + SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND); + return true; +} + bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args) { if(!*args) @@ -3751,7 +3859,7 @@ bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args) // converting string that we try to find to lower case wstrToLower( wnamepart ); - uint32 counter = 0; // Counter for figure out that we found smth. + bool found = false; // Search in TaxiNodes.dbc for (uint32 id = 0; id < sTaxiNodesStore.GetNumRows(); id++) @@ -3790,12 +3898,14 @@ bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args) else PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CONSOLE, id, name.c_str(), localeNames[loc], nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z); - ++counter; + + if(!found) + found = true; } } } - if (counter == 0) // if counter == 0 then we found nth - SendSysMessage(LANG_COMMAND_NOSPELLFOUND); + if (!found) + SendSysMessage(LANG_COMMAND_NOTAXINODEFOUND); return true; } @@ -3813,7 +3923,7 @@ bool ChatHandler::HandleLookupMapCommand(const char* args) wstrToLower(wnamepart); - uint32 counter = 0; + bool found = false; // search in Map.dbc for(uint32 id = 0; id < sMapStore.GetNumRows(); id++) @@ -3892,12 +4002,13 @@ bool ChatHandler::HandleLookupMapCommand(const char* args) else SendSysMessage(ss.str().c_str()); - counter++; + if(!found) + found = true; } } } - if(!counter) + if(!found) SendSysMessage(LANG_COMMAND_NOMAPFOUND); return true; @@ -4672,11 +4783,7 @@ void ChatHandler::HandleCharacterLevel(Player* player, uint64 player_guid, uint3 else { // update level and XP at level, all other will be updated at loading - Tokens values; - Player::LoadValuesArrayFromDB(values,player_guid); - Player::SetUInt32ValueInArray(values,UNIT_FIELD_LEVEL,newlevel); - Player::SetUInt32ValueInArray(values,PLAYER_XP,0); - Player::SaveValuesArrayInDB(values,player_guid); + CharacterDatabase.PExecute("UPDATE characters SET level = '%u', xp = 0 WHERE guid = '%u'", newlevel, GUID_LOPART(player_guid)); } } @@ -4701,7 +4808,7 @@ bool ChatHandler::HandleCharacterLevelCommand(const char* args) if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) return false; - int32 oldlevel = target ? target->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,target_guid); + int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid); int32 newlevel = levelStr ? atoi(levelStr) : oldlevel; if(newlevel < 1) @@ -4740,7 +4847,7 @@ bool ChatHandler::HandleLevelUpCommand(const char* args) if(!extractPlayerTarget(nameStr,&target,&target_guid,&target_name)) return false; - int32 oldlevel = target ? target->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,target_guid); + int32 oldlevel = target ? target->getLevel() : Player::GetLevelFromDB(target_guid); int32 addlevel = levelStr ? atoi(levelStr) : 1; int32 newlevel = oldlevel + addlevel; @@ -4823,57 +4930,6 @@ bool ChatHandler::HandleHideAreaCommand(const char* args) return true; } -bool ChatHandler::HandleDebugUpdate(const char* args) -{ - if(!*args) - return false; - - uint32 updateIndex; - uint32 value; - - char* pUpdateIndex = strtok((char*)args, " "); - - Unit* chr = getSelectedUnit(); - if (chr == NULL) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if(!pUpdateIndex) - { - return true; - } - updateIndex = atoi(pUpdateIndex); - //check updateIndex - if(chr->GetTypeId() == TYPEID_PLAYER) - { - if (updateIndex>=PLAYER_END) return true; - } - else - { - if (updateIndex>=UNIT_END) return true; - } - - char* pvalue = strtok(NULL, " "); - if (!pvalue) - { - value=chr->GetUInt32Value(updateIndex); - - PSendSysMessage(LANG_UPDATE, chr->GetGUIDLow(),updateIndex,value); - return true; - } - - value=atoi(pvalue); - - PSendSysMessage(LANG_UPDATE_CHANGE, chr->GetGUIDLow(),updateIndex,value); - - chr->SetUInt32Value(updateIndex,value); - - return true; -} - bool ChatHandler::HandleBankCommand(const char* /*args*/) { m_session->SendShowBank( m_session->GetPlayer()->GetGUID() ); @@ -4923,106 +4979,6 @@ bool ChatHandler::HandleChangeWeather(const char* args) return true; } -bool ChatHandler::HandleDebugSetValue(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - - if (!px || !py) - return false; - - WorldObject* target = getSelectedObject(); - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = target->GetGUID(); - - uint32 Opcode = (uint32)atoi(px); - if(Opcode >= target->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); - return false; - } - uint32 iValue; - float fValue; - bool isint32 = true; - if(pz) - isint32 = (bool)atoi(pz); - if(isint32) - { - iValue = (uint32)atoi(py); - sLog.outDebug(GetTrinityString(LANG_SET_UINT), GUID_LOPART(guid), Opcode, iValue); - target->SetUInt32Value( Opcode , iValue ); - PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), Opcode,iValue); - } - else - { - fValue = (float)atof(py); - sLog.outDebug(GetTrinityString(LANG_SET_FLOAT), GUID_LOPART(guid), Opcode, fValue); - target->SetFloatValue( Opcode , fValue ); - PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), Opcode,fValue); - } - - return true; -} - -bool ChatHandler::HandleDebugGetValue(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* pz = strtok(NULL, " "); - - if (!px) - return false; - - Unit* target = getSelectedUnit(); - if(!target) - { - SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - SetSentErrorMessage(true); - return false; - } - - uint64 guid = target->GetGUID(); - - uint32 Opcode = (uint32)atoi(px); - if(Opcode >= target->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, GUID_LOPART(guid), target->GetValuesCount()); - return false; - } - uint32 iValue; - float fValue; - bool isint32 = true; - if(pz) - isint32 = (bool)atoi(pz); - - if(isint32) - { - iValue = target->GetUInt32Value( Opcode ); - sLog.outDebug(GetTrinityString(LANG_GET_UINT), GUID_LOPART(guid), Opcode, iValue); - PSendSysMessage(LANG_GET_UINT_FIELD, GUID_LOPART(guid), Opcode, iValue); - } - else - { - fValue = target->GetFloatValue( Opcode ); - sLog.outDebug(GetTrinityString(LANG_GET_FLOAT), GUID_LOPART(guid), Opcode, fValue); - PSendSysMessage(LANG_GET_FLOAT_FIELD, GUID_LOPART(guid), Opcode, fValue); - } - - return true; -} - bool ChatHandler::HandleDebugSet32Bit(const char* args) { if(!*args) @@ -5056,38 +5012,6 @@ bool ChatHandler::HandleDebugSet32Bit(const char* args) return true; } -bool ChatHandler::HandleDebugMod32Value(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 Opcode = (uint32)atoi(px); - int Value = atoi(py); - - if(Opcode >= m_session->GetPlayer()->GetValuesCount()) - { - PSendSysMessage(LANG_TOO_BIG_INDEX, Opcode, m_session->GetPlayer()->GetGUIDLow(), m_session->GetPlayer( )->GetValuesCount()); - return false; - } - - sLog.outDebug(GetTrinityString(LANG_CHANGE_32BIT), Opcode, Value); - - int CurrentValue = (int)m_session->GetPlayer( )->GetUInt32Value( Opcode ); - - CurrentValue += Value; - m_session->GetPlayer( )->SetUInt32Value( Opcode , (uint32)CurrentValue ); - - PSendSysMessage(LANG_CHANGE_32BIT_FIELD, Opcode,CurrentValue); - - return true; -} - bool ChatHandler::HandleTeleAddCommand(const char * args) { if(!*args) @@ -5243,9 +5167,6 @@ bool ChatHandler::HandleResetHonorCommand (const char * args) static bool HandleResetStatsOrLevelHelper(Player* player) { - PlayerInfo const *info = objmgr.GetPlayerInfo(player->getRace(), player->getClass()); - if(!info) return false; - ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(player->getClass()); if(!cEntry) { @@ -5268,21 +5189,7 @@ static bool HandleResetStatsOrLevelHelper(Player* player) // reset only if player not in some form; if(player->m_form==FORM_NONE) - { - switch(player->getGender()) - { - case GENDER_FEMALE: - player->SetDisplayId(info->displayId_f); - player->SetNativeDisplayId(info->displayId_f); - break; - case GENDER_MALE: - player->SetDisplayId(info->displayId_m); - player->SetNativeDisplayId(info->displayId_m); - break; - default: - break; - } - } + player->InitDisplayIds(); player->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP ); player->SetByteValue(UNIT_FIELD_BYTES_2, 3, player->m_form); @@ -5310,6 +5217,8 @@ bool ChatHandler::HandleResetLevelCommand(const char * args) ? sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) : sWorld.getConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); + target->_ApplyAllLevelScaleItemMods(false); + target->SetLevel(start_level); target->InitRunes(); target->InitStatsForLevel(true); @@ -5318,6 +5227,8 @@ bool ChatHandler::HandleResetLevelCommand(const char * args) target->InitTalentForLevel(); target->SetUInt32Value(PLAYER_XP,0); + target->_ApplyAllLevelScaleItemMods(true); + // reset level for pet if(Pet* pet = target->GetPet()) pet->SynchronizeLevelWithOwner(); @@ -5374,42 +5285,52 @@ bool ChatHandler::HandleResetTalentsCommand(const char * args) uint64 target_guid; std::string target_name; if (!extractPlayerTarget((char*)args,&target,&target_guid,&target_name)) + { + // Try reset talents as Hunter Pet + Creature* creature = getSelectedCreature(); + if (!*args && creature && creature->isPet()) + { + Unit *owner = creature->GetOwner(); + if(owner && owner->GetTypeId() == TYPEID_PLAYER && ((Pet *)creature)->IsPermanentPetFor((Player*)owner)) + { + ((Pet *)creature)->resetTalents(true); + ((Player*)owner)->SendTalentsInfoData(true); + + ChatHandler((Player*)owner).SendSysMessage(LANG_RESET_PET_TALENTS); + if(!m_session || m_session->GetPlayer()!=((Player*)owner)) + PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE,GetNameLink((Player*)owner).c_str()); + } + return true; + } + + SendSysMessage(LANG_NO_CHAR_SELECTED); + SetSentErrorMessage(true); return false; + } if (target) { target->resetTalents(true); - + target->SendTalentsInfoData(false); ChatHandler(target).SendSysMessage(LANG_RESET_TALENTS); if (!m_session || m_session->GetPlayer()!=target) PSendSysMessage(LANG_RESET_TALENTS_ONLINE,GetNameLink(target).c_str()); + Pet* pet = target->GetPet(); + Pet::resetTalentsForAllPetsOf(target,pet); + if(pet) + target->SendTalentsInfoData(true); return true; } else if (target_guid) { - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",uint32(AT_LOGIN_RESET_TALENTS), GUID_LOPART(target_guid) ); + uint32 at_flags = AT_LOGIN_NONE | AT_LOGIN_RESET_PET_TALENTS; + CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'",at_flags, GUID_LOPART(target_guid) ); std::string nameLink = playerLink(target_name); PSendSysMessage(LANG_RESET_TALENTS_OFFLINE,nameLink.c_str()); return true; } - // Try reset talents as Hunter Pet - Creature* creature = getSelectedCreature(); - if (creature && creature->isPet() && ((Pet *)creature)->getPetType() == HUNTER_PET) - { - ((Pet *)creature)->resetTalents(true); - Unit *owner = creature->GetOwner(); - if (owner && owner->GetTypeId() == TYPEID_PLAYER) - { - Player* owner_player = (Player *)owner; - ChatHandler(owner_player).SendSysMessage(LANG_RESET_PET_TALENTS); - if(!m_session || m_session->GetPlayer()!=owner_player) - PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE,GetNameLink(owner_player).c_str()); - } - return true; - } - SendSysMessage(LANG_NO_CHAR_SELECTED); SetSentErrorMessage(true); return false; @@ -5434,21 +5355,11 @@ bool ChatHandler::HandleResetAllCommand(const char * args) } else if(casename=="talents") { - atLogin = AT_LOGIN_RESET_TALENTS; + atLogin = AtLoginFlags(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS); sWorld.SendWorldText(LANG_RESETALL_TALENTS); if(!m_session) SendSysMessage(LANG_RESETALL_TALENTS); } - else if(casename=="pet_spells") - { - CharacterDatabase.PExecute("UPDATE character_pet SET load_flags = load_flags | '%u' WHERE (load_flags & '%u') = '0'",uint32(AT_LOAD_RESET_SPELLS),uint32(AT_LOAD_RESET_SPELLS)); - HashMapHolder<Player>::MapType const& plist = ObjectAccessor::Instance().GetPlayers(); - for(HashMapHolder<Player>::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr) - if (itr->second->GetPet()) - itr->second->SetPetAtLoginFlag(AT_LOAD_RESET_SPELLS); - sWorld.SendWorldText(LANG_RESETALL_PET_SPELLS); - return true; - } else { PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE,args); @@ -5774,8 +5685,9 @@ bool ChatHandler::HandleQuestComplete(const char* args) } else if(creature > 0) { - for(uint16 z = 0; z < creaturecount; ++z) - player->KilledMonster(creature,0); + if(CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creature)) + for(uint16 z = 0; z < creaturecount; ++z) + player->KilledMonster(cInfo,0); } else if(creature < 0) { @@ -5997,7 +5909,7 @@ bool ChatHandler::HandleBanInfoCharacterCommand(const char* args) bool ChatHandler::HandleBanInfoHelper(uint32 accountid, char const* accountname) { - QueryResult *result = LoginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid); + QueryResult *result = loginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid); if(!result) { PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname); @@ -6037,8 +5949,8 @@ bool ChatHandler::HandleBanInfoIPCommand(const char* args) std::string IP = cIP; - LoginDatabase.escape_string(IP); - QueryResult *result = LoginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str()); + loginDatabase.escape_string(IP); + QueryResult *result = loginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str()); if(!result) { PSendSysMessage(LANG_BANINFO_NOIP); @@ -6056,14 +5968,14 @@ bool ChatHandler::HandleBanInfoIPCommand(const char* args) bool ChatHandler::HandleBanListCharacterCommand(const char* args) { - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); char* cFilter = strtok ((char*)args, " "); if(!cFilter) return false; std::string filter = cFilter; - LoginDatabase.escape_string(filter); + loginDatabase.escape_string(filter); QueryResult* result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),filter.c_str()); if (!result) { @@ -6076,22 +5988,22 @@ bool ChatHandler::HandleBanListCharacterCommand(const char* args) bool ChatHandler::HandleBanListAccountCommand(const char* args) { - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); char* cFilter = strtok((char*)args, " "); std::string filter = cFilter ? cFilter : ""; - LoginDatabase.escape_string(filter); + loginDatabase.escape_string(filter); QueryResult* result; if(filter.empty()) { - result = LoginDatabase.Query("SELECT account.id, username FROM account, account_banned" + result = loginDatabase.Query("SELECT account.id, username FROM account, account_banned" " WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id"); } else { - result = LoginDatabase.PQuery("SELECT account.id, username FROM account, account_banned" + result = loginDatabase.PQuery("SELECT account.id, username FROM account, account_banned" " WHERE account.id = account_banned.id AND active = 1 AND username "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" GROUP BY account.id", filter.c_str()); } @@ -6117,7 +6029,7 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result) Field* fields = result->Fetch(); uint32 accountid = fields[0].GetUInt32(); - QueryResult* banresult = LoginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid); + QueryResult* banresult = loginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid); if(banresult) { Field* fields2 = banresult->Fetch(); @@ -6148,7 +6060,7 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result) accmgr.GetName (account_id,account_name); // No SQL injection. id is uint32. - QueryResult *banInfo = LoginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id); + QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id); if (banInfo) { Field *fields2 = banInfo->Fetch(); @@ -6185,23 +6097,23 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result) bool ChatHandler::HandleBanListIPCommand(const char* args) { - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); char* cFilter = strtok((char*)args, " "); std::string filter = cFilter ? cFilter : ""; - LoginDatabase.escape_string(filter); + loginDatabase.escape_string(filter); QueryResult* result; if(filter.empty()) { - result = LoginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" + result = loginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" " WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP())" " ORDER BY unbandate" ); } else { - result = LoginDatabase.PQuery( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" + result = loginDatabase.PQuery( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned" " WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) AND ip "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'") " ORDER BY unbandate",filter.c_str() ); } @@ -6287,7 +6199,7 @@ bool ChatHandler::HandleRespawnCommand(const char* /*args*/) TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::RespawnDo>, GridTypeMapContainer > obj_worker(worker); CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, obj_worker, *MapManager::Instance().GetMap(pl->GetMapId(), pl)); + cell_lock->Visit(cell_lock, obj_worker, *pl->GetMap()); return true; } @@ -6362,18 +6274,18 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args) char* name_str = strtok(NULL, " "); std::string name; - if(name_str) + if (name_str) { name = name_str; // normalize the name if specified and check if it exists - if(!normalizePlayerName(name)) + if (!normalizePlayerName(name)) { PSendSysMessage(LANG_INVALID_CHARACTER_NAME); SetSentErrorMessage(true); return false; } - if(!ObjectMgr::IsValidName(name,true)) + if (ObjectMgr::CheckPlayerName(name,true) != CHAR_NAME_SUCCESS) { PSendSysMessage(LANG_INVALID_CHARACTER_NAME); SetSentErrorMessage(true); @@ -6385,17 +6297,17 @@ bool ChatHandler::HandlePDumpLoadCommand(const char *args) uint32 guid = 0; - if(guid_str) + if (guid_str) { guid = atoi(guid_str); - if(!guid) + if (!guid) { PSendSysMessage(LANG_INVALID_CHARACTER_GUID); SetSentErrorMessage(true); return false; } - if(objmgr.GetPlayerAccountIdByGUID(guid)) + if (objmgr.GetPlayerAccountIdByGUID(guid)) { PSendSysMessage(LANG_CHARACTER_GUID_IN_USE,guid); SetSentErrorMessage(true); @@ -6970,7 +6882,7 @@ bool ChatHandler::HandleInstanceSaveDataCommand(const char * /*args*/) bool ChatHandler::HandleGMListFullCommand(const char* /*args*/) { ///- Get the accounts with GM Level >0 - QueryResult *result = LoginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" ); + QueryResult *result = loginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" ); if(result) { SendSysMessage(LANG_GMLIST); @@ -7079,7 +6991,7 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args) return false; // No SQL injection - LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",lev,account_id); + loginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",lev,account_id); PSendSysMessage(LANG_ACCOUNT_SETADDON,account_name.c_str(),account_id,lev); return true; } @@ -7330,8 +7242,7 @@ bool ChatHandler::HandleModifyGenderCommand(const char *args) player->SetByteValue(PLAYER_BYTES_3, 0, gender); // Change display ID - player->SetDisplayId(gender ? info->displayId_f : info->displayId_m); - player->SetNativeDisplayId(gender ? info->displayId_f : info->displayId_m); + player->InitDisplayIds(); char const* gender_full = gender ? "female" : "male"; diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp index 172a6ef46c2..6b5f22b6a6b 100644 --- a/src/game/LootHandler.cpp +++ b/src/game/LootHandler.cpp @@ -259,6 +259,10 @@ void WorldSession::HandleLootOpcode( WorldPacket & recv_data ) uint64 guid; recv_data >> guid; + // Check possible cheat + if(!_player->isAlive()) + return; + GetPlayer()->SendLoot(guid, LOOT_CORPSE); } diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index 5654f540da1..b54d7b90774 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -1152,7 +1152,7 @@ void LoadLootTemplates_Gameobject() { if(GameObjectInfo const* gInfo = sGOStorage.LookupEntry<GameObjectInfo>(i)) { - if(uint32 lootid = GameObject::GetLootId(gInfo)) + if(uint32 lootid = gInfo->GetLootId()) { if(!ids_set.count(lootid)) LootTemplates_Gameobject.ReportNotExistedId(lootid); @@ -1323,10 +1323,12 @@ void LoadLootTemplates_Spell() if(!ids_set.count(spell_id)) { - // not report about not trainable spells (optionally supported by DB) except with SPELL_ATTR_EX2_UNK14 (clams) - // 61756 (Northrend Inscription Research (FAST QA VERSION) for example - if ((spellInfo->Attributes & SPELL_ATTR_UNK5) || (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK14)) + // not report about not trainable spells (optionally supported by DB) + // ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example + if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_UNK5)) + { LootTemplates_Spell.ReportNotExistedId(spell_id); + } } else ids_set.erase(spell_id); diff --git a/src/game/Mail.cpp b/src/game/Mail.cpp index 0af4999092f..94f40f0079e 100644 --- a/src/game/Mail.cpp +++ b/src/game/Mail.cpp @@ -32,6 +32,15 @@ #include "AuctionHouseBot.h" #include "DBCStores.h" +enum MailShowFlags +{ + MAIL_SHOW_UNK0 = 0x0001, + MAIL_SHOW_DELETE = 0x0002, // forced show delete button instead return button + MAIL_SHOW_AUCTION = 0x0004, // from old comment + MAIL_SHOW_COD = 0x0008, // show subject prefix + MAIL_SHOW_UNK4 = 0x0010, +}; + void MailItem::deleteItem( bool inDB ) { if(item) @@ -381,7 +390,7 @@ void WorldSession::HandleMailReturnToSender(WorldPacket & recv_data ) } } - if (m->sender == AHBplayerGUID) + if (m->sender == auctionbot.GetAHBplayerGUID()) { SendReturnToSender(MAIL_CREATURE, GetAccountId(), m->receiver, m->sender, m->subject, m->itemTextId, &mi, m->money, m->mailTemplateId); } @@ -567,7 +576,7 @@ void WorldSession::HandleMailTakeMoney(WorldPacket & recv_data ) // save money and mail to prevent cheating CharacterDatabase.BeginTransaction(); - pl->SaveDataFieldToDB(); // contains money + pl->SaveGoldToDB(); pl->_SaveMail(); CharacterDatabase.CommitTransaction(); } @@ -611,6 +620,14 @@ void WorldSession::HandleGetMailList(WorldPacket & recv_data ) if(data.wpos()+next_mail_size > maxPacketSize) break; + uint32 show_flags = 0; + if ((*itr)->messageType != MAIL_NORMAL) + show_flags |= MAIL_SHOW_DELETE; + if ((*itr)->messageType == MAIL_AUCTION) + show_flags |= MAIL_SHOW_AUCTION; + if ((*itr)->COD) + show_flags |= MAIL_SHOW_COD; + data << (uint16) 0x0040; // unknown 2.3.0, different values data << (uint32) (*itr)->messageID; // Message ID data << (uint8) (*itr)->messageType; // Message Type @@ -634,7 +651,7 @@ void WorldSession::HandleGetMailList(WorldPacket & recv_data ) data << (uint32) 0; // unknown data << (uint32) (*itr)->stationery; // stationery (Stationery.dbc) data << (uint32) (*itr)->money; // Gold - data << (uint32) 0x04; // unknown, 0x4 - auction, 0x10 - normal + data << (uint32) show_flags; // unknown, 0x4 - auction, 0x10 - normal // Time data << (float) ((*itr)->expire_time-time(NULL))/DAY; data << (uint32) (*itr)->mailTemplateId; // mail template (MailTemplate.dbc) @@ -772,38 +789,40 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/ ) { data << (uint32) 0; // float data << (uint32) 0; // count + uint32 count = 0; + time_t now = time(NULL); for(PlayerMails::iterator itr = _player->GetmailBegin(); itr != _player->GetmailEnd(); ++itr) { Mail *m = (*itr); - // not checked yet, already must be delivered - if((m->checked & MAIL_CHECK_MASK_READ)==0 && (m->deliver_time <= time(NULL))) - { - ++count; + // must be not checked yet + if(m->checked & MAIL_CHECK_MASK_READ) + continue; - if(count > 2) - { - count = 2; - break; - } + // and already delivered + if(now < m->deliver_time) + continue; - data << (uint64) m->sender; // sender guid + data << (uint64) m->sender; // sender guid - switch(m->messageType) - { - case MAIL_AUCTION: - data << (uint32) 2; - data << (uint32) 2; - data << (uint32) m->stationery; - break; - default: - data << (uint32) 0; - data << (uint32) 0; - data << (uint32) m->stationery; - break; - } - data << (uint32) 0xC6000000; // float unk, time or something + switch(m->messageType) + { + case MAIL_AUCTION: + data << (uint32) 2; + data << (uint32) 2; + data << (uint32) m->stationery; + break; + default: + data << (uint32) 0; + data << (uint32) 0; + data << (uint32) m->stationery; + break; } + data << (uint32) 0xC6000000; // float unk, time or something + + ++count; + if(count == 2) // do not display more than 2 mails + break; } data.put<uint32>(4, count); } @@ -817,7 +836,7 @@ void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recv_data*/ ) void WorldSession::SendMailTo(Player* receiver, uint8 messageType, uint8 stationery, uint32 sender_guidlow_or_entry, uint32 receiver_guidlow, std::string subject, uint32 itemTextId, MailItemsInfo* mi, uint32 money, uint32 COD, uint32 checked, uint32 deliver_delay, uint16 mailTemplateId) { - if (receiver_guidlow == AHBplayerGUID) + if (receiver_guidlow == auctionbot.GetAHBplayerGUID()) { if(messageType == MAIL_AUCTION && mi) // auction mail with items { diff --git a/src/game/Makefile.am b/src/game/Makefile.am index ed918234265..bc5dace3985 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -624,6 +624,7 @@ libmangosgame_a_SOURCES = \ Channel.cpp \ Channel.h \ ChannelHandler.cpp \ + ChannelMgr.cpp \ ChannelMgr.h \ CharacterHandler.cpp \ Chat.cpp \ @@ -840,11 +841,8 @@ libmangosgame_a_SOURCES = \ GroupRefManager.h >>>>>>> 5a6594330caefc0dc00a5fe792dcb0e344b457cb:src/game/Makefile.am -## Link against shared library -libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/vmap/libmangosvmaps.a - ## Additional files to include when running 'make dist' # Precompiled Headers for WIN EXTRA_DIST = \ pchdef.cpp \ - pchdef.h
\ No newline at end of file + pchdef.h diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 6dbb0e37c86..47925102892 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -20,6 +20,7 @@ #include "MapManager.h" #include "Player.h" +#include "Vehicle.h" #include "GridNotifiers.h" #include "Log.h" #include "GridStates.h" @@ -36,6 +37,7 @@ #include "Group.h" #include "MapRefManager.h" #include "Vehicle.h" +#include "WaypointManager.h" #include "MapInstanced.h" #include "InstanceSaveMgr.h" @@ -46,9 +48,20 @@ GridState* si_GridStates[MAX_GRID_STATE]; +struct ScriptAction +{ + uint64 sourceGUID; + uint64 targetGUID; + uint64 ownerGUID; // owner of source if source is item + ScriptInfo const* script; // pointer to static script data +}; + Map::~Map() { UnloadAll(); + + if(!m_scriptSchedule.empty()) + sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size()); } bool Map::ExistMap(uint32 mapid,int gx,int gy) @@ -127,14 +140,12 @@ void Map::LoadMap(int gx,int gy, bool reload) if(GridMaps[gx][gy]) return; - Map* baseMap = const_cast<Map*>(MapManager::Instance().CreateBaseMap(i_id)); - // load grid map for base map - if (!baseMap->GridMaps[gx][gy]) - baseMap->EnsureGridCreated(GridPair(63-gx,63-gy)); + if (!m_parentMap->GridMaps[gx][gy]) + m_parentMap->EnsureGridCreated(GridPair(63-gx,63-gy)); - ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(gx,gy)); - GridMaps[gx][gy] = baseMap->GridMaps[gx][gy]; + ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridPair(gx,gy)); + GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; return; } @@ -144,7 +155,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]) { - sLog.outDetail("Unloading already loaded map %u before reloading.",i_id); + sLog.outDetail("Unloading already loaded map %u before reloading.",GetId()); delete (GridMaps[gx][gy]); GridMaps[gx][gy]=NULL; } @@ -153,7 +164,7 @@ void Map::LoadMap(int gx,int gy, bool reload) char *tmp=NULL; int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1; tmp = new char[len]; - snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),i_id,gx,gy); + snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),GetId(),gx,gy); sLog.outDetail("Loading map %s",tmp); // loading data GridMaps[gx][gy] = new GridMap(); @@ -187,11 +198,10 @@ void Map::DeleteStateMachine() delete si_GridStates[GRID_STATE_REMOVAL]; } -Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode) - : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), - i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), +Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) + : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0), m_activeNonPlayersIter(m_activeNonPlayers.end()), - i_gridExpiry(expiry) + i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this) , i_lock(true) { m_notifyTimer.SetInterval(IN_MILISECONDS/2); @@ -364,6 +374,13 @@ void Map::DeleteFromWorld(T* obj) delete obj; } +template<> +void Map::DeleteFromWorld(Player* pl) +{ + ObjectAccessor::Instance().RemoveObject(pl); + delete pl; +} + template<class T> void Map::AddNotifier(T*) { @@ -393,7 +410,7 @@ Map::EnsureGridCreated(const GridPair &p) Guard guard(*this); if(!getNGrid(p.x_coord, p.y_coord)) { - sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, i_id, i_InstanceId); + sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, GetId(), i_InstanceId); setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)), p.x_coord, p.y_coord); @@ -425,11 +442,11 @@ Map::EnsureGridLoadedAtEnter(const Cell &cell, Player *player) if (player) { player->SendDelayResponse(MAX_GRID_LOAD_TIME); - DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), i_id); + DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), GetId()); } else { - DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id); + DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), GetId()); } ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f); @@ -450,7 +467,7 @@ bool Map::EnsureGridLoaded(const Cell &cell) assert(grid != NULL); if( !isGridObjectDataLoaded(cell.GridX(), cell.GridY()) ) { - sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), i_id, i_InstanceId); + sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), GetId(), i_InstanceId); ObjectGridLoader loader(*grid, this, cell); loader.LoadN(); @@ -474,10 +491,8 @@ void Map::LoadGrid(float x, float y) bool Map::Add(Player *player) { - player->GetMapRef().link(this, player); - - player->SetInstanceId(GetInstanceId()); - + // Check if we are adding to correct map + assert (player->GetMap() == this); // update player state for other player and visa-versa CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); Cell cell(p); @@ -504,6 +519,8 @@ Map::Add(T *obj) return; } + obj->SetMap(this); + Cell cell(p); if(obj->isActiveObject()) EnsureGridLoadedAtEnter(cell); @@ -525,7 +542,6 @@ Map::Add(T *obj) //also, trigger needs to cast spell, if not update, cannot see visual //if(obj->GetTypeId() != TYPEID_UNIT) UpdateObjectVisibility(obj,cell,p); - AddNotifier(obj); } @@ -633,12 +649,14 @@ void Map::AddUnitToNotify(Unit* u) } } -void Map::RemoveUnitFromNotify(int32 slot) +void Map::RemoveUnitFromNotify(Unit *unit, int32 slot) { if(i_lock) { - assert(slot < i_unitsToNotifyBacklog.size()); - i_unitsToNotifyBacklog[slot] = NULL; + if(slot < i_unitsToNotifyBacklog.size() && i_unitsToNotifyBacklog[slot] == unit) + i_unitsToNotifyBacklog[slot] = NULL; + else if(slot < i_unitsToNotify.size() && i_unitsToNotify[slot] == unit) + i_unitsToNotify[slot] = NULL; } else { @@ -774,37 +792,39 @@ void Map::Update(const uint32 &t_diff) // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended - if (IsBattleGroundOrArena()) - return; - - for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); ) + if (!IsBattleGroundOrArena()) { - NGridType *grid = i->getSource(); - GridInfo *info = i->getSource()->getGridInfoRef(); - ++i; // The update might delete the map and we need the next map before the iterator gets invalid - assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE); - si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff); + for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); ) + { + NGridType *grid = i->getSource(); + GridInfo *info = i->getSource()->getGridInfoRef(); + ++i; // The update might delete the map and we need the next map before the iterator gets invalid + assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE); + si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff); + } } + + ///- Process necessary scripts + if (!m_scriptSchedule.empty()) + ScriptsProcess(); } void Map::Remove(Player *player, bool remove) { - // this may be called during Map::Update - // after decrement+unlink, ++m_mapRefIter will continue correctly - // when the first element of the list is being removed - // nocheck_prev will return the padding element of the RefManager - // instead of NULL in the case of prev - if(m_mapRefIter == player->GetMapRef()) - m_mapRefIter = m_mapRefIter->nocheck_prev(); - player->GetMapRef().unlink(); CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) { + if(remove) + player->CleanupsBeforeDelete(); + // invalid coordinates player->RemoveFromWorld(); if( remove ) + { + player->ResetMap(); DeleteFromWorld(player); + } return; } @@ -821,6 +841,9 @@ void Map::Remove(Player *player, bool remove) NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); assert(grid != NULL); + if(remove) + player->CleanupsBeforeDelete(); + player->RemoveFromWorld(); RemoveFromGrid(player,grid,cell); @@ -870,6 +893,7 @@ Map::Remove(T *obj, bool remove) UpdateObjectVisibility(obj,cell,p); + obj->ResetMap(); if( remove ) { // if option set then object already saved at this moment @@ -1010,7 +1034,6 @@ void Map::MoveAllCreaturesInMoveList() if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0) sLog.outDebug("Creature (GUID: %u Entry: %u ) can't be move to unloaded respawn grid.",c->GetGUIDLow(),c->GetEntry()); #endif - c->CleanupsBeforeDelete(); AddObjectToRemoveList(c); } } @@ -1121,7 +1144,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll) if(!unloadAll && ActiveObjectsNearGrid(x, y) ) return false; - sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, i_id); + sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, GetId()); ObjectGridUnloader unloader(*grid); @@ -1167,13 +1190,29 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll) VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gy, gx); } else - ((MapInstanced*)(MapManager::Instance().CreateBaseMap(i_id)))->RemoveGridMapReference(GridPair(gx, gy)); + ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridPair(gx, gy)); + GridMaps[gx][gy] = NULL; } - DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, i_id); + DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, GetId()); return true; } +void Map::RemoveAllPlayers() +{ + if(HavePlayers()) + { + sLog.outError("Map::UnloadAll: there are still players in the instance at unload, should not happen!"); + + for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + { + Player* plr = itr->getSource(); + if(!plr->IsBeingTeleportedFar()) + plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation()); + } + } +} + void Map::UnloadAll() { // clear all delayed moves, useless anyway do this moves before map unload. @@ -1297,11 +1336,11 @@ bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size) map_heightHeader header; fseek(in, offset, SEEK_SET); fread(&header, sizeof(header), 1, in); - if (header.fourcc != uint32(MAP_HEIGTH_MAGIC)) + if (header.fourcc != uint32(MAP_HEIGHT_MAGIC)) return false; m_gridHeight = header.gridHeight; - if (!(header.flags & MAP_HEIGHT_NO_HIGHT)) + if (!(header.flags & MAP_HEIGHT_NO_HEIGHT)) { if ((header.flags & MAP_HEIGHT_AS_INT16)) { @@ -1350,12 +1389,12 @@ bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size) m_liquid_height= header.height; m_liquidLevel = header.liquidLevel; - if (!(header.flags&MAP_LIQUID_NO_TYPE)) + if (!(header.flags & MAP_LIQUID_NO_TYPE)) { m_liquid_type = new uint8 [16*16]; fread(m_liquid_type, sizeof(uint8), 16*16, in); } - if (!(header.flags&MAP_LIQUID_NO_HIGHT)) + if (!(header.flags & MAP_LIQUID_NO_HEIGHT)) { m_liquid_map = new float [m_liquid_width*m_liquid_height]; fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in); @@ -1792,7 +1831,7 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const areaflag = gmap->getArea(x, y); // this used while not all *.map files generated (instances) else - areaflag = GetAreaFlagByMapId(i_id); + areaflag = GetAreaFlagByMapId(GetId()); //FIXME: some hacks for areas above or underground for ground area // required for area specific spells/etc, until map/vmap data @@ -1990,7 +2029,7 @@ void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 area zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0; } -bool Map::IsInWater(float x, float y, float pZ) const +bool Map::IsInWater(float x, float y, float pZ, float min_depth) const { // Check surface in x, y point for liquid if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) @@ -1998,7 +2037,7 @@ bool Map::IsInWater(float x, float y, float pZ) const LiquidData liquid_status; if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, &liquid_status)) { - if (liquid_status.level - liquid_status.depth_level > 2) + if (liquid_status.level - liquid_status.depth_level > min_depth) return true; } } @@ -2097,7 +2136,7 @@ void Map::SendInitTransports( Player * player ) for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i) { // send data for current transport in other place - if((*i) != player->GetTransport() && (*i)->GetMapId()==i_id) + if((*i) != player->GetTransport() && (*i)->GetMapId()==GetId()) { (*i)->BuildCreateUpdateBlockForPlayer(&transData, player); } @@ -2123,7 +2162,7 @@ void Map::SendRemoveTransports( Player * player ) // except used transport for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i) - if((*i) != player->GetTransport() && (*i)->GetMapId()!=i_id) + if((*i) != player->GetTransport() && (*i)->GetMapId()!=GetId()) (*i)->BuildOutOfRangeUpdateBlock(&transData); WorldPacket packet; @@ -2151,6 +2190,8 @@ void Map::AddObjectToRemoveList(WorldObject *obj) { assert(obj->GetMapId()==GetId() && obj->GetInstanceId()==GetInstanceId()); + obj->CleanupsBeforeDelete(); // remove or simplify at least cross referenced links + i_objectsToRemove.insert(obj); //sLog.outDebug("Object (GUID: %u TypeId: %u ) added to removing list.",obj->GetGUIDLow(),obj->GetTypeId()); } @@ -2326,8 +2367,8 @@ template void Map::Remove(DynamicObject *, bool); /* ******* Dungeon Instance Maps ******* */ -InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode) - : Map(id, expiry, InstanceId, SpawnMode), +InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) + : Map(id, expiry, InstanceId, SpawnMode, _parent), m_resetAfterUnload(false), m_unloadWhenEmpty(false), i_data(NULL), i_script_id(0) { @@ -2388,8 +2429,9 @@ bool InstanceMap::Add(Player *player) { Guard guard(*this); - if(!CanEnter(player)) - return false; + // Check moved to void WorldSession::HandleMoveWorldportAckOpcode() + //if(!CanEnter(player)) + //return false; // Dungeon only code if(IsDungeon()) @@ -2617,15 +2659,7 @@ void InstanceMap::PermBindAllPlayers(Player *player) void InstanceMap::UnloadAll() { - if(HavePlayers()) - { - sLog.outError("InstanceMap::UnloadAll: there are still players in the instance at unload, should not happen!"); - for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - { - Player* plr = itr->getSource(); - plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation()); - } - } + assert(!HavePlayers()); if(m_resetAfterUnload == true) objmgr.DeleteRespawnTimeForInstance(GetInstanceId()); @@ -2662,8 +2696,8 @@ uint32 InstanceMap::GetMaxPlayers() const /* ******* Battleground Instance Maps ******* */ -BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId) - : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL) +BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent) + : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL, _parent) { } @@ -2692,8 +2726,9 @@ bool BattleGroundMap::Add(Player * player) { { Guard guard(*this); - if(!CanEnter(player)) - return false; + //Check moved to void WorldSession::HandleMoveWorldportAckOpcode() + //if(!CanEnter(player)) + //return false; // reset instance validity, battleground maps do not homebind player->m_InstanceValid = true; } @@ -2711,21 +2746,847 @@ void BattleGroundMap::SetUnload() m_unloadTimer = MIN_UNLOAD_DELAY; } -void BattleGroundMap::UnloadAll() +void BattleGroundMap::RemoveAllPlayers() { - while(HavePlayers()) + if(HavePlayers()) { - if(Player * plr = m_mapRefManager.getFirst()->getSource()) + for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) { - plr->TeleportTo(plr->GetBattleGroundEntryPoint()); - // TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator. - // just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop - // note that this remove is not needed if the code works well in other places - plr->GetMapRef().unlink(); + Player* plr = itr->getSource(); + if(!plr->IsBeingTeleportedFar()) + plr->TeleportTo(plr->GetBattleGroundEntryPoint()); } } +} - Map::UnloadAll(); +/// Put scripts in the execution queue +void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target) +{ + ///- Find the script map + ScriptMapMap::const_iterator s = scripts.find(id); + if (s == scripts.end()) + return; + + // prepare static data + uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; //some script commands doesn't have source + uint64 targetGUID = target ? target->GetGUID() : (uint64)0; + uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; + + ///- Schedule script execution for all scripts in the script map + ScriptMap const *s2 = &(s->second); + bool immedScript = false; + for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter) + { + ScriptAction sa; + sa.sourceGUID = sourceGUID; + sa.targetGUID = targetGUID; + sa.ownerGUID = ownerGUID; + + sa.script = &iter->second; + m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(time_t(sWorld.GetGameTime() + iter->first), sa)); + if (iter->first == 0) + immedScript = true; + + sWorld.IncreaseScheduledScriptsCount(); + } + ///- If one of the effects should be immediate, launch the script execution + if (/*start &&*/ immedScript) + ScriptsProcess(); +} + +void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target) +{ + // NOTE: script record _must_ exist until command executed + + // prepare static data + uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; + uint64 targetGUID = target ? target->GetGUID() : (uint64)0; + uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; + + ScriptAction sa; + sa.sourceGUID = sourceGUID; + sa.targetGUID = targetGUID; + sa.ownerGUID = ownerGUID; + + sa.script = &script; + m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(time_t(sWorld.GetGameTime() + delay), sa)); + + sWorld.IncreaseScheduledScriptsCount(); + + ///- If effects should be immediate, launch the script execution + if(delay == 0) + ScriptsProcess(); +} + +/// Process queued scripts +void Map::ScriptsProcess() +{ + if (m_scriptSchedule.empty()) + return; + + ///- Process overdue queued scripts + std::multimap<time_t, ScriptAction>::iterator iter = m_scriptSchedule.begin(); + // ok as multimap is a *sorted* associative container + while (!m_scriptSchedule.empty() && (iter->first <= sWorld.GetGameTime())) + { + ScriptAction const& step = iter->second; + + Object* source = NULL; + + if(step.sourceGUID) + { + switch(GUID_HIPART(step.sourceGUID)) + { + case HIGHGUID_ITEM: + // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM + { + Player* player = HashMapHolder<Player>::Find(step.ownerGUID); + if(player) + source = player->GetItemByGuid(step.sourceGUID); + break; + } + case HIGHGUID_UNIT: + source = HashMapHolder<Creature>::Find(step.sourceGUID); + break; + case HIGHGUID_PET: + source = HashMapHolder<Pet>::Find(step.sourceGUID); + break; + case HIGHGUID_VEHICLE: + source = HashMapHolder<Vehicle>::Find(step.sourceGUID); + break; + case HIGHGUID_PLAYER: + source = HashMapHolder<Player>::Find(step.sourceGUID); + break; + case HIGHGUID_GAMEOBJECT: + source = HashMapHolder<GameObject>::Find(step.sourceGUID); + break; + case HIGHGUID_CORPSE: + source = HashMapHolder<Corpse>::Find(step.sourceGUID); + break; + case HIGHGUID_MO_TRANSPORT: + for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) + { + if((*iter)->GetGUID() == step.sourceGUID) + { + source = reinterpret_cast<Object*>(*iter); + break; + } + } + break; + default: + sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID)); + break; + } + } + + //if(source && !source->IsInWorld()) source = NULL; + + Object* target = NULL; + + if(step.targetGUID) + { + switch(GUID_HIPART(step.targetGUID)) + { + case HIGHGUID_UNIT: + target = HashMapHolder<Creature>::Find(step.targetGUID); + break; + case HIGHGUID_PET: + target = HashMapHolder<Pet>::Find(step.targetGUID); + break; + case HIGHGUID_VEHICLE: + target = HashMapHolder<Vehicle>::Find(step.targetGUID); + break; + case HIGHGUID_PLAYER: // empty GUID case also + target = HashMapHolder<Player>::Find(step.targetGUID); + break; + case HIGHGUID_GAMEOBJECT: + target = HashMapHolder<GameObject>::Find(step.targetGUID); + break; + case HIGHGUID_CORPSE: + target = HashMapHolder<Corpse>::Find(step.targetGUID); + break; + default: + sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID)); + break; + } + } + + //if(target && !target->IsInWorld()) target = NULL; + + switch (step.script->command) + { + case SCRIPT_COMMAND_TALK: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature."); + break; + } + + if(source->GetTypeId()!=TYPEID_UNIT) + { + sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + if(step.script->datalong > 3) + { + sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong); + break; + } + + uint64 unit_target = target ? target->GetGUID() : 0; + + //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text + switch(step.script->datalong) + { + case 0: // Say + ((Creature *)source)->Say(step.script->dataint, LANG_UNIVERSAL, unit_target); + break; + case 1: // Whisper + if(!unit_target) + { + sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong); + break; + } + ((Creature *)source)->Whisper(step.script->dataint,unit_target); + break; + case 2: // Yell + ((Creature *)source)->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target); + break; + case 3: // Emote text + ((Creature *)source)->TextEmote(step.script->dataint, unit_target); + break; + default: + break; // must be already checked at load + } + break; + } + + case SCRIPT_COMMAND_EMOTE: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature."); + break; + } + + if(source->GetTypeId()!=TYPEID_UNIT) + { + sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + ((Creature *)source)->HandleEmoteCommand(step.script->datalong); + break; + case SCRIPT_COMMAND_FIELD_SET: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object."); + break; + } + if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", + step.script->datalong,source->GetValuesCount(),source->GetTypeId()); + break; + } + + source->SetUInt32Value(step.script->datalong, step.script->datalong2); + break; + case SCRIPT_COMMAND_MOVE_TO: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature."); + break; + } + + if(source->GetTypeId()!=TYPEID_UNIT) + { + sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + ((Creature*)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 ); + ((Creature*)source)->GetMap()->CreatureRelocation(((Creature*)source), step.script->x, step.script->y, step.script->z, 0); + break; + case SCRIPT_COMMAND_FLAG_SET: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object."); + break; + } + if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", + step.script->datalong,source->GetValuesCount(),source->GetTypeId()); + break; + } + + source->SetFlag(step.script->datalong, step.script->datalong2); + break; + case SCRIPT_COMMAND_FLAG_REMOVE: + if(!source) + { + sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object."); + break; + } + if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) + { + sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).", + step.script->datalong,source->GetValuesCount(),source->GetTypeId()); + break; + } + + source->RemoveFlag(step.script->datalong, step.script->datalong2); + break; + + case SCRIPT_COMMAND_TELEPORT_TO: + { + // accept player in any one from target/source arg + if (!target && !source) + { + sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object."); + break; + } + + // must be only Player + if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER)) + { + sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); + break; + } + + Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source; + + pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o); + break; + } + + case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: + { + if(!step.script->datalong) // creature not specified + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object."); + break; + } + + WorldObject* summoner = dynamic_cast<WorldObject*>(source); + + if(!summoner) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + float x = step.script->x; + float y = step.script->y; + float z = step.script->z; + float o = step.script->o; + + Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2); + if (!pCreature) + { + sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong); + break; + } + + break; + } + + case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: + { + if(!step.script->datalong) // gameobject not specified + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object."); + break; + } + + WorldObject* summoner = dynamic_cast<WorldObject*>(source); + + if(!summoner) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + GameObject *go = NULL; + int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2; + + CellPair p(MaNGOS::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong); + MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(summoner, go,go_check); + + TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker); + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *summoner->GetMap()); + + if ( !go ) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong); + break; + } + + if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE || + go->GetGoType()==GAMEOBJECT_TYPE_DOOR || + go->GetGoType()==GAMEOBJECT_TYPE_BUTTON || + go->GetGoType()==GAMEOBJECT_TYPE_TRAP ) + { + sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong); + break; + } + + if( go->isSpawned() ) + break; //gameobject already spawned + + go->SetLootState(GO_READY); + go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds + + go->GetMap()->Add(go); + break; + } + case SCRIPT_COMMAND_OPEN_DOOR: + { + if(!step.script->datalong) // door not specified + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + Unit* caster = (Unit*)source; + + GameObject *door = NULL; + int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; + + CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); + MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check); + + TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker); + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *caster->GetMap()); + + if (!door) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong); + break; + } + if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR) + { + sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType()); + break; + } + + if (door->GetGoState() != GO_STATE_READY) + break; //door already open + + door->UseDoorOrButton(time_to_close); + + if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) + ((GameObject*)target)->UseDoorOrButton(time_to_close); + break; + } + case SCRIPT_COMMAND_CLOSE_DOOR: + { + if(!step.script->datalong) // guid for door not specified + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door."); + break; + } + + if(!source) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + Unit* caster = (Unit*)source; + + GameObject *door = NULL; + int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; + + CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); + MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check); + + TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker); + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *caster->GetMap()); + + if ( !door ) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong); + break; + } + if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR ) + { + sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType()); + break; + } + + if( door->GetGoState() == GO_STATE_READY ) + break; //door already closed + + door->UseDoorOrButton(time_to_open); + + if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) + ((GameObject*)target)->UseDoorOrButton(time_to_open); + + break; + } + case SCRIPT_COMMAND_QUEST_EXPLORED: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source."); + break; + } + + if(!target) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target."); + break; + } + + // when script called for item spell casting then target == (unit or GO) and source is player + WorldObject* worldObject; + Player* player; + + if(target->GetTypeId()==TYPEID_PLAYER) + { + if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + worldObject = (WorldObject*)source; + player = (Player*)target; + } + else + { + if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); + break; + } + + if(source->GetTypeId()!=TYPEID_PLAYER) + { + sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + worldObject = (WorldObject*)target; + player = (Player*)source; + } + + // quest id and flags checked at script loading + if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && + (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) ) + player->AreaExploredOrEventHappens(step.script->datalong); + else + player->FailQuest(step.script->datalong); + + break; + } + + case SCRIPT_COMMAND_ACTIVATE_OBJECT: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + if(!target) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject."); + break; + } + + if(target->GetTypeId()!=TYPEID_GAMEOBJECT) + { + sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); + break; + } + + Unit* caster = (Unit*)source; + + GameObject *go = (GameObject*)target; + + go->Use(caster); + break; + } + + case SCRIPT_COMMAND_REMOVE_AURA: + { + Object* cmdTarget = step.script->datalong2 ? source : target; + + if(!cmdTarget) + { + sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target"); + break; + } + + if(!cmdTarget->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId()); + break; + } + + ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong); + break; + } + + case SCRIPT_COMMAND_CAST_SPELL: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster."); + break; + } + + Object* cmdTarget = step.script->datalong2 & 0x01 ? source : target; + + if(!cmdTarget) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x01 ? "source" : "target"); + break; + } + + if(!cmdTarget->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x01 ? "source" : "target",cmdTarget->GetTypeId()); + break; + } + + Unit* spellTarget = (Unit*)cmdTarget; + + Object* cmdSource = step.script->datalong2 & 0x02 ? target : source; + + if(!cmdSource) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x02 ? "target" : "source"); + break; + } + + if(!cmdSource->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x02 ? "target" : "source", cmdSource->GetTypeId()); + break; + } + + Unit* spellSource = (Unit*)cmdSource; + + //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast + spellSource->CastSpell(spellTarget,step.script->datalong,false); + + break; + } + + case SCRIPT_COMMAND_LOAD_PATH: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_START_MOVE is tried to apply to NON-existing unit."); + break; + } + + if(!source->isType(TYPEMASK_UNIT)) + { + sLog.outError("SCRIPT_COMMAND_START_MOVE source mover isn't unit (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + if(!WaypointMgr.GetPath(step.script->datalong)) + { + sLog.outError("SCRIPT_COMMAND_START_MOVE source mover has an invallid path, skipping.", step.script->datalong2); + break; + } + + dynamic_cast<Unit*>(source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2); + break; + } + + case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: + { + if(!step.script->datalong || !step.script->datalong2) + { + sLog.outError("SCRIPT_COMMAND_CALLSCRIPT calls invallid db_script_id or lowguid not present: skipping."); + break; + } + //our target + Creature* target = NULL; + + if(source) //using grid searcher + { + CellPair p(Trinity::ComputeCellPair(((Unit*)source)->GetPositionX(), ((Unit*)source)->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + //sLog.outDebug("Attempting to find Creature: Db GUID: %i", step.script->datalong); + Trinity::CreatureWithDbGUIDCheck target_check(((Unit*)source), step.script->datalong); + Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(((Unit*)source), target, target_check); + + TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker); + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, unit_checker, *(((Unit*)source)->GetMap())); + } + else //check hashmap holders + { + if(CreatureData const* data = objmgr.GetCreatureData(step.script->datalong)) + target = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), target); + } + //sLog.outDebug("attempting to pass target..."); + if(!target) + break; + //sLog.outDebug("target passed"); + //Lets choose our ScriptMap map + ScriptMapMap *datamap = NULL; + switch(step.script->dataint) + { + case 1://QUEST END SCRIPTMAP + datamap = &sQuestEndScripts; + break; + case 2://QUEST START SCRIPTMAP + datamap = &sQuestStartScripts; + break; + case 3://SPELLS SCRIPTMAP + datamap = &sSpellScripts; + break; + case 4://GAMEOBJECTS SCRIPTMAP + datamap = &sGameObjectScripts; + break; + case 5://EVENTS SCRIPTMAP + datamap = &sEventScripts; + break; + case 6://WAYPOINTS SCRIPTMAP + datamap = &sWaypointScripts; + break; + default: + sLog.outError("SCRIPT_COMMAND_CALLSCRIPT ERROR: no scriptmap present... ignoring"); + break; + } + //if no scriptmap present... + if(!datamap) + break; + + uint32 script_id = step.script->datalong2; + //insert script into schedule but do not start it + ScriptsStart(*datamap, script_id, target, NULL/*, false*/); + break; + } + + case SCRIPT_COMMAND_KILL: + { + if(!source || ((Creature*)source)->isDead()) + break; + + ((Creature*)source)->DealDamage(((Creature*)source), ((Creature*)source)->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + + switch(step.script->dataint) + { + case 0: break; //return false not remove corpse + case 1: ((Creature*)source)->RemoveCorpse(); break; + } + break; + } + + case SCRIPT_COMMAND_PLAY_SOUND: + { + if(!source) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for NULL creature."); + break; + } + + WorldObject* pSource = dynamic_cast<WorldObject*>(source); + if(!pSource) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for non-world object (TypeId: %u), skipping.",source->GetTypeId()); + break; + } + + // bitmask: 0/1=anyone/target, 0/2=with distance dependent + Player* pTarget = NULL; + if(step.script->datalong2 & 1) + { + if(!target) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for NULL target."); + break; + } + + if(target->GetTypeId()!=TYPEID_PLAYER) + { + sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for non-player (TypeId: %u), skipping.",target->GetTypeId()); + break; + } + + pTarget = (Player*)target; + } + + // bitmask: 0/1=anyone/target, 0/2=with distance dependent + if(step.script->datalong2 & 2) + pSource->PlayDistanceSound(step.script->datalong,pTarget); + else + pSource->PlayDirectSound(step.script->datalong,pTarget); + break; + } + default: + sLog.outError("Unknown script command %u called.",step.script->command); + break; + } + + m_scriptSchedule.erase(iter); + sWorld.DecreaseScheduledScriptCount(); + + iter = m_scriptSchedule.begin(); + } + return; } Creature* @@ -2774,3 +3635,10 @@ Map::GetDynamicObject(uint64 guid) return NULL; return ret; } + +void Map::UpdateIteratorBack(Player *player) +{ + if(m_mapRefIter == player->GetMapRef()) + m_mapRefIter = m_mapRefIter->nocheck_prev(); +} + diff --git a/src/game/Map.h b/src/game/Map.h index 4caa1942c3c..68d5b90f48d 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -43,9 +43,13 @@ class WorldPacket; class InstanceData; class Group; class InstanceSave; +class Object; class WorldObject; class TempSummon; +class Player; class CreatureGroup; +struct ScriptInfo; +struct ScriptAction; typedef ACE_RW_Thread_Mutex GridRWLock; @@ -74,10 +78,11 @@ typedef MaNGOS::SingleThreaded<GridRWLock>::Lock NullGuard; #define MAP_MAGIC 'SPAM' #define MAP_VERSION_MAGIC '0.1w' #define MAP_AREA_MAGIC 'AERA' -#define MAP_HEIGTH_MAGIC 'TGHM' +#define MAP_HEIGHT_MAGIC 'TGHM' #define MAP_LIQUID_MAGIC 'QILM' -struct map_fileheader{ +struct map_fileheader +{ uint32 mapMagic; uint32 versionMagic; uint32 areaMapOffset; @@ -89,17 +94,20 @@ struct map_fileheader{ }; #define MAP_AREA_NO_AREA 0x0001 -struct map_areaHeader{ + +struct map_areaHeader +{ uint32 fourcc; uint16 flags; uint16 gridArea; }; -#define MAP_HEIGHT_NO_HIGHT 0x0001 +#define MAP_HEIGHT_NO_HEIGHT 0x0001 #define MAP_HEIGHT_AS_INT16 0x0002 #define MAP_HEIGHT_AS_INT8 0x0004 -struct map_heightHeader{ +struct map_heightHeader +{ uint32 fourcc; uint32 flags; float gridHeight; @@ -107,8 +115,10 @@ struct map_heightHeader{ }; #define MAP_LIQUID_NO_TYPE 0x0001 -#define MAP_LIQUID_NO_HIGHT 0x0002 -struct map_liquidHeader{ +#define MAP_LIQUID_NO_HEIGHT 0x0002 + +struct map_liquidHeader +{ uint32 fourcc; uint16 flags; uint16 liquidType; @@ -119,7 +129,8 @@ struct map_liquidHeader{ float liquidLevel; }; -enum ZLiquidStatus{ +enum ZLiquidStatus +{ LIQUID_MAP_NO_WATER = 0x00000000, LIQUID_MAP_ABOVE_WATER = 0x00000001, LIQUID_MAP_WATER_WALK = 0x00000002, @@ -138,7 +149,8 @@ enum ZLiquidStatus{ #define MAP_LIQUID_TYPE_DARK_WATER 0x10 #define MAP_LIQUID_TYPE_WMO_WATER 0x20 -struct LiquidData{ +struct LiquidData +{ uint32 type; float level; float depth_level; @@ -251,7 +263,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj { friend class MapReference; public: - Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); + Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); virtual ~Map(); // currently unused for normal maps @@ -298,7 +310,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj } time_t GetGridExpiry(void) const { return i_gridExpiry; } - uint32 GetId(void) const { return i_id; } + uint32 GetId(void) const { return i_mapEntry->MapID; } static bool ExistMap(uint32 mapid, int gx, int gy); static bool ExistVMap(uint32 mapid, int gx, int gy); @@ -306,11 +318,13 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj static void InitStateMachine(); static void DeleteStateMachine(); + Map const * GetParent() const { return m_parentMap; } + // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height float GetHeight(float x, float y, float z, bool pCheckVMap=true) const; float GetVmapHeight(float x, float y, float z, bool useMaps) const; - bool IsInWater(float x, float y, float z) const; // does not use z pos. This is for future use + bool IsInWater(float x, float y, float z, float min_depth = 2.0f) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0) const; @@ -325,22 +339,23 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj uint32 GetAreaId(float x, float y, float z) const { - return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),i_id); + return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),GetId()); } uint32 GetZoneId(float x, float y, float z) const { - return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),i_id); + return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),GetId()); } void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const { - GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),i_id); + GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),GetId()); } virtual void MoveAllCreaturesInMoveList(); virtual void RemoveAllObjectsInRemoveList(); virtual void RelocationNotify(); + virtual void RemoveAllPlayers(); bool CreatureRespawnRelocation(Creature *c); // used only in MoveAllCreaturesInMoveList and ObjectGridUnloader @@ -389,13 +404,17 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj bool ActiveObjectsNearGrid(uint32 x, uint32 y) const; void AddUnitToNotify(Unit* unit); - void RemoveUnitFromNotify(int32 slot); + void RemoveUnitFromNotify(Unit *unit, int32 slot); void SendToPlayers(WorldPacket const* data) const; typedef MapRefManager PlayerList; PlayerList const& GetPlayers() const { return m_mapRefManager; } + //per-map script storage + void ScriptsStart(std::map<uint32, std::multimap<uint32, ScriptInfo> > const& scripts, uint32 id, Object* source, Object* target); + void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); + // must called with AddToWorld template<class T> void AddToActive(T* obj) { AddToActiveHelper(obj); } @@ -414,6 +433,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj template<class NOTIFIER> void VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier); CreatureGroupHolderType CreatureGroupHolder; + void UpdateIteratorBack(Player *player); + #ifdef MAP_BASED_RAND_GEN MTRand mtRand; int32 irand(int32 min, int32 max) { return int32 (mtRand.randInt(max - min)) + min; } @@ -465,6 +486,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x,y)->setGridObjectDataLoaded(pLoaded); } void setNGrid(NGridType* grid, uint32 x, uint32 y); + void ScriptsProcess(); void UpdateActiveCells(const float &x, const float &y, const uint32 &t_diff); protected: @@ -474,7 +496,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj MapEntry const* i_mapEntry; uint8 i_spawnMode; - uint32 i_id; uint32 i_InstanceId; uint32 m_unloadTimer; @@ -487,6 +508,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj private: + //used for fast base_map (e.g. MapInstanced class object) search for + //InstanceMaps and BattleGroundMaps... + Map* m_parentMap; + typedef GridReadGuard ReadGuard; typedef GridWriteGuard WriteGuard; @@ -502,6 +527,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj std::vector<Unit*> i_unitsToNotify; std::set<WorldObject *> i_objectsToRemove; std::map<WorldObject*, bool> i_objectsToSwitch; + std::multimap<time_t, ScriptAction> m_scriptSchedule; // Type specific code for add/remove to/from grid template<class T> @@ -553,7 +579,7 @@ enum InstanceResetMethod class TRINITY_DLL_SPEC InstanceMap : public Map { public: - InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); + InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); ~InstanceMap(); bool Add(Player *); void Remove(Player *, bool); @@ -578,14 +604,14 @@ class TRINITY_DLL_SPEC InstanceMap : public Map class TRINITY_DLL_SPEC BattleGroundMap : public Map { public: - BattleGroundMap(uint32 id, time_t, uint32 InstanceId); + BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent); ~BattleGroundMap(); bool Add(Player *); void Remove(Player *, bool); bool CanEnter(Player* player); void SetUnload(); - void UnloadAll(); + void RemoveAllPlayers(); }; /*inline diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp index ca106d6506c..e423abbad31 100644 --- a/src/game/MapInstanced.cpp +++ b/src/game/MapInstanced.cpp @@ -46,7 +46,10 @@ void MapInstanced::Update(const uint32& t) { if(i->second->CanUnload(t)) { - DestroyInstance(i); // iterator incremented + if(!DestroyInstance(i)) // iterator incremented + { + //m_unloadTimer + } } else { @@ -116,17 +119,8 @@ void MapInstanced::UnloadAll() - create the instance if it's not created already - the player is not actually added to the instance (only in InstanceMap::Add) */ -Map* MapInstanced::GetInstance(const WorldObject* obj) +Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player, uint32 instanceId) { - if(obj->GetTypeId() == TYPEID_UNIT) - { - assert(obj->GetMapId() == GetId() && obj->GetInstanceId()); - return _FindMap(obj->GetInstanceId()); - } - - Player* player = (Player*)obj; - uint32 instanceId = player->GetInstanceId(); - if(instanceId) if(Map *map = _FindMap(instanceId)) return map; @@ -134,28 +128,12 @@ Map* MapInstanced::GetInstance(const WorldObject* obj) if(IsBattleGroundOrArena()) { instanceId = player->GetBattleGroundId(); - if(instanceId) - { if(Map *map = _FindMap(instanceId)) return map; - else - return CreateBattleGround(instanceId); - } - else - return NULL; - } - - InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty()); - InstanceSave *pSave = pBind ? pBind->save : NULL; - if(!pBind || !pBind->perm) - { - if(Group *group = player->GetGroup()) - if(InstanceGroupBind *groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty())) - pSave = groupBind->save; + return CreateBattleGround(instanceId); } - - if(pSave) + else if(InstanceSave *pSave = player->GetInstanceSave(GetId())) { if(!instanceId) { @@ -202,10 +180,10 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, // some instances only have one difficulty if (entry && !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; - sLog.outDebug("MapInstanced::CreateInstance: %smap instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); + sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); - InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty); - assert(map->IsDungeon()); + InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); + ASSERT(map->IsDungeon()); bool load_data = save != NULL; map->CreateInstanceData(load_data); @@ -221,23 +199,23 @@ BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId) sLog.outDebug("MapInstanced::CreateBattleGround: map bg %d for %d created.", InstanceId, GetId()); - BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId); - assert(map->IsBattleGroundOrArena()); + BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this); + ASSERT(map->IsBattleGroundOrArena()); m_InstancedMaps[InstanceId] = map; return map; } -void MapInstanced::DestroyInstance(uint32 InstanceId) -{ - InstancedMaps::iterator itr = m_InstancedMaps.find(InstanceId); - if(itr != m_InstancedMaps.end()) - DestroyInstance(itr); -} - // increments the iterator after erase -void MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) +bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) { + itr->second->RemoveAllPlayers(); + if(itr->second->HavePlayers()) + { + ++itr; + return false; + } + itr->second->UnloadAll(); // should only unload VMaps if this is the last instance and grid unloading is enabled if(m_InstancedMaps.size() <= 1 && sWorld.getConfig(CONFIG_GRID_UNLOAD)) @@ -250,13 +228,12 @@ void MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) // erase map delete itr->second; m_InstancedMaps.erase(itr++); + return true; } bool MapInstanced::CanEnter(Player *player) { - if(Map* map = GetInstance(player)) - return map->CanEnter(player); - - return false; + //assert(false); + return true; } diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h index 6338726fd47..851fe8942a0 100644 --- a/src/game/MapInstanced.h +++ b/src/game/MapInstanced.h @@ -42,10 +42,9 @@ class TRINITY_DLL_DECL MapInstanced : public Map void UnloadAll(); bool CanEnter(Player* player); - Map* GetInstance(const WorldObject* obj); + Map* CreateInstance(const uint32 mapId, Player * player, uint32 instanceId); Map* FindMap(uint32 InstanceId) const { return _FindMap(InstanceId); } - void DestroyInstance(uint32 InstanceId); - void DestroyInstance(InstancedMaps::iterator &itr); + bool DestroyInstance(InstancedMaps::iterator &itr); void AddGridMapReference(const GridPair &p) { diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 5fde20c55eb..297bc1a3874 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -117,10 +117,14 @@ MapManager::_createBaseMap(uint32 id) { m = new MapInstanced(id, i_gridCleanUpDelay); } - else + else if (entry) { m = new Map(id, i_gridCleanUpDelay, 0, 0); } + else + { + assert(false); + } i_maps[id] = m; } @@ -128,13 +132,13 @@ MapManager::_createBaseMap(uint32 id) return m; } -Map* MapManager::GetMap(uint32 id, const WorldObject* obj) +Map* MapManager::CreateMap(uint32 id, const WorldObject* obj, uint32 instanceId) { ASSERT(obj); //if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId()); Map *m = _createBaseMap(id); - if (m && obj && m->Instanceable()) m = ((MapInstanced*)m)->GetInstance(obj); + if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) m = ((MapInstanced*)m)->CreateInstance(id, (Player*)obj, instanceId); return m; } @@ -230,13 +234,6 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player) return true; } -void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId) -{ - Map *m = _createBaseMap(mapid); - if (m && m->Instanceable()) - ((MapInstanced*)m)->DestroyInstance(instanceId); -} - void MapManager::RemoveBonesFromMap(uint32 mapid, uint64 guid, float x, float y) { bool remove_result = _createBaseMap(mapid)->RemoveBones(guid, x, y); @@ -259,20 +256,19 @@ MapManager::Update(uint32 diff) MapMapType::iterator iter; std::vector<Map*> update_queue(i_maps.size()); int omp_set_num_threads(sWorld.getConfig(CONFIG_NUMTHREADS)); - for(iter = i_maps.begin(), i=0;iter != i_maps.end(); ++iter, i++) - update_queue[i]=iter->second; + for(iter = i_maps.begin(), i=0;iter != i_maps.end(); ++iter, i++) + update_queue[i]=iter->second; /* - gomp in gcc <4.4 version cannot parallelise loops using random access iterators - so until gcc 4.4 isnt standard, we need the update_queue workaround + gomp in gcc <4.4 version cannot parallelise loops using random access iterators + so until gcc 4.4 isnt standard, we need the update_queue workaround */ #pragma omp parallel for schedule(dynamic) private(i) shared(update_queue) for(int32 i = 0; i < i_maps.size(); ++i) { checkAndCorrectGridStatesArray(); // debugging code, should be deleted some day - update_queue[i]->Update(i_timer.GetCurrent()); - sWorld.RecordTimeDiff("UpdateMap %u", update_queue[i]->GetId()); - // sLog.outError("This is thread %d out of %d threads,updating map %u",omp_get_thread_num(),omp_get_num_threads(),iter->second->GetId()); - + update_queue[i]->Update(i_timer.GetCurrent()); + sWorld.RecordTimeDiff("UpdateMap %u", update_queue[i]->GetId()); + // sLog.outError("This is thread %d out of %d threads,updating map %u",omp_get_thread_num(),omp_get_num_threads(),iter->second->GetId()); } #else for(MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) diff --git a/src/game/MapManager.h b/src/game/MapManager.h index b07a26ed0f0..118a057c9af 100644 --- a/src/game/MapManager.h +++ b/src/game/MapManager.h @@ -39,13 +39,10 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS:: public: - Map* GetMap(uint32, const WorldObject* obj); + Map* CreateMap(uint32, const WorldObject* obj, uint32 instanceId); Map const* CreateBaseMap(uint32 id) const { return const_cast<MapManager*>(this)->_createBaseMap(id); } Map* FindMap(uint32 mapid, uint32 instanceId = 0) const; - // only const version for outer users - void DeleteInstance(uint32 mapid, uint32 instanceId); - uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const { Map const* m = CreateBaseMap(mapid); diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index f5a1013f085..48fdda872e9 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -231,7 +231,7 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data ) uint32 team = _player->GetTeam(); uint32 security = GetSecurity(); bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); - bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST); + uint32 gmLevelInWhoList = sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); WorldPacket data( SMSG_WHO, 50 ); // guess size data << clientcount; // clientcount place holder @@ -248,10 +248,14 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data ) continue; // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST - if ((itr->second->GetSession()->GetSecurity() > SEC_PLAYER && !gmInWhoList)) + if ((itr->second->GetSession()->GetSecurity() > gmLevelInWhoList)) continue; } + //do not process players which are not in world + if(!(itr->second->IsInWorld())) + continue; + // check if target is globally visible for player if (!(itr->second->IsVisibleGloballyFor(_player))) continue; @@ -1014,10 +1018,11 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recv_data) uint32 size = adata->Data.size(); + uLongf destSize = compressBound(size); + ByteBuffer dest; - dest.resize(size); + dest.resize(destSize); - uLongf destSize = size; if(size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK) { sLog.outDebug("RAD: Failed to compress account data"); @@ -1040,40 +1045,41 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data) CHECK_PACKET_SIZE(recv_data,1+2+1+1); sLog.outDebug( "WORLD: Received CMSG_SET_ACTION_BUTTON" ); - uint8 button, misc, type; - uint16 action; - recv_data >> button >> action >> misc >> type; - sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u MISC: %u", button, action, type, misc ); - if(action==0) + uint8 button; + uint32 packetData; + recv_data >> button >> packetData; + + uint32 action = ACTION_BUTTON_ACTION(packetData); + uint8 type = ACTION_BUTTON_TYPE(packetData); + + sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u", button, action, type ); + if (!packetData) { sLog.outDetail( "MISC: Remove action from button %u", button ); - GetPlayer()->removeActionButton(button); } else { - if(type==ACTION_BUTTON_MACRO || type==ACTION_BUTTON_CMACRO) - { - sLog.outDetail( "MISC: Added Macro %u into button %u", action, button ); - GetPlayer()->addActionButton(button,action,type,misc); - } - else if(type==ACTION_BUTTON_EQSET) - { - sLog.outDetail( "MISC: Added EquipmentSet %u into button %u", action, button ); - GetPlayer()->addActionButton(button,action,type,misc); - } - else if(type==ACTION_BUTTON_SPELL) + switch(type) { - sLog.outDetail( "MISC: Added Spell %u into button %u", action, button ); - GetPlayer()->addActionButton(button,action,type,misc); - } - else if(type==ACTION_BUTTON_ITEM) - { - sLog.outDetail( "MISC: Added Item %u into button %u", action, button ); - GetPlayer()->addActionButton(button,action,type,misc); + case ACTION_BUTTON_MACRO: + case ACTION_BUTTON_CMACRO: + sLog.outDetail( "MISC: Added Macro %u into button %u", action, button ); + break; + case ACTION_BUTTON_EQSET: + sLog.outDetail( "MISC: Added EquipmentSet %u into button %u", action, button ); + break; + case ACTION_BUTTON_SPELL: + sLog.outDetail( "MISC: Added Spell %u into button %u", action, button ); + break; + case ACTION_BUTTON_ITEM: + sLog.outDetail( "MISC: Added Item %u into button %u", action, button ); + break; + default: + sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button ); + return; } - else - sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button ); + GetPlayer()->addActionButton(button,action,type); } } @@ -1210,15 +1216,17 @@ void WorldSession::HandleWardenDataOpcode(WorldPacket& /*recv_data*/) */ } -void WorldSession::HandlePlayedTime(WorldPacket& /*recv_data*/) +void WorldSession::HandlePlayedTime(WorldPacket& recv_data) { - uint32 TotalTimePlayed = GetPlayer()->GetTotalPlayedTime(); - uint32 LevelPlayedTime = GetPlayer()->GetLevelPlayedTime(); + CHECK_PACKET_SIZE(recv_data, 1); - WorldPacket data(SMSG_PLAYED_TIME, 9); - data << TotalTimePlayed; - data << LevelPlayedTime; - data << uint8(0); + uint8 unk1; + recv_data >> unk1; // 0 or 1 expected + + WorldPacket data(SMSG_PLAYED_TIME, 4 + 4 + 1); + data << uint32(_player->GetTotalPlayedTime()); + data << uint32(_player->GetLevelPlayedTime()); + data << uint8(unk1); // 0 - will not show in chat frame SendPacket(&data); } @@ -1350,7 +1358,7 @@ void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data) uint32 accid = plr->GetSession()->GetAccountId(); - QueryResult *result = LoginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid); + QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid); if(!result) { SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str()); @@ -1488,7 +1496,7 @@ void WorldSession::HandleSetTitleOpcode( WorldPacket & recv_data ) recv_data >> title; // -1 at none - if(title > 0 && title < 192) + if(title > 0 && title < MAX_TITLE_INDEX) { if(!GetPlayer()->HasTitle(title)) return; diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 7d7733763cd..f0ff9ec05d7 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -66,27 +66,30 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->SetSemaphoreTeleportFar(false); + Map * oldMap = GetPlayer()->GetMap(); // relocate the player to the teleport destination - GetPlayer()->SetMapId(loc.mapid); - GetPlayer()->Relocate(loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation); + Map * newMap = MapManager::Instance().CreateMap(loc.mapid, GetPlayer(), 0); + // the CanEnter checks are done in TeleporTo but conditions may change + // while the player is in transit, for example the map may get full + if (!newMap || !newMap->CanEnter(GetPlayer())) + { + sLog.outError("Map %d could not be created for player %d, porting player to homebind", loc.mapid, GetPlayer()->GetGUIDLow()); + GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); + return; + } + else + GetPlayer()->Relocate(loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation); - // since the MapId is set before the GetInstance call, the InstanceId must be set to 0 - // to let GetInstance() determine the proper InstanceId based on the player's binds - GetPlayer()->SetInstanceId(0); + GetPlayer()->ResetMap(); + GetPlayer()->SetMap(newMap); GetPlayer()->SendInitialPacketsBeforeAddToMap(); - // the CanEnter checks are done in TeleporTo but conditions may change - // while the player is in transit, for example the map may get full if(!GetPlayer()->GetMap()->Add(GetPlayer())) { - sLog.outDebug("WORLD: teleport of player %s (%d) to location %d, %f, %f, %f, %f failed", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation); - // teleport the player home - if(!GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation())) - { - // the player must always be able to teleport home - sLog.outError("WORLD: failed to teleport player %s (%d) to homebind location %d, %f, %f, %f, %f!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); - assert(false); - } + sLog.outError("WORLD: failed to teleport player %s (%d) to map %d because of unknown reason!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid); + GetPlayer()->ResetMap(); + GetPlayer()->SetMap(oldMap); + GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation()); return; } @@ -156,11 +159,14 @@ void WorldSession::HandleMoveWorldportAckOpcode() // resummon pet GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); + + //lets process all delayed operations on successful teleport + GetPlayer()->ProcessDelayedOperations(); } void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) { - CHECK_PACKET_SIZE(recv_data, 8+4); + CHECK_PACKET_SIZE(recv_data, 8+4+4); sLog.outDebug("MSG_MOVE_TELEPORT_ACK"); uint64 guid; @@ -202,6 +208,9 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) // resummon pet GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); + + //lets process all delayed operations on successful teleport + GetPlayer()->ProcessDelayedOperations(); } void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) @@ -223,7 +232,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) if(recv_data.size() != recv_data.rpos()) { - sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is %u bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); + sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is " SIZEFMTD " bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); KickPlayer(); return; } @@ -294,6 +303,12 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) mover->m_movementInfo = movementInfo; + if(mover->m_Vehicle) + { + mover->SetOrientation(movementInfo.o); + return; + } + if(plMover) // nothing is charmed, or player charmed { plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); @@ -332,9 +347,6 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) } else // creature charmed { - uint32 entry = mover->GetEntry(); - if(mover->m_Vehicle) - return; mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); /*if(mover->canFly()) diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index c60d368659a..bb9823ee71f 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -422,7 +422,7 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data ) uint64 npcGUID; recv_data >> npcGUID; - if(!GetPlayer()->isAlive()) + if(!GetPlayer()->IsInWorld() || !GetPlayer()->isAlive()) return; Creature *unit = GetPlayer()->GetNPCIfCanInteractWith(npcGUID,UNIT_NPC_FLAG_INNKEEPER); @@ -442,7 +442,7 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data ) void WorldSession::SendBindPoint(Creature *npc) { // prevent set homebind to instances in any case - if(sMapStore.LookupEntry(GetPlayer()->GetMapId())->Instanceable()) + if(GetPlayer()->GetMap()->Instanceable()) return; uint32 bindspell = 3286; diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 3561621f0bd..69a286289b3 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -259,13 +259,13 @@ void Object::BuildOutOfRangeUpdateBlock(UpdateData * data) const data->AddOutOfRangeGUID(GetGUID()); } -void Object::DestroyForPlayer(Player *target) const +void Object::DestroyForPlayer( Player *target, bool anim ) const { ASSERT(target); WorldPacket data(SMSG_DESTROY_OBJECT, 8); data << uint64(GetGUID()); - data << uint8(0); // WotLK (bool) + data << uint8(anim ? 1 : 0); // WotLK (bool), may be despawn animation target->GetSession()->SendPacket( &data ); } @@ -477,6 +477,13 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask if (((GameObject*)this)->GetGoArtKit()) updateMask->SetBit(GAMEOBJECT_BYTES_1); } + else if (isType(TYPEMASK_UNIT)) + { + if( ((Unit*)this)->HasFlag(UNIT_FIELD_AURASTATE, PER_CASTER_AURA_STATE_MASK)) + { + updateMask->SetBit(UNIT_FIELD_AURASTATE); + } + } } else // case UPDATETYPE_VALUES { @@ -489,6 +496,13 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask updateMask->SetBit(GAMEOBJECT_DYNAMIC); updateMask->SetBit(GAMEOBJECT_BYTES_1); } + else if (isType(TYPEMASK_UNIT)) + { + if( ((Unit*)this)->HasFlag(UNIT_FIELD_AURASTATE, PER_CASTER_AURA_STATE_MASK)) + { + updateMask->SetBit(UNIT_FIELD_AURASTATE); + } + } } WPAssert(updateMask && updateMask->GetCount() == m_valuesCount); @@ -513,6 +527,11 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask *data << uint32(appendValue); } + else if (index == UNIT_FIELD_AURASTATE) + { + // Check per caster aura states to not enable using a pell in client if specified aura is not by target + *data << ((Unit*)this)->BuildAuraStateUpdateForTarget(target); + } // FIXME: Some values at server stored in float format but must be sent to client in uint32 format else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME) { @@ -730,7 +749,7 @@ void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const void Object::SetInt32Value( uint16 index, int32 value ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); if(m_int32Values[ index ] != value) { @@ -749,7 +768,7 @@ void Object::SetInt32Value( uint16 index, int32 value ) void Object::SetUInt32Value( uint16 index, uint32 value ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); if(m_uint32Values[ index ] != value) { @@ -768,7 +787,7 @@ void Object::SetUInt32Value( uint16 index, uint32 value ) void Object::SetUInt64Value( uint16 index, const uint64 &value ) { - ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index + 1 < m_valuesCount || PrintIndexError( index, true ) ); if(*((uint64*)&(m_uint32Values[ index ])) != value) { m_uint32Values[ index ] = *((uint32*)&value); @@ -829,7 +848,7 @@ bool Object::RemoveUInt64Value(uint16 index, const uint64 &value) void Object::SetFloatValue( uint16 index, float value ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); if(m_floatValues[ index ] != value) { @@ -848,7 +867,7 @@ void Object::SetFloatValue( uint16 index, float value ) void Object::SetByteValue( uint16 index, uint8 offset, uint8 value ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); if(offset > 4) { @@ -874,7 +893,7 @@ void Object::SetByteValue( uint16 index, uint8 offset, uint8 value ) void Object::SetUInt16Value( uint16 index, uint8 offset, uint16 value ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); if(offset > 2) { @@ -948,7 +967,7 @@ void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply) void Object::SetFlag( uint16 index, uint32 newFlag ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); uint32 oldval = m_uint32Values[ index ]; uint32 newval = oldval | newFlag; @@ -969,7 +988,7 @@ void Object::SetFlag( uint16 index, uint32 newFlag ) void Object::RemoveFlag( uint16 index, uint32 oldFlag ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); uint32 oldval = m_uint32Values[ index ]; uint32 newval = oldval & ~oldFlag; @@ -990,7 +1009,7 @@ void Object::RemoveFlag( uint16 index, uint32 oldFlag ) void Object::SetByteFlag( uint16 index, uint8 offset, uint8 newFlag ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); if(offset > 4) { @@ -1015,7 +1034,7 @@ void Object::SetByteFlag( uint16 index, uint8 offset, uint8 newFlag ) void Object::RemoveByteFlag( uint16 index, uint8 offset, uint8 oldFlag ) { - ASSERT( index < m_valuesCount || PrintIndexError( index , true ) ); + ASSERT( index < m_valuesCount || PrintIndexError( index, true ) ); if(offset > 4) { @@ -1047,9 +1066,9 @@ bool Object::PrintIndexError(uint32 index, bool set) const } WorldObject::WorldObject() - : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), - m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f) - , m_map(NULL), m_zoneScript(NULL) + : m_phaseMask(PHASEMASK_NORMAL), + m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f), m_currMap(NULL) + , m_zoneScript(NULL) , m_isActive(false), IsTempWorldObject(false) , m_name("") { @@ -1096,11 +1115,13 @@ void WorldObject::setActive( bool on ) } } -void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask ) +void WorldObject::CleanupsBeforeDelete() { - Object::_Create(guidlow, 0, guidhigh); +} - m_mapId = mapid; +void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 phaseMask ) +{ + Object::_Create(guidlow, 0, guidhigh); m_phaseMask = phaseMask; } @@ -1430,7 +1451,7 @@ bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2, void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const { - if(distance==0) + if(distance == 0) { rand_x = x; rand_y = y; @@ -1621,8 +1642,6 @@ void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisp void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 targetGuid) const { - bool pre = (msgtype==CHAT_MSG_MONSTER_EMOTE || msgtype==CHAT_MSG_RAID_BOSS_EMOTE); - *data << (uint8)msgtype; *data << (uint32)language; *data << (uint64)GetGUID(); @@ -1635,9 +1654,7 @@ void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* *data << (uint32)1; // target name length *data << (uint8)0; // target name } - *data << (uint32)(strlen(text)+1+(pre?3:0)); - if(pre) - data->append("%s ",3); + *data << (uint32)(strlen(text)+1); *data << text; *data << (uint8)0; // ChatTag } @@ -1668,23 +1685,20 @@ void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /* void WorldObject::SendObjectDeSpawnAnim(uint64 guid) { WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8); - data << guid; + data << uint64(guid); SendMessageToSet(&data, true); } -Map* WorldObject::_getMap() -{ - return m_map = MapManager::Instance().GetMap(GetMapId(), this); -} - -Map* WorldObject::_findMap() +void WorldObject::SetMap(Map * map) { - return m_map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); + ASSERT(map); + m_currMap = map; } Map const* WorldObject::GetBaseMap() const { - return MapManager::Instance().CreateBaseMap(GetMapId()); + ASSERT(m_currMap); + return m_currMap->GetParent(); } void WorldObject::AddObjectToRemoveList() @@ -1720,6 +1734,8 @@ TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float a mask = SUMMON_MASK_PUPPET; else if(properties->Type == SUMMON_TYPE_MINIPET) mask = SUMMON_MASK_MINION; + else if (properties->Flags & 512) // Mirror Image, Summon Gargoyle + mask = SUMMON_MASK_GUARDIAN; } uint32 phase = PHASEMASK_NORMAL, team = 0; @@ -1992,6 +2008,36 @@ GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range) return go; } +void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange) +{ + CellPair pair(Trinity::ComputeCellPair(this->GetPositionX(), this->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Trinity::AllGameObjectsWithEntryInRange check(this, uiEntry, fMaxSearchRange); + Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, lList, check); + TypeContainerVisitor<Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange>, GridTypeMapContainer> visitor(searcher); + + CellLock<GridReadGuard> cell_lock(cell, pair); + cell_lock->Visit(cell_lock, visitor, *(this->GetMap())); +} + +void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange) +{ + CellPair pair(Trinity::ComputeCellPair(this->GetPositionX(), this->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Trinity::AllCreaturesOfEntryInRange check(this, uiEntry, fMaxSearchRange); + Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, lList, check); + TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange>, GridTypeMapContainer> visitor(searcher); + + CellLock<GridReadGuard> cell_lock(cell, pair); + cell_lock->Visit(cell_lock, visitor, *(this->GetMap())); +} + /* namespace MaNGOS { diff --git a/src/game/Object.h b/src/game/Object.h index 8e86ff1c87b..c44dd4fd65c 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -160,7 +160,7 @@ class TRINITY_DLL_SPEC Object uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); } void SetEntry(uint32 entry) { SetUInt32Value(OBJECT_FIELD_ENTRY, entry); } - uint8 GetTypeId() const { return m_objectTypeId; } + TypeID GetTypeId() const { return m_objectTypeId; } bool isType(uint16 mask) const { return (mask & m_objectType); } virtual void BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const; @@ -171,7 +171,7 @@ class TRINITY_DLL_SPEC Object void BuildMovementUpdateBlock( UpdateData * data, uint32 flags = 0 ) const; void BuildUpdate(UpdateDataMapType &); - virtual void DestroyForPlayer( Player *target ) const; + virtual void DestroyForPlayer( Player *target, bool anim = false ) const; const int32& GetInt32Value( uint16 index ) const { @@ -337,7 +337,7 @@ class TRINITY_DLL_SPEC Object uint16 m_objectType; - uint8 m_objectTypeId; + TypeID m_objectTypeId; uint16 m_updateFlag; union @@ -371,7 +371,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object virtual void Update ( uint32 /*time_diff*/ ) { } - void _Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask); + void _Create( uint32 guidlow, HighGuid guidhigh, uint32 phaseMask); void Relocate(WorldObject *obj) { @@ -407,7 +407,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object void GetPosition( float &x, float &y, float &z ) const { x = m_positionX; y = m_positionY; z = m_positionZ; } void GetPosition( WorldLocation &loc ) const - { loc.mapid = m_mapId; GetPosition(loc.coord_x, loc.coord_y, loc.coord_z); loc.orientation = GetOrientation(); } + { loc.mapid = GetMapId(); GetPosition(loc.coord_x, loc.coord_y, loc.coord_z); loc.orientation = GetOrientation(); } void GetPosition(Position pos) const { pos[0] = m_positionX; pos[1] = m_positionY; pos[2] = m_positionZ; pos[3] = m_orientation; } float GetOrientation( ) const { return m_orientation; } @@ -439,10 +439,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object void GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z ) const; - void SetMapId(uint32 newMap) { m_mapId = newMap; m_map = NULL; } - uint32 GetMapId() const { return m_mapId; } - void SetInstanceId(uint32 val) { m_InstanceId = val; m_map = NULL; } - uint32 GetInstanceId() const { return m_InstanceId; } + virtual uint32 GetMapId() const { return m_currMap ? m_currMap->GetId() : 0; } + virtual uint32 GetInstanceId() const { return m_currMap ? m_currMap->GetInstanceId() : 0; } virtual void SetPhaseMask(uint32 newPhaseMask, bool update); uint32 GetPhaseMask() const { return m_phaseMask; } @@ -470,8 +468,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object float GetDistanceZ(const WorldObject* obj) const; bool IsInMap(const WorldObject* obj) const { - return IsInWorld() && obj->IsInWorld() && GetMapId()==obj->GetMapId() && - GetInstanceId()==obj->GetInstanceId() && InSamePhase(obj); + return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj); } bool IsWithinDist3d(float x, float y, float z, float dist2compare) const; bool IsWithinDist2d(float x, float y, float dist2compare) const; @@ -498,6 +495,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object bool HasInArc( const float arcangle, const WorldObject* obj ) const; bool IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size = 0) const; + virtual void CleanupsBeforeDelete(); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units + virtual void SendMessageToSet(WorldPacket *data, bool self); virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self); @@ -518,7 +517,6 @@ class TRINITY_DLL_SPEC WorldObject : public Object void SendObjectDeSpawnAnim(uint64 guid); virtual void SaveRespawnTime() {} - void AddObjectToRemoveList(); // main visibility check function in normal case (ignore grey zone distance check) @@ -530,8 +528,13 @@ class TRINITY_DLL_SPEC WorldObject : public Object // Low Level Packets void SendPlaySound(uint32 Sound, bool OnlySelf); - Map * GetMap() const { return m_map ? m_map : const_cast<WorldObject*>(this)->_getMap(); } - Map * FindMap() const { return m_map ? m_map : const_cast<WorldObject*>(this)->_findMap(); } + virtual void SetMap(Map * map); + Map * GetMap() const { ASSERT(m_currMap); return m_currMap; } + Map * FindMap() const { return m_currMap; } + //used to check all object's GetMap() calls when object is not in world! + virtual void ResetMap() { assert(m_currMap); m_currMap = NULL; } + + //this function should be removed in nearest time... Map const* GetBaseMap() const; void SetZoneScript(); @@ -545,6 +548,9 @@ class TRINITY_DLL_SPEC WorldObject : public Object Creature* FindNearestCreature(uint32 entry, float range, bool alive = true); GameObject* FindNearestGameObject(uint32 entry, float range); + void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange); + void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange); + bool isActiveObject() const { return m_isActive; } void setActive(bool isActiveObject); void SetWorldObject(bool apply); @@ -555,10 +561,10 @@ class TRINITY_DLL_SPEC WorldObject : public Object #ifdef MAP_BASED_RAND_GEN int32 irand(int32 min, int32 max) const { return int32 (GetMap()->mtRand.randInt(max - min)) + min; } - uint32 urand(uint32 min, uint32 max) const { return GetMap()->mtRand.randInt(max - min) + min; } - int32 rand32() const { return GetMap()->mtRand.randInt(); } - double rand_norm() const { return GetMap()->mtRand.randExc(); } - double rand_chance() const { return GetMap()->mtRand.randExc(100.0); } + uint32 urand(uint32 min, uint32 max) const { return GetMap()->mtRand.randInt(max - min) + min;} + int32 rand32() const { return GetMap()->mtRand.randInt();} + double rand_norm() const { return GetMap()->mtRand.randExc();} + double rand_chance() const { return GetMap()->mtRand.randExc(100.0);} #endif protected: @@ -568,13 +574,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object ZoneScript *m_zoneScript; private: - uint32 m_mapId; // object at map with map_id - uint32 m_InstanceId; // in map copy with instance id + Map * m_currMap; //current object's Map location uint32 m_phaseMask; // in area phase state - Map *m_map; - - Map* _getMap(); - Map* _findMap(); float m_positionX; float m_positionY; diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index b420e4af4b2..43d3d0a1534 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -46,7 +46,11 @@ INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK); INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex); ObjectAccessor::ObjectAccessor() {} -ObjectAccessor::~ObjectAccessor() {} +ObjectAccessor::~ObjectAccessor() +{ + for(Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr) + delete itr->second; +} Creature* ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, uint64 guid) @@ -60,7 +64,7 @@ ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, uint64 guid) if(IS_VEHICLE_GUID(guid)) return GetVehicle(guid); - return u.GetMap()->GetCreature(guid); + return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL; } /* @@ -135,7 +139,11 @@ Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, u Player* ObjectAccessor::FindPlayer(uint64 guid) { - return GetObjectInWorld(guid, (Player*)NULL); + Player * plr = GetObjectInWorld(guid, (Player*)NULL); + if(!plr || !plr->IsInWorld()) + return NULL; + + return plr; } Player* @@ -145,7 +153,7 @@ ObjectAccessor::FindPlayerByName(const char *name) HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer(); HashMapHolder<Player>::MapType::iterator iter = m.begin(); for(; iter != m.end(); ++iter) - if( ::strcmp(name, iter->second->GetName()) == 0 ) + if(iter->second->IsInWorld() && ( ::strcmp(name, iter->second->GetName()) == 0 )) return iter->second; return NULL; } @@ -346,8 +354,6 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia) // bones->m_inWorld = m_inWorld; // don't overwrite world state // bones->m_type = m_type; // don't overwrite type bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation()); - bones->SetMapId(corpse->GetMapId()); - bones->SetInstanceId(corpse->GetInstanceId()); bones->SetPhaseMask(corpse->GetPhaseMask(), false); bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES); diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 80aac0bcf92..1941ccea30c 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -103,8 +103,14 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, if(!guid) return NULL; - if(IS_PLAYER_GUID(guid)) - return (Unit*)HashMapHolder<Player>::Find(guid); + if (IS_PLAYER_GUID(guid)) + { + Unit * u = (Unit*)HashMapHolder<Player>::Find(guid); + if(!u || !u->IsInWorld()) + return NULL; + + return u; + } if(IS_CREATURE_GUID(guid)) return (Unit*)HashMapHolder<Creature>::Find(guid); @@ -115,6 +121,24 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, return (Unit*)HashMapHolder<Vehicle>::Find(guid); } + static Unit* GetUnitInOrOutOfWorld(uint64 guid, Unit* /*fake*/) + { + if(!guid) + return NULL; + + if (IS_PLAYER_GUID(guid)) + { + Unit * u = (Unit*)HashMapHolder<Player>::Find(guid); + if(!u) + return NULL; + + return u; + } + // Other object types than player are unloaded while out of world + return GetObjectInWorld(guid, ((Unit*)NULL)); + } + + template<class T> static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/) { T* obj = HashMapHolder<T>::Find(guid); @@ -144,6 +168,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, static Object* GetObjectByTypeMask(WorldObject const &, uint64, uint32 typemask); static Creature* GetCreatureOrPetOrVehicle(WorldObject const &, uint64); static Unit* GetUnit(WorldObject const &, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); } + static Unit* GetUnitInOrOutOfWorld(WorldObject const &, uint64 guid) { return GetUnitInOrOutOfWorld(guid, (Unit*)NULL); } static Pet* GetPet(Unit const &, uint64 guid) { return GetPet(guid); } static Player* GetPlayer(Unit const &, uint64 guid) { return FindPlayer(guid); } static Corpse* GetCorpse(WorldObject const &u, uint64 guid); @@ -204,7 +229,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, Corpse* GetCorpseForPlayerGUID(uint64 guid); void RemoveCorpse(Corpse *corpse); - void AddCorpse(Corpse* corpse); + void AddCorpse(Corpse *corpse); void AddCorpsesToGrid(GridPair const& gridpair,GridType& grid,Map* map); Corpse* ConvertCorpseForPlayer(uint64 player_guid, bool insignia = false); diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index 368edce0a53..d08e3010a78 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -126,6 +126,7 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager<T> & obj->GetGridRef().link(&m, obj); addUnitState(obj,cell); + obj->SetMap(map); obj->AddToWorld(); if(obj->isActiveObject()) map->AddToActive(obj); @@ -184,6 +185,7 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType obj->GetGridRef().link(&m, obj); addUnitState(obj,cell); + obj->SetMap(map); obj->AddToWorld(); if(obj->isActiveObject()) map->AddToActive(obj); diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index cbf445ebc6b..ec300715f86 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -178,6 +178,9 @@ ObjectMgr::~ObjectMgr() for (CachePlayerInfoMap::iterator itr = m_mPlayerInfoMap.begin(); itr != m_mPlayerInfoMap.end(); ++itr) delete itr->second; + for (ArenaTeamMap::iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) + delete itr->second; + for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) itr->second.Clear(); @@ -635,7 +638,7 @@ void ObjectMgr::LoadCreatureTemplates() // used later for scale CreatureDisplayInfoEntry const* displayScaleEntry = NULL; - + if (cInfo->DisplayID_A[0]) { CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->DisplayID_A[0]); @@ -703,6 +706,18 @@ void ObjectMgr::LoadCreatureTemplates() if (!displayScaleEntry) sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in DisplayID_A/DisplayID_A2/DisplayID_H/DisplayID_H2", cInfo->Entry); + for(int k = 0; k < MAX_KILL_CREDIT; ++k) + { + if(cInfo->KillCredit[k]) + { + if(!GetCreatureTemplate(cInfo->KillCredit[k])) + { + sLog.outErrorDb("Creature (Entry: %u) has not existed creature entry in `KillCredit%d` (%u)",cInfo->Entry,k+1,cInfo->KillCredit[k]); + const_cast<CreatureInfo*>(cInfo)->KillCredit[k] = 0; + } + } + } + if (cInfo->unit_class && ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class); @@ -786,7 +801,7 @@ void ObjectMgr::LoadCreatureTemplates() const_cast<CreatureInfo*>(cInfo)->scale = 1.0f; } - //const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank); + const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank); } } @@ -865,17 +880,17 @@ void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* endAura.effect_idx = 0; } -void ObjectMgr::LoadCreatureAddons() +void ObjectMgr::LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment) { - sCreatureInfoAddonStorage.Load(); + creatureaddons.Load(); - sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount ); + sLog.outString(">> Loaded %u %s", creatureaddons.RecordCount, comment); sLog.outString(); // check data correctness and convert 'auras' - for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) + for(uint32 i = 1; i < creatureaddons.MaxEntry; ++i) { - CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i); + CreatureDataAddon const* addon = creatureaddons.LookupEntry<CreatureDataAddon>(i); if(!addon) continue; @@ -883,49 +898,41 @@ void ObjectMgr::LoadCreatureAddons() { if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) { - sLog.outErrorDb("Creature (Entry %u) have invalid displayInfoId for mount (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->mount); + sLog.outErrorDb("Creature (%s %u) have invalid displayInfoId for mount (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->mount, creatureaddons.GetTableName()); const_cast<CreatureDataAddon*>(addon)->mount = 0; } } if (!sEmotesStore.LookupEntry(addon->emote)) - sLog.outErrorDb("Creature (Entry %u) have invalid emote (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->emote); + sLog.outErrorDb("Creature (%s %u) have invalid emote (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->emote, creatureaddons.GetTableName()); - ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_template_addon", "Entry"); + /*if (addon->move_flags & (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)) + { + sLog.outErrorDb("Creature (%s %u) movement flags mask defined in `%s` include forbidden flags (" I32FMT ") that can crash client, cleanup at load.", entryName, addon->guidOrEntry, creatureaddons.GetTableName(), (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)); + const_cast<CreatureDataAddon*>(addon)->move_flags &= ~(MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4); + }*/ - if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry)) - sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry); + ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), creatureaddons.GetTableName(), entryName); } +} - sCreatureDataAddonStorage.Load(); - - sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount ); - sLog.outString(); - - // check data correctness and convert 'auras' - for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) - { - CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i); - if(!addon) - continue; - - if (addon->mount) - { - if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) - { - sLog.outErrorDb("Creature (GUID %u) have invalid displayInfoId for mount (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->mount); - const_cast<CreatureDataAddon*>(addon)->mount = 0; - } - } +void ObjectMgr::LoadCreatureAddons() +{ + LoadCreatureAddons(sCreatureInfoAddonStorage,"Entry","creature template addons"); - if (!sEmotesStore.LookupEntry(addon->emote)) - sLog.outErrorDb("Creature (GUID %u) have invalid emote (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->emote); + // check entry ids + for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) + if(CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i)) + if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry)) + sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `%s`",addon->guidOrEntry, sCreatureInfoAddonStorage.GetTableName()); - ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_addon", "GUIDLow"); + LoadCreatureAddons(sCreatureDataAddonStorage,"GUID","creature addons"); - if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end()) - sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); - } + // check entry ids + for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) + if(CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i)) + if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end()) + sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); } EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) @@ -1533,6 +1540,12 @@ void ObjectMgr::LoadGameobjects() data.rotation2 = fields[ 9].GetFloat(); data.rotation3 = fields[10].GetFloat(); data.spawntimesecs = fields[11].GetInt32(); + + if (data.spawntimesecs==0 && gInfo->IsDespawnAtAction()) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but gameobejct marked as despawnable at action.",guid,data.id); + } + data.animprogress = fields[12].GetUInt32(); data.ArtKit = 0; @@ -2035,6 +2048,12 @@ void ObjectMgr::LoadItemPrototypes() const_cast<ItemPrototype*>(proto)->Stackable = 1000; } + if(proto->ContainerSlots > MAX_BAG_SIZE) + { + sLog.outErrorDb("Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).",i,proto->ContainerSlots,MAX_BAG_SIZE); + const_cast<ItemPrototype*>(proto)->ContainerSlots = MAX_BAG_SIZE; + } + if(proto->StatsCount > MAX_ITEM_PROTO_STATS) { sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS); @@ -2706,8 +2725,8 @@ void ObjectMgr::LoadPlayerInfo() // Load playercreate actions { - // 0 1 2 3 4 5 - QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action"); + // 0 1 2 3 4 + QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type FROM playercreateinfo_action"); uint32 count = 0; @@ -2742,10 +2761,7 @@ void ObjectMgr::LoadPlayerInfo() } PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - pInfo->action[0].push_back(fields[2].GetUInt16()); - pInfo->action[1].push_back(fields[3].GetUInt16()); - pInfo->action[2].push_back(fields[4].GetUInt16()); - pInfo->action[3].push_back(fields[5].GetUInt16()); + pInfo->action.push_back(PlayerCreateInfoAction(fields[2].GetUInt8(),fields[3].GetUInt32(),fields[4].GetUInt8())); bar.step(); ++count; @@ -3901,13 +3917,20 @@ void ObjectMgr::LoadQuests() qinfo->RewSpell = 0; // no spell reward will display for this quest } - else if(!SpellMgr::IsSpellValid(spellInfo)) + if(!SpellMgr::IsSpellValid(spellInfo)) { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.", + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest will not have a spell reward.", qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); qinfo->RewSpell = 0; // no spell reward will display for this quest } + if(GetTalentSpellCost(qinfo->RewSpell)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); + qinfo->RewSpell = 0; // no spell reward will display for this quest + continue; + } } if(qinfo->RewSpellCast) @@ -3921,13 +3944,20 @@ void ObjectMgr::LoadQuests() qinfo->RewSpellCast = 0; // no spell will be casted on player } - else if(!SpellMgr::IsSpellValid(spellInfo)) + if(!SpellMgr::IsSpellValid(spellInfo)) { - sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.", + sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest will not have a spell reward.", qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); qinfo->RewSpellCast = 0; // no spell will be casted on player } + if(GetTalentSpellCost(qinfo->RewSpellCast)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); + qinfo->RewSpellCast = 0; // no spell will be casted on player + continue; + } } if(qinfo->RewMailTemplateId) @@ -6131,6 +6161,16 @@ inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,ui goInfo->id,goInfo->type,N,dataN); } +inline void CheckGOConsumable(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + // 0/1 correct values + if (dataN <= 1) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) consumable field value.", + goInfo->id,goInfo->type,N,dataN); +} + void ObjectMgr::LoadGameobjectInfo() { SQLGameObjectLoader loader; @@ -6173,6 +6213,8 @@ void ObjectMgr::LoadGameobjectInfo() if (goInfo->chest.lockId) CheckGOLockId(goInfo,goInfo->chest.lockId,0); + CheckGOConsumable(goInfo,goInfo->chest.consumable,3); + if (goInfo->chest.linkedTrapId) // linked trap CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7); break; @@ -6208,6 +6250,8 @@ void ObjectMgr::LoadGameobjectInfo() if (goInfo->goober.lockId) CheckGOLockId(goInfo,goInfo->goober.lockId,0); + CheckGOConsumable(goInfo,goInfo->goober.consumable,3); + if (goInfo->goober.pageId) // pageId { if (!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId)) @@ -7054,18 +7098,24 @@ bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bo return false; } -bool ObjectMgr::IsValidName( const std::string& name, bool create ) +uint8 ObjectMgr::CheckPlayerName( const std::string& name, bool create ) { std::wstring wname; if(!Utf8toWStr(name,wname)) - return false; + return CHAR_NAME_INVALID_CHARACTER; - if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME) - return false; + if(wname.size() > MAX_PLAYER_NAME) + return CHAR_NAME_TOO_LONG; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_PLAYER_NAME); + if(wname.size() < minName) + return CHAR_NAME_TOO_SHORT; uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES); + if(!isValidString(wname,strictMask,false,create)) + return CHAR_NAME_MIXED_LANGUAGES; - return isValidString(wname,strictMask,false,create); + return CHAR_NAME_SUCCESS; } bool ObjectMgr::IsValidCharterName( const std::string& name ) @@ -7074,7 +7124,11 @@ bool ObjectMgr::IsValidCharterName( const std::string& name ) if(!Utf8toWStr(name,wname)) return false; - if(wname.size() < 1) + if(wname.size() > MAX_CHARTER_NAME) + return false; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_CHARTER_NAME); + if(wname.size() < minName) return false; uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES); @@ -7082,18 +7136,24 @@ bool ObjectMgr::IsValidCharterName( const std::string& name ) return isValidString(wname,strictMask,true); } -bool ObjectMgr::IsValidPetName( const std::string& name ) +PetNameInvalidReason ObjectMgr::CheckPetName( const std::string& name ) { std::wstring wname; if(!Utf8toWStr(name,wname)) - return false; + return PET_NAME_INVALID; - if(wname.size() < 1) - return false; + if(wname.size() > MAX_PET_NAME) + return PET_NAME_TOO_LONG; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_PET_NAME); + if(wname.size() < minName) + return PET_NAME_TOO_SHORT; uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES); + if(!isValidString(wname,strictMask,false)) + return PET_NAME_MIXED_LANGUAGES; - return isValidString(wname,strictMask,false); + return PET_NAME_SUCCESS; } int ObjectMgr::GetIndexForLocale( LocaleConstant loc ) @@ -7158,7 +7218,7 @@ void ObjectMgr::LoadGameObjectForQuests() // scan GO chest with loot including quest items case GAMEOBJECT_TYPE_CHEST: { - uint32 loot_id = GameObject::GetLootId(goInfo); + uint32 loot_id = goInfo->GetLootId(); // find quest loot for GO if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id)) diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index f5189116463..b770c3044a4 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -234,7 +234,7 @@ enum ConditionType CONDITION_SKILL = 7, // skill_id skill_value CONDITION_QUESTREWARDED = 8, // quest_id 0 CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active. - CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD Å„ommission aura active + CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD commission aura active CONDITION_NO_AURA = 11, // spell_id effindex CONDITION_ACTIVE_EVENT = 12, // event_id CONDITION_INSTANCE_DATA = 13, // entry data @@ -312,8 +312,10 @@ struct GM_Ticket typedef std::list<GM_Ticket*> GmTicketList; SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial); -#define MAX_PLAYER_NAME 12 // max allowed by client name length +#define MAX_PLAYER_NAME 12 // max allowed by client name length #define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length ( > MAX_PLAYER_NAME for support declined names ) +#define MAX_PET_NAME 12 // max allowed by client name length +#define MAX_CHARTER_NAME 24 // max allowed by client name length bool normalizePlayerName(std::string& name); @@ -628,6 +630,7 @@ class ObjectMgr CachePlayerInfoMap m_mPlayerInfoMap; uint32 CreateItemText(std::string text); + void AddItemText(uint32 itemTextId, std::string text) { mItemTexts[itemTextId] = text; } std::string GetItemText( uint32 id ) { ItemTextMap::const_iterator itr = mItemTexts.find( id ); @@ -759,9 +762,9 @@ class ObjectMgr bool IsReservedName(const std::string& name) const; // name with valid structure and symbols - static bool IsValidName( const std::string& name, bool create = false ); + static uint8 CheckPlayerName( const std::string& name, bool create = false ); + static PetNameInvalidReason CheckPetName( const std::string& name ); static bool IsValidCharterName( const std::string& name ); - static bool IsValidPetName( const std::string& name ); static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names); @@ -845,7 +848,7 @@ class ObjectMgr GM_Ticket *GetGMTicket(uint64 ticketGuid) { for(GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i) - if((*i) && (*i)->guid == ticketGuid && (*i)->closed == 0) + if((*i) && (*i)->guid == ticketGuid) return (*i); return NULL; @@ -943,6 +946,7 @@ class ObjectMgr private: void LoadScripts(ScriptMapMap& scripts, char const* tablename); void CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids); + void LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment); void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr); void LoadQuestRelationsHelper(QuestRelations& map,char const* table); diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index b66786f9d91..8fd57ad52be 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -1025,7 +1025,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x3E2*/ { "SMSG_COMSAT_CONNECT_FAIL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x3E3*/ { "SMSG_VOICE_CHAT_STATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x3E4*/ { "CMSG_REPORT_PVP_AFK", STATUS_LOGGEDIN, &WorldSession::HandleReportPvPAFK }, - /*0x3E5*/ { "CMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x3E5*/ { "SMSG_REPORT_PVP_AFK_RESULT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x3E6*/ { "CMSG_GUILD_BANKER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankerActivate }, /*0x3E7*/ { "CMSG_GUILD_BANK_QUERY_TAB", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankQueryTab }, /*0x3E8*/ { "SMSG_GUILD_BANK_LIST", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -1053,7 +1053,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x3FE*/ { "MSG_GUILD_BANK_MONEY_WITHDRAWN", STATUS_LOGGEDIN, &WorldSession::HandleGuildBankMoneyWithdrawn }, /*0x3FF*/ { "MSG_GUILD_EVENT_LOG_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleGuildEventLogQueryOpcode }, /*0x400*/ { "CMSG_MAELSTROM_RENAME_GUILD", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x401*/ { "CMSG_GET_MIRRORIMAGE_DATA", STATUS_LOGGEDIN, &WorldSession::HandleMirrrorImageDataRequest }, /*0x402*/ { "SMSG_MIRRORIMAGE_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x403*/ { "SMSG_FORCE_DISPLAY_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x404*/ { "SMSG_SPELL_CHANCE_RESIST_PUSHBACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h index b3d9c4f8f11..b468cc64978 100644 --- a/src/game/Opcodes.h +++ b/src/game/Opcodes.h @@ -694,8 +694,8 @@ enum Opcodes CMSG_GROUP_ASSISTANT_LEADER = 0x28F, CMSG_BUYBACK_ITEM = 0x290, SMSG_SERVER_MESSAGE = 0x291, - CMSG_MEETINGSTONE_JOIN = 0x292, - CMSG_MEETINGSTONE_LEAVE = 0x293, // SMSG? + CMSG_MEETINGSTONE_JOIN = 0x292, // lua: SetSavedInstanceExtend + SMSG_MEETINGSTONE_LEAVE = 0x293, CMSG_MEETINGSTONE_CHEAT = 0x294, SMSG_MEETINGSTONE_SETQUEUE = 0x295, CMSG_MEETINGSTONE_INFO = 0x296, @@ -1033,7 +1033,7 @@ enum Opcodes SMSG_COMSAT_CONNECT_FAIL = 0x3E2, SMSG_VOICE_CHAT_STATUS = 0x3E3, CMSG_REPORT_PVP_AFK = 0x3E4, - CMSG_REPORT_PVP_AFK_RESULT = 0x3E5, + SMSG_REPORT_PVP_AFK_RESULT = 0x3E5, // SMSG? CMSG_GUILD_BANKER_ACTIVATE = 0x3E6, CMSG_GUILD_BANK_QUERY_TAB = 0x3E7, SMSG_GUILD_BANK_LIST = 0x3E8, diff --git a/src/game/OutdoorPvP.cpp b/src/game/OutdoorPvP.cpp index fd1cf87e6d6..d3c96f53fcb 100644 --- a/src/game/OutdoorPvP.cpp +++ b/src/game/OutdoorPvP.cpp @@ -116,7 +116,6 @@ bool OPvPCapturePoint::DelCreature(uint32 type) // Don't save respawn time cr->SetRespawnTime(0); cr->RemoveCorpse(); - cr->CleanupsBeforeDelete(); // explicit removal from map // beats me why this is needed, but with the recent removal "cleanup" some creatures stay in the map if "properly" deleted // so this is a big fat workaround, if AddObjectToRemoveList and DoDelayedMovesAndRemoves worked correctly, this wouldn't be needed @@ -360,7 +359,7 @@ void OPvPCapturePoint::SendObjectiveComplete(uint32 id,uint64 guid) // send to all players present in the area for(PlayerSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) - (*itr)->KilledMonster(id, guid); + (*itr)->KilledMonsterCredit(id, guid); } void OutdoorPvP::HandleKill(Player *killer, Unit * killed) diff --git a/src/game/OutdoorPvPNA.cpp b/src/game/OutdoorPvPNA.cpp index 53bf1a3c770..7a421b848ba 100644 --- a/src/game/OutdoorPvPNA.cpp +++ b/src/game/OutdoorPvPNA.cpp @@ -33,7 +33,7 @@ void OutdoorPvPNA::HandleKillImpl(Player *plr, Unit * killed) { if(killed->GetTypeId() == TYPEID_PLAYER && plr->GetTeam() != ((Player*)killed)->GetTeam()) { - plr->KilledMonster(NA_CREDIT_MARKER,0); // 0 guid, btw it isn't even used in killedmonster function :S + plr->KilledMonsterCredit(NA_CREDIT_MARKER,0); // 0 guid, btw it isn't even used in killedmonster function :S if(plr->GetTeam() == ALLIANCE) plr->CastSpell(plr,NA_KILL_TOKEN_ALLIANCE,true); else diff --git a/src/game/OutdoorPvPSI.cpp b/src/game/OutdoorPvPSI.cpp index c1f47db49c7..e60888c7e08 100644 --- a/src/game/OutdoorPvPSI.cpp +++ b/src/game/OutdoorPvPSI.cpp @@ -107,7 +107,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger) // add 20 cenarion circle repu plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20); // complete quest - plr->KilledMonster(SI_TURNIN_QUEST_CM_A,0); + plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_A,0); } return true; case SI_AREATRIGGER_H: @@ -132,7 +132,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player *plr, uint32 trigger) // add 20 cenarion circle repu plr->GetReputationMgr().ModifyReputation(sFactionStore.LookupEntry(609),20); // complete quest - plr->KilledMonster(SI_TURNIN_QUEST_CM_H,0); + plr->KilledMonsterCredit(SI_TURNIN_QUEST_CM_H,0); } return true; } @@ -156,7 +156,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId) { // he dropped it further, summon mound GameObject * go = new GameObject; - Map * map = MapManager::Instance().GetMap(plr->GetMapId(), plr); + Map * map = plr->GetMap(); if(!map) { delete go; @@ -186,7 +186,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player *plr, uint32 spellId) { // he dropped it further, summon mound GameObject * go = new GameObject; - Map * map = MapManager::Instance().GetMap(plr->GetMapId(), plr); + Map * map = plr->GetMap(); if(!map) { delete go; diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 7448d6440ce..05764beec11 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -49,10 +49,15 @@ m_declinedname(NULL), m_owner(owner) m_summonMask |= SUMMON_MASK_PET; if(type == HUNTER_PET) m_summonMask |= SUMMON_MASK_HUNTER_PET; + + if (!(m_summonMask & SUMMON_MASK_CONTROLABLE_GUARDIAN)) + { + m_summonMask |= SUMMON_MASK_CONTROLABLE_GUARDIAN; + InitCharmInfo(); + } + m_name = "Pet"; m_regenTimer = 4000; - - owner->SetPetAtLoginFlag(0); } Pet::~Pet() @@ -93,24 +98,24 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool if (petnumber) // known petnumber entry 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags " + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND id = '%u'", ownerid, petnumber); else if (current) // current pet (slot 0) 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags " + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND slot = '%u'", ownerid, PET_SAVE_AS_CURRENT ); else if (petentry) // known petentry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets) // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags " + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND entry = '%u' AND (slot = '%u' OR slot > '%u') ", ownerid, petentry,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); else // any current or other non-stabled pet (for hunter "call pet") // 0 1 2(?) 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags " + result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType " "FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u') ", ownerid,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); @@ -151,7 +156,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool } uint32 pet_number = fields[0].GetUInt32(); - + if (current && owner->IsPetNeedBeTemporaryUnsummoned()) { owner->SetTemporaryUnsummonedPetNumber(pet_number); @@ -168,7 +173,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool } float px, py, pz; - owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, GetFollowAngle()); Relocate(px, py, pz, owner->GetOrientation()); if (!IsPositionValid()) @@ -284,29 +289,16 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool uint32 timediff = (time(NULL) - fields[14].GetUInt32()); _LoadAuras(timediff); - uint8 loadFlags = fields[19].GetUInt8(); - owner->SetPetAtLoginFlag(loadFlags); - if (loadFlags & AT_LOAD_RESET_SPELLS) - { - CharacterDatabase.PExecute("UPDATE character_pet SET load_flags = load_flags & ~ %u WHERE id = '%u'",uint32(AT_LOAD_RESET_SPELLS),pet_number); - loadFlags &= ~uint8(AT_LOAD_RESET_SPELLS); - CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u'",pet_number); - InitPetCreateSpells(); - resetTalents(true); - } - else + // load action bar, if data broken will fill later by default spells. + if (!is_temporary_summoned) { - // load action bar, if data broken will fill later by default spells. - if (!is_temporary_summoned) - { - m_charmInfo->LoadPetActionBar(fields[13].GetCppString()); + m_charmInfo->LoadPetActionBar(fields[13].GetCppString()); - _LoadSpells(); - _LoadSpellCooldowns(); - LearnPetPassives(); - InitLevelupSpellsForLevel(); - CastPetAuras(current); - } + _LoadSpells(); + _LoadSpellCooldowns(); + LearnPetPassives(); + InitLevelupSpellsForLevel(); + CastPetAuras(current); } CleanupActionBar(); // remove unknown spells from action bar after load @@ -408,7 +400,7 @@ void Pet::SavePetToDB(PetSaveMode mode) owner,PET_SAVE_AS_CURRENT,PET_SAVE_LAST_STABLE_SLOT); // save pet std::ostringstream ss; - ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType, load_flags) " + ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) " << "VALUES (" << m_charmInfo->GetPetNumber() << ", " << GetEntry() << ", " @@ -427,8 +419,8 @@ void Pet::SavePetToDB(PetSaveMode mode) // save only spell slots from action bar for(uint32 i = ACTION_BAR_INDEX_PET_SPELL_START; i < ACTION_BAR_INDEX_PET_SPELL_END; ++i) { - ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " - << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; + ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << " " + << uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << " "; }; ss << "', " @@ -436,8 +428,7 @@ void Pet::SavePetToDB(PetSaveMode mode) << uint32(m_resetTalentsCost) << ", " << uint64(m_resetTalentsTime) << ", " << GetUInt32Value(UNIT_CREATED_BY_SPELL) << ", " - << uint32(getPetType()) << ", " - << (pOwner->GetAtLoginFlag()>>AT_LOAD_PET_FLAGS) << ")"; + << uint32(getPetType()) << ")"; CharacterDatabase.Execute( ss.str().c_str() ); CharacterDatabase.CommitTransaction(); @@ -448,7 +439,6 @@ void Pet::SavePetToDB(PetSaveMode mode) RemoveAllAuras(); DeleteFromDB(m_charmInfo->GetPetNumber()); } - pOwner->SetPetAtLoginFlag(0); } void Pet::DeleteFromDB(uint32 guidlow) @@ -732,9 +722,6 @@ bool Pet::CreateBaseAtCreature(Creature* creature) } uint32 guid=objmgr.GenerateLowGuid(HIGHGUID_PET); - sLog.outDebug("SetInstanceID()"); - SetInstanceId(creature->GetInstanceId()); - sLog.outDebug("Create pet"); uint32 pet_number = objmgr.GeneratePetNumber(); if(!Create(guid, creature->GetMap(), creature->GetPhaseMask(), creature->GetEntry(), pet_number)) @@ -941,6 +928,16 @@ bool Guardian::InitStatsForLevel(uint32 petlevel) SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 4 + petlevel)); break; } + case 31216: // Mirror Image + { + SetBonusDamage( int32(m_owner->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_FROST) * 0.33f)); + if(!pInfo) + { + SetCreateMana(28 + 30*petlevel); + SetCreateHealth(28 + 10*petlevel); + } + break; + } default: { if(!pInfo) @@ -1081,7 +1078,7 @@ void Pet::_LoadSpells() { Field *fields = result->Fetch(); - addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt16()), PETSPELL_UNCHANGED); + addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt8()), PETSPELL_UNCHANGED); } while( result->NextRow() ); @@ -1346,8 +1343,8 @@ bool Pet::learnSpell(uint32 spell_id) if(!m_loading) { - WorldPacket data(SMSG_PET_LEARNED_SPELL, 2); - data << uint16(spell_id); + WorldPacket data(SMSG_PET_LEARNED_SPELL, 4); + data << uint32(spell_id); m_owner->GetSession()->SendPacket(&data); m_owner->PetSpellInitialize(); } @@ -1399,8 +1396,8 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab) { if(!m_loading) { - WorldPacket data(SMSG_PET_REMOVED_SPELL, 2); - data << uint16(spell_id); + WorldPacket data(SMSG_PET_REMOVED_SPELL, 4); + data << uint32(spell_id); m_owner->GetSession()->SendPacket(&data); } return true; @@ -1464,12 +1461,12 @@ void Pet::CleanupActionBar() { for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) if(UnitActionBarEntry const* ab = m_charmInfo->GetActionBarEntry(i)) - if(ab->SpellOrAction && ab->IsActionBarForSpell()) + if(ab->GetAction() && ab->IsActionBarForSpell()) { - if(!HasSpell(ab->SpellOrAction)) + if(!HasSpell(ab->GetAction())) m_charmInfo->SetActionBar(i, 0, ACT_PASSIVE); - else if(ab->Type == ACT_ENABLED) - ToggleAutocast(ab->SpellOrAction, true); + else if(ab->GetType() == ACT_ENABLED) + ToggleAutocast(ab->GetAction(), true); } } @@ -1490,6 +1487,10 @@ bool Pet::resetTalents(bool no_cost) if (!owner || owner->GetTypeId()!=TYPEID_PLAYER) return false; + // not need after this call + if(((Player*)owner)->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) + ((Player*)owner)->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS,true); + CreatureInfo const * ci = GetCreatureInfo(); if(!ci) return false; @@ -1576,6 +1577,90 @@ bool Pet::resetTalents(bool no_cost) return true; } +void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* online_pet /*= NULL*/) +{ + // not need after this call + if(((Player*)owner)->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS)) + ((Player*)owner)->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS,true); + + // reset for online + if(online_pet) + online_pet->resetTalents(true); + + // now need only reset for offline pets (all pets except online case) + uint32 except_petnumber = online_pet ? online_pet->GetCharmInfo()->GetPetNumber() : 0; + + QueryResult *resultPets = CharacterDatabase.PQuery( + "SELECT id FROM character_pet WHERE owner = '%u' AND id <> '%u'", + owner->GetGUIDLow(),except_petnumber); + + // no offline pets + if(!resultPets) + return; + + QueryResult *result = CharacterDatabase.PQuery( + "SELECT DISTINCT pet_spell.spell FROM pet_spell, character_pet " + "WHERE character_pet.owner = '%u' AND character_pet.id = pet_spell.guid AND character_pet.id <> %u", + owner->GetGUIDLow(),except_petnumber); + + if(!result) + { + delete resultPets; + return; + } + + bool need_comma = false; + std::ostringstream ss; + ss << "DELETE FROM pet_spell WHERE guid IN ("; + + do + { + Field *fields = resultPets->Fetch(); + + uint32 id = fields[0].GetUInt32(); + + if(need_comma) + ss << ","; + + ss << id; + + need_comma = true; + } + while( resultPets->NextRow() ); + + delete resultPets; + + ss << ") AND spell IN ("; + + bool need_execute = false; + do + { + Field *fields = result->Fetch(); + + uint32 spell = fields[0].GetUInt32(); + + if(!GetTalentSpellCost(spell)) + continue; + + if(need_execute) + ss << ","; + + ss << spell; + + need_execute = true; + } + while( result->NextRow() ); + + delete result; + + if(!need_execute) + return; + + ss << ")"; + + CharacterDatabase.Execute(ss.str().c_str()); +} + void Pet::InitTalentForLevel() { uint32 level = getLevel(); @@ -1693,10 +1778,10 @@ bool Pet::IsPermanentPetFor(Player* owner) bool Pet::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number) { - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); - SetPhaseMask(phaseMask,false); + assert(map); + SetMap(map); + SetPhaseMask(phaseMask,false); Object::_Create(guidlow, pet_number, HIGHGUID_PET); m_DBTableGuid = guidlow; @@ -1761,7 +1846,7 @@ void Pet::CastPetAuras(bool current) void Pet::CastPetAura(PetAura const* aura) { - uint16 auraId = aura->GetAura(GetEntry()); + uint32 auraId = aura->GetAura(GetEntry()); if(!auraId) return; diff --git a/src/game/Pet.h b/src/game/Pet.h index 49daad429ed..88287ce5dee 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -89,14 +89,11 @@ enum PetTalk PET_TALK_ATTACK = 1 }; -enum AtLoadFlags -{ - AT_LOAD_NONE = 0, - AT_LOAD_RESET_SPELLS = 1, -}; - enum PetNameInvalidReason { + // custom, not send + PET_NAME_SUCCESS = 0, + PET_NAME_INVALID = 1, PET_NAME_NO_NAME = 2, PET_NAME_TOO_SHORT = 3, @@ -212,6 +209,7 @@ class Pet : public Guardian void InitPetCreateSpells(); bool resetTalents(bool no_cost = false); + static void resetTalentsForAllPetsOf(Player* owner, Pet* online_pet = NULL); uint32 resetTalentsCost() const; void InitTalentForLevel(); diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp index 7851ee6773f..0fcc707b104 100644 --- a/src/game/PetAI.cpp +++ b/src/game/PetAI.cpp @@ -74,7 +74,7 @@ void PetAI::_stopAttack() if(owner && m_creature->GetCharmInfo() && m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW)) { - m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); + m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle()); } else { @@ -112,17 +112,22 @@ void PetAI::UpdateAI(const uint32 diff) if(owner->isInCombat() && !(m_creature->HasReactState(REACT_PASSIVE) || m_creature->GetCharmInfo()->HasCommandState(COMMAND_STAY))) AttackStart(owner->getAttackerForHelper()); else if(m_creature->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW) && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) - m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); + m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle()); } + else if (owner && !m_creature->hasUnitState(UNIT_STAT_FOLLOW)) // no charm info and no victim + m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST, m_creature->GetFollowAngle()); if(!me->GetCharmInfo()) return; + bool inCombat = me->getVictim(); + + // Autocast (casted only in combat or persistent spells in any state) if (m_creature->GetGlobalCooldown() == 0 && !m_creature->hasUnitState(UNIT_STAT_CASTING)) { - bool inCombat = me->getVictim(); + typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList; + TargetSpellList targetSpellStore; - //Autocast for (uint8 i = 0; i < m_creature->GetPetAutoSpellSize(); ++i) { uint32 spellID = m_creature->GetPetAutoSpellOnPos(i); @@ -136,20 +141,38 @@ void PetAI::UpdateAI(const uint32 diff) // ignore some combinations of combat state and combat/noncombat spells if (!inCombat) { + // ignore attacking spells, and allow only self/around spells if (!IsPositiveSpell(spellInfo->Id)) continue; + + // non combat spells allowed + // only pet spells have IsNonCombatSpell and not fit this reqs: + // Consume Shadows, Lesser Invisibility, so ignore checks for its + if (!IsNonCombatSpell(spellInfo)) + { + // allow only spell without spell cost or with spell cost but not duration limit + int32 duration = GetSpellDuration(spellInfo); + if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0) + continue; + + // allow only spell without cooldown > duration + int32 cooldown = GetSpellRecoveryTime(spellInfo); + if (cooldown >= 0 && duration >= 0 && cooldown > duration) + continue; + } } else { + // just ignore non-combat spells if (IsNonCombatSpell(spellInfo)) continue; } Spell *spell = new Spell(m_creature, spellInfo, false, 0); - if(inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim())) + if (inCombat && !m_creature->hasUnitState(UNIT_STAT_FOLLOW) && spell->CanAutoCast(m_creature->getVictim())) { - m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(m_creature->getVictim(), spell)); + targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(m_creature->getVictim(), spell)); continue; } else @@ -165,7 +188,7 @@ void PetAI::UpdateAI(const uint32 diff) if(spell->CanAutoCast(Target)) { - m_targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(Target, spell)); + targetSpellStore.push_back(std::make_pair<Unit*, Spell*>(Target, spell)); spellUsed = true; break; } @@ -176,14 +199,14 @@ void PetAI::UpdateAI(const uint32 diff) } //found units to cast on to - if(!m_targetSpellStore.empty()) + if (!targetSpellStore.empty()) { - uint32 index = urand(0, m_targetSpellStore.size() - 1); + uint32 index = urand(0, targetSpellStore.size() - 1); - Spell* spell = m_targetSpellStore[index].second; - Unit* target = m_targetSpellStore[index].first; + Spell* spell = targetSpellStore[index].second; + Unit* target = targetSpellStore[index].first; - m_targetSpellStore.erase(m_targetSpellStore.begin() + index); + targetSpellStore.erase(targetSpellStore.begin() + index); SpellCastTargets targets; targets.setUnitTarget( target ); @@ -202,11 +225,10 @@ void PetAI::UpdateAI(const uint32 diff) spell->prepare(&targets); } - while (!m_targetSpellStore.empty()) - { - delete m_targetSpellStore.begin()->second; - m_targetSpellStore.erase(m_targetSpellStore.begin()); - } + + // deleted cached Spell objects + for(TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr) + delete itr->second; } } diff --git a/src/game/PetAI.h b/src/game/PetAI.h index 67ce6edefe3..918259cd098 100644 --- a/src/game/PetAI.h +++ b/src/game/PetAI.h @@ -50,9 +50,6 @@ class TRINITY_DLL_DECL PetAI : public CreatureAI bool inCombat; std::set<uint64> m_AllySet; uint32 m_updateAlliesTimer; - - typedef std::pair<Unit*, Spell*> TargetSpellPair; - std::vector<TargetSpellPair> m_targetSpellStore; }; #endif diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 3960b59d6d4..3de8ee028d3 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -37,17 +37,18 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) CHECK_PACKET_SIZE(recv_data, 8+2+2+8); uint64 guid1; - uint16 spellid; - uint16 flag; + uint32 data; uint64 guid2; recv_data >> guid1; //pet guid - recv_data >> spellid; - recv_data >> flag; //delete = 0x0700 CastSpell = C100 + recv_data >> data; recv_data >> guid2; //tag guid + uint32 spellid = UNIT_ACTION_BUTTON_ACTION(data); + uint8 flag = UNIT_ACTION_BUTTON_TYPE(data); //delete = 0x07 CastSpell = C1 + // used also for charmed creature Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); - sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) ); + sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), uint32(flag), spellid, uint32(GUID_LOPART(guid2)) ); if(!pet) { sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid1)) ); @@ -89,7 +90,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid switch(flag) { - case ACT_COMMAND: //0x0700 + case ACT_COMMAND: //0x07 switch(spellid) { case COMMAND_STAY: //flat=1792 //STAY @@ -101,7 +102,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid case COMMAND_FOLLOW: //spellid=1792 //FOLLOW pet->AttackStop(); pet->InterruptNonMeleeSpells(false); - pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); + pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,pet->GetFollowAngle()); charmInfo->SetCommandState( COMMAND_FOLLOW ); break; case COMMAND_ATTACK: //spellid=1792 //ATTACK @@ -151,7 +152,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid pet->SendPetAIReaction(guid1); } } - else // charmed player + else // charmed player { if(pet->getVictim() && pet->getVictim() != TargetUnit) pet->AttackStop(); @@ -183,10 +184,10 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid } break; default: - sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid); + sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } break; - case ACT_REACTION: // 0x600 + case ACT_REACTION: // 0x6 switch(spellid) { case REACT_PASSIVE: //passive @@ -197,9 +198,9 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid break; } break; - case ACT_DISABLED: // 0x8100 spell (disabled), ignore - case ACT_PASSIVE: // 0x0100 - case ACT_ENABLED: // 0xC100 spell + case ACT_DISABLED: // 0x81 spell (disabled), ignore + case ACT_PASSIVE: // 0x01 + case ACT_ENABLED: // 0xC1 spell { Unit* unit_target = NULL; if (((Creature*)pet)->GetGlobalCooldown() > 0) @@ -291,7 +292,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid pet->SendPetCastFail(spellid, result); if(!((Creature*)pet)->HasSpellCooldown(spellid)) - pet->SendPetClearCooldown(spellid); + GetPlayer()->SendClearCooldown(spellid, pet); spell->finish(false); delete spell; @@ -299,7 +300,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid break; } default: - sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid); + sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid); } } @@ -350,9 +351,6 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION" ); uint64 petguid; - uint32 position; - uint16 spell_id; - uint16 act_state; uint8 count; recv_data >> petguid; @@ -375,11 +373,16 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) count = (recv_data.size() == 24) ? 2 : 1; for(uint8 i = 0; i < count; ++i) { + uint32 position; + uint32 data; + recv_data >> position; - recv_data >> spell_id; - recv_data >> act_state; + recv_data >> data; - sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state); + uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data); + uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data); + + sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, uint32(act_state)); //ignore invalid position if(position >= MAX_UNIT_ACTION_BAR_INDEX) @@ -435,9 +438,10 @@ void WorldSession::HandlePetRename( WorldPacket & recv_data ) pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() ) return; - if(!ObjectMgr::IsValidPetName(name)) + PetNameInvalidReason res = ObjectMgr::CheckPetName(name); + if(res != PET_NAME_SUCCESS) { - SendPetNameInvalid(PET_NAME_INVALID, name, NULL); + SendPetNameInvalid(res, name, NULL); return; } @@ -497,6 +501,9 @@ void WorldSession::HandlePetAbandon( WorldPacket & recv_data ) recv_data >> guid; //pet guid sLog.outDetail( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid) ); + if(!_player->IsInWorld()) + return; + // pet/charmed Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, guid); if(pet) @@ -551,10 +558,9 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket ) sLog.outDetail("CMSG_PET_SPELL_AUTOCAST"); uint64 guid; - uint16 spellid; - uint16 spellid2; //maybe second spell, automatically toggled off when first toggled on? + uint32 spellid; uint8 state; //1 for on, 0 for off - recvPacket >> guid >> spellid >> spellid2 >> state; + recvPacket >> guid >> spellid >> state; if(!_player->GetGuardianPet() && !_player->GetCharm()) return; @@ -615,12 +621,6 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) return; } - if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->GetGlobalCooldown() > 0) - { - caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY); - return; - } - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); if(!spellInfo) { @@ -628,6 +628,13 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) return; } + if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD + if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->GetGlobalCooldown() > 0) + { + caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY); + return; + } + // do not cast not learned spells if(!caster->HasSpell(spellid) || IsPassiveSpell(spellid)) return; @@ -669,12 +676,12 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) if(caster->GetTypeId() == TYPEID_PLAYER) { if(!((Player*)caster)->HasSpellCooldown(spellid)) - caster->SendPetClearCooldown(spellid); + GetPlayer()->SendClearCooldown(spellid, caster); } else { if(!((Creature*)caster)->HasSpellCooldown(spellid)) - caster->SendPetClearCooldown(spellid); + GetPlayer()->SendClearCooldown(spellid, caster); } spell->finish(false); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 17203faadde..8a3a4bffd93 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -316,10 +316,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE); - // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE] - // this must help in case next save after mass player load after server startup - m_nextSave = urand(m_nextSave/2,m_nextSave*3/2); - clearResurrectRequestData(); memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT); @@ -341,6 +337,11 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa mSemaphoreTeleport_Near = false; mSemaphoreTeleport_Far = false; + m_DelayedOperations = 0; + m_bCanDelayTeleport = false; + m_bHasDelayedTeleport = false; + m_teleport_options = 0; + pTrader = 0; ClearTrade(); @@ -471,6 +472,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_lastFallZ = 0; m_ControlledByPlayer = true; + + sWorld.IncreasePlayerCount(); } Player::~Player () @@ -478,6 +481,10 @@ Player::~Player () // it must be unloaded already in PlayerLogout and accessed only for loggined player //m_social = NULL; + // Player may still set map - remove it to correctly unload instances + if (FindMap()) + ResetMap(); + // Note: buy back item already deleted from DB when player was saved for(uint8 i = 0; i < PLAYER_SLOTS_COUNT; ++i) { @@ -503,6 +510,8 @@ Player::~Player () delete m_declinedname; delete m_runes; + + sWorld.DecreasePlayerCount(); } void Player::CleanupsBeforeDelete() @@ -539,10 +548,6 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++) m_items[i] = NULL; - m_race = race; - m_class = class_; - - SetMapId(info->mapId); Relocate(info->positionX,info->positionY,info->positionZ); ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(class_); @@ -552,32 +557,19 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 return false; } + SetMap(MapManager::Instance().CreateMap(info->mapId, this, 0)); + uint8 powertype = cEntry->powerType; SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE); SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f); - switch(gender) - { - case GENDER_FEMALE: - SetDisplayId(info->displayId_f ); - SetNativeDisplayId(info->displayId_f ); - break; - case GENDER_MALE: - SetDisplayId(info->displayId_m ); - SetNativeDisplayId(info->displayId_m ); - break; - default: - sLog.outError("Invalid gender %u for player",gender); - return false; - break; - } - - setFactionForRace(m_race); + setFactionForRace(race); uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 ); SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) ); + InitDisplayIds(); SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP ); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE ); SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER); @@ -676,8 +668,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 // Played time m_Last_tick = time(NULL); - m_Played_time[0] = 0; - m_Played_time[1] = 0; + m_Played_time[PLAYED_TIME_TOTAL] = 0; + m_Played_time[PLAYED_TIME_LEVEL] = 0; // base stats and related field values InitStatsForLevel(); @@ -707,21 +699,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 learnDefaultSpells(); // original action bar - std::list<uint16>::const_iterator action_itr[4]; - for(uint8 i=0; i<4; i++) - action_itr[i] = info->action[i].begin(); - - for (; action_itr[0]!=info->action[0].end() && action_itr[1]!=info->action[1].end();) - { - uint16 taction[4]; - for(uint8 i=0; i<4 ;i++) - taction[i] = (*action_itr[i]); - - addActionButton((uint8)taction[0], taction[1], (uint8)taction[2], (uint8)taction[3]); - - for(uint8 i=0; i<4 ;i++) - ++action_itr[i]; - } + for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr) + addActionButton(action_itr->button,action_itr->action,action_itr->type); // original items CharStartOutfitEntry const* oEntry = NULL; @@ -746,7 +725,6 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 uint32 item_id = oEntry->ItemId[j]; - // Hack for not existed item id in dbc 3.0.3 if(item_id==40582) continue; @@ -758,22 +736,23 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 continue; } - // max stack by default (mostly 1), 1 for infinity stackable - uint32 count = iProto->Stackable > 0 ? uint32(iProto->Stackable) : 1; + // BuyCount by default + uint32 count = iProto->BuyCount; + // special amount for foor/drink if(iProto->Class==ITEM_CLASS_CONSUMABLE && iProto->SubClass==ITEM_SUBCLASS_FOOD) { switch(iProto->Spells[0].SpellCategory) { case 11: // food - if(iProto->Stackable > 4) - count = 4; + count = getClass()==CLASS_DEATH_KNIGHT ? 10 : 4; break; case 59: // drink - if(iProto->Stackable > 2) - count = 2; + count = 2; break; } + if(iProto->Stackable < count) + count = iProto->Stackable; } StoreNewItemInBestSlots(item_id, count); @@ -1138,7 +1117,10 @@ void Player::Update( uint32 p_time ) // Having this would prevent more aura charges to be dropped, so let's crash assert (!m_spellModTakingSpell); + //used to implement delayed far teleports + SetCanDelayTeleport(true); Unit::Update( p_time ); + SetCanDelayTeleport(false); time_t now = time (NULL); @@ -1346,8 +1328,8 @@ void Player::Update( uint32 p_time ) { if (p_time >= m_DetectInvTimer) { - m_DetectInvTimer = 3000; HandleStealthedUnitsDetection(); + m_DetectInvTimer = 3000; } else m_DetectInvTimer -= p_time; @@ -1357,8 +1339,8 @@ void Player::Update( uint32 p_time ) if (now > m_Last_tick) { uint32 elapsed = uint32(now - m_Last_tick); - m_Played_time[0] += elapsed; // Total played time - m_Played_time[1] += elapsed; // Level played time + m_Played_time[PLAYED_TIME_TOTAL] += elapsed; // Total played time + m_Played_time[PLAYED_TIME_LEVEL] += elapsed; // Level played time m_Last_tick = now; } @@ -1394,8 +1376,12 @@ void Player::Update( uint32 p_time ) //if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID()))) { RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); - return; } + + //we should execute delayed teleports only for alive(!) players + //because we don't want player's ghost teleported from graveyard + if(IsHasDelayedTeleport() && isAlive()) + TeleportTo(m_teleport_dest, m_teleport_options); } void Player::setDeathState(DeathState s) @@ -1452,53 +1438,67 @@ void Player::setDeathState(DeathState s) } } -void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) +bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) { + // 0 1 2 3 4 5 6 7 + // "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " + // 8 9 10 11 12 13 14 + // "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " + // 15 16 17 18 19 20 + // "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_declinedname.genitive " + Field *fields = result->Fetch(); - *p_data << uint64(GetGUID()); - *p_data << m_name; + uint32 guid = fields[0].GetUInt32(); + uint8 pRace = fields[2].GetUInt8(); + uint8 pClass = fields[3].GetUInt8(); - *p_data << uint8(getRace()); - uint8 pClass = getClass(); - *p_data << uint8(pClass); - *p_data << uint8(getGender()); + PlayerInfo const *info = objmgr.GetPlayerInfo(pRace, pClass); + if(!info) + { + sLog.outError("Player %u has incorrect race/class pair. Don't build enum.", guid); + return false; + } + + *p_data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); + *p_data << fields[1].GetString(); // name + *p_data << uint8(pRace); // race + *p_data << uint8(pClass); // class + *p_data << uint8(fields[4].GetUInt8()); // gender - uint32 bytes = GetUInt32Value(PLAYER_BYTES); - *p_data << uint8(bytes); - *p_data << uint8(bytes >> 8); - *p_data << uint8(bytes >> 16); - *p_data << uint8(bytes >> 24); + uint32 playerBytes = fields[5].GetUInt32(); + *p_data << uint8(playerBytes); // skin + *p_data << uint8(playerBytes >> 8); // face + *p_data << uint8(playerBytes >> 16); // hair style + *p_data << uint8(playerBytes >> 24); // hair color - bytes = GetUInt32Value(PLAYER_BYTES_2); - *p_data << uint8(bytes); + uint32 playerBytes2 = fields[6].GetUInt32(); + *p_data << uint8(playerBytes2 & 0xFF); // facial hair - *p_data << uint8(getLevel()); // player level - // do not use GetMap! it will spawn a new instance since the bound instances are not loaded - uint32 zoneId = fields[10].GetUInt32(); - sLog.outDebug("Player::BuildEnumData: map:%u, x:%f, y:%f, z:%f zone:%u", GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), zoneId); - *p_data << uint32(zoneId); - *p_data << uint32(GetMapId()); + *p_data << uint8(fields[7].GetUInt8()); // level + *p_data << uint32(fields[8].GetUInt32()); // zone + *p_data << uint32(fields[9].GetUInt32()); // map - *p_data << GetPositionX(); - *p_data << GetPositionY(); - *p_data << GetPositionZ(); + *p_data << fields[10].GetFloat(); // x + *p_data << fields[11].GetFloat(); // y + *p_data << fields[12].GetFloat(); // z - // guild id - *p_data << uint32(fields[14].GetUInt32()); + *p_data << uint32(fields[13].GetUInt32()); // guild id uint32 char_flags = 0; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM)) + uint32 playerFlags = fields[14].GetUInt32(); + uint32 atLoginFlags = fields[15].GetUInt32(); + if(playerFlags & PLAYER_FLAGS_HIDE_HELM) char_flags |= CHARACTER_FLAG_HIDE_HELM; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK)) + if(playerFlags & PLAYER_FLAGS_HIDE_CLOAK) char_flags |= CHARACTER_FLAG_HIDE_CLOAK; - if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + if(playerFlags & PLAYER_FLAGS_GHOST) char_flags |= CHARACTER_FLAG_GHOST; - if(HasAtLoginFlag(AT_LOGIN_RENAME)) + if(atLoginFlags & AT_LOGIN_RENAME) char_flags |= CHARACTER_FLAG_RENAME; if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED)) { - if(!fields[15].GetCppString().empty()) + if(!fields[20].GetCppString().empty()) char_flags |= CHARACTER_FLAG_DECLINED; } else @@ -1506,7 +1506,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) *p_data << uint32(char_flags); // character flags // character customize (flags?) - *p_data << uint32(HasAtLoginFlag(AT_LOGIN_CUSTOMIZE) ? 1 : 0); + *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? 1 : 0); *p_data << uint8(1); // unknown // Pets info @@ -1515,15 +1515,15 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) uint32 petLevel = 0; uint32 petFamily = 0; - // show pet at selection character in character list only for non-ghost character - if (result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT)) + // show pet at selection character in character list only for non-ghost character + if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT)) { - uint32 entry = fields[11].GetUInt32(); + uint32 entry = fields[16].GetUInt32(); CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry); if(cInfo) { - petDisplayId = fields[12].GetUInt32(); - petLevel = fields[13].GetUInt32(); + petDisplayId = fields[17].GetUInt32(); + petLevel = fields[18].GetUInt32(); petFamily = cInfo->family; } } @@ -1533,36 +1533,45 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) *p_data << uint32(petFamily); } + // TODO: do not access data field here + Tokens data = StrSplit(fields[19].GetCppString(), " "); + for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++) { uint32 visualbase = PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2); - uint32 item_id = GetUInt32Value(visualbase); + uint32 item_id = GetUInt32ValueFromArray(data, visualbase); const ItemPrototype * proto = objmgr.GetItemPrototype(item_id); + if(!proto) + { + *p_data << uint32(0); + *p_data << uint8(0); + *p_data << uint32(0); + continue; + } + SpellItemEnchantmentEntry const *enchant = NULL; + uint32 enchants = GetUInt32ValueFromArray(data, visualbase + 1); for(uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot) { - uint32 enchantId = GetUInt16Value(visualbase + 1, enchantSlot); + // values stored in 2 uint16 + uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot*16); + if(!enchantId) + continue; + if(enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId)) break; } - if (proto != NULL) - { - *p_data << uint32(proto->DisplayInfoID); - *p_data << uint8(proto->InventoryType); - *p_data << uint32(enchant ? enchant->aura_id : 0); - } - else - { - *p_data << uint32(0); - *p_data << uint8(0); - *p_data << uint32(0); // enchant? - } + *p_data << uint32(proto->DisplayInfoID); + *p_data << uint8(proto->InventoryType); + *p_data << uint32(enchant ? enchant->aura_id : 0); } *p_data << uint32(0); // first bag display id *p_data << uint8(0); // first bag inventory type *p_data << uint32(0); // enchant? + + return true; } bool Player::ToggleAFK() @@ -1611,6 +1620,27 @@ void Player::SendTeleportAckMsg() GetSession()->SendPacket(&data); } +void Player::TeleportOutOfMap(Map *oldMap) +{ + while(IsBeingTeleportedFar()) + GetSession()->HandleMoveWorldportAckOpcode(); + + if(FindMap() != oldMap) + return; + + TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); + + while(IsBeingTeleportedFar()) + GetSession()->HandleMoveWorldportAckOpcode(); + + if(FindMap() == oldMap) + { + sLog.outCrash("Cannot teleport player out of map!"); + ResetMap(); + assert(false); + } +} + bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options) { if(!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) @@ -1683,6 +1713,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if ((GetMapId() == mapid) && (!m_transport)) { + //lets reset far teleport flag if it wasn't reset during chained teleports + SetSemaphoreTeleportFar(false); + //setup delayed teleport flag + SetDelayedTeleportFlag(IsCanDelayTeleport()); + //if teleport spell is casted in Unit::Update() func + //then we need to delay it until update process will be finished + if(IsHasDelayedTeleport()) + { + SetSemaphoreTeleportNear(true); + //lets save teleport destination for player + m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); + m_teleport_options = options; + return true; + } + if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { //same map, only remove pet if out of range for new position @@ -1697,7 +1742,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); SetFallInformation(0, z); - // code for finish transfer called in WorldSession::HandleMovementOpcodes() + // code for finish transfer called in WorldSession::HandleMovementOpcodes() // at client packet MSG_MOVE_TELEPORT_ACK SetSemaphoreTeleportNear(true); // near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing @@ -1712,6 +1757,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati } else { + if(getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !isGameMaster() + && !IsActiveQuest(13165)) + return false; + // far teleport to another map Map* oldmap = IsInWorld() ? GetMap() : NULL; // check if we can enter before stopping combat / removing pet / totems / interrupting spells @@ -1726,6 +1775,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati Map *map = MapManager::Instance().FindMap(mapid); if (!map || map->CanEnter(this)) { + //lets reset near teleport flag if it wasn't reset during chained teleports + SetSemaphoreTeleportNear(false); + //setup delayed teleport flag + SetDelayedTeleportFlag(IsCanDelayTeleport()); + //if teleport spell is casted in Unit::Update() func + //then we need to delay it until update process will be finished + if(IsHasDelayedTeleport()) + { + SetSemaphoreTeleportFar(true); + //lets save teleport destination for player + m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); + m_teleport_options = options; + return true; + } + SetSelection(0); CombatStop(); @@ -1755,6 +1819,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if(IsNonMeleeSpellCasted(true)) InterruptNonMeleeSpells(true); + //remove auras before removing from map... + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); + if(!GetSession()->PlayerLogout()) { // send transfer packets @@ -1801,8 +1868,6 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // if the player is saved before worldportack (at logout for example) // this will be used instead of the current location in SaveToDB - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); - // move packet sent by client always after far teleport // code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet SetSemaphoreTeleportFar(true); @@ -1813,6 +1878,53 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati return true; } +void Player::ProcessDelayedOperations() +{ + if(m_DelayedOperations == 0) + return; + + if(m_DelayedOperations & DELAYED_RESURRECT_PLAYER) + { + ResurrectPlayer(0.0f, false); + + if(GetMaxHealth() > m_resurrectHealth) + SetHealth( m_resurrectHealth ); + else + SetHealth( GetMaxHealth() ); + + if(GetMaxPower(POWER_MANA) > m_resurrectMana) + SetPower(POWER_MANA, m_resurrectMana ); + else + SetPower(POWER_MANA, GetMaxPower(POWER_MANA) ); + + SetPower(POWER_RAGE, 0 ); + SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) ); + + SpawnCorpseBones(); + } + + if(m_DelayedOperations & DELAYED_SAVE_PLAYER) + { + SaveToDB(); + } + + if(m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER) + { + CastSpell(this, 26013, true); // Deserter + } + + //we have executed ALL delayed ops, so clear the flag + m_DelayedOperations = 0; +} + +void Player::ScheduleDelayedOperation(uint32 operation) +{ + if(operation >= DELAYED_END) + return; + + m_DelayedOperations |= operation; +} + void Player::AddToWorld() { ///- Do not add/remove the player from the object storage @@ -1863,33 +1975,6 @@ void Player::RemoveFromWorld() } } -void Player::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ) -{ - float addRage; - - float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911; - - if(attacker) - { - addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2); - - // talent who gave more rage on attack - addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f; - } - else - { - addRage = damage/rageconversion*2.5; - - // Berserker Rage effect - if(HasAura(18499)) - addRage *= 1.3; - } - - addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME); - - ModifyPower(POWER_RAGE, uint32(addRage*10)); -} - void Player::RegenerateAll() { if (m_regenTimer != 0) @@ -2372,9 +2457,12 @@ void Player::GiveLevel(uint32 level) SetUInt32Value(PLAYER_NEXT_LEVEL_XP, objmgr.GetXPForLevel(level)); //update level, max level of skills - if(getLevel()!= level) - m_Played_time[1] = 0; // Level Played Time reset + m_Played_time[PLAYED_TIME_LEVEL] = 0; // Level Played Time reset + + _ApplyAllLevelScaleItemMods(false); + SetLevel(level); + UpdateSkillsForLevel (); // save base values (bonuses already included in stored stats @@ -2402,6 +2490,8 @@ void Player::GiveLevel(uint32 level) SetPower(POWER_FOCUS, 0); SetPower(POWER_HAPPINESS, 0); + _ApplyAllLevelScaleItemMods(true); + // update level to hunter/summon pet if (Pet* pet = GetPet()) pet->SynchronizeLevelWithOwner(); @@ -2603,7 +2693,7 @@ void Player::InitStatsForLevel(bool reapplyMods) void Player::SendInitialSpells() { time_t curTime = time(NULL); - time_t infTime = curTime + MONTH/2; + time_t infTime = curTime + infinityCooldownDelayCheck; uint16 spellCount = 0; @@ -2637,18 +2727,21 @@ void Player::SendInitialSpells() if(!sEntry) continue; - // not send infinity cooldown - if(itr->second.end > infTime) - continue; - data << uint32(itr->first); - time_t cooldown = 0; - if(itr->second.end > curTime) - cooldown = (itr->second.end-curTime)*IN_MILISECONDS; - data << uint16(itr->second.itemid); // cast item id data << uint16(sEntry->Category); // 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_MILISECONDS : 0; + if(sEntry->Category) // may be wrong, but anyway better than nothing... { data << uint32(0); // cooldown @@ -2897,7 +2990,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if(!rankSpellId || rankSpellId==spell_id) continue; - removeSpell(rankSpellId); + removeSpell(rankSpellId,false,false); } } } @@ -3125,7 +3218,6 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const switch(spellInfo->Id) { // some spells not have stance data expected cast at form change or present - case 5420: need_cast = (m_form == FORM_TREE); break; case 5419: need_cast = (m_form == FORM_TRAVEL); break; case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break; case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break; @@ -3173,7 +3265,7 @@ void Player::learnSpell(uint32 spell_id, bool dependent) GetSession()->SendPacket(&data); } -void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_for_low_rank) +void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank) { PlayerSpellMap::iterator itr = m_spells.find(spell_id); if (itr == m_spells.end()) @@ -3193,7 +3285,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_ SpellsRequiringSpellMap const& reqMap = spellmgr.GetSpellsRequiringSpell(); SpellsRequiringSpellMap::const_iterator itr2 = reqMap.find(spell_id); for (uint32 i=reqMap.count(spell_id);i>0;i--,itr2++) - removeSpell(itr2->second,disabled); + removeSpell(itr2->second,disabled,false); // re-search, it can be corrupted in prev loop itr = m_spells.find(spell_id); @@ -3223,8 +3315,9 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_ RemoveAurasDueToSpell(spell_id); // remove pet auras - if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id)) - RemovePetAura(petSpell); + for(int i = 0; i < MAX_SPELL_EFFECTS; ++i) + if(PetAura const* petSpell = spellmgr.GetPetAura(spell_id, i)) + RemovePetAura(petSpell); // free talent points uint32 talentCosts = GetTalentSpellCost(spell_id); @@ -3321,15 +3414,17 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_ { SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); - // if talent then lesser rank also talent and need learn + // if talent then lesser rank also talent and need learn if(talentCosts) { - //learnSpell (prev_id,false); + // I cannot see why mangos has these lines. + //if(learn_low_rank) + // learnSpell (prev_id,false); } - // if ranked non-stackable spell: need activate lesser rank and update dendence state + // if ranked non-stackable spell: need activate lesser rank and update dendence state else if(cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) { - // need manually update dependence state (learn spell ignore like attempts) + // need manually update dependence state (learn spell ignore like attempts) PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id); if (prev_itr != m_spells.end()) { @@ -3341,19 +3436,16 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_ } // now re-learn if need re-activate - if(cur_active && !prev_itr->second->active) + if(cur_active && !prev_itr->second->active && learn_low_rank) { if(addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled)) { - if(update_action_bar_for_low_rank) - { - // downgrade spell ranks in spellbook and action bar - WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); - data << uint32(spell_id); - data << uint32(prev_id); - GetSession()->SendPacket( &data ); - prev_activate = true; - } + // downgrade spell ranks in spellbook and action bar + WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); + data << uint32(spell_id); + data << uint32(prev_id); + GetSession()->SendPacket( &data ); + prev_activate = true; } } } @@ -3374,14 +3466,10 @@ void Player::RemoveSpellCooldown( uint32 spell_id, bool update /* = false */ ) m_spellCooldowns.erase(spell_id); if(update) - { - WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8); - data << uint32(spell_id); - data << uint64(GetGUID()); - SendDirectMessage(&data); - } + SendClearCooldown(spell_id, this); } +// I am not sure which one is more efficient void Player::RemoveCategoryCooldown( uint32 cat ) { SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat); @@ -3390,6 +3478,22 @@ void Player::RemoveCategoryCooldown( uint32 cat ) RemoveSpellCooldown(*i_scset, true); } +void Player::RemoveSpellCategoryCooldown(uint32 cat, bool update /* = false */) +{ + SpellCategoryStore::const_iterator ct = sSpellCategoryStore.find(cat); + if (ct == sSpellCategoryStore.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() { // remove cooldowns on spells that has < 15 min CD @@ -3405,13 +3509,8 @@ void Player::RemoveArenaSpellCooldowns() entry->RecoveryTime <= 15 * MINUTE * IN_MILISECONDS && entry->CategoryRecoveryTime <= 15 * MINUTE * IN_MILISECONDS ) { - // notify player - WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8); - data << uint32(itr->first); - data << uint64(GetGUID()); - GetSession()->SendPacket(&data); - // remove cooldown - m_spellCooldowns.erase(itr); + // remove & notify + RemoveSpellCooldown(itr->first, true); } } } @@ -3421,12 +3520,8 @@ void Player::RemoveAllSpellCooldown() if(!m_spellCooldowns.empty()) { for(SpellCooldowns::const_iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); ++itr) - { - WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8); - data << uint32(itr->first); - data << uint64(GetGUID()); - GetSession()->SendPacket(&data); - } + SendClearCooldown(itr->first, this); + m_spellCooldowns.clear(); } } @@ -3451,7 +3546,7 @@ void Player::_LoadSpellCooldowns(QueryResult *result) if(!sSpellStore.LookupEntry(spell_id)) { - sLog.outError("Player %u have unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id); + sLog.outError("Player %u has unknown spell %u in `character_spell_cooldown`, skipping.",GetGUIDLow(),spell_id); continue; } @@ -3474,7 +3569,7 @@ void Player::_SaveSpellCooldowns() CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow()); time_t curTime = time(NULL); - time_t infTime = curTime + MONTH/2; + time_t infTime = curTime + infinityCooldownDelayCheck; // remove outdated and save active for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();) @@ -3528,10 +3623,7 @@ bool Player::resetTalents(bool no_cost) { // not need after this call if(HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) - { - m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_TALENTS; - CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_TALENTS), GetGUIDLow()); - } + RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS,true); uint32 talentPointsForLevel = CalculateTalentsPoints(); @@ -3585,7 +3677,13 @@ bool Player::resetTalents(bool no_cost) uint32 itrFirstId = spellmgr.GetFirstSpellInChain(itr->first); // unlearn if first rank is talent or learned by talent - if (itrFirstId == talentInfo->RankID[j] || spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId)) + if (itrFirstId == talentInfo->RankID[j]) + { + removeSpell(itr->first,!IsPassiveSpell(itr->first),false); + itr = GetSpellMap().begin(); + continue; + } + else if (spellmgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId)) { removeSpell(itr->first,!IsPassiveSpell(itr->first)); itr = GetSpellMap().begin(); @@ -3791,9 +3889,9 @@ void Player::BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) Unit::BuildCreateUpdateBlockForPlayer( data, target ); } -void Player::DestroyForPlayer( Player *target ) const +void Player::DestroyForPlayer( Player *target, bool anim ) const { - Unit::DestroyForPlayer( target ); + Unit::DestroyForPlayer( target, anim ); for(uint8 i = 0; i < INVENTORY_SLOT_BAG_END; i++) { @@ -4036,7 +4134,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC CharacterDatabase.PExecute("DELETE FROM character_equipmentsets WHERE guid = '%u'",guid); CharacterDatabase.CommitTransaction(); - //LoginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID); + //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID); if(updateRealmChars) sWorld.UpdateRealmCharCount(accountId); } @@ -4458,7 +4556,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g uint32 dmultiplier = dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class,ditemProto->SubClass)]; uint32 costs = uint32(LostDurability*dmultiplier*double(dQualitymodEntry->quality_mod)); - costs = uint32(costs * discountMod); + costs = uint32(costs * discountMod) * sWorld.getRate(RATE_REPAIRCOST); if (costs==0) //fix for ITEM_QUALITY_ARTIFACT costs = 1; @@ -5214,6 +5312,9 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType) if(m_form == FORM_TREE) return; // use weapon but not skill up + if(pVictim && pVictim->GetTypeId() == TYPEID_UNIT && (((Creature*)pVictim)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_SKILLGAIN)) + return; + uint32 weapon_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_WEAPON); switch(attType) @@ -5557,65 +5658,69 @@ void Player::SendInitialActionButtons() const sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() ); WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4)); - data << uint8(0); // can be 0, 1, 2 + data << uint8(0); // can be 0, 1, 2 (talent spec) for(int button = 0; button < MAX_ACTION_BUTTONS; ++button) { ActionButtonList::const_iterator itr = m_actionButtons.find(button); if(itr != m_actionButtons.end() && itr->second.uState != ACTIONBUTTON_DELETED) - { - data << uint16(itr->second.action); - data << uint8(itr->second.misc); - data << uint8(itr->second.type); - } + data << uint32(itr->second.packedData); else - { data << uint32(0); - } } GetSession()->SendPacket( &data ); sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() ); } -bool Player::addActionButton(const uint8 button, const uint16 action, const uint8 type, const uint8 misc) +ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type) { if(button >= MAX_ACTION_BUTTONS) { sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() ); - return false; + return NULL; } - // check cheating with adding non-known spells to action bar - if(type==ACTION_BUTTON_SPELL) + if(action >= MAX_ACTION_BUTTON_ACTION_VALUE) { - if(!sSpellStore.LookupEntry(action)) - { - sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() ); - return false; - } - - if(!HasSpell(action)) - { - sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() ); - return false; - } + sLog.outError( "Action %u not added into button %u for player %s: action must be < %u", action, button, GetName(), MAX_ACTION_BUTTON_ACTION_VALUE ); + return NULL; } - ActionButtonList::iterator buttonItr = m_actionButtons.find(button); + switch(type) + { + case ACTION_BUTTON_SPELL: + if(!sSpellStore.LookupEntry(action)) + { + sLog.outError( "Action %u not added into button %u for player %s: spell not exist", action, button, GetName() ); + return NULL; + } - if (buttonItr==m_actionButtons.end()) - { // just add new button - m_actionButtons[button] = ActionButton(action,type,misc); + if(!HasSpell(action)) + { + sLog.outError( "Action %u not added into button %u for player %s: player don't known this spell", action, button, GetName() ); + return NULL; + } + break; + case ACTION_BUTTON_ITEM: + if(!objmgr.GetItemPrototype(action)) + { + sLog.outError( "Action %u not added into button %u for player %s: item not exist", action, button, GetName() ); + return NULL; + } + break; + default: + break; // pther cases not checked at this moment } - else - { // change state of current button - ActionButtonUpdateState uState = buttonItr->second.uState; - buttonItr->second = ActionButton(action,type,misc); - if (uState != ACTIONBUTTON_NEW) buttonItr->second.uState = ACTIONBUTTON_CHANGED; - }; - sLog.outDetail( "Player '%u' Added Action '%u' to Button '%u'", GetGUIDLow(), action, button ); - return true; + + // it create new button (NEW state) if need or return existed + ActionButton& ab = m_actionButtons[button]; + + // set data and update to CHANGED if not NEW + ab.SetActionAndType(action,ActionButtonType(type)); + + sLog.outDetail( "Player '%u' Added Action '%u' (type %u) to Button '%u'", GetGUIDLow(), action, uint32(type), button ); + return &ab; } void Player::removeActionButton(uint8 button) @@ -5883,7 +5988,7 @@ int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, in if (percent <= 0.0f) return 0; - return int32(rep*percent*0.01f); + return int32(rep*percent)/100; } //Calculates how many reputation points player gains in victim's enemy factions @@ -6010,7 +6115,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt } // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if(GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) + if(HasAura(SPELL_AURA_PLAYER_INACTIVE)) return false; uint64 victim_guid = 0; @@ -6259,6 +6364,19 @@ uint32 Player::GetZoneIdFromDB(uint64 guid) return zone; } +uint32 Player::GetLevelFromDB(uint64 guid) +{ + QueryResult *result = CharacterDatabase.PQuery( "SELECT level FROM characters WHERE guid='%u'", GUID_LOPART(guid) ); + if (!result) + return 0; + + Field* fields = result->Fetch(); + uint32 level = fields[0].GetUInt32(); + delete result; + + return level; +} + void Player::UpdateArea(uint32 newArea) { // FFA_PVP flags are area and not zone id dependent @@ -6328,10 +6446,11 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) } pvpInfo.inNoPvPArea = false; - if((zone->flags & AREA_FLAG_SANCTUARY) || zone->mapid == 609) // in sanctuary + if(zone->IsSanctuary()) // in sanctuary { SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); pvpInfo.inNoPvPArea = true; + CombatStopWithPets(); } else { @@ -6456,22 +6575,6 @@ void Player::DuelComplete(DuelCompleteType type) duel->opponent->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1); } - // cool-down duel spell - /*data.Initialize(SMSG_SPELL_COOLDOWN, 17); - - data<<GetGUID(); - data<<uint8(0x0); - - data<<(uint32)7266; - data<<uint32(0x0); - GetSession()->SendPacket(&data); - data.Initialize(SMSG_SPELL_COOLDOWN, 17); - data<<duel->opponent->GetGUID(); - data<<uint8(0x0); - data<<(uint32)7266; - data<<uint32(0x0); - duel->opponent->GetSession()->SendPacket(&data);*/ - //Remove Duel Flag object GameObject* obj = GetMap()->GetGameObject(GetUInt64Value(PLAYER_DUEL_ARBITER)); if(obj) @@ -6568,13 +6671,16 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply) sLog.outDebug("_ApplyItemMods complete."); } -void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply) +void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply, bool only_level_scale /*= false*/) { if(slot >= INVENTORY_SLOT_BAG_END || !proto) return; - ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : 0; - ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : 0; + ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : NULL; + ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : NULL; + + if(only_level_scale && !(ssd && ssv)) + return; for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) { @@ -6755,7 +6861,8 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl } // Add armor bonus from ArmorDamageModifier if > 0 if (proto->ArmorDamageModifier > 0) - armor+=proto->ArmorDamageModifier; + armor += uint32(proto->ArmorDamageModifier); + if (armor) HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply); @@ -7015,17 +7122,48 @@ void Player::UpdateEquipSpellsAtFormChange() } } } - -void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPrototype const * proto) +void Player::CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx) { - Unit * Target = damageInfo->target; - WeaponAttackType attType = damageInfo->attackType; - - if (!Target || Target == this ) + if(!target || !target->isAlive() || target == this) return; + for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) + { + // If usable, try to cast item spell + if (Item * item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i)) + if(!item->IsBroken()) + if (ItemPrototype const *proto = item->GetProto()) + { + // Additional check for weapons + if (proto->Class==ITEM_CLASS_WEAPON) + { + // offhand item cannot proc from main hand hit etc + EquipmentSlots slot; + switch (attType) + { + case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break; + case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break; + case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break; + default: slot = EQUIPMENT_SLOT_END; break; + } + if (slot != i) + continue; + // Check if item is useable (forms or disarm) + if (attType == BASE_ATTACK) + { + if (!((Player*)this)->IsUseEquipedWeapon(true)) + continue; + } + } + ((Player*)this)->CastItemCombatSpell(target, attType, procVictim, procEx, item, proto); + } + } +} + +void Player::CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item *item, ItemPrototype const * proto) +{ // Can do effect if any damage done to target - if (damageInfo->damage) + if (procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE) //if (damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE) { for (int i = 0; i < 5; i++) @@ -7048,7 +7186,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro } // not allow proc extra attack spell at extra attack - if( m_extraAttacks && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) + if( m_extraAttacks && IsSpellHaveEffect(spellInfo, SPELL_EFFECT_ADD_EXTRA_ATTACKS) ) return; float chance = spellInfo->procChance; @@ -7064,7 +7202,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro } if (roll_chance_f(chance)) - CastSpell(Target, spellInfo->Id, true, item); + CastSpell(target, spellInfo->Id, true, item); } } @@ -7084,13 +7222,13 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro if (entry && entry->procEx) { // Check hit/crit/dodge/parry requirement - if((entry->procEx & damageInfo->procEx) == 0) + if((entry->procEx & procEx) == 0) continue; } else { // Can do effect if any damage done to target - if (!(damageInfo->damage)) + if (!(procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)) //if (!(damageInfo->procVictim & PROC_FLAG_TAKEN_ANY_DAMAGE)) continue; } @@ -7105,10 +7243,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro float chance = pEnchant->amount[s] != 0 ? float(pEnchant->amount[s]) : GetWeaponProcChance(); if (entry && entry->PPMChance) - { - uint32 WeaponSpeed = GetAttackTime(attType); - chance = GetPPMProcChance(WeaponSpeed, entry->PPMChance, spellInfo); - } + chance = GetPPMProcChance(proto->Delay, entry->PPMChance, spellInfo); else if (entry && entry->customChance) chance = entry->customChance; @@ -7120,7 +7255,7 @@ void Player::CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPro if(IsPositiveSpell(pEnchant->spellid[s])) CastSpell(this, pEnchant->spellid[s], true, item); else - CastSpell(Target, pEnchant->spellid[s], true, item); + CastSpell(target, pEnchant->spellid[s], true, item); } } } @@ -7309,6 +7444,24 @@ void Player::_ApplyAllItemMods() sLog.outDebug("_ApplyAllItemMods complete."); } +void Player::_ApplyAllLevelScaleItemMods(bool apply) +{ + for (int i = 0; i < INVENTORY_SLOT_BAG_END; ++i) + { + if(m_items[i]) + { + if(m_items[i]->IsBroken()) + continue; + + ItemPrototype const *proto = m_items[i]->GetProto(); + if(!proto) + continue; + + _ApplyItemBonuses(proto,i, apply, true); + } + } +} + void Player::_ApplyAmmoBonuses() { // check ammo @@ -7434,7 +7587,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (go->getLootState() == GO_READY) { - uint32 lootid = go->GetLootId(); + uint32 lootid = go->GetGOInfo()->GetLootId(); //TODO: fix this big hack if((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S)) @@ -9040,39 +9193,42 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV Item* pItem2 = GetItemByPos( bag, slot ); // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) + if (pItem2==pSrcItem) pItem2 = NULL; uint32 need_space; // empty specific slot - check item fit to slot - if( !pItem2 || swap ) + if (!pItem2 || swap) { - if( bag == INVENTORY_SLOT_BAG_0 ) + if (bag == INVENTORY_SLOT_BAG_0) { // keyring case - if(slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)) + if (slot >= KEYRING_SLOT_START && slot < KEYRING_SLOT_START+GetMaxKeyringSize() && !(pProto->BagFamily & BAG_FAMILY_MASK_KEYS)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; // currencytoken case - if(slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)) + if (slot >= CURRENCYTOKEN_SLOT_START && slot < CURRENCYTOKEN_SLOT_END && !(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; // prevent cheating - if(slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END) + if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END || slot >= PLAYER_SLOT_END) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; } else { Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); - if( !pBag ) + if (!pBag) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; ItemPrototype const* pBagProto = pBag->GetProto(); - if( !pBagProto ) + if (!pBagProto) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - if( !ItemCanGoIntoBag(pProto,pBagProto) ) + if (slot >= pBagProto->ContainerSlots) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + + if (!ItemCanGoIntoBag(pProto,pBagProto)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; } @@ -9083,22 +9239,22 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV else { // check item type - if(pItem2->GetEntry() != pProto->ItemId) + if (pItem2->GetEntry() != pProto->ItemId) return EQUIP_ERR_ITEM_CANT_STACK; // check free space - if(pItem2->GetCount() >= pProto->GetMaxStackSize()) + if (pItem2->GetCount() >= pProto->GetMaxStackSize()) return EQUIP_ERR_ITEM_CANT_STACK; // free stack space or infinity need_space = pProto->GetMaxStackSize() - pItem2->GetCount(); } - if(need_space > count) + if (need_space > count) need_space = count; ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space); - if(!newPosition.isContainedIn(dest)) + if (!newPosition.isContainedIn(dest)) { dest.push_back(newPosition); count -= need_space; @@ -9109,55 +9265,55 @@ uint8 Player::_CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountV uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot ) const { // skip specific bag already processed in first called _CanStoreItem_InBag - if(bag==skip_bag) + if (bag==skip_bag) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag ); - if( !pBag ) + if (!pBag) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; ItemPrototype const* pBagProto = pBag->GetProto(); - if( !pBagProto ) + if (!pBagProto) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; // specialized bag mode or non-specilized - if( non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER) ) + if (non_specialized != (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - if( !ItemCanGoIntoBag(pProto,pBagProto) ) + if (!ItemCanGoIntoBag(pProto,pBagProto)) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; for(uint32 j = 0; j < pBag->GetBagSize(); j++) { // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot - if(j==skip_slot) + if (j==skip_slot) continue; Item* pItem2 = GetItemByPos( bag, j ); // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) + if (pItem2==pSrcItem) pItem2 = NULL; // if merge skip empty, if !merge skip non-empty - if((pItem2!=NULL)!=merge) + if ((pItem2!=NULL)!=merge) continue; - if( pItem2 ) + if (pItem2) { - if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize()) + if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize()) { uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount(); if(need_space > count) need_space = count; ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) + if (!newPosition.isContainedIn(dest)) { dest.push_back(newPosition); count -= need_space; - if(count==0) + if (count==0) return EQUIP_ERR_OK; } } @@ -9165,16 +9321,16 @@ uint8 Player::_CanStoreItem_InBag( uint8 bag, ItemPosCountVec &dest, ItemPrototy else { uint32 need_space = pProto->GetMaxStackSize(); - if(need_space > count) + if (need_space > count) need_space = count; ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) + if (!newPosition.isContainedIn(dest)) { dest.push_back(newPosition); count -= need_space; - if(count==0) + if (count==0) return EQUIP_ERR_OK; } } @@ -9187,33 +9343,33 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, for(uint32 j = slot_begin; j < slot_end; j++) { // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot - if(INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot) + if (INVENTORY_SLOT_BAG_0==skip_bag && j==skip_slot) continue; Item* pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, j ); // ignore move item (this slot will be empty at move) - if(pItem2==pSrcItem) + if (pItem2==pSrcItem) pItem2 = NULL; // if merge skip empty, if !merge skip non-empty - if((pItem2!=NULL)!=merge) + if ((pItem2!=NULL)!=merge) continue; - if( pItem2 ) + if (pItem2) { - if(pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize()) + if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize()) { uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount(); - if(need_space > count) + if (need_space > count) need_space = count; ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) + if (!newPosition.isContainedIn(dest)) { dest.push_back(newPosition); count -= need_space; - if(count==0) + if (count==0) return EQUIP_ERR_OK; } } @@ -9221,16 +9377,16 @@ uint8 Player::_CanStoreItem_InInventorySlots( uint8 slot_begin, uint8 slot_end, else { uint32 need_space = pProto->GetMaxStackSize(); - if(need_space > count) + if (need_space > count) need_space = count; ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); - if(!newPosition.isContainedIn(dest)) + if (!newPosition.isContainedIn(dest)) { dest.push_back(newPosition); count -= need_space; - if(count==0) + if (count==0) return EQUIP_ERR_OK; } } @@ -9243,16 +9399,16 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 sLog.outDebug( "STORAGE: CanStoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, entry, count); ItemPrototype const *pProto = objmgr.GetItemPrototype(entry); - if( !pProto ) + if (!pProto) { - if(no_space_count) + if (no_space_count) *no_space_count = count; return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND; } - if(pItem && pItem->IsBindedNotWith(this)) + if (pItem && pItem->IsBindedNotWith(this)) { - if(no_space_count) + if (no_space_count) *no_space_count = count; return EQUIP_ERR_DONT_OWN_THAT_ITEM; } @@ -9260,11 +9416,11 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 // check count of items (skip for auto move for same player from bank) uint32 no_similar_count = 0; // can't store this amount similar items uint8 res = _CanTakeMoreSimilarItems(entry,count,pItem,&no_similar_count); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(count==no_similar_count) + if (count==no_similar_count) { - if(no_space_count) + if (no_space_count) *no_space_count = no_similar_count; return res; } @@ -9272,22 +9428,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 } // in specific slot - if( bag != NULL_BAG && slot != NULL_SLOT ) + if (bag != NULL_BAG && slot != NULL_SLOT) { res = _CanStoreItem_InSpecificSlot(bag,slot,dest,pProto,count,swap,pItem); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9296,45 +9452,45 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 // not specific slot or have space for partly store only in specific slot // in specific bag - if( bag != NULL_BAG ) + if (bag != NULL_BAG) { // search stack in bag for merge to - if( pProto->Stackable != 1 ) + if (pProto->Stackable != 1) { - if( bag == INVENTORY_SLOT_BAG_0 ) // inventory + if (bag == INVENTORY_SLOT_BAG_0) // inventory { res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9343,22 +9499,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 { // we need check 2 time (specialized/non_specialized), use NULL_BAG to prevent skipping bag res = _CanStoreItem_InBag(bag,dest,pProto,count,true,false,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) res = _CanStoreItem_InBag(bag,dest,pProto,count,true,true,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9366,83 +9522,83 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 } // search free slot in bag for place to - if( bag == INVENTORY_SLOT_BAG_0 ) // inventory + if(bag == INVENTORY_SLOT_BAG_0) // inventory { // search free slot - keyring case - if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) + if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS) { uint32 keyringSize = GetMaxKeyringSize(); res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } - else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) + else if (pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) { res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9450,22 +9606,22 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 else // equipped bag { res = _CanStoreItem_InBag(bag,dest,pProto,count,false,false,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) res = _CanStoreItem_InBag(bag,dest,pProto,count,false,true,pItem,NULL_BAG,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9475,58 +9631,58 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 // not specific bag or have space for partly store only in specific bag // search stack for merge to - if( pProto->Stackable != 1 ) + if (pProto->Stackable != 1) { res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } - if( pProto->BagFamily ) + if (pProto->BagFamily) { for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { res = _CanStoreItem_InBag(i,dest,pProto,count,true,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) continue; - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9536,15 +9692,15 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { res = _CanStoreItem_InBag(i,dest,pProto,count,true,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) continue; - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9552,45 +9708,45 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 } // search free slot - special bag case - if( pProto->BagFamily ) + if (pProto->BagFamily) { - if(pProto->BagFamily & BAG_FAMILY_MASK_KEYS) + if (pProto->BagFamily & BAG_FAMILY_MASK_KEYS) { uint32 keyringSize = GetMaxKeyringSize(); res = _CanStoreItem_InInventorySlots(KEYRING_SLOT_START,KEYRING_SLOT_START+keyringSize,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } - else if(pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) + else if (pProto->BagFamily & BAG_FAMILY_MASK_CURRENCY_TOKENS) { res = _CanStoreItem_InInventorySlots(CURRENCYTOKEN_SLOT_START,CURRENCYTOKEN_SLOT_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9599,15 +9755,15 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 for(uint32 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { res = _CanStoreItem_InBag(i,dest,pProto,count,false,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) continue; - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9616,19 +9772,19 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 // search free slot res = _CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START,INVENTORY_SLOT_ITEM_END,dest,pProto,count,false,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) { - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return res; } - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } @@ -9636,21 +9792,21 @@ uint8 Player::_CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, uint3 for(uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { res = _CanStoreItem_InBag(i,dest,pProto,count,false,true,pItem,bag,slot); - if(res!=EQUIP_ERR_OK) + if (res!=EQUIP_ERR_OK) continue; - if(count==0) + if (count==0) { - if(no_similar_count==0) + if (no_similar_count==0) return EQUIP_ERR_OK; - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; } } - if(no_space_count) + if (no_space_count) *no_space_count = count + no_similar_count; return EQUIP_ERR_INVENTORY_FULL; @@ -10378,7 +10534,7 @@ uint8 Player::CanUseAmmo( uint32 item ) const return EQUIP_ERR_CANT_EQUIP_LEVEL_I; // Requires No Ammo - if(GetDummyAura(46699)) + if(HasAura(46699)) return EQUIP_ERR_BAG_FULL6; return EQUIP_ERR_OK; @@ -10474,7 +10630,7 @@ Item* Player::_StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, boo uint8 bag = pos >> 8; uint8 slot = pos & 255; - sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), count); + sLog.outDebug( "STORAGE: StoreItem bag = %u, slot = %u, item = %u, count = %u, guid = %u", bag, slot, pItem->GetEntry(), count, pItem->GetGUIDLow()); Item *pItem2 = GetItemByPos( bag, slot ); @@ -10581,7 +10737,6 @@ Item* Player::EquipNewItem( uint16 pos, uint32 item, bool update ) Item* Player::EquipItem( uint16 pos, Item *pItem, bool update ) { - AddEnchantmentDurations(pItem); AddItemDurations(pItem); @@ -12311,7 +12466,11 @@ void Player::PrepareQuestMenu( uint64 guid ) } else { - GameObject *pGameObject = GetMap()->GetGameObject(guid); + //we should obtain map pointer from GetMap() in 99% of cases. Special case + //only for quests which cast teleport spells on player + Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); + ASSERT(_map); + GameObject *pGameObject = _map->GetGameObject(guid); if( pGameObject ) { pObject = (Object*)pGameObject; @@ -12333,8 +12492,8 @@ void Player::PrepareQuestMenu( uint64 guid ) qm.AddMenuItem(quest_id, DIALOG_STATUS_UNK2); else if ( status == QUEST_STATUS_INCOMPLETE ) qm.AddMenuItem(quest_id, DIALOG_STATUS_UNK2); - else if (status == QUEST_STATUS_AVAILABLE ) - qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT); + //else if (status == QUEST_STATUS_AVAILABLE ) + // qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT); } for(QuestRelations::const_iterator i = pObjectQR->lower_bound(pObject->GetEntry()); i != pObjectQR->upper_bound(pObject->GetEntry()); ++i) @@ -12464,7 +12623,11 @@ Quest const * Player::GetNextQuest( uint64 guid, Quest const *pQuest ) } else { - GameObject *pGameObject = GetMap()->GetGameObject(guid); + //we should obtain map pointer from GetMap() in 99% of cases. Special case + //only for quests which cast teleport spells on player + Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); + ASSERT(_map); + GameObject *pGameObject = _map->GetGameObject(guid); if( pGameObject ) { pObject = (Object*)pGameObject; @@ -12746,7 +12909,7 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver ) //starting initial quest script if(questGiver && pQuest->GetQuestStartScript()!=0) - sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this); + GetMap()->ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this); // Some spells applied at quest activation SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true); @@ -12798,11 +12961,15 @@ void Player::IncompleteQuest( uint32 quest_id ) void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce ) { + //this THING should be here to protect code from quest, which cast on player far teleport as a reward + //should work fine, cause far teleport will be executed in Player::Update() + SetCanDelayTeleport(true); + uint32 quest_id = pQuest->GetQuestId(); for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++ ) { - if ( pQuest->ReqItemId[i] ) + if (pQuest->ReqItemId[i]) DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true); } @@ -12810,29 +12977,29 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver // SetTimedQuest( 0 ); m_timedquests.erase(pQuest->GetQuestId()); - if ( pQuest->GetRewChoiceItemsCount() > 0 ) + if (pQuest->GetRewChoiceItemsCount() > 0) { - if( pQuest->RewChoiceItemId[reward] ) + if (uint32 itemId = pQuest->RewChoiceItemId[reward]) { ItemPosCountVec dest; - if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewChoiceItemId[reward], pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK ) + if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, pQuest->RewChoiceItemCount[reward] ) == EQUIP_ERR_OK) { - Item* item = StoreNewItem( dest, pQuest->RewChoiceItemId[reward], true); + Item* item = StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); SendNewItem(item, pQuest->RewChoiceItemCount[reward], true, false); } } } - if ( pQuest->GetRewItemsCount() > 0 ) + if (pQuest->GetRewItemsCount() > 0) { for (uint32 i=0; i < pQuest->GetRewItemsCount(); ++i) { - if( pQuest->RewItemId[i] ) + if (uint32 itemId = pQuest->RewItemId[i]) { ItemPosCountVec dest; - if( CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, pQuest->RewItemId[i], pQuest->RewItemCount[i] ) == EQUIP_ERR_OK ) + if (CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, pQuest->RewItemCount[i] ) == EQUIP_ERR_OK) { - Item* item = StoreNewItem( dest, pQuest->RewItemId[i], true); + Item* item = StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); SendNewItem(item, pQuest->RewItemCount[i], true, false); } } @@ -12841,13 +13008,8 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver RewardReputation( pQuest ); - if( pQuest->GetRewSpellCast() > 0 ) - CastSpell( this, pQuest->GetRewSpellCast(), true); - else if( pQuest->GetRewSpell() > 0) - CastSpell( this, pQuest->GetRewSpell(), true); - uint16 log_slot = FindQuestSlot( quest_id ); - if( log_slot < MAX_QUEST_LOG_SIZE) + if (log_slot < MAX_QUEST_LOG_SIZE) SetQuestSlot(log_slot,0); QuestStatusData& q_status = mQuestStatus[quest_id]; @@ -12855,7 +13017,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver // Not give XP in case already completed once repeatable quest uint32 XP = q_status.m_rewarded ? 0 : uint32(pQuest->XPValue( this )*sWorld.getRate(RATE_XP_QUEST)); - if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) + if (getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) GiveXP( XP , NULL ); else { @@ -12865,33 +13027,33 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver } // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative - if(pQuest->GetRewOrReqMoney()) + if (pQuest->GetRewOrReqMoney()) { ModifyMoney( pQuest->GetRewOrReqMoney() ); - if(pQuest->GetRewOrReqMoney() > 0) + if (pQuest->GetRewOrReqMoney() > 0) GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney()); } // honor reward - if(pQuest->GetRewHonorableKills()) - RewardHonor(NULL, 0, Trinity::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills())); + if (pQuest->GetRewHonorableKills()) + RewardHonor(NULL, 0, MaNGOS::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills())); // title reward - if(pQuest->GetCharTitleId()) + if (pQuest->GetCharTitleId()) { - if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId())) + if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(pQuest->GetCharTitleId())) SetTitle(titleEntry); } - if(pQuest->GetBonusTalents()) + if (pQuest->GetBonusTalents()) { m_questRewardTalentCount+=pQuest->GetBonusTalents(); InitTalentForLevel(); } // Send reward mail - if(pQuest->GetRewMailTemplateId()) + if (pQuest->GetRewMailTemplateId()) { MailMessageType mailType; uint32 senderGuidOrEntry; @@ -12929,9 +13091,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver uint32 max_slot = questMailLoot.GetMaxSlotInLootFor(this); for(uint32 i = 0; mi.size() < MAX_MAIL_ITEMS && i < max_slot; ++i) { - if(LootItem* lootitem = questMailLoot.LootItemInSlot(i,this)) + if (LootItem* lootitem = questMailLoot.LootItemInSlot(i,this)) { - if(Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this)) + if (Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,this)) { item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); @@ -12942,23 +13104,30 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver WorldSession::SendMailTo(this, mailType, MAIL_STATIONERY_NORMAL, senderGuidOrEntry, GetGUIDLow(), "", 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE,pQuest->GetRewMailDelaySecs(),pQuest->GetRewMailTemplateId()); } - if(pQuest->IsDaily()) + if (pQuest->IsDaily()) { SetDailyQuestStatus(quest_id); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST, 1); } - if ( !pQuest->IsRepeatable() ) + if (!pQuest->IsRepeatable()) SetQuestStatus(quest_id, QUEST_STATUS_COMPLETE); else SetQuestStatus(quest_id, QUEST_STATUS_NONE); q_status.m_rewarded = true; + if (q_status.uState != QUEST_NEW) + q_status.uState = QUEST_CHANGED; - if(announce) + if (announce) SendQuestReward( pQuest, XP, questGiver ); - if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED; + // cast spells after mark quest complete (some spells have quest completed state reqyurements in spell_area data) + if (pQuest->GetRewSpellCast() > 0) + CastSpell( this, pQuest->GetRewSpellCast(), true); + else if ( pQuest->GetRewSpell() > 0) + CastSpell( this, pQuest->GetRewSpell(), true); + if (pQuest->GetZoneOrSort() > 0) GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE, pQuest->GetZoneOrSort()); GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); @@ -12990,6 +13159,9 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver if( !HasAura(itr->second->spellId) ) CastSpell(this,itr->second->spellId,true); } + + //lets remove flag for delayed teleports + SetCanDelayTeleport(false); } void Player::FailQuest( uint32 quest_id ) @@ -13657,7 +13829,17 @@ void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count ) UpdateForQuestWorldObjects(); } -void Player::KilledMonster( uint32 entry, uint64 guid ) +void Player::KilledMonster( CreatureInfo const* cInfo, uint64 guid ) +{ + if(cInfo->Entry) + KilledMonsterCredit(cInfo->Entry,guid); + + for(int i = 0; i < MAX_KILL_CREDIT; ++i) + if(cInfo->KillCredit[i]) + KilledMonsterCredit(cInfo->KillCredit[i],guid); +} + +void Player::KilledMonsterCredit( uint32 entry, uint64 guid ) { uint32 addkillcount = 1; GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, entry, addkillcount); @@ -13987,7 +14169,7 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive GetSession()->SendPacket( &data ); if (pQuest->GetQuestCompleteScript() != 0) - sWorld.ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this); + GetMap()->ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this); } void Player::SendQuestFailed( uint32 quest_id ) @@ -14074,8 +14256,8 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid ) bool delete_result = true; if (!result) { - // 0 1 2 3 4 5 6 7 8 9 10 - result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login, zone FROM characters WHERE guid = '%u'",guid); + // 0 1 2 3 4 5 6 7 8 9 10 11 + result = CharacterDatabase.PQuery("SELECT guid, data, name, position_x, position_y, position_z, map, totaltime, leveltime, at_login, zone, level FROM characters WHERE guid = '%u'",guid); if (!result) return false; } @@ -14098,11 +14280,17 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid ) m_name = fields[2].GetCppString(); Relocate(fields[3].GetFloat(),fields[4].GetFloat(),fields[5].GetFloat()); - SetMapId(fields[6].GetUInt32()); + Map *map = MapManager::Instance().CreateMap(fields[6].GetUInt32(), this, 0); + SetMap(map); + + // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE] + // this must help in case next save after mass player load after server startup + m_nextSave = urand(m_nextSave/2,m_nextSave*3/2); + // the instance id is not needed at character enum - m_Played_time[0] = fields[7].GetUInt32(); - m_Played_time[1] = fields[8].GetUInt32(); + m_Played_time[PLAYED_TIME_TOTAL] = fields[7].GetUInt32(); + m_Played_time[PLAYED_TIME_LEVEL] = fields[8].GetUInt32(); m_atLoginFlags = fields[9].GetUInt32(); @@ -14308,8 +14496,8 @@ float Player::GetFloatValueFromDB(uint16 index, uint64 guid) bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) { - //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 [28] [29] 30 31 32 33 34 35 36 37 38 39 40 - //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid); + //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 + //QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", guid); QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM); if(!result) @@ -14336,7 +14524,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) m_name = fields[3].GetCppString(); // check name limitations - if(!ObjectMgr::IsValidName(m_name) || (GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name))) + if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS || + GetSession()->GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(m_name)) { delete result; CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME),guid); @@ -14353,6 +14542,23 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // overwrite possible wrong/corrupted guid SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); + // overwrite some data fields + uint32 bytes0 = GetUInt32Value(UNIT_FIELD_BYTES_0) & 0xFF000000; + bytes0 |= fields[4].GetUInt8(); // race + bytes0 |= fields[5].GetUInt8() << 8; // class + bytes0 |= fields[6].GetUInt8() << 16; // gender + SetUInt32Value(UNIT_FIELD_BYTES_0, bytes0); + + SetUInt32Value(UNIT_FIELD_LEVEL, fields[7].GetUInt8()); + SetUInt32Value(PLAYER_XP, fields[8].GetUInt32()); + SetUInt32Value(PLAYER_FIELD_COINAGE, fields[9].GetUInt32()); + SetUInt32Value(PLAYER_BYTES, fields[10].GetUInt32()); + SetUInt32Value(PLAYER_BYTES_2, fields[11].GetUInt32()); + SetUInt32Value(PLAYER_BYTES_3, (GetUInt32Value(PLAYER_BYTES_3) & ~1) | fields[6].GetUInt8()); + SetUInt32Value(PLAYER_FLAGS, fields[12].GetUInt32()); + + InitDisplayIds(); + // cleanup inventory related item value fields (its will be filled correctly in _LoadInventory) for(uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) { @@ -14373,12 +14579,9 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) sLog.outDebug("Load Basic value of player %s is: ", m_name.c_str()); outDebugValues(); - m_race = fields[4].GetUInt8(); - //Need to call it to initialize m_team (m_team can be calculated from m_race) + //Need to call it to initialize m_team (m_team can be calculated from race) //Other way is to saves m_team into characters table. - setFactionForRace(m_race); - - m_class = fields[5].GetUInt8(); + setFactionForRace(getRace()); // load home bind and check in same time class/race pair, it used later for restore broken positions if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND))) @@ -14389,18 +14592,13 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) InitPrimaryProfessions(); // to max set before any spell loaded - // init saved position, and fix it later if problematic - uint32 transGUID = fields[24].GetUInt32(); - Relocate(fields[6].GetFloat(),fields[7].GetFloat(),fields[8].GetFloat(),fields[10].GetFloat()); - SetMapId(fields[9].GetUInt32()); - SetInstanceId(fields[41].GetFloat()); - SetDifficulty(fields[32].GetUInt32()); // may be changed in _LoadGroup + SetDifficulty(fields[39].GetUInt32()); // may be changed in _LoadGroup _LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP)); _LoadArenaTeamInfo(holder->GetResult(PLAYER_LOGIN_QUERY_LOADARENAINFO)); - uint32 arena_currency = GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY) + fields[33].GetUInt32(); + uint32 arena_currency = GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY) + fields[40].GetUInt32(); if (arena_currency > sWorld.getConfig(CONFIG_MAX_ARENA_POINTS)) arena_currency = sWorld.getConfig(CONFIG_MAX_ARENA_POINTS); @@ -14424,35 +14622,42 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) _LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES)); + // load player map related values + uint32 transGUID = fields[31].GetUInt32(); + Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat()); + uint32 mapId = fields[16].GetUInt32(); + uint32 instanceId = fields[41].GetFloat(); + std::string taxi_nodes = fields[38].GetCppString(); + + MapEntry const * mapEntry = sMapStore.LookupEntry(mapId); if(!IsPositionValid()) { sLog.outError("Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); - RelocateToHomebind(); + RelocateToHomebind(mapId); transGUID = 0; + instanceId = 0; m_movementInfo.t_x = 0.0f; m_movementInfo.t_y = 0.0f; m_movementInfo.t_z = 0.0f; m_movementInfo.t_o = 0.0f; } - - uint32 bgid = fields[34].GetUInt32(); - uint32 bgteam = fields[35].GetUInt32(); - - if(bgid) //saved in BattleGround + // Player was saved in Arena or Bg + else if (mapEntry && mapEntry->IsBattleGroundOrArena()) { - SetBattleGroundEntryPoint(fields[36].GetUInt32(),fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat()); + // Get Entry Point(bg master) or Homebind + SetBattleGroundEntryPoint(fields[43].GetUInt32(),fields[44].GetFloat(),fields[45].GetFloat(),fields[46].GetFloat(),fields[47].GetFloat()); - // check entry point and fix to homebind if need - MapEntry const* mapEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid); - if(!mapEntry || mapEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint)) + MapEntry const* bgEntry = sMapStore.LookupEntry(m_bgEntryPoint.mapid); + if(!bgEntry || bgEntry->Instanceable() || !MapManager::IsValidMapCoord(m_bgEntryPoint)) SetBattleGroundEntryPoint(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ,0.0f); - BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(bgid, BATTLEGROUND_TYPE_NONE); - + // Bg still exists - join it! + BattleGround *currentBg = sBattleGroundMgr.GetBattleGround(instanceId, BATTLEGROUND_TYPE_NONE); if(currentBg && currentBg->IsPlayerInBattleGround(GetGUID())) { + uint32 bgteam = fields[42].GetUInt32(); BattleGroundQueueTypeId bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(currentBg->GetTypeID(), currentBg->GetArenaType()); AddBattleGroundQueueId(bgQueueTypeId); @@ -14465,38 +14670,25 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) SetInviteForBattleGroundQueueType(bgQueueTypeId,currentBg->GetInstanceID()); } + // Bg was not found - go to Entry Point else { + // Do not look for instance if bg not found + instanceId = 0; const WorldLocation& _loc = GetBattleGroundEntryPoint(); - SetMapId(_loc.mapid); + mapId = _loc.mapid; Relocate(_loc.coord_x, _loc.coord_y, _loc.coord_z, _loc.orientation); - //RemoveArenaAuras(true); } } - else + else if (transGUID != 0) { - MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId()); - // if server restart after player save in BG or area - // player can have current coordinates in to BG/Arean map, fix this - if(!mapEntry || mapEntry->IsBattleGroundOrArena()) - { - // return to BG master - SetMapId(fields[36].GetUInt32()); - Relocate(fields[37].GetFloat(),fields[38].GetFloat(),fields[39].GetFloat(),fields[40].GetFloat()); - - // check entry point and fix to homebind if need - mapEntry = sMapStore.LookupEntry(GetMapId()); - if(!mapEntry || mapEntry->IsBattleGroundOrArena() || !IsPositionValid()) - RelocateToHomebind(); - } - } + // There are no transports on instances + instanceId = 0; - if (transGUID != 0) - { - m_movementInfo.t_x = fields[20].GetFloat(); - m_movementInfo.t_y = fields[21].GetFloat(); - m_movementInfo.t_z = fields[22].GetFloat(); - m_movementInfo.t_o = fields[23].GetFloat(); + m_movementInfo.t_x = fields[27].GetFloat(); + m_movementInfo.t_y = fields[28].GetFloat(); + m_movementInfo.t_z = fields[29].GetFloat(); + m_movementInfo.t_o = fields[30].GetFloat(); if( !Trinity::IsValidMapCoord( GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y, @@ -14508,7 +14700,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) guid,GetPositionX()+m_movementInfo.t_x,GetPositionY()+m_movementInfo.t_y, GetPositionZ()+m_movementInfo.t_z,GetOrientation()+m_movementInfo.t_o); - RelocateToHomebind(); + RelocateToHomebind(mapId); m_movementInfo.t_x = 0.0f; m_movementInfo.t_y = 0.0f; @@ -14517,112 +14709,146 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) transGUID = 0; } - } - - if (transGUID != 0) - { - for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) + else { - if( (*iter)->GetGUIDLow() == transGUID) + for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) { - MapEntry const* transMapEntry = sMapStore.LookupEntry((*iter)->GetMapId()); - // client without expansion support - if(GetSession()->Expansion() < transMapEntry->Expansion()) + if( (*iter)->GetGUIDLow() == transGUID) { - sLog.outDebug("Player %s using client without required expansion tried login at transport at non accessible map %u", GetName(), (*iter)->GetMapId()); + m_transport = *iter; + m_transport->AddPassenger(this); + mapId = (m_transport->GetMapId()); break; } - - m_transport = *iter; - m_transport->AddPassenger(this); - SetMapId(m_transport->GetMapId()); - break; } - } - - if(!m_transport) - { - sLog.outError("Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.", - guid,transGUID); + if(!m_transport) + { + sLog.outError("Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.", + guid,transGUID); - RelocateToHomebind(); + RelocateToHomebind(mapId); - m_movementInfo.t_x = 0.0f; - m_movementInfo.t_y = 0.0f; - m_movementInfo.t_z = 0.0f; - m_movementInfo.t_o = 0.0f; + m_movementInfo.t_x = 0.0f; + m_movementInfo.t_y = 0.0f; + m_movementInfo.t_z = 0.0f; + m_movementInfo.t_o = 0.0f; - transGUID = 0; + transGUID = 0; + } } } - else // not transport case + else if (!taxi_nodes.empty()) // Taxi Flight path loaded from db { - MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId()); - // client without expansion support - if(GetSession()->Expansion() < mapEntry->Expansion()) + // There are no flightpaths in instances + instanceId = 0; + + if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam())) + { + // problems with taxi path loading + TaxiNodesEntry const* nodeEntry = NULL; + if(uint32 node_id = m_taxi.GetTaxiSource()) + nodeEntry = sTaxiNodesStore.LookupEntry(node_id); + + if(!nodeEntry) // don't know taxi start node, to homebind + { + sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow()); + RelocateToHomebind(mapId); + } + else // have start node, to it + { + sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow()); + mapId = nodeEntry->map_id; + Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f); + } + } + // Taxi path loading succesfull + else if(uint32 node_id = m_taxi.GetTaxiSource()) { - sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), GetMapId()); - RelocateToHomebind(); + // save source node as recall coord to prevent recall and fall from sky + TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id); + assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString + Relocate(nodeEntry->x,nodeEntry->y,nodeEntry->z,0); + mapId = nodeEntry->map_id; + // flight will started later } } + // Map could be changed before + mapEntry = sMapStore.LookupEntry(mapId); + // client without expansion support + if(GetSession()->Expansion() < mapEntry->Expansion()) + { + sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), mapId); + RelocateToHomebind(mapId); + instanceId = 0; + } + + // fix crash (because of if(Map *map = _FindMap(instanceId)) in MapInstanced::CreateInstance) + if(instanceId) + if(InstanceSave * save = GetInstanceSave(mapId)) + if(save->GetInstanceId() != instanceId) + instanceId = 0; // NOW player must have valid map // load the player's map here if it's not already loaded - Map *map = GetMap(); + Map *map = MapManager::Instance().CreateMap(mapId, this, instanceId); if (!map) { - AreaTrigger const* at = objmgr.GetGoBackTrigger(GetMapId()); + instanceId = 0; + AreaTrigger const* at = objmgr.GetGoBackTrigger(mapId); if(at) { - SetMapId(at->target_mapId); + sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,mapId,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); Relocate(at->target_X, at->target_Y, at->target_Z, GetOrientation()); - sLog.outError("Player (guidlow %d) is teleported to gobacktrigger (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + mapId = at->target_mapId; } else { - RelocateToHomebind(); - sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,GetMapId(),GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + sLog.outError("Player (guidlow %d) is teleported to home (Map: %u X: %f Y: %f Z: %f O: %f).",guid,mapId,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + RelocateToHomebind(mapId); } - map = GetMap(); + map = MapManager::Instance().CreateMap(mapId, this, 0); if(!map) { - sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); - delete result; - return false; - - /*SetMapId(info->mapId); + PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass()); + mapId = info->mapId; Relocate(info->positionX,info->positionY,info->positionZ,0.0f); - - map = GetMap(); - if(!map) + sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + map = MapManager::Instance().CreateMap(mapId, this, 0); + if (!map) { - sLog.outError("ERROR: Player (guidlow %d) have invalid coordinates (X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); - sLog.outError("CRASH."); - assert(false); - }*/ + sLog.outError("ERROR: Player (guidlow %d) has invalid default map coordinates (X: %f Y: %f Z: %f O: %f). or instance couldn't be created",guid,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + delete result; + return false; + } } } - // since the player may not be bound to the map yet, make sure subsequent - // getmap calls won't create new maps - SetInstanceId(map->GetInstanceId()); - // if the player is in an instance and it has been reset in the meantime teleport him to the entrance - if(GetInstanceId() && !sInstanceSaveManager.GetInstanceSave(GetInstanceId())) + if(instanceId && !sInstanceSaveManager.GetInstanceSave(instanceId)) { - AreaTrigger const* at = objmgr.GetMapEntranceTrigger(GetMapId()); + AreaTrigger const* at = objmgr.GetMapEntranceTrigger(mapId); if(at) Relocate(at->target_X, at->target_Y, at->target_Z, at->target_Orientation); else - sLog.outError("Player %s(GUID: %u) logged in to a reset instance (map: %u) and there is no area-trigger leading to this map. Thus he can't be ported back to the entrance. This _might_ be an exploit attempt.", GetName(), GetGUIDLow(), GetMapId()); + { + sLog.outError("Player %s(GUID: %u) logged in to a reset instance (map: %u) and there is no area-trigger leading to this map. Thus he can't be ported back to the entrance. This _might_ be an exploit attempt.", GetName(), GetGUIDLow(), mapId); + RelocateToHomebind(mapId); + instanceId = 0; + } } + SetMap(map); + + // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE] + // this must help in case next save after mass player load after server startup + m_nextSave = urand(m_nextSave/2,m_nextSave*3/2); + SaveRecallPosition(); time_t now = time(NULL); - time_t logoutTime = time_t(fields[16].GetUInt64()); + time_t logoutTime = time_t(fields[23].GetUInt64()); // since last logout (in seconds) uint64 time_diff = uint64(now - logoutTime); @@ -14637,27 +14863,27 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) uint16 newDrunkenValue = uint16(soberFactor*(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFE)); SetDrunkValue(newDrunkenValue); - m_rest_bonus = fields[15].GetFloat(); + m_rest_bonus = fields[22].GetFloat(); //speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour) float bubble0 = 0.031; //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour) float bubble1 = 0.125; - if((int32)fields[16].GetUInt32() > 0) + if(time_diff > 0) { - float bubble = fields[17].GetUInt32() > 0 + float bubble = fields[24].GetUInt32() > 0 ? bubble1*sWorld.getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY) : bubble0*sWorld.getRate(RATE_REST_OFFLINE_IN_WILDERNESS); SetRestBonus(GetRestBonus()+ time_diff*((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP)/72000)*bubble); } - m_cinematic = fields[12].GetUInt32(); - m_Played_time[0]= fields[13].GetUInt32(); - m_Played_time[1]= fields[14].GetUInt32(); + m_cinematic = fields[19].GetUInt32(); + m_Played_time[PLAYED_TIME_TOTAL]= fields[20].GetUInt32(); + m_Played_time[PLAYED_TIME_LEVEL]= fields[21].GetUInt32(); - m_resetTalentsCost = fields[18].GetUInt32(); - m_resetTalentsTime = time_t(fields[19].GetUInt64()); + m_resetTalentsCost = fields[25].GetUInt32(); + m_resetTalentsTime = time_t(fields[26].GetUInt64()); // reserve some flags uint32 old_safe_flags = GetUInt32Value(PLAYER_FLAGS) & ( PLAYER_FLAGS_HIDE_CLOAK | PLAYER_FLAGS_HIDE_HELM ); @@ -14665,30 +14891,28 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) if( HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM) ) SetUInt32Value(PLAYER_FLAGS, 0 | old_safe_flags); - m_taxi.LoadTaxiMask( fields[11].GetString() ); // must be before InitTaxiNodesForLevel + m_taxi.LoadTaxiMask( fields[18].GetString() ); // must be before InitTaxiNodesForLevel - uint32 extraflags = fields[25].GetUInt32(); + uint32 extraflags = fields[32].GetUInt32(); - m_stableSlots = fields[26].GetUInt32(); + m_stableSlots = fields[33].GetUInt32(); if(m_stableSlots > MAX_PET_STABLES) { sLog.outError("Player can have not more %u stable slots, but have in DB %u",MAX_PET_STABLES,uint32(m_stableSlots)); m_stableSlots = MAX_PET_STABLES; } - m_atLoginFlags = fields[27].GetUInt32(); + m_atLoginFlags = fields[34].GetUInt32(); // Honor system // Update Honor kills data m_lastHonorUpdateTime = logoutTime; UpdateHonorFields(); - m_deathExpireTime = (time_t)fields[30].GetUInt64(); + m_deathExpireTime = (time_t)fields[37].GetUInt64(); if(m_deathExpireTime > now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP) m_deathExpireTime = now+MAX_DEATH_COUNT*DEATH_EXPIRE_STEP-1; - std::string taxi_nodes = fields[31].GetCppString(); - delete result; // clear channel spell data (if saved at channel spell casting) @@ -14774,42 +14998,6 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) SetUInt32Value(PLAYER_CHOSEN_TITLE, 0); } - // Not finish taxi flight path - if(!m_taxi.LoadTaxiDestinationsFromString(taxi_nodes,GetTeam())) - { - // problems with taxi path loading - TaxiNodesEntry const* nodeEntry = NULL; - if(uint32 node_id = m_taxi.GetTaxiSource()) - nodeEntry = sTaxiNodesStore.LookupEntry(node_id); - - if(!nodeEntry) // don't know taxi start node, to homebind - { - sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow()); - RelocateToHomebind(); - SaveRecallPosition(); // save as recall also to prevent recall and fall from sky - } - else // have start node, to it - { - sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow()); - SetMapId(nodeEntry->map_id); - Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f); - SaveRecallPosition(); // save as recall also to prevent recall and fall from sky - } - m_taxi.ClearTaxiDestinations(); - } - else if(uint32 node_id = m_taxi.GetTaxiSource()) - { - // save source node as recall coord to prevent recall and fall from sky - TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id); - assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString - m_recallMap = nodeEntry->map_id; - m_recallX = nodeEntry->x; - m_recallY = nodeEntry->y; - m_recallZ = nodeEntry->z; - - // flight will started later - } - // has to be called after last Relocate() in Player::LoadFromDB SetFallInformation(0, GetPositionZ()); @@ -14928,7 +15116,7 @@ void Player::_LoadActions(QueryResult *result) { m_actionButtons.clear(); - //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow()); + //QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type FROM character_action WHERE guid = '%u' ORDER BY button",GetGUIDLow()); if(result) { @@ -14937,9 +15125,11 @@ void Player::_LoadActions(QueryResult *result) Field *fields = result->Fetch(); uint8 button = fields[0].GetUInt8(); + uint32 action = fields[1].GetUInt32(); + uint8 type = fields[2].GetUInt8(); - if(addActionButton(button, fields[1].GetUInt16(), fields[2].GetUInt8(), fields[3].GetUInt8())) - m_actionButtons[button].uState = ACTIONBUTTON_UNCHANGED; + if(ActionButton* ab = addActionButton(button, action, type)) + ab->uState = ACTIONBUTTON_UNCHANGED; else { sLog.outError( " ...at loading, and will deleted in DB also"); @@ -15012,7 +15202,7 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff) delete result; } - if(m_class == CLASS_WARRIOR) + if(getClass() == CLASS_WARRIOR && !HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) CastSpell(this,SPELL_ID_PASSIVE_BATTLE_STANCE,true); } @@ -15248,7 +15438,7 @@ void Player::_LoadMailedItems(Mail *mail) if(!proto) { - sLog.outError( "Player %u have unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID); + sLog.outError( "Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template,mail->messageID); CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guid_low); continue; @@ -15508,7 +15698,7 @@ void Player::_LoadSpells(QueryResult *result) { Field *fields = result->Fetch(); - addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, false, fields[2].GetBool()); + addSpell(fields[0].GetUInt32(), fields[1].GetBool(), false, false, fields[2].GetBool()); } while( result->NextRow() ); @@ -15595,6 +15785,19 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) return NULL; } +InstanceSave * Player::GetInstanceSave(uint32 mapid) +{ + InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty()); + InstanceSave *pSave = pBind ? pBind->save : NULL; + if(!pBind || !pBind->perm) + { + if(Group *group = GetGroup()) + if(InstanceGroupBind *groupBind = group->GetBoundInstance(mapid, GetDifficulty())) + pSave = groupBind->save; + } + return pSave; +} + void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) { BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); @@ -15764,8 +15967,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report { if(ar->levelMin && getLevel() < ar->levelMin) LevelMin = ar->levelMin; - else if(ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC - && getLevel() < ar->heroicLevelMin) + if(ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin) LevelMin = ar->heroicLevelMin; if(ar->levelMax && getLevel() > ar->levelMax) LevelMax = ar->levelMax; @@ -15807,7 +16009,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report if(report) { if(missingItem) - GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), ar->levelMin, objmgr.GetItemPrototype(missingItem)->Name1); + GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, objmgr.GetItemPrototype(missingItem)->Name1); else if(missingKey) SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY); else if(missingHeroicQuest) @@ -15882,30 +16084,19 @@ void Player::SaveToDB() // delay auto save at any saves (manual, in code, or autosave) m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE); + //lets allow only players in world to be saved + if(IsBeingTeleportedFar()) + { + ScheduleDelayedOperation(DELAYED_SAVE_PLAYER); + return; + } + // first save/honor gain after midnight will also update the player's honor fields UpdateHonorFields(); - uint32 is_save_resting = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0; - //save, far from tavern/city - //save, but in tavern/city sLog.outDebug("The value of player %s at save: ", m_name.c_str()); outDebugValues(); - // save state (after auras removing), if aura remove some flags then it must set it back by self) - uint32 tmp_bytes = GetUInt32Value(UNIT_FIELD_BYTES_1); - uint32 tmp_bytes2 = GetUInt32Value(UNIT_FIELD_BYTES_2); - uint32 tmp_flags = GetUInt32Value(UNIT_FIELD_FLAGS); - uint32 tmp_pflags = GetUInt32Value(PLAYER_FLAGS); - uint32 tmp_displayid = GetDisplayId(); - - // Set player sit state to standing on save, also stealth and shifted form - SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_STAND); - SetByteValue(UNIT_FIELD_BYTES_2, 3, 0); // shapeshift - RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); - SetDisplayId(GetNativeDisplayId()); - - bool inworld = IsInWorld(); - CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",GetGUIDLow()); @@ -15914,7 +16105,7 @@ void Player::SaveToDB() CharacterDatabase.escape_string(sql_name); std::ostringstream ss; - ss << "INSERT INTO characters (guid,account,name,race,class," + ss << "INSERT INTO characters (guid,account,name,race,class,gender,level,xp,money,playerBytes,playerBytes2,playerFlags," "map, instance_id, dungeon_difficulty, position_x, position_y, position_z, orientation, data, " "taximask, online, cinematic, " "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, " @@ -15923,8 +16114,15 @@ void Player::SaveToDB() << GetGUIDLow() << ", " << GetSession()->GetAccountId() << ", '" << sql_name << "', " - << m_race << ", " - << m_class << ", "; + << (uint32)getRace() << ", " + << (uint32)getClass() << ", " + << (uint32)getGender() << ", " + << getLevel() << ", " + << GetUInt32Value(PLAYER_XP) << ", " + << GetMoney() << ", " + << GetUInt32Value(PLAYER_BYTES) << ", " + << GetUInt32Value(PLAYER_BYTES_2) << ", " + << GetUInt32Value(PLAYER_FLAGS) << ", "; if(!IsBeingTeleported()) { @@ -15955,69 +16153,48 @@ void Player::SaveToDB() ss << "', "; - ss << m_taxi; // string with TaxiMaskSize numbers + ss << m_taxi << ", "; // string with TaxiMaskSize numbers - ss << ", "; - ss << (inworld ? 1 : 0); + ss << (IsInWorld() ? 1 : 0) << ", "; - ss << ", "; - ss << m_cinematic; + ss << m_cinematic << ", "; - ss << ", "; - ss << m_Played_time[0]; - ss << ", "; - ss << m_Played_time[1]; + ss << m_Played_time[PLAYED_TIME_TOTAL] << ", "; + ss << m_Played_time[PLAYED_TIME_LEVEL] << ", "; - ss << ", "; - ss << finiteAlways(m_rest_bonus); - ss << ", "; - ss << (uint64)time(NULL); - ss << ", "; - ss << is_save_resting; - ss << ", "; - ss << m_resetTalentsCost; - ss << ", "; - ss << (uint64)m_resetTalentsTime; + ss << finiteAlways(m_rest_bonus) << ", "; + ss << (uint64)time(NULL) << ", "; + ss << (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) ? 1 : 0) << ", "; + //save, far from tavern/city + //save, but in tavern/city + ss << m_resetTalentsCost << ", "; + ss << (uint64)m_resetTalentsTime << ", "; - ss << ", "; - ss << finiteAlways(m_movementInfo.t_x); - ss << ", "; - ss << finiteAlways(m_movementInfo.t_y); - ss << ", "; - ss << finiteAlways(m_movementInfo.t_z); - ss << ", "; - ss << finiteAlways(m_movementInfo.t_o); - ss << ", "; + ss << finiteAlways(m_movementInfo.t_x) << ", "; + ss << finiteAlways(m_movementInfo.t_y) << ", "; + ss << finiteAlways(m_movementInfo.t_z) << ", "; + ss << finiteAlways(m_movementInfo.t_o) << ", "; if (m_transport) ss << m_transport->GetGUIDLow(); else ss << "0"; - ss << ", "; - ss << m_ExtraFlags; - ss << ", "; - ss << uint32(m_stableSlots); // to prevent save uint8 as char + ss << m_ExtraFlags << ", "; - ss << ", "; - ss << uint32(m_atLoginFlags & ((1<<AT_LOAD_PET_FLAGS) -1)); + ss << uint32(m_stableSlots) << ", "; // to prevent save uint8 as char - ss << ", "; - ss << GetZoneId(); + ss << uint32(m_atLoginFlags) << ", "; - ss << ", "; - ss << (uint64)m_deathExpireTime; + ss << GetZoneId() << ", "; - ss << ", '"; - ss << m_taxi.SaveTaxiDestinationsToString(); + ss << (uint64)m_deathExpireTime << ", '"; - ss << "', '0', "; - ss << GetSession()->GetLatency(); - ss << ", "; - ss << GetBattleGroundId(); - ss << ", "; - ss << GetBGTeam(); - ss << ", "; + ss << m_taxi.SaveTaxiDestinationsToString() << "', "; + ss << "'0', "; // arena_pending_points + ss << GetSession()->GetLatency() << ", "; + ss << GetBattleGroundId() << ", "; + ss << GetBGTeam() << ", "; ss << m_bgEntryPoint.mapid << ", " << finiteAlways(m_bgEntryPoint.coord_x) << ", " << finiteAlways(m_bgEntryPoint.coord_y) << ", " @@ -16044,13 +16221,6 @@ void Player::SaveToDB() CharacterDatabase.CommitTransaction(); - // restore state (before aura apply, if aura remove flag then aura must set it ack by self) - SetDisplayId(tmp_displayid); - SetUInt32Value(UNIT_FIELD_BYTES_1, tmp_bytes); - SetUInt32Value(UNIT_FIELD_BYTES_2, tmp_bytes2); - SetUInt32Value(UNIT_FIELD_FLAGS, tmp_flags); - SetUInt32Value(PLAYER_FLAGS, tmp_pflags); - // save pet (hunter pet level and experience and all type pets health/mana). if(Pet* pet = GetPet()) pet->SavePetToDB(PET_SAVE_AS_CURRENT); @@ -16060,8 +16230,12 @@ void Player::SaveToDB() void Player::SaveInventoryAndGoldToDB() { _SaveInventory(); - //money is in data field - SaveDataFieldToDB(); + SaveGoldToDB(); +} + +void Player::SaveGoldToDB() +{ + CharacterDatabase.PExecute("UPDATE characters SET money = '%u' WHERE guid = '%u'", GetMoney(), GetGUIDLow()); } void Player::_SaveActions() @@ -16071,14 +16245,14 @@ void Player::_SaveActions() switch (itr->second.uState) { case ACTIONBUTTON_NEW: - CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type,misc) VALUES ('%u', '%u', '%u', '%u', '%u')", - GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc ); + CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type) VALUES ('%u', '%u', '%u', '%u')", + GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType() ); itr->second.uState = ACTIONBUTTON_UNCHANGED; ++itr; break; case ACTIONBUTTON_CHANGED: - CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u', misc= '%u' WHERE guid= '%u' AND button= '%u' ", - (uint32)itr->second.action, (uint32)itr->second.type, (uint32)itr->second.misc, GetGUIDLow(), (uint32)itr->first ); + CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u' WHERE guid= '%u' AND button= '%u' ", + (uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), GetGUIDLow(), (uint32)itr->first ); itr->second.uState = ACTIONBUTTON_UNCHANGED; ++itr; break; @@ -16089,7 +16263,7 @@ void Player::_SaveActions() default: ++itr; break; - }; + } } } @@ -16103,13 +16277,11 @@ void Player::_SaveAuras() // skip: // area auras or single cast auras casted by other unit // passive auras and stances - if (itr->second->IsPassive() - || itr->second->IsAuraType(SPELL_AURA_MOD_SHAPESHIFT) - || itr->second->IsRemovedOnShapeLost()) + if (itr->second->IsPassive()) continue; - bool isCaster = itr->second->GetCasterGUID() == GetGUID(); - if (!isCaster) - if (itr->second->IsSingleTarget() + + if (itr->second->GetCasterGUID() != GetGUID()) + if (IsSingleTargetSpell(itr->second->GetSpellProto()) || itr->second->IsAreaAura()) continue; @@ -16330,7 +16502,7 @@ void Player::outDebugValues() const sLog.outDebug("HP is: \t\t\t%u\t\tMP is: \t\t\t%u",GetMaxHealth(), GetMaxPower(POWER_MANA)); sLog.outDebug("AGILITY is: \t\t%f\t\tSTRENGTH is: \t\t%f",GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH)); sLog.outDebug("INTELLECT is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_INTELLECT), GetStat(STAT_SPIRIT)); - sLog.outDebug("STAMINA is: \t\t%f\t\tSPIRIT is: \t\t%f",GetStat(STAT_STAMINA), GetStat(STAT_SPIRIT)); + sLog.outDebug("STAMINA is: \t\t%f",GetStat(STAT_STAMINA)); sLog.outDebug("Armor is: \t\t%u\t\tBlock is: \t\t%f",GetArmor(), GetFloatValue(PLAYER_BLOCK_PERCENTAGE)); sLog.outDebug("HolyRes is: \t\t%u\t\tFireRes is: \t\t%u",GetResistance(SPELL_SCHOOL_HOLY), GetResistance(SPELL_SCHOOL_FIRE)); sLog.outDebug("NatureRes is: \t\t%u\t\tFrostRes is: \t\t%u",GetResistance(SPELL_SCHOOL_NATURE), GetResistance(SPELL_SCHOOL_FROST)); @@ -16465,38 +16637,20 @@ void Player::SetFloatValueInDB(uint16 index, float value, uint64 guid) void Player::Customize(uint64 guid, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair) { - Tokens tokens; - if(!LoadValuesArrayFromDB(tokens, guid)) - return; - - uint32 unit_bytes0 = GetUInt32ValueFromArray(tokens, UNIT_FIELD_BYTES_0); - uint8 race = unit_bytes0 & 0xFF; - uint8 class_ = (unit_bytes0 >> 8) & 0xFF; - - PlayerInfo const* info = objmgr.GetPlayerInfo(race, class_); - if(!info) + // 0 + QueryResult* result = CharacterDatabase.PQuery("SELECT playerBytes2 FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); + if(!result) return; - unit_bytes0 &= ~(0xFF << 16); - unit_bytes0 |= (gender << 16); - SetUInt32ValueInArray(tokens, UNIT_FIELD_BYTES_0, unit_bytes0); - - SetUInt32ValueInArray(tokens, UNIT_FIELD_DISPLAYID, gender ? info->displayId_f : info->displayId_m); - SetUInt32ValueInArray(tokens, UNIT_FIELD_NATIVEDISPLAYID, gender ? info->displayId_f : info->displayId_m); - - SetUInt32ValueInArray(tokens, PLAYER_BYTES, (skin | (face << 8) | (hairStyle << 16) | (hairColor << 24))); + Field* fields = result->Fetch(); - uint32 player_bytes2 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_2); + uint32 player_bytes2 = fields[0].GetUInt32(); player_bytes2 &= ~0xFF; player_bytes2 |= facialHair; - SetUInt32ValueInArray(tokens, PLAYER_BYTES_2, player_bytes2); - uint32 player_bytes3 = GetUInt32ValueFromArray(tokens, PLAYER_BYTES_3); - player_bytes3 &= ~0xFF; - player_bytes3 |= gender; - SetUInt32ValueInArray(tokens, PLAYER_BYTES_3, player_bytes3); + CharacterDatabase.PExecute("UPDATE characters SET gender = '%u', playerBytes = '%u', playerBytes2 = '%u' WHERE guid = '%u'", gender, skin | (face << 8) | (hairStyle << 16) | (hairColor << 24), player_bytes2, GUID_LOPART(guid)); - SaveValuesArrayInDB(tokens, guid); + delete result; } void Player::SendAttackSwingDeadTarget() @@ -16523,10 +16677,10 @@ void Player::SendAttackSwingBadFacingAttack() GetSession()->SendPacket( &data ); } -void Player::SendAutoRepeatCancel() +void Player::SendAutoRepeatCancel(Unit *target) { - WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, GetPackGUID().size()); - data.append(GetPackGUID()); // may be it's target guid + WorldPacket data(SMSG_CANCEL_AUTO_REPEAT, target->GetPackGUID().size()); + data.append(target->GetPackGUID()); // may be it's target guid GetSession()->SendPacket( &data ); } @@ -16751,7 +16905,6 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) SetMinion(pet, false); - pet->CleanupsBeforeDelete(); pet->AddObjectToRemoveList(); pet->m_removed = true; @@ -16784,8 +16937,14 @@ void Player::StopCastingCharm() if(GetCharmGUID()) { - sLog.outCrash("Player %s is not able to uncharm unit (Entry: %u, Type: %u)", GetName(), charm->GetEntry(), charm->GetTypeId()); - assert(false); + sLog.outCrash("Player %s (GUID: " UI64FMTD " is not able to uncharm unit (GUID: " UI64FMTD " Entry: %u, Type: %u)", GetName(), GetGUID(), GetCharmGUID(), charm->GetEntry(), charm->GetTypeId()); + if(charm->GetCharmerGUID()) + { + sLog.outCrash("Charmed unit has charmer guid " UI64FMTD, charm->GetCharmerGUID()); + assert(false); + } + else + SetCharm(charm, false); } } @@ -16911,8 +17070,7 @@ void Player::PetSpellInitialize() if(itr->second.state == PETSPELL_REMOVED) continue; - data << uint16(itr->first); - data << uint16(itr->second.active); // pet spell active state isn't boolean + data << uint32(MAKE_UNIT_ACTION_BUTTON(itr->first,itr->second.active)); ++addlist; } } @@ -17037,7 +17195,7 @@ void Player::CharmSpellInitialize() { for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i) { - if(charmInfo->GetCharmSpell(i)->spellId) + if(charmInfo->GetCharmSpell(i)->GetAction()) ++addlist; } } @@ -17062,11 +17220,8 @@ void Player::CharmSpellInitialize() for(uint32 i = 0; i < MAX_SPELL_CHARM; ++i) { CharmSpellEntry *cspell = charmInfo->GetCharmSpell(i); - if(cspell->spellId) - { - data << uint16(cspell->spellId); - data << uint16(cspell->active); - } + if(cspell->GetAction()) + data << uint32(cspell->packedData); } } @@ -17162,6 +17317,10 @@ void Player::RestoreSpellMods(Spell * spell) else mod->charges++; + // Do not set more spellmods than avalible + if (mod->ownerAura->GetAuraCharges() < mod->charges) + mod->charges = mod->ownerAura->GetAuraCharges(); + // Skip this check for now - aura charges may change due to various reason // TODO: trac these changes correctly //assert (mod->ownerAura->GetAuraCharges() <= mod->charges); @@ -17189,11 +17348,7 @@ void Player::RemoveSpellMods(Spell * spell) checkedSpells.find(aur->GetParentAura()) != checkedSpells.end()) continue; - flag96 const * mask = spellmgr.GetSpellAffect(aur->GetId(), aur->GetEffIndex()); - if (!mask) - mask = &spellInfo->EffectSpellClassMask[aur->GetEffIndex()]; - - if (spell->m_spellInfo->SpellFamilyFlags & *mask) + if (spell->m_spellInfo->SpellFamilyFlags & spellInfo->EffectSpellClassMask[aur->GetEffIndex()]) { checkedSpells.insert(aur->GetParentAura()); spell->m_appliedMods.erase(aur->GetParentAura()); @@ -17248,6 +17403,9 @@ void Player::SetSpellModTakingSpell(Spell * spell, bool apply) if (!spell || (m_spellModTakingSpell && m_spellModTakingSpell != spell)) return; + if (apply && spell->getState() == SPELL_STATE_FINISHED) + return; + if (apply) m_spellModTakingSpell = spell; else @@ -17360,19 +17518,38 @@ void Player::HandleStealthedUnitsDetection() Trinity::UnitListSearcher<Trinity::AnyStealthedCheck > searcher(this, stealthedUnits, u_check); VisitNearbyObject(World::GetMaxVisibleDistance(), searcher); - for (std::list<Unit*>::iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i) + for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i) { - if (!HaveAtClient(*i) && canSeeOrDetect(*i, true)) + if((*i)==this) + continue; + + bool hasAtClient = HaveAtClient((*i)); + bool hasDetected = canSeeOrDetect(*i, true); + + if (hasDetected) { - (*i)->SendUpdateToPlayer(this); - m_clientGUIDs.insert((*i)->GetGUID()); + if(!hasAtClient) + { + (*i)->SendUpdateToPlayer(this); + m_clientGUIDs.insert((*i)->GetGUID()); - #ifdef TRINITY_DEBUG - if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) - sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i)); - #endif + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0) + sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i)); + #endif - SendInitialVisiblePackets(*i); + // target aura duration for caster show only if target exist at caster client + // send data at target visibility change (adding to client) + SendInitialVisiblePackets(*i); + } + } + else + { + if(hasAtClient) + { + (*i)->DestroyForPlayer(this); + m_clientGUIDs.erase((*i)->GetGUID()); + } } } } @@ -17382,8 +17559,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc if(nodes.size() < 2) return false; - // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi - if(GetSession()->isLogingOut() || isInCombat()) + // not let cheating with start flight in time of logout process || while in combat || has type state: stunned || has type state: root + if(GetSession()->isLogingOut() || isInCombat() || hasUnitState(UNIT_STAT_STUNNED) || hasUnitState(UNIT_STAT_ROOT)) { WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); data << uint32(ERR_TAXIPLAYERBUSY); @@ -17585,6 +17762,14 @@ bool Player::ActivateTaxiPathTo( uint32 taxi_path_id, uint32 spellid /*= 0*/ ) return ActivateTaxiPathTo(nodes,NULL,spellid); } +void Player::CleanupAfterTaxiFlight() +{ + m_taxi.ClearTaxiDestinations(); // not destinations, clear source node + Unmount(); + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + getHostilRefManager().setOnlineOfflineState(true); +} + void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ) { // last check 2.0.10 @@ -17666,17 +17851,47 @@ void Player::InitDataForForm(bool reapplyMods) UpdateAttackPowerAndDamage(true); } +void Player::InitDisplayIds() +{ + PlayerInfo const *info = objmgr.GetPlayerInfo(getRace(), getClass()); + if(!info) + { + sLog.outError("Player %u has incorrect race/class pair. Can't init display ids.", GetGUIDLow()); + return; + } + + uint8 gender = getGender(); + switch(gender) + { + case GENDER_FEMALE: + SetDisplayId(info->displayId_f ); + SetNativeDisplayId(info->displayId_f ); + break; + case GENDER_MALE: + SetDisplayId(info->displayId_m ); + SetNativeDisplayId(info->displayId_m ); + break; + default: + sLog.outError("Invalid gender %u for player",gender); + return; + } +} + // Return true is the bought item has a max count to force refresh of window by caller -bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot) +bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot) { // cheating attempt - if(count < 1) count = 1; + if (count < 1) count = 1; - if(!isAlive()) + // cheating attempt + if(slot > MAX_BAG_SIZE && slot !=NULL_SLOT) + return false; + + if (!isAlive()) return false; ItemPrototype const *pProto = objmgr.GetItemPrototype( item ); - if( !pProto ) + if (!pProto) { SendBuyError( BUY_ERR_CANT_FIND_ITEM, NULL, item, 0); return false; @@ -17698,7 +17913,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint } size_t vendor_slot = vItems->FindItemSlot(item); - if(vendor_slot >= vItems->GetItemCount()) + if (vendor_slot >= vItems->GetItemCount()) { SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0); return false; @@ -17707,39 +17922,39 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint VendorItem const* crItem = vItems->m_items[vendor_slot]; // check current item amount if it limited - if( crItem->maxcount != 0 ) + if (crItem->maxcount != 0) { - if(pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count ) + if (pCreature->GetVendorItemCurrentCount(crItem) < pProto->BuyCount * count ) { SendBuyError( BUY_ERR_ITEM_ALREADY_SOLD, pCreature, item, 0); return false; } } - if( uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank) + if (uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank) { SendBuyError( BUY_ERR_REPUTATION_REQUIRE, pCreature, item, 0); return false; } - if(crItem->ExtendedCost) + if (crItem->ExtendedCost) { ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); - if(!iece) + if (!iece) { sLog.outError("Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); return false; } // honor points price - if(GetHonorPoints() < (iece->reqhonorpoints * count)) + if (GetHonorPoints() < (iece->reqhonorpoints * count)) { SendEquipError(EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS, NULL, NULL); return false; } // arena points price - if(GetArenaPoints() < (iece->reqarenapoints * count)) + if (GetArenaPoints() < (iece->reqarenapoints * count)) { SendEquipError(EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS, NULL, NULL); return false; @@ -17769,63 +17984,38 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint // reputation discount price = uint32(floor(price * GetReputationPriceDiscount(pCreature))); - if( GetMoney() < price ) + if (GetMoney() < price) { SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, item, 0); return false; } - uint8 bag = 0; // init for case invalid bagGUID - - if (bagguid != NULL_BAG && slot != NULL_SLOT) - { - if( bagguid == GetGUID() ) - { - bag = INVENTORY_SLOT_BAG_0; - } - else - { - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END;i++) - { - if( Bag *pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0,i) ) - { - if( bagguid == pBag->GetGUID() ) - { - if(slot < pBag->GetBagSlot() && !pBag->GetItemByPos(slot)) - bag = i; - break; - } - } - } - } - } - - if( IsInventoryPos( bag, slot ) || (bagguid == NULL_BAG && slot == NULL_SLOT) ) + if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot)) { ItemPosCountVec dest; uint8 msg = CanStoreNewItem( bag, slot, dest, item, pProto->BuyCount * count ); - if( msg != EQUIP_ERR_OK ) + if (msg != EQUIP_ERR_OK) { SendEquipError( msg, NULL, NULL ); return false; } ModifyMoney( -(int32)price ); - if(crItem->ExtendedCost) // case for new honor system + if (crItem->ExtendedCost) // case for new honor system { ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); - if(iece->reqhonorpoints) + if (iece->reqhonorpoints) ModifyHonorPoints( - int32(iece->reqhonorpoints * count)); - if(iece->reqarenapoints) + if (iece->reqarenapoints) ModifyArenaPoints( - int32(iece->reqarenapoints * count)); for (uint8 i = 0; i < 5; ++i) { - if(iece->reqitem[i]) + if (iece->reqitem[i]) DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true); } } - if(Item *it = StoreNewItem( dest, item, true )) + if (Item *it = StoreNewItem( dest, item, true )) { uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count); @@ -17839,9 +18029,9 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint SendNewItem(it, pProto->BuyCount*count, true, false, false); } } - else if( IsEquipmentPos( bag, slot ) ) + else if (IsEquipmentPos(bag, slot)) { - if(pProto->BuyCount * count != 1) + if (pProto->BuyCount * count != 1) { SendEquipError( EQUIP_ERR_ITEM_CANT_BE_EQUIPPED, NULL, NULL ); return false; @@ -17849,19 +18039,19 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint uint16 dest; uint8 msg = CanEquipNewItem( slot, dest, item, false ); - if( msg != EQUIP_ERR_OK ) + if (msg != EQUIP_ERR_OK) { SendEquipError( msg, NULL, NULL ); return false; } ModifyMoney( -(int32)price ); - if(crItem->ExtendedCost) // case for new honor system + if (crItem->ExtendedCost) // case for new honor system { ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); - if(iece->reqhonorpoints) + if (iece->reqhonorpoints) ModifyHonorPoints( - int32(iece->reqhonorpoints)); - if(iece->reqarenapoints) + if (iece->reqarenapoints) ModifyArenaPoints( - int32(iece->reqarenapoints)); for (uint8 i = 0; i < 5; ++i) { @@ -17870,7 +18060,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint } } - if(Item *it = EquipNewItem( dest, item, true )) + if (Item *it = EquipNewItem( dest, item, true )) { uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count); @@ -17892,7 +18082,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint return false; } - return crItem->maxcount!=0; + return crItem->maxcount != 0; } uint32 Player::GetMaxPersonalArenaRatingRequirement() @@ -18051,8 +18241,8 @@ void Player::AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 it { // 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+MONTH : 0; - recTime = rec > 0 ? curTime+MONTH : catrecTime; + catrecTime = catrec > 0 ? curTime+infinityCooldownDelay : 0; + recTime = rec > 0 ? curTime+infinityCooldownDelay : catrecTime; } else { @@ -18314,7 +18504,16 @@ void Player::LeaveBattleground(bool teleportToEntryPoint) if( bg->isBattleGround() && !isGameMaster() && sWorld.getConfig(CONFIG_BATTLEGROUND_CAST_DESERTER) ) { if( bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN ) + { + //lets check if player was teleported from BG and schedule delayed Deserter spell cast + if(IsBeingTeleportedFar()) + { + ScheduleDelayedOperation(DELAYED_SPELL_CAST_DESERTER); + return; + } + CastSpell(this, 26013, true); // Deserter + } } } } @@ -18322,7 +18521,7 @@ void Player::LeaveBattleground(bool teleportToEntryPoint) bool Player::CanJoinToBattleground() const { // check Deserter debuff - if(GetDummyAura(26013)) + if(HasAura(26013)) return false; return true; @@ -18558,7 +18757,7 @@ void Player::UpdateVisibilityOf(WorldObject* target) { if(HaveAtClient(target)) { - if(!target->isVisibleForInState(this,true)) + if(!target->isVisibleForInState(this, true)) { target->DestroyForPlayer(this); m_clientGUIDs.erase(target->GetGUID()); @@ -18656,17 +18855,19 @@ void Player::SendComboPoints() } } -void Player::AddComboPoints(Unit* target, int8 count) +void Player::AddComboPoints(Unit* target, int8 count, Spell * spell) { if(!count) return; + int8 * comboPoints = spell ? &spell->m_comboPointGain : &m_comboPoints; + // without combo points lost (duration checked in aura) RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS); if(target->GetGUID() == m_comboTarget) { - m_comboPoints += count; + *comboPoints += count; } else { @@ -18675,13 +18876,26 @@ void Player::AddComboPoints(Unit* target, int8 count) target2->RemoveComboPointHolder(GetGUIDLow()); m_comboTarget = target->GetGUID(); - m_comboPoints = count; + *comboPoints = count; target->AddComboPointHolder(GetGUIDLow()); } + if (*comboPoints > 5) *comboPoints = 5; + else if (*comboPoints < 0) *comboPoints = 0; + + if (!spell) + SendComboPoints(); +} + +void Player::GainSpellComboPoints(int8 count) +{ + if(!count) + return; + + m_comboPoints += count; if (m_comboPoints > 5) m_comboPoints = 5; - if (m_comboPoints < 0) m_comboPoints = 0; + else if (m_comboPoints < 0) m_comboPoints = 0; SendComboPoints(); } @@ -18746,11 +18960,6 @@ void Player::SendInitialPacketsBeforeAddToMap() m_reputationMgr.SendInitialReputations(); m_achievementMgr.SendAllAchievementData(); - // update zone - uint32 newzone, newarea; - GetZoneAndAreaId(newzone,newarea); - UpdateZone(newzone,newarea); // also call SendInitWorldStates(); - SendEquipmentSetList(); data.Initialize(SMSG_LOGIN_SETTIMESPEED, 4 + 4 + 4); @@ -18762,6 +18971,11 @@ void Player::SendInitialPacketsBeforeAddToMap() void Player::SendInitialPacketsAfterAddToMap() { + // update zone + uint32 newzone, newarea; + GetZoneAndAreaId(newzone,newarea); + UpdateZone(newzone,newarea); // also call SendInitWorldStates(); + WorldPacket data(SMSG_TIME_SYNC_REQ, 4); // new 2.0.x, enable movement data << uint32(0x00000000); // on blizz it increments periodically GetSession()->SendPacket(&data); @@ -18883,17 +19097,14 @@ void Player::resetSpells() { // not need after this call if(HasAtLoginFlag(AT_LOGIN_RESET_SPELLS)) - { - m_atLoginFlags = m_atLoginFlags & ~AT_LOGIN_RESET_SPELLS; - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login & ~ %u WHERE guid ='%u'", uint32(AT_LOGIN_RESET_SPELLS), GetGUIDLow()); - } + RemoveAtLoginFlag(AT_LOGIN_RESET_SPELLS,true); // make full copy of map (spells removed and marked as deleted at another spell remove // and we can't use original map for safe iterative with visit each spell at loop end PlayerSpellMap smap = GetSpellMap(); for(PlayerSpellMap::const_iterator iter = smap.begin();iter != smap.end(); ++iter) - removeSpell(iter->first); // only iter->first can be accessed, object by iter->second can be deleted already + removeSpell(iter->first,false,false); // only iter->first can be accessed, object by iter->second can be deleted already learnDefaultSpells(); learnQuestRewardedSpells(); @@ -18954,8 +19165,10 @@ void Player::learnQuestRewardedSpells(Quest const* quest) if(!learnedInfo) return; + uint32 profSpell = spellmgr.GetSpellRequired(learned_0); + // specialization - if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0) + if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0 && profSpell) { // search other specialization for same prof for(PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) @@ -18972,11 +19185,7 @@ void Player::learnQuestRewardedSpells(Quest const* quest) continue; // compare same chain spells - if(spellmgr.GetFirstSpellInChain(itr->first) != first_spell) - continue; - - // now we have 2 specialization, learn possible only if found is lesser specialization rank - if(!spellmgr.IsHighRankOfSpell(learned_0,itr->first)) + if (spellmgr.GetSpellRequired(itr->first) == profSpell) return; } } @@ -19273,7 +19482,7 @@ void Player::SummonIfPossible(bool agree) if(isInFlight()) { GetMotionMaster()->MovementExpired(); - m_taxi.ClearTaxiDestinations(); + CleanupAfterTaxiFlight(); } // drop flag at summon @@ -19572,7 +19781,7 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim) { // normal creature (not pet/etc) can be only in !PvP case if(pVictim->GetTypeId()==TYPEID_UNIT) - pGroupGuy->KilledMonster(pVictim->GetEntry(), pVictim->GetGUID()); + pGroupGuy->KilledMonster(((Creature*)pVictim)->GetCreatureInfo(), pVictim->GetGUID()); } } } @@ -19597,7 +19806,7 @@ bool Player::RewardPlayerAndGroupAtKill(Unit* pVictim) // normal creature (not pet/etc) can be only in !PvP case if(pVictim->GetTypeId()==TYPEID_UNIT) - KilledMonster(pVictim->GetEntry(),pVictim->GetGUID()); + KilledMonster(((Creature*)pVictim)->GetCreatureInfo(), pVictim->GetGUID()); } } return xp || honored_kill; @@ -19621,26 +19830,23 @@ void Player::RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewar // quest objectives updated only for alive group member or dead but with not released body if(pGroupGuy->isAlive()|| !pGroupGuy->GetCorpse()) - pGroupGuy->KilledMonster(creature_id, creature_guid); + pGroupGuy->KilledMonsterCredit(creature_id, creature_guid); } } else // if (!pGroup) - KilledMonster(creature_id, creature_guid); + KilledMonsterCredit(creature_id, creature_guid); } bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const { - if (pRewardSource->IsWithinDistInMap(this,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))) - return true; + const WorldObject* player = GetCorpse(); + if(!player || isAlive()) + player = this; - if (isAlive()) + if(player->GetMapId() != pRewardSource->GetMapId() || player->GetInstanceId() != pRewardSource->GetInstanceId()) return false; - Corpse* corpse = GetCorpse(); - if (!corpse) - return false; - - return pRewardSource->IsWithinDistInMap(corpse,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)); + return pRewardSource->GetDistance(player) <= sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE); } uint32 Player::GetBaseWeaponSkillValue (WeaponAttackType attType) const @@ -19662,6 +19868,14 @@ void Player::ResurectUsingRequestData() if(IS_PLAYER_GUID(m_resurrectGUID)) TeleportTo(m_resurrectMap, m_resurrectX, m_resurrectY, m_resurrectZ, GetOrientation()); + //we cannot resurrect player when we triggered far teleport + //player will be resurrected upon teleportation + if(IsBeingTeleportedFar()) + { + ScheduleDelayedOperation(DELAYED_RESURRECT_PLAYER); + return; + } + ResurrectPlayer(0.0f,false); if(GetMaxHealth() > m_resurrectHealth) @@ -19693,13 +19907,6 @@ void Player::SetClientControl(Unit* target, uint8 allowMove) void Player::UpdateZoneDependentAuras( uint32 newZone ) { - // remove new continent flight forms - if( !IsAllowUseFlyMountsHere() ) - { - RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED); - RemoveAurasByType(SPELL_AURA_FLY); - } - // Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAreaMapBounds(newZone); for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) @@ -20122,7 +20329,7 @@ bool Player::isTotalImmune() bool Player::HasTitle(uint32 bitIndex) { - if (bitIndex > 192) + if (bitIndex > MAX_TITLE_INDEX) return false; uint32 fieldIndexOffset = bitIndex / 32; @@ -20130,11 +20337,30 @@ bool Player::HasTitle(uint32 bitIndex) return HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag); } -void Player::SetTitle(CharTitlesEntry const* title) +void Player::SetTitle(CharTitlesEntry const* title, bool lost) { uint32 fieldIndexOffset = title->bit_index / 32; uint32 flag = 1 << (title->bit_index % 32); - SetFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag); + + if(lost) + { + if(!HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag)) + return; + + RemoveFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag); + } + else + { + if(HasFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag)) + return; + + SetFlag(PLAYER__FIELD_KNOWN_TITLES + fieldIndexOffset, flag); + } + + WorldPacket data(SMSG_TITLE_EARNED, 4 + 4); + data << uint32(title->bit_index); + data << uint32(lost ? 0 : 1); // 1 - earned, 0 - lost + GetSession()->SendPacket(&data); } /*-----------------------TRINITY--------------------------*/ @@ -20230,6 +20456,7 @@ void Player::InitRunes() m_runes = new Runes; m_runes->runeState = 0; + m_runes->lastUsedRune = RUNE_BLOOD; for(uint32 i = 0; i < MAX_RUNES; ++i) { @@ -20272,29 +20499,25 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons uint32 Player::CalculateTalentsPoints() const { - uint32 base_talent = getLevel() < 10 ? 0 : uint32((getLevel()-9)*sWorld.getRate(RATE_TALENT)); + uint32 base_talent = getLevel() < 10 ? 0 : getLevel()-9; - if(getClass() != CLASS_DEATH_KNIGHT) - return base_talent; + if(getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609) + return uint32(base_talent * sWorld.getRate(RATE_TALENT)); - uint32 talentPointsForLevel = - (getLevel() < 56 ? 0 : uint32((getLevel()-55)*sWorld.getRate(RATE_TALENT))) - + m_questRewardTalentCount; + uint32 talentPointsForLevel = getLevel() < 56 ? 0 : getLevel() - 55; + talentPointsForLevel += m_questRewardTalentCount; if(talentPointsForLevel > base_talent) talentPointsForLevel = base_talent; - return talentPointsForLevel; + return uint32(talentPointsForLevel * sWorld.getRate(RATE_TALENT)); } -bool Player::IsAllowUseFlyMountsHere() const +bool Player::IsKnowHowFlyIn(uint32 mapid, uint32 zone) const { - if (isGameMaster()) - return true; - - uint32 zoneId = GetZoneId(); - uint32 v_map = GetVirtualMapForMapAndZone(GetMapId(), zoneId); - return v_map == 530 || v_map == 571 && HasSpell(54197) && zoneId != 4197; + // continent checked in SpellMgr::GetSpellAllowedInLocationError at cast and area update + uint32 v_map = GetVirtualMapForMapAndZone(mapid, zone); + return v_map != 571 || HasSpell(54197) && zone != 4197; // Cold Weather Flying } void Player::learnSpellHighRank(uint32 spellid) @@ -20484,7 +20707,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) damage = GetMaxHealth(); // Gust of Wind - if (GetDummyAura(43621)) + if (HasAura(43621)) damage = GetMaxHealth()/2; EnvironmentalDamage(DAMAGE_FALL, damage); @@ -20502,7 +20725,12 @@ void Player::HandleFall(MovementInfo const& movementInfo) void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 miscvalue1/*=0*/, uint32 miscvalue2/*=0*/, Unit *unit/*=NULL*/, uint32 time/*=0*/ ) { - GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time); + GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1, miscvalue2, unit, time); +} + +void Player::CompletedAchievement(AchievementEntry const* entry) +{ + GetAchievementMgr().CompletedAchievement(entry); } void Player::LearnTalent(uint32 talentId, uint32 talentRank) @@ -21130,3 +21358,37 @@ void Player::ActivateSpec(uint32 specNum) resetTalents(true); } + +void Player::RemoveAtLoginFlag( AtLoginFlags f, bool in_db_also /*= false*/ ) +{ + m_atLoginFlags &= ~f; + + if(in_db_also) + CharacterDatabase.PExecute("UPDATE characters set at_login = at_login & ~ %u WHERE guid ='%u'", uint32(f), GetGUIDLow()); +} + +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 + // after decrement+unlink, ++m_mapRefIter will continue correctly + // when the first element of the list is being removed + // nocheck_prev will return the padding element of the RefManager + // instead of NULL in the case of prev + GetMap()->UpdateIteratorBack(this); + Unit::ResetMap(); + GetMapRef().unlink(); +} + +void Player::SetMap(Map * map) +{ + Unit::SetMap(map); + m_mapRef.link(map, this); +} diff --git a/src/game/Player.h b/src/game/Player.h index 111e5def205..a63cb719d6f 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -57,7 +57,6 @@ typedef std::deque<Mail*> PlayerMails; #define PLAYER_MAX_SKILLS 127 #define PLAYER_MAX_DAILY_QUESTS 25 -#define AT_LOAD_PET_FLAGS 16 // Note: SPELLMOD_* values is aura types in fact enum SpellModType @@ -135,24 +134,40 @@ enum ActionButtonUpdateState ACTIONBUTTON_DELETED = 3 }; +enum ActionButtonType +{ + ACTION_BUTTON_SPELL = 0x00, + ACTION_BUTTON_C = 0x01, // click? + ACTION_BUTTON_EQSET = 0x20, + ACTION_BUTTON_MACRO = 0x40, + ACTION_BUTTON_CMACRO = ACTION_BUTTON_C | ACTION_BUTTON_MACRO, + ACTION_BUTTON_ITEM = 0x80 +}; + +#define ACTION_BUTTON_ACTION(X) (uint32(X) & 0x00FFFFFF) +#define ACTION_BUTTON_TYPE(X) ((uint32(X) & 0xFF000000) >> 24) +#define MAX_ACTION_BUTTON_ACTION_VALUE (0x00FFFFFF+1) + struct ActionButton { - ActionButton() : action(0), type(0), misc(0), uState( ACTIONBUTTON_NEW ) {} - ActionButton(uint16 _action, uint8 _type, uint8 _misc) : action(_action), type(_type), misc(_misc), uState( ACTIONBUTTON_NEW ) {} + ActionButton() : packedData(0), uState( ACTIONBUTTON_NEW ) {} - uint16 action; - uint8 type; - uint8 misc; + uint32 packedData; ActionButtonUpdateState uState; -}; -enum ActionButtonType -{ - ACTION_BUTTON_SPELL = 0, - ACTION_BUTTON_EQSET = 32, - ACTION_BUTTON_MACRO = 64, - ACTION_BUTTON_CMACRO= 65, - ACTION_BUTTON_ITEM = 128 + // helpers + ActionButtonType GetType() const { return ActionButtonType(ACTION_BUTTON_TYPE(packedData)); } + uint32 GetAction() const { return ACTION_BUTTON_ACTION(packedData); } + void SetActionAndType(uint32 action, ActionButtonType type) + { + uint32 newData = action | (uint32(type) << 24); + if (newData != packedData) + { + packedData = newData; + if (uState != ACTIONBUTTON_NEW) + uState = ACTIONBUTTON_CHANGED; + } + } }; #define MAX_ACTION_BUTTONS 132 //checked in 2.3.0 @@ -192,6 +207,18 @@ struct PlayerLevelInfo typedef std::list<uint32> PlayerCreateInfoSpells; +struct PlayerCreateInfoAction +{ + PlayerCreateInfoAction() : button(0), type(0), action(0) {} + PlayerCreateInfoAction(uint8 _button, uint32 _action, uint8 _type) : button(_button), type(_type), action(_action) {} + + uint8 button; + uint8 type; + uint32 action; +}; + +typedef std::list<PlayerCreateInfoAction> PlayerCreateInfoActions; + struct PlayerInfo { // existence checked by displayId != 0 // existence checked by displayId != 0 @@ -208,7 +235,7 @@ struct PlayerInfo uint16 displayId_f; PlayerCreateInfoItems item; PlayerCreateInfoSpells spell; - std::list<uint16> action[4]; + PlayerCreateInfoActions action; PlayerLevelInfo* levelInfo; //[level-1] 0..MaxPlayerLevel-1 }; @@ -267,6 +294,7 @@ struct Runes { RuneInfo runes[MAX_RUNES]; uint8 runeState; // mask of available runes + RuneType lastUsedRune; void SetRuneState(uint8 index, bool set = true) { @@ -450,6 +478,8 @@ enum PlayerFlags #define PLAYER_TITLE_HAND_OF_ADAL UI64LIT(0x0000008000000000) // 39 #define PLAYER_TITLE_VENGEFUL_GLADIATOR UI64LIT(0x0000010000000000) // 40 +#define MAX_TITLE_INDEX (3*64) // 3 uint64 fields + // used in PLAYER_FIELD_BYTES values enum PlayerFieldByteFlags { @@ -510,11 +540,12 @@ enum PlayerExtraFlags // 2^n values enum AtLoginFlags { - AT_LOGIN_NONE = 0, - AT_LOGIN_RENAME = 1, - AT_LOGIN_RESET_SPELLS = 2, - AT_LOGIN_RESET_TALENTS = 4, - AT_LOGIN_CUSTOMIZE = 8, + AT_LOGIN_NONE = 0x00, + AT_LOGIN_RENAME = 0x01, + AT_LOGIN_RESET_SPELLS = 0x02, + AT_LOGIN_RESET_TALENTS = 0x04, + AT_LOGIN_CUSTOMIZE = 0x08, + AT_LOGIN_RESET_PET_TALENTS = 0x10, }; typedef std::map<uint32, QuestStatusData> QuestStatusMap; @@ -726,6 +757,14 @@ enum EnviromentalDamage DAMAGE_FALL_TO_VOID = 6 // custom case for fall without durability loss }; +enum PlayedTimeIndex +{ + PLAYED_TIME_TOTAL = 0, + PLAYED_TIME_LEVEL = 1 +}; + +#define MAX_PLAYED_TIME_INDEX 2 + // used at player loading query list preparing, and later result selection enum PlayerLoginQueryIndex { @@ -753,6 +792,14 @@ enum PlayerLoginQueryIndex MAX_PLAYER_LOGIN_QUERY = 21 }; +enum PlayerDelayedOperations +{ + DELAYED_SAVE_PLAYER = 1, + DELAYED_RESURRECT_PLAYER = 2, + DELAYED_SPELL_CAST_DESERTER = 4, + DELAYED_END +}; + // Player summoning auto-decline time (in secs) #define MAX_PLAYER_SUMMON_DELAY (2*MINUTE) #define MAX_MONEY_AMOUNT (0x7FFFFFFF-1) @@ -853,10 +900,11 @@ class TRINITY_DLL_SPEC Player : public Unit void RemoveFromWorld(); bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0); + void TeleportOutOfMap(Map *oldMap); bool TeleportTo(WorldLocation const &loc, uint32 options = 0) { - return TeleportTo(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, options); + return TeleportTo(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation, options); } void SetSummonPoint(uint32 mapid, float x, float y, float z) @@ -873,7 +921,7 @@ class TRINITY_DLL_SPEC Player : public Unit void Update( uint32 time ); - void BuildEnumData( QueryResult * result, WorldPacket * p_data ); + static bool BuildEnumData( QueryResult * result, WorldPacket * p_data ); void SetInWater(bool apply); @@ -905,6 +953,7 @@ class TRINITY_DLL_SPEC Player : public Unit void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); } bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = NULL, uint32 spellid = 0); bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0); + void CleanupAfterTaxiFlight(); // mount_id can be used in scripting calls bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; } void SetAcceptWhispers(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; } @@ -926,9 +975,9 @@ class TRINITY_DLL_SPEC Player : public Unit // Played Time Stuff time_t m_logintime; time_t m_Last_tick; - uint32 m_Played_time[2]; - uint32 GetTotalPlayedTime() { return m_Played_time[0]; }; - uint32 GetLevelPlayedTime() { return m_Played_time[1]; }; + uint32 m_Played_time[MAX_PLAYED_TIME_INDEX]; + uint32 GetTotalPlayedTime() { return m_Played_time[PLAYED_TIME_TOTAL]; }; + uint32 GetLevelPlayedTime() { return m_Played_time[PLAYED_TIME_LEVEL]; }; void setDeathState(DeathState s); // overwrite Unit::setDeathState @@ -1090,7 +1139,7 @@ class TRINITY_DLL_SPEC Player : public Unit return mainItem && mainItem->GetProto()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip(); } void SendNewItem( Item *item, uint32 count, bool received, bool created, bool broadcast = false ); - bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint64 bagguid, uint8 slot); + bool BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint8 bag, uint8 slot); float GetReputationPriceDiscount( Creature const* pCreature ) const; Player* GetTrader() const { return pTrader; } @@ -1193,7 +1242,8 @@ class TRINITY_DLL_SPEC Player : public Unit void GroupEventHappens( uint32 questId, WorldObject const* pEventObject ); void ItemAddedQuestCheck( uint32 entry, uint32 count ); void ItemRemovedQuestCheck( uint32 entry, uint32 count ); - void KilledMonster( uint32 entry, uint64 guid ); + void KilledMonster( CreatureInfo const* cInfo, uint64 guid ); + void KilledMonsterCredit( uint32 entry, uint64 guid ); void CastedCreatureOrGO( uint32 entry, uint64 guid, uint32 spell_id ); void TalkedToCreature( uint32 entry, uint64 guid ); void MoneyChanged( uint32 value ); @@ -1234,6 +1284,7 @@ class TRINITY_DLL_SPEC Player : public Unit static uint32 GetUInt32ValueFromDB(uint16 index, uint64 guid); static float GetFloatValueFromDB(uint16 index, uint64 guid); static uint32 GetZoneIdFromDB(uint64 guid); + static uint32 GetLevelFromDB(uint64 guid); static bool LoadPositionFromDB(uint32& mapid, float& x,float& y,float& z,float& o, bool& in_flight, uint64 guid); /*********************************************************/ @@ -1242,6 +1293,7 @@ class TRINITY_DLL_SPEC Player : public Unit void SaveToDB(); void SaveInventoryAndGoldToDB(); // fast save function for item/money cheating preventing + void SaveGoldToDB(); void SaveDataFieldToDB(); static bool SaveValuesArrayInDB(Tokens const& data,uint64 guid); static void SetUInt32ValueInArray(Tokens& data,uint16 index, uint32 value); @@ -1256,7 +1308,6 @@ class TRINITY_DLL_SPEC Player : public Unit void SetBindPoint(uint64 guid); void SendTalentWipeConfirm(uint64 guid); - void RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ); void SendPetSkillWipeConfirm(); void CalcRage( uint32 damage,bool attacker ); void RegenerateAll(); @@ -1292,7 +1343,8 @@ class TRINITY_DLL_SPEC Player : public Unit uint8 GetComboPoints() { return m_comboPoints; } const uint64& GetComboTarget() const { return m_comboTarget; } - void AddComboPoints(Unit* target, int8 count); + void AddComboPoints(Unit* target, int8 count, Spell * spell = NULL); + void GainSpellComboPoints(int8 count); void ClearComboPoints(); void SendComboPoints(); @@ -1356,7 +1408,7 @@ class TRINITY_DLL_SPEC Player : public Unit void SendInitialSpells(); bool addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled); void learnSpell(uint32 spell_id, bool dependent); - void removeSpell(uint32 spell_id, bool disabled = false, bool update_action_bar_for_low_rank = false); + void removeSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true); void resetSpells(); void learnDefaultSpells(); void learnQuestRewardedSpells(); @@ -1398,6 +1450,8 @@ class TRINITY_DLL_SPEC Player : public Unit 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(SpellEntry const *spellInfo, SpellModifier *mod, Spell * spell = NULL); template <class T> T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell * spell = NULL); @@ -1406,6 +1460,8 @@ class TRINITY_DLL_SPEC Player : public Unit 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 { SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); @@ -1422,6 +1478,9 @@ class TRINITY_DLL_SPEC Player : public Unit void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL); void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ); void RemoveSpellCooldown(uint32 spell_id, bool update = false); + void RemoveSpellCategoryCooldown(uint32 cat, bool update = false); + void SendClearCooldown( uint32 spell_id, Unit* target ); + void RemoveCategoryCooldown(uint32 cat); void RemoveArenaSpellCooldowns(); void RemoveAllSpellCooldown(); @@ -1454,7 +1513,7 @@ class TRINITY_DLL_SPEC Player : public Unit m_cinematic = cine; } - bool addActionButton(uint8 button, uint16 action, uint8 type, uint8 misc); + ActionButton* addActionButton(uint8 button, uint32 action, uint8 type); void removeActionButton(uint8 button); void SendInitialActionButtons() const; @@ -1597,7 +1656,7 @@ class TRINITY_DLL_SPEC Player : public Unit void SetSession(WorldSession *s) { m_session = s; } void BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const; - void DestroyForPlayer( Player *target ) const; + void DestroyForPlayer( Player *target, bool anim = false ) const; void SendDelayResponse(const uint32); void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP); @@ -1607,7 +1666,7 @@ class TRINITY_DLL_SPEC Player : public Unit void SendAttackSwingDeadTarget(); void SendAttackSwingNotInRange(); void SendAttackSwingBadFacingAttack(); - void SendAutoRepeatCancel(); + void SendAutoRepeatCancel(Unit *target); void SendExplorationExperience(uint32 Area, uint32 Experience); void SendDungeonDifficulty(bool IsInGroup); @@ -1681,6 +1740,7 @@ class TRINITY_DLL_SPEC Player : public Unit bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; } void SetSemaphoreTeleportNear(bool semphsetting) { mSemaphoreTeleport_Near = semphsetting; } void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; } + void ProcessDelayedOperations(); void CheckExploreSystem(void); @@ -1690,6 +1750,8 @@ class TRINITY_DLL_SPEC Player : public Unit static uint32 getFactionForRace(uint8 race); void setFactionForRace(uint8 race); + void InitDisplayIds(); + bool IsAtGroupRewardDistance(WorldObject const* pRewardSource) const; bool RewardPlayerAndGroupAtKill(Unit* pVictim); void RewardPlayerAndGroupAtEvent(uint32 creature_id,WorldObject* pRewardSource); @@ -1755,7 +1817,8 @@ class TRINITY_DLL_SPEC Player : public Unit void _ApplyItemMods(Item *item,uint8 slot,bool apply); void _RemoveAllItemMods(); void _ApplyAllItemMods(); - void _ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply); + void _ApplyAllLevelScaleItemMods(bool apply); + void _ApplyItemBonuses(ItemPrototype const *proto,uint8 slot,bool apply, bool only_level_scale = false); void _ApplyAmmoBonuses(); bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot); void ToggleMetaGemsActive(uint8 exceptslot, bool apply); @@ -1765,8 +1828,9 @@ class TRINITY_DLL_SPEC Player : public Unit void ApplyItemEquipSpell(Item *item, bool apply, bool form_change = false); void ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply, bool form_change = false); void UpdateEquipSpellsAtFormChange(); - void CastItemCombatSpell(Item *item, CalcDamageInfo *damageInfo, ItemPrototype const * proto); + void CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx); void CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 cast_count, uint32 glyphIndex); + void CastItemCombatSpell(Unit *target, WeaponAttackType attType, uint32 procVictim, uint32 procEx, Item *item, ItemPrototype const * proto); void SendEquipmentSetList(); void SetEquipmentSet(uint32 index, EquipmentSet eqset); @@ -1942,7 +2006,7 @@ class TRINITY_DLL_SPEC Player : public Unit } void HandleFall(MovementInfo const& movementInfo); - bool IsAllowUseFlyMountsHere() const; + bool IsKnowHowFlyIn(uint32 mapid, uint32 zone) const; void SetClientControl(Unit* target, uint8 allowMove); @@ -1970,7 +2034,7 @@ class TRINITY_DLL_SPEC Player : public Unit float m_homebindX; float m_homebindY; float m_homebindZ; - void RelocateToHomebind() { SetMapId(m_homebindMapId); Relocate(m_homebindX,m_homebindY,m_homebindZ); } + void RelocateToHomebind(uint32 & newMap) { newMap = m_homebindMapId; Relocate(m_homebindX,m_homebindY,m_homebindZ); } // currently visible objects at player client typedef std::set<uint64> ClientGUIDs; @@ -1989,15 +2053,13 @@ class TRINITY_DLL_SPEC Player : public Unit void UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObject*>& visibleNow); // Stealth detection system - uint32 m_DetectInvTimer; void HandleStealthedUnitsDetection(); uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; } void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; } - uint32 GetAtLoginFlag() { return m_atLoginFlags; } - void SetPetAtLoginFlag(uint8 f) { m_atLoginFlags |= uint32(f<<AT_LOAD_PET_FLAGS); } + void RemoveAtLoginFlag(AtLoginFlags f, bool in_db_also = false); LookingForGroup m_lookingForGroup; @@ -2025,6 +2087,7 @@ class TRINITY_DLL_SPEC Player : public Unit BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES]; InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty); BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } + InstanceSave * GetInstanceSave(uint32 mapid); void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false); InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); @@ -2061,6 +2124,10 @@ class TRINITY_DLL_SPEC Player : public Unit GridReference<Player> &GetGridRef() { return m_gridRef; } MapReference &GetMapRef() { return m_mapRef; } + // Set map to player and add reference + void SetMap(Map * map); + void ResetMap(); + bool isAllowedToLoot(Creature* creature); DeclinedName const* GetDeclinedNames() const { return m_declinedname; } @@ -2068,6 +2135,8 @@ class TRINITY_DLL_SPEC Player : public Unit uint8 GetBaseRune(uint8 index) const { return m_runes->runes[index].BaseRune; } uint8 GetCurrentRune(uint8 index) const { return m_runes->runes[index].CurrentRune; } uint8 GetRuneCooldown(uint8 index) const { return m_runes->runes[index].Cooldown; } + RuneType GetLastUsedRune() { return m_runes->lastUsedRune; } + void SetLastUsedRune(RuneType type) { m_runes->lastUsedRune = type; } void SetBaseRune(uint8 index, uint8 baseRune) { m_runes->runes[index].BaseRune = baseRune; } void SetCurrentRune(uint8 index, uint8 currentRune) { m_runes->runes[index].CurrentRune = currentRune; } void SetRuneCooldown(uint8 index, uint8 cooldown) { m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); } @@ -2075,11 +2144,14 @@ class TRINITY_DLL_SPEC Player : public Unit void ResyncRunes(uint8 count); void AddRunePower(uint8 index); void InitRunes(); + AchievementMgr& GetAchievementMgr() { return m_achievementMgr; } - void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0); + void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1 = 0, uint32 miscvalue2 = 0, Unit *unit = NULL, uint32 time = 0); + void CompletedAchievement(AchievementEntry const* entry); + bool HasTitle(uint32 bitIndex); bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); } - void SetTitle(CharTitlesEntry const* title); + void SetTitle(CharTitlesEntry const* title, bool lost = false); //bool isActiveObject() const { return true; } bool canSeeSpellClickOn(Creature const* creature) const; @@ -2175,8 +2247,6 @@ class TRINITY_DLL_SPEC Player : public Unit void outDebugValues() const; uint64 m_lootGuid; - uint32 m_race; - uint32 m_class; uint32 m_team; uint32 m_nextSave; time_t m_speakTime; @@ -2313,6 +2383,13 @@ class TRINITY_DLL_SPEC Player : public Unit int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest); void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData ); + bool IsCanDelayTeleport() const { return m_bCanDelayTeleport; } + void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; } + bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; } + void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; } + + void ScheduleDelayedOperation(uint32 operation); + GridReference<Player> m_gridRef; MapReference m_mapRef; @@ -2329,9 +2406,16 @@ class TRINITY_DLL_SPEC Player : public Unit // Current teleport data WorldLocation m_teleport_dest; + uint32 m_teleport_options; bool mSemaphoreTeleport_Near; bool mSemaphoreTeleport_Far; + uint32 m_DelayedOperations; + bool m_bCanDelayTeleport; + bool m_bHasDelayedTeleport; + + uint32 m_DetectInvTimer; + // Temporary removed pet cache uint32 m_temporaryUnsummonedPetNumber; uint32 m_oldpetspell; diff --git a/src/game/PlayerDump.cpp b/src/game/PlayerDump.cpp index 73939115211..06550269856 100644 --- a/src/game/PlayerDump.cpp +++ b/src/game/PlayerDump.cpp @@ -304,19 +304,19 @@ void PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tabl // collect guids switch ( type ) { - case DTT_INVENTORY: - StoreGUID(result,3,items); break; // item guid collection - case DTT_ITEM: - StoreGUID(result,0,ITEM_FIELD_ITEM_TEXT_ID,texts); break; - // item text id collection - case DTT_PET: - StoreGUID(result,0,pets); break; // pet guid collection - case DTT_MAIL: - StoreGUID(result,0,mails); // mail id collection - StoreGUID(result,6,texts); break; // item text id collection - case DTT_MAIL_ITEM: - StoreGUID(result,1,items); break; // item guid collection - default: break; + case DTT_INVENTORY: + StoreGUID(result,3,items); break; // item guid collection + case DTT_ITEM: + StoreGUID(result,0,ITEM_FIELD_ITEM_TEXT_ID,texts); break; + // item text id collection + case DTT_PET: + StoreGUID(result,0,pets); break; // pet guid collection + case DTT_MAIL: + StoreGUID(result,0,mails); // mail id collection + StoreGUID(result,7,texts); break; // item text id collection + case DTT_MAIL_ITEM: + StoreGUID(result,1,items); break; // item guid collection + default: break; } dump += CreateDumpString(tableTo, result); @@ -332,7 +332,7 @@ void PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tabl std::string PlayerDumpWriter::GetDump(uint32 guid) { std::string dump; - + dump += "IMPORTANT NOTE: This sql queries not created for apply directly, use '.pdump load' command in console or client chat instead.\n"; dump += "IMPORTANT NOTE: NOT APPLY ITS DIRECTLY to character DB or you will DAMAGE and CORRUPT character DB\n\n"; @@ -395,7 +395,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s { QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", account); uint8 charcount = 0; - if ( result ) + if (result) { Field *fields=result->Fetch(); charcount = fields[0].GetUInt8(); @@ -407,7 +407,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s } FILE *fin = fopen(file.c_str(), "r"); - if(!fin) + if (!fin) return DUMP_FILE_OPEN_ERROR; QueryResult * result = NULL; @@ -415,7 +415,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s // make sure the same guid doesn't already exist and is safe to use bool incHighest = true; - if(guid != 0 && guid < objmgr.m_hiCharGuid) + if (guid != 0 && guid < objmgr.m_hiCharGuid) { result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE guid = '%d'", guid); if (result) @@ -429,10 +429,10 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s guid = objmgr.m_hiCharGuid; // normalize the name if specified and check if it exists - if(!normalizePlayerName(name)) + if (!normalizePlayerName(name)) name = ""; - if(ObjectMgr::IsValidName(name,true)) + if (ObjectMgr::CheckPlayerName(name,true) == CHAR_NAME_SUCCESS) { CharacterDatabase.escape_string(name); // for safe, we use name only for sql quearies anyway result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str()); @@ -442,7 +442,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s delete result; } } - else name = ""; + else + name = ""; // name encoded or empty @@ -453,6 +454,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s std::map<uint32,uint32> items; std::map<uint32,uint32> mails; + std::map<uint32,uint32> itemTexts; char buf[32000] = ""; typedef std::map<uint32, uint32> PetIds; // old->new petid relation @@ -547,8 +549,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s if (result) { delete result; - // rename on login: `at_login` field 30 in raw field list - if(!changenth(line, 30, "1")) + + if(!changenth(line, 37, "1")) // rename on login: `at_login` field 37 in raw field list ROLLBACK(DUMP_FILE_BROKEN); } } @@ -581,6 +583,8 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s ROLLBACK(DUMP_FILE_BROKEN); if(!changetoknth(vals, ITEM_FIELD_OWNER+1, newguid)) ROLLBACK(DUMP_FILE_BROKEN); + if(!changetokGuid(vals, ITEM_FIELD_ITEM_TEXT_ID+1, itemTexts, objmgr.m_ItemTextId,true)) + ROLLBACK(DUMP_FILE_BROKEN); if(!changenth(line, 3, vals.c_str())) ROLLBACK(DUMP_FILE_BROKEN); break; @@ -638,10 +642,12 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s } case DTT_MAIL: // mail { - // id,messageType,stationery,sender,receiver + // id,messageType,stationery,mailtemplate,sender,receiver,subject,itemText if(!changeGuid(line, 1, mails, objmgr.m_mailid)) ROLLBACK(DUMP_FILE_BROKEN); - if(!changenth(line, 5, newguid)) + if(!changenth(line, 6, newguid)) + ROLLBACK(DUMP_FILE_BROKEN); + if(!changeGuid(line, 8, itemTexts, objmgr.m_ItemTextId)) ROLLBACK(DUMP_FILE_BROKEN); break; } @@ -656,6 +662,18 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s ROLLBACK(DUMP_FILE_BROKEN); break; } + case DTT_ITEM_TEXT: // item_text + { + // id + if(!changeGuid(line, 1, itemTexts, objmgr.m_ItemTextId)) + ROLLBACK(DUMP_FILE_BROKEN); + + // add it to cache + uint32 id= atoi(getnth(line,1).c_str()); + std::string text = getnth(line,2); + objmgr.AddItemText(id,text); + break; + } default: sLog.outError("Unknown dump table type: %u",type); break; @@ -669,6 +687,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s objmgr.m_hiItemGuid += items.size(); objmgr.m_mailid += mails.size(); + objmgr.m_ItemTextId += itemTexts.size(); if(incHighest) ++objmgr.m_hiCharGuid; diff --git a/src/game/PointMovementGenerator.cpp b/src/game/PointMovementGenerator.cpp index ed057854aaa..ffd036e9c21 100644 --- a/src/game/PointMovementGenerator.cpp +++ b/src/game/PointMovementGenerator.cpp @@ -30,9 +30,9 @@ template<class T> void PointMovementGenerator<T>::Initialize(T &unit) { unit.StopMoving(); - unit.clearUnitState(UNIT_STAT_MOVING); Traveller<T> traveller(unit); - i_destinationHolder.SetDestination(traveller,i_x,i_y,i_z, !unit.hasUnitState(UNIT_STAT_JUMPING)); + // knockback effect has UNIT_STAT_JUMPING set,so if here we disable sentmonstermove there will be creature position sync problem between client and server + i_destinationHolder.SetDestination(traveller,i_x,i_y,i_z, true /* !unit.hasUnitState(UNIT_STAT_JUMPING)*/); if (unit.GetTypeId() == TYPEID_UNIT && ((Creature*)&unit)->canFly()) unit.AddUnitMovementFlag(MOVEMENTFLAG_FLYING); diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp index 09a1d4293b7..dd0834b80f4 100644 --- a/src/game/PoolHandler.cpp +++ b/src/game/PoolHandler.cpp @@ -127,10 +127,7 @@ void PoolGroup<Creature>::Despawn1Object(uint32 guid) objmgr.RemoveCreatureFromGrid(guid, data); if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL)) - { - pCreature->CleanupsBeforeDelete(); pCreature->AddObjectToRemoveList(); - } } } diff --git a/src/game/QueryHandler.cpp b/src/game/QueryHandler.cpp index 9da24d404f9..b70a85c58e2 100644 --- a/src/game/QueryHandler.cpp +++ b/src/game/QueryHandler.cpp @@ -65,17 +65,17 @@ void WorldSession::SendNameQueryOpcodeFromDB(uint64 guid) CharacterDatabase.AsyncPQuery(&WorldSession::SendNameQueryOpcodeFromDBCallBack, GetAccountId(), !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ? // ------- Query Without Declined Names -------- - // 0 1 2 - "SELECT guid, name, SUBSTRING(data, LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))+2, LENGTH(SUBSTRING_INDEX(data, ' ', '%u')) - LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))-1) " + // 0 1 2 3 4 + "SELECT guid, name, race, gender, class " "FROM characters WHERE guid = '%u'" : // --------- Query With Declined Names --------- - // 0 1 2 - "SELECT characters.guid, name, SUBSTRING(data, LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))+2, LENGTH(SUBSTRING_INDEX(data, ' ', '%u')) - LENGTH(SUBSTRING_INDEX(data, ' ', '%u'))-1), " - // 3 4 5 6 7 + // 0 1 2 3 4 + "SELECT characters.guid, name, race, gender, class, " + // 5 6 7 8 9 "genitive, dative, accusative, instrumental, prepositional " "FROM characters LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid WHERE characters.guid = '%u'", - UNIT_FIELD_BYTES_0, UNIT_FIELD_BYTES_0+1, UNIT_FIELD_BYTES_0, GUID_LOPART(guid)); + GUID_LOPART(guid)); } void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult *result, uint32 accountId) @@ -93,31 +93,35 @@ void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult *result, uint32 Field *fields = result->Fetch(); uint32 guid = fields[0].GetUInt32(); std::string name = fields[1].GetCppString(); - uint32 field = 0; + uint8 pRace = 0, pGender = 0, pClass = 0; if(name == "") name = session->GetTrinityString(LANG_NON_EXIST_CHARACTER); else - field = fields[2].GetUInt32(); + { + pRace = fields[2].GetUInt8(); + pGender = fields[3].GetUInt8(); + pClass = fields[4].GetUInt8(); + } // guess size WorldPacket data( SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+1+10) ); data.appendPackGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); data << uint8(0); // added in 3.1 data << name; - data << uint8(0); - data << uint8(field & 0xFF); - data << uint8((field >> 16) & 0xFF); - data << uint8((field >> 8) & 0xFF); + data << uint8(0); // realm name for cross realm BG usage + data << uint8(pRace); // race + data << uint8(pGender); // gender + data << uint8(pClass); // class - // if the first declined name field (3) is empty, the rest must be too - if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[3].GetCppString() != "") + // if the first declined name field (5) is empty, the rest must be too + if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && fields[5].GetCppString() != "") { data << uint8(1); // is declined - for(int i = 3; i < MAX_DECLINED_NAME_CASES+3; ++i) + for(int i = 5; i < MAX_DECLINED_NAME_CASES+5; ++i) data << fields[i].GetCppString(); } else - data << uint8(0); // is declined + data << uint8(0); // is not declined session->SendPacket( &data ); delete result; @@ -187,8 +191,8 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data ) data << uint32(ci->type); // CreatureType.dbc data << uint32(ci->family); // CreatureFamily.dbc data << uint32(ci->rank); // Creature Rank (elite, boss, etc) - data << uint32(ci->unk1); // new in 3.1, creature entry? - data << uint32(ci->unk2); // new in 3.1, creature entry? + data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit + data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit data << uint32(ci->DisplayID_A[0]); // modelid_male1 data << uint32(ci->DisplayID_H[0]); // modelid_female1 ? data << uint32(ci->DisplayID_A[1]); // modelid_male2 ? diff --git a/src/game/QuestDef.h b/src/game/QuestDef.h index c3285ec816c..412c66cf9fd 100644 --- a/src/game/QuestDef.h +++ b/src/game/QuestDef.h @@ -96,9 +96,9 @@ enum QuestStatus { QUEST_STATUS_NONE = 0, QUEST_STATUS_COMPLETE = 1, - QUEST_STATUS_UNAVAILABLE = 2, + //QUEST_STATUS_UNAVAILABLE = 2, QUEST_STATUS_INCOMPLETE = 3, - QUEST_STATUS_AVAILABLE = 4, + //QUEST_STATUS_AVAILABLE = 4, MAX_QUEST_STATUS }; diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp index b2478860c61..52d2ee6d77a 100644 --- a/src/game/QuestHandler.cpp +++ b/src/game/QuestHandler.cpp @@ -439,60 +439,56 @@ void WorldSession::HandlePushQuestToParty(WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,4); - uint32 quest; - recvPacket >> quest; + uint32 questId; + recvPacket >> questId; - sLog.outDebug( "WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", quest ); + sLog.outDebug("WORLD: Received CMSG_PUSHQUESTTOPARTY quest = %u", questId); - Quest const *pQuest = objmgr.GetQuestTemplate(quest); - if( pQuest ) + if (Quest const *pQuest = objmgr.GetQuestTemplate(questId)) { - if( _player->GetGroup() ) + if (Group* pGroup = _player->GetGroup()) { - Group *pGroup = _player->GetGroup(); - if( pGroup ) + for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) { - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player *pPlayer = itr->getSource(); - if (!pPlayer || pPlayer == _player) // skip self - continue; + Player *pPlayer = itr->getSource(); - _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST); + if (!pPlayer || pPlayer == _player) // skip self + continue; - if( !pPlayer->SatisfyQuestStatus( pQuest, false ) ) - { - _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_HAVE_QUEST ); - continue; - } + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_SHARING_QUEST); - if( pPlayer->GetQuestStatus( quest ) == QUEST_STATUS_COMPLETE ) - { - _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_FINISH_QUEST ); - continue; - } + if (!pPlayer->SatisfyQuestStatus(pQuest, false)) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_HAVE_QUEST); + continue; + } - if( !pPlayer->CanTakeQuest( pQuest, false ) ) - { - _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_CANT_TAKE_QUEST ); - continue; - } + if (pPlayer->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_FINISH_QUEST); + continue; + } - if( !pPlayer->SatisfyQuestLog( false ) ) - { - _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_LOG_FULL ); - continue; - } + if (!pPlayer->CanTakeQuest(pQuest, false)) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_CANT_TAKE_QUEST); + continue; + } - if( pPlayer->GetDivider() != 0 ) - { - _player->SendPushToPartyResponse( pPlayer, QUEST_PARTY_MSG_BUSY ); - continue; - } + if (!pPlayer->SatisfyQuestLog(false)) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_LOG_FULL); + continue; + } - pPlayer->PlayerTalkClass->SendQuestGiverQuestDetails( pQuest, _player->GetGUID(), true ); - pPlayer->SetDivider( _player->GetGUID() ); + if (pPlayer->GetDivider() != 0) + { + _player->SendPushToPartyResponse(pPlayer, QUEST_PARTY_MSG_BUSY); + continue; } + + pPlayer->PlayerTalkClass->SendQuestGiverQuestDetails(pQuest, _player->GetGUID(), true); + pPlayer->SetDivider(_player->GetGUID()); } } } diff --git a/src/game/ReputationMgr.cpp b/src/game/ReputationMgr.cpp index ee7ca8d44a4..e4ed5b0db2e 100644 --- a/src/game/ReputationMgr.cpp +++ b/src/game/ReputationMgr.cpp @@ -255,7 +255,7 @@ bool ReputationMgr::SetOneFactionReputation(FactionEntry const* factionEntry, in if(incremental) { // int32 *= float cause one point loss? - standing = (int32)((float)standing * sWorld.getRate(RATE_REPUTATION_GAIN)); + standing = floor( (float)standing * sWorld.getRate(RATE_REPUTATION_GAIN) + 0.5 ); standing += itr->second.Standing + BaseRep; } @@ -475,4 +475,4 @@ void ReputationMgr::UpdateRankCounters( ReputationRank old_rank, ReputationRank ++m_reveredFactionCount; if(new_rank >= REP_HONORED) ++m_honoredFactionCount; -}
\ No newline at end of file +} diff --git a/src/game/ReputationMgr.h b/src/game/ReputationMgr.h index b81634119df..d63c518eb82 100644 --- a/src/game/ReputationMgr.h +++ b/src/game/ReputationMgr.h @@ -21,9 +21,16 @@ #include "Common.h" #include "SharedDefines.h" +#include "Language.h" #include "DBCStructure.h" #include <map> +static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] = +{ + LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL, + LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED +}; + enum FactionFlags { FACTION_FLAG_VISIBLE = 0x01, // makes visible in client (set or can be set at interaction with target of this faction) diff --git a/src/game/ScriptCalls.cpp b/src/game/ScriptCalls.cpp index fec1afb08ae..b8870c2a1dd 100644 --- a/src/game/ScriptCalls.cpp +++ b/src/game/ScriptCalls.cpp @@ -79,6 +79,7 @@ bool LoadScriptingModule(char const* libName) ||!(testScript->ItemQuestAccept =(scriptCallItemQuestAccept )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemQuestAccept" )) ||!(testScript->GOQuestAccept =(scriptCallGOQuestAccept )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"GOQuestAccept" )) ||!(testScript->ItemUse =(scriptCallItemUse )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemUse" )) + ||!(testScript->ItemExpire =(scriptCallItemExpire )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"ItemExpire" )) ||!(testScript->EffectDummyGameObj =(scriptCallEffectDummyGameObj )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyGameObj" )) ||!(testScript->EffectDummyCreature =(scriptCallEffectDummyCreature )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyCreature" )) ||!(testScript->EffectDummyItem =(scriptCallEffectDummyItem )TRINITY_GET_PROC_ADDR(testScript->hScriptsLib,"EffectDummyItem" )) diff --git a/src/game/ScriptCalls.h b/src/game/ScriptCalls.h index 4e23f9f576d..0eae69cb505 100644 --- a/src/game/ScriptCalls.h +++ b/src/game/ScriptCalls.h @@ -59,6 +59,7 @@ typedef bool(TRINITY_IMPORT * scriptCallItemQuestAccept)(Player *player, Item *, typedef bool(TRINITY_IMPORT * scriptCallGOQuestAccept)(Player *player, GameObject *, Quest const*); typedef bool(TRINITY_IMPORT * scriptCallGOChooseReward)(Player *player, GameObject *, Quest const*, uint32 opt ); typedef bool(TRINITY_IMPORT * scriptCallItemUse) (Player *player, Item *_Item, SpellCastTargets const& targets); +typedef bool(TRINITY_IMPORT * scriptCallItemExpire) (Player *player, ItemPrototype const *_ItemProto); typedef bool(TRINITY_IMPORT * scriptCallEffectDummyGameObj) (Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget); typedef bool(TRINITY_IMPORT * scriptCallEffectDummyCreature) (Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget); typedef bool(TRINITY_IMPORT * scriptCallEffectDummyItem) (Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget); @@ -89,6 +90,7 @@ typedef struct scriptCallItemQuestAccept ItemQuestAccept; scriptCallGOQuestAccept GOQuestAccept; scriptCallItemUse ItemUse; + scriptCallItemExpire ItemExpire; scriptCallEffectDummyGameObj EffectDummyGameObj; scriptCallEffectDummyCreature EffectDummyCreature; scriptCallEffectDummyItem EffectDummyItem; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index e958f911440..987eea769f5 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -249,8 +249,9 @@ enum SpellCategory #define SPELL_ATTR_CASTABLE_WHILE_SITTING 0x08000000 // 27 castable while sitting #define SPELL_ATTR_CANT_USED_IN_COMBAT 0x10000000 // 28 Cannot be used in combat #define SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY 0x20000000 // 29 unaffected by invulnerability (hmm possible not...) -#define SPELL_ATTR_BREAKABLE_BY_DAMAGE 0x40000000 // 30 breakable by damage? +#define SPELL_ATTR_BREAKABLE_BY_DAMAGE 0x40000000 // 30 #define SPELL_ATTR_CANT_CANCEL 0x80000000 // 31 positive aura can't be canceled + #define SPELL_ATTR_EX_DISMISS_PET 0x00000001 // 0 dismiss pet and not allow to summon new one? #define SPELL_ATTR_EX_DRAIN_ALL_POWER 0x00000002 // 1 use all power (Only paladin Lay of Hands and Bunyanize) #define SPELL_ATTR_EX_CHANNELED_1 0x00000004 // 2 channeled target @@ -270,7 +271,7 @@ enum SpellCategory #define SPELL_ATTR_EX_UNK16 0x00010000 // 16 on immuniy #define SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET 0x00020000 // 17 #define SPELL_ATTR_EX_UNK18 0x00040000 // 18 -#define SPELL_ATTR_EX_UNK19 0x00080000 // 19 +#define SPELL_ATTR_EX_CANT_TARGET_SELF 0x00080000 // 19 Applies only to unit target - for example Divine Intervention (19752) #define SPELL_ATTR_EX_REQ_COMBO_POINTS1 0x00100000 // 20 Req combo points on target #define SPELL_ATTR_EX_UNK21 0x00200000 // 21 #define SPELL_ATTR_EX_REQ_COMBO_POINTS2 0x00400000 // 22 Req combo points on target @@ -320,11 +321,11 @@ enum SpellCategory #define SPELL_ATTR_EX3_UNK0 0x00000001 // 0 #define SPELL_ATTR_EX3_UNK1 0x00000002 // 1 #define SPELL_ATTR_EX3_UNK2 0x00000004 // 2 -#define SPELL_ATTR_EX3_UNK3 0x00000008 // 3 +#define SPELL_ATTR_EX3_BLOCKABLE_SPELL 0x00000008 // 3 Only dmg class melee in 3.1.3 #define SPELL_ATTR_EX3_UNK4 0x00000010 // 4 Druid Rebirth only this spell have this flag #define SPELL_ATTR_EX3_UNK5 0x00000020 // 5 #define SPELL_ATTR_EX3_UNK6 0x00000040 // 6 -#define SPELL_ATTR_EX3_UNK7 0x00000080 // 7 separate stack for every caster +#define SPELL_ATTR_EX3_STACKS_FOR_DIFFERENT_CASTERS 0x00000080 // 7 separate stack for every caster #define SPELL_ATTR_EX3_PLAYERS_ONLY 0x00000100 // 8 Player only? #define SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2 0x00000200 // 9 triggered from effect? #define SPELL_ATTR_EX3_MAIN_HAND 0x00000400 // 10 Main hand weapon required @@ -336,7 +337,7 @@ enum SpellCategory #define SPELL_ATTR_EX3_UNK16 0x00010000 // 16 no triggers effects that trigger on casting a spell?? #define SPELL_ATTR_EX3_NO_INITIAL_AGGRO 0x00020000 // 17 Soothe Animal, 39758, Mind Soothe #define SPELL_ATTR_EX3_UNK18 0x00040000 // 18 -#define SPELL_ATTR_EX3_UNK19 0x00080000 // 19 spells triggered by spell with this flag can't proc caster auras and can proc from triggered (swings too - 20178) +#define SPELL_ATTR_EX3_DISABLE_PROC 0x00080000 // 19 during aura proc no spells can trigger (20178, 20375) #define SPELL_ATTR_EX3_DEATH_PERSISTENT 0x00100000 // 20 Death persistent spells #define SPELL_ATTR_EX3_UNK21 0x00200000 // 21 #define SPELL_ATTR_EX3_REQ_WAND 0x00400000 // 22 Req wand @@ -358,7 +359,7 @@ enum SpellCategory #define SPELL_ATTR_EX4_UNK5 0x00000020 // 5 #define SPELL_ATTR_EX4_NOT_STEALABLE 0x00000040 // 6 although such auras might be dispellable, they cannot be stolen #define SPELL_ATTR_EX4_UNK7 0x00000080 // 7 -#define SPELL_ATTR_EX4_UNK8 0x00000100 // 8 +#define SPELL_ATTR_EX4_FIXED_DAMAGE 0x00000100 // 8 decimate, share damage? #define SPELL_ATTR_EX4_UNK9 0x00000200 // 9 #define SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST 0x00000400 // 10 Rogue Shiv have this flag #define SPELL_ATTR_EX4_UNK11 0x00000800 // 11 @@ -593,7 +594,7 @@ enum SpellEffects SPELL_EFFECT_SUMMON_PET = 56, SPELL_EFFECT_LEARN_PET_SPELL = 57, SPELL_EFFECT_WEAPON_DAMAGE = 58, - SPELL_EFFECT_OPEN_LOCK_ITEM = 59, + SPELL_EFFECT_CREATE_RANDOM_ITEM = 59, SPELL_EFFECT_PROFICIENCY = 60, SPELL_EFFECT_SEND_EVENT = 61, SPELL_EFFECT_POWER_BURN = 62, @@ -666,10 +667,10 @@ enum SpellEffects SPELL_EFFECT_APPLY_AREA_AURA_ENEMY = 129, SPELL_EFFECT_REDIRECT_THREAT = 130, SPELL_EFFECT_131 = 131, - SPELL_EFFECT_132 = 132, + SPELL_EFFECT_PLAY_MUSIC = 132, SPELL_EFFECT_UNLEARN_SPECIALIZATION = 133, SPELL_EFFECT_KILL_CREDIT2 = 134, - SPELL_EFFECT_135 = 135, + SPELL_EFFECT_CALL_PET = 135, SPELL_EFFECT_HEAL_PCT = 136, SPELL_EFFECT_ENERGIZE_PCT = 137, SPELL_EFFECT_138 = 138, @@ -702,196 +703,201 @@ enum SpellEffects enum SpellCastResult { - SPELL_FAILED_AFFECTING_COMBAT = 0, - SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1, - SPELL_FAILED_ALREADY_AT_FULL_MANA = 2, - SPELL_FAILED_ALREADY_AT_FULL_POWER = 3, - SPELL_FAILED_ALREADY_BEING_TAMED = 4, - SPELL_FAILED_ALREADY_HAVE_CHARM = 5, - SPELL_FAILED_ALREADY_HAVE_SUMMON = 6, - SPELL_FAILED_ALREADY_OPEN = 7, - SPELL_FAILED_AURA_BOUNCED = 8, - SPELL_FAILED_AUTOTRACK_INTERRUPTED = 9, - SPELL_FAILED_BAD_IMPLICIT_TARGETS = 10, - SPELL_FAILED_BAD_TARGETS = 11, - SPELL_FAILED_CANT_BE_CHARMED = 12, - SPELL_FAILED_CANT_BE_DISENCHANTED = 13, - SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 14, - SPELL_FAILED_CANT_BE_MILLED = 15, - SPELL_FAILED_CANT_BE_PROSPECTED = 16, - SPELL_FAILED_CANT_CAST_ON_TAPPED = 17, - SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 18, - SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 19, - SPELL_FAILED_CANT_STEALTH = 20, - SPELL_FAILED_CASTER_AURASTATE = 21, - SPELL_FAILED_CASTER_DEAD = 22, - SPELL_FAILED_CHARMED = 23, - SPELL_FAILED_CHEST_IN_USE = 24, - SPELL_FAILED_CONFUSED = 25, - SPELL_FAILED_DONT_REPORT = 26, - SPELL_FAILED_EQUIPPED_ITEM = 27, - SPELL_FAILED_EQUIPPED_ITEM_CLASS = 28, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 29, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 30, - SPELL_FAILED_ERROR = 31, - SPELL_FAILED_FIZZLE = 32, - SPELL_FAILED_FLEEING = 33, - SPELL_FAILED_FOOD_LOWLEVEL = 34, - SPELL_FAILED_HIGHLEVEL = 35, - SPELL_FAILED_HUNGER_SATIATED = 36, - SPELL_FAILED_IMMUNE = 37, - SPELL_FAILED_INCORRECT_AREA = 38, - SPELL_FAILED_INTERRUPTED = 39, - SPELL_FAILED_INTERRUPTED_COMBAT = 40, - SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 41, - SPELL_FAILED_ITEM_GONE = 42, - SPELL_FAILED_ITEM_NOT_FOUND = 43, - SPELL_FAILED_ITEM_NOT_READY = 44, - SPELL_FAILED_LEVEL_REQUIREMENT = 45, - SPELL_FAILED_LINE_OF_SIGHT = 46, - SPELL_FAILED_LOWLEVEL = 47, - SPELL_FAILED_LOW_CASTLEVEL = 48, - SPELL_FAILED_MAINHAND_EMPTY = 49, - SPELL_FAILED_MOVING = 50, - SPELL_FAILED_NEED_AMMO = 51, - SPELL_FAILED_NEED_AMMO_POUCH = 52, - SPELL_FAILED_NEED_EXOTIC_AMMO = 53, - SPELL_FAILED_NEED_MORE_ITEMS = 54, - SPELL_FAILED_NOPATH = 55, - SPELL_FAILED_NOT_BEHIND = 56, - SPELL_FAILED_NOT_FISHABLE = 57, - SPELL_FAILED_NOT_FLYING = 58, - SPELL_FAILED_NOT_HERE = 59, - SPELL_FAILED_NOT_INFRONT = 60, - SPELL_FAILED_NOT_IN_CONTROL = 61, - SPELL_FAILED_NOT_KNOWN = 62, - SPELL_FAILED_NOT_MOUNTED = 63, - SPELL_FAILED_NOT_ON_TAXI = 64, - SPELL_FAILED_NOT_ON_TRANSPORT = 65, - SPELL_FAILED_NOT_READY = 66, - SPELL_FAILED_NOT_SHAPESHIFT = 67, - SPELL_FAILED_NOT_STANDING = 68, - SPELL_FAILED_NOT_TRADEABLE = 69, - SPELL_FAILED_NOT_TRADING = 70, - SPELL_FAILED_NOT_UNSHEATHED = 71, - SPELL_FAILED_NOT_WHILE_GHOST = 72, - SPELL_FAILED_NOT_WHILE_LOOTING = 73, - SPELL_FAILED_NO_AMMO = 74, - SPELL_FAILED_NO_CHARGES_REMAIN = 75, - SPELL_FAILED_NO_CHAMPION = 76, - SPELL_FAILED_NO_COMBO_POINTS = 77, - SPELL_FAILED_NO_DUELING = 78, - SPELL_FAILED_NO_ENDURANCE = 79, - SPELL_FAILED_NO_FISH = 80, - SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 81, - SPELL_FAILED_NO_MOUNTS_ALLOWED = 82, - SPELL_FAILED_NO_PET = 83, - SPELL_FAILED_NO_POWER = 84, - SPELL_FAILED_NOTHING_TO_DISPEL = 85, - SPELL_FAILED_NOTHING_TO_STEAL = 86, - SPELL_FAILED_ONLY_ABOVEWATER = 87, - SPELL_FAILED_ONLY_DAYTIME = 88, - SPELL_FAILED_ONLY_INDOORS = 89, - SPELL_FAILED_ONLY_MOUNTED = 90, - SPELL_FAILED_ONLY_NIGHTTIME = 91, - SPELL_FAILED_ONLY_OUTDOORS = 92, - SPELL_FAILED_ONLY_SHAPESHIFT = 93, - SPELL_FAILED_ONLY_STEALTHED = 94, - SPELL_FAILED_ONLY_UNDERWATER = 95, - SPELL_FAILED_OUT_OF_RANGE = 96, - SPELL_FAILED_PACIFIED = 97, - SPELL_FAILED_POSSESSED = 98, - SPELL_FAILED_REAGENTS = 99, - SPELL_FAILED_REQUIRES_AREA = 100, - SPELL_FAILED_REQUIRES_SPELL_FOCUS = 101, - SPELL_FAILED_ROOTED = 102, - SPELL_FAILED_SILENCED = 103, - SPELL_FAILED_SPELL_IN_PROGRESS = 104, - SPELL_FAILED_SPELL_LEARNED = 105, - SPELL_FAILED_SPELL_UNAVAILABLE = 106, - SPELL_FAILED_STUNNED = 107, - SPELL_FAILED_TARGETS_DEAD = 108, - SPELL_FAILED_TARGET_AFFECTING_COMBAT = 109, - SPELL_FAILED_TARGET_AURASTATE = 110, - SPELL_FAILED_TARGET_DUELING = 111, - SPELL_FAILED_TARGET_ENEMY = 112, - SPELL_FAILED_TARGET_ENRAGED = 113, - SPELL_FAILED_TARGET_FRIENDLY = 114, - SPELL_FAILED_TARGET_IN_COMBAT = 115, - SPELL_FAILED_TARGET_IS_PLAYER = 116, - SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 117, - SPELL_FAILED_TARGET_NOT_DEAD = 118, - SPELL_FAILED_TARGET_NOT_IN_PARTY = 119, - SPELL_FAILED_TARGET_NOT_LOOTED = 120, - SPELL_FAILED_TARGET_NOT_PLAYER = 121, - SPELL_FAILED_TARGET_NO_POCKETS = 122, - SPELL_FAILED_TARGET_NO_WEAPONS = 123, - SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 124, - SPELL_FAILED_TARGET_UNSKINNABLE = 125, - SPELL_FAILED_THIRST_SATIATED = 126, - SPELL_FAILED_TOO_CLOSE = 127, - SPELL_FAILED_TOO_MANY_OF_ITEM = 128, - SPELL_FAILED_TOTEM_CATEGORY = 129, - SPELL_FAILED_TOTEMS = 130, - SPELL_FAILED_TRY_AGAIN = 131, - SPELL_FAILED_UNIT_NOT_BEHIND = 132, - SPELL_FAILED_UNIT_NOT_INFRONT = 133, - SPELL_FAILED_WRONG_PET_FOOD = 134, - SPELL_FAILED_NOT_WHILE_FATIGUED = 135, - SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 136, - SPELL_FAILED_NOT_WHILE_TRADING = 137, - SPELL_FAILED_TARGET_NOT_IN_RAID = 138, - SPELL_FAILED_TARGET_FREEFORALL = 139, - SPELL_FAILED_NO_EDIBLE_CORPSES = 140, - SPELL_FAILED_ONLY_BATTLEGROUNDS = 141, - SPELL_FAILED_TARGET_NOT_GHOST = 142, - SPELL_FAILED_TRANSFORM_UNUSABLE = 143, - SPELL_FAILED_WRONG_WEATHER = 144, - SPELL_FAILED_DAMAGE_IMMUNE = 145, - SPELL_FAILED_PREVENTED_BY_MECHANIC = 146, - SPELL_FAILED_PLAY_TIME = 147, - SPELL_FAILED_REPUTATION = 148, - SPELL_FAILED_MIN_SKILL = 149, - SPELL_FAILED_NOT_IN_ARENA = 150, - SPELL_FAILED_NOT_ON_SHAPESHIFT = 151, - SPELL_FAILED_NOT_ON_STEALTHED = 152, - SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 153, - SPELL_FAILED_NOT_ON_MOUNTED = 154, - SPELL_FAILED_TOO_SHALLOW = 155, - SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 156, - SPELL_FAILED_TARGET_IS_TRIVIAL = 157, - SPELL_FAILED_BM_OR_INVISGOD = 158, - SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 159, - SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 160, - SPELL_FAILED_NOT_IDLE = 161, - SPELL_FAILED_NOT_INACTIVE = 162, - SPELL_FAILED_PARTIAL_PLAYTIME = 163, - SPELL_FAILED_NO_PLAYTIME = 164, - SPELL_FAILED_NOT_IN_BATTLEGROUND = 165, - SPELL_FAILED_NOT_IN_RAID_INSTANCE = 166, - SPELL_FAILED_ONLY_IN_ARENA = 167, - SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 168, - SPELL_FAILED_ON_USE_ENCHANT = 169, - SPELL_FAILED_NOT_ON_GROUND = 170, - SPELL_FAILED_CUSTOM_ERROR = 171, - SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 172, - SPELL_FAILED_TOO_MANY_SOCKETS = 173, - SPELL_FAILED_INVALID_GLYPH = 174, - SPELL_FAILED_UNIQUE_GLYPH = 175, - SPELL_FAILED_GLYPH_SOCKET_LOCKED = 176, - SPELL_FAILED_NO_VALID_TARGETS = 177, - SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178, - SPELL_FAILED_NOT_IN_BARBERSHOP = 179, - SPELL_FAILED_FISHING_TOO_LOW = 180, - SPELL_FAILED_UNKNOWN = 181, - - SPELL_CAST_OK = 255 //custom value, don't must be send to client + SPELL_FAILED_AFFECTING_COMBAT = 0x00, + SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 0x01, + SPELL_FAILED_ALREADY_AT_FULL_MANA = 0x02, + SPELL_FAILED_ALREADY_AT_FULL_POWER = 0x03, + SPELL_FAILED_ALREADY_BEING_TAMED = 0x04, + SPELL_FAILED_ALREADY_HAVE_CHARM = 0x05, + SPELL_FAILED_ALREADY_HAVE_SUMMON = 0x06, + SPELL_FAILED_ALREADY_OPEN = 0x07, + SPELL_FAILED_AURA_BOUNCED = 0x08, + SPELL_FAILED_AUTOTRACK_INTERRUPTED = 0x09, + SPELL_FAILED_BAD_IMPLICIT_TARGETS = 0x0A, + SPELL_FAILED_BAD_TARGETS = 0x0B, + SPELL_FAILED_CANT_BE_CHARMED = 0x0C, + SPELL_FAILED_CANT_BE_DISENCHANTED = 0x0D, + SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 0x0E, + SPELL_FAILED_CANT_BE_MILLED = 0x0F, + SPELL_FAILED_CANT_BE_PROSPECTED = 0x10, + SPELL_FAILED_CANT_CAST_ON_TAPPED = 0x11, + SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 0x12, + SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 0x13, + SPELL_FAILED_CANT_STEALTH = 0x14, + SPELL_FAILED_CASTER_AURASTATE = 0x15, + SPELL_FAILED_CASTER_DEAD = 0x16, + SPELL_FAILED_CHARMED = 0x17, + SPELL_FAILED_CHEST_IN_USE = 0x18, + SPELL_FAILED_CONFUSED = 0x19, + SPELL_FAILED_DONT_REPORT = 0x1A, + SPELL_FAILED_EQUIPPED_ITEM = 0x1B, + SPELL_FAILED_EQUIPPED_ITEM_CLASS = 0x1C, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 0x1D, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 0x1E, + SPELL_FAILED_ERROR = 0x1F, + SPELL_FAILED_FIZZLE = 0x20, + SPELL_FAILED_FLEEING = 0x21, + SPELL_FAILED_FOOD_LOWLEVEL = 0x22, + SPELL_FAILED_HIGHLEVEL = 0x23, + SPELL_FAILED_HUNGER_SATIATED = 0x24, + SPELL_FAILED_IMMUNE = 0x25, + SPELL_FAILED_INCORRECT_AREA = 0x26, + SPELL_FAILED_INTERRUPTED = 0x27, + SPELL_FAILED_INTERRUPTED_COMBAT = 0x28, + SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 0x29, + SPELL_FAILED_ITEM_GONE = 0x2A, + SPELL_FAILED_ITEM_NOT_FOUND = 0x2B, + SPELL_FAILED_ITEM_NOT_READY = 0x2C, + SPELL_FAILED_LEVEL_REQUIREMENT = 0x2D, + SPELL_FAILED_LINE_OF_SIGHT = 0x2E, + SPELL_FAILED_LOWLEVEL = 0x2F, + SPELL_FAILED_LOW_CASTLEVEL = 0x30, + SPELL_FAILED_MAINHAND_EMPTY = 0x31, + SPELL_FAILED_MOVING = 0x32, + SPELL_FAILED_NEED_AMMO = 0x33, + SPELL_FAILED_NEED_AMMO_POUCH = 0x34, + SPELL_FAILED_NEED_EXOTIC_AMMO = 0x35, + SPELL_FAILED_NEED_MORE_ITEMS = 0x36, + SPELL_FAILED_NOPATH = 0x37, + SPELL_FAILED_NOT_BEHIND = 0x38, + SPELL_FAILED_NOT_FISHABLE = 0x39, + SPELL_FAILED_NOT_FLYING = 0x3A, + SPELL_FAILED_NOT_HERE = 0x3B, + SPELL_FAILED_NOT_INFRONT = 0x3C, + SPELL_FAILED_NOT_IN_CONTROL = 0x3D, + SPELL_FAILED_NOT_KNOWN = 0x3E, + SPELL_FAILED_NOT_MOUNTED = 0x3F, + SPELL_FAILED_NOT_ON_TAXI = 0x40, + SPELL_FAILED_NOT_ON_TRANSPORT = 0x41, + SPELL_FAILED_NOT_READY = 0x42, + SPELL_FAILED_NOT_SHAPESHIFT = 0x43, + SPELL_FAILED_NOT_STANDING = 0x44, + SPELL_FAILED_NOT_TRADEABLE = 0x45, + SPELL_FAILED_NOT_TRADING = 0x46, + SPELL_FAILED_NOT_UNSHEATHED = 0x47, + SPELL_FAILED_NOT_WHILE_GHOST = 0x48, + SPELL_FAILED_NOT_WHILE_LOOTING = 0x49, + SPELL_FAILED_NO_AMMO = 0x4A, + SPELL_FAILED_NO_CHARGES_REMAIN = 0x4B, + SPELL_FAILED_NO_CHAMPION = 0x4C, + SPELL_FAILED_NO_COMBO_POINTS = 0x4D, + SPELL_FAILED_NO_DUELING = 0x4E, + SPELL_FAILED_NO_ENDURANCE = 0x4F, + SPELL_FAILED_NO_FISH = 0x50, + SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 0x51, + SPELL_FAILED_NO_MOUNTS_ALLOWED = 0x52, + SPELL_FAILED_NO_PET = 0x53, + SPELL_FAILED_NO_POWER = 0x54, + SPELL_FAILED_NOTHING_TO_DISPEL = 0x55, + SPELL_FAILED_NOTHING_TO_STEAL = 0x56, + SPELL_FAILED_ONLY_ABOVEWATER = 0x57, + SPELL_FAILED_ONLY_DAYTIME = 0x58, + SPELL_FAILED_ONLY_INDOORS = 0x59, + SPELL_FAILED_ONLY_MOUNTED = 0x5A, + SPELL_FAILED_ONLY_NIGHTTIME = 0x5B, + SPELL_FAILED_ONLY_OUTDOORS = 0x5C, + SPELL_FAILED_ONLY_SHAPESHIFT = 0x5D, + SPELL_FAILED_ONLY_STEALTHED = 0x5E, + SPELL_FAILED_ONLY_UNDERWATER = 0x5F, + SPELL_FAILED_OUT_OF_RANGE = 0x60, + SPELL_FAILED_PACIFIED = 0x61, + SPELL_FAILED_POSSESSED = 0x62, + SPELL_FAILED_REAGENTS = 0x63, + SPELL_FAILED_REQUIRES_AREA = 0x64, + SPELL_FAILED_REQUIRES_SPELL_FOCUS = 0x65, + SPELL_FAILED_ROOTED = 0x66, + SPELL_FAILED_SILENCED = 0x67, + SPELL_FAILED_SPELL_IN_PROGRESS = 0x68, + SPELL_FAILED_SPELL_LEARNED = 0x69, + SPELL_FAILED_SPELL_UNAVAILABLE = 0x6A, + SPELL_FAILED_STUNNED = 0x6B, + SPELL_FAILED_TARGETS_DEAD = 0x6C, + SPELL_FAILED_TARGET_AFFECTING_COMBAT = 0x6D, + SPELL_FAILED_TARGET_AURASTATE = 0x6E, + SPELL_FAILED_TARGET_DUELING = 0x6F, + SPELL_FAILED_TARGET_ENEMY = 0x70, + SPELL_FAILED_TARGET_ENRAGED = 0x71, + SPELL_FAILED_TARGET_FRIENDLY = 0x72, + SPELL_FAILED_TARGET_IN_COMBAT = 0x73, + SPELL_FAILED_TARGET_IS_PLAYER = 0x74, + SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 0x75, + SPELL_FAILED_TARGET_NOT_DEAD = 0x76, + SPELL_FAILED_TARGET_NOT_IN_PARTY = 0x77, + SPELL_FAILED_TARGET_NOT_LOOTED = 0x78, + SPELL_FAILED_TARGET_NOT_PLAYER = 0x79, + SPELL_FAILED_TARGET_NO_POCKETS = 0x7A, + SPELL_FAILED_TARGET_NO_WEAPONS = 0x7B, + SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 0x7C, + SPELL_FAILED_TARGET_UNSKINNABLE = 0x7D, + SPELL_FAILED_THIRST_SATIATED = 0x7E, + SPELL_FAILED_TOO_CLOSE = 0x7F, + SPELL_FAILED_TOO_MANY_OF_ITEM = 0x80, + SPELL_FAILED_TOTEM_CATEGORY = 0x81, + SPELL_FAILED_TOTEMS = 0x82, + SPELL_FAILED_TRY_AGAIN = 0x83, + SPELL_FAILED_UNIT_NOT_BEHIND = 0x84, + SPELL_FAILED_UNIT_NOT_INFRONT = 0x85, + SPELL_FAILED_WRONG_PET_FOOD = 0x86, + SPELL_FAILED_NOT_WHILE_FATIGUED = 0x87, + SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 0x88, + SPELL_FAILED_NOT_WHILE_TRADING = 0x89, + SPELL_FAILED_TARGET_NOT_IN_RAID = 0x8A, + SPELL_FAILED_TARGET_FREEFORALL = 0x8B, + SPELL_FAILED_NO_EDIBLE_CORPSES = 0x8C, + SPELL_FAILED_ONLY_BATTLEGROUNDS = 0x8D, + SPELL_FAILED_TARGET_NOT_GHOST = 0x8E, + SPELL_FAILED_TRANSFORM_UNUSABLE = 0x8F, + SPELL_FAILED_WRONG_WEATHER = 0x90, + SPELL_FAILED_DAMAGE_IMMUNE = 0x91, + SPELL_FAILED_PREVENTED_BY_MECHANIC = 0x92, + SPELL_FAILED_PLAY_TIME = 0x93, + SPELL_FAILED_REPUTATION = 0x94, + SPELL_FAILED_MIN_SKILL = 0x95, + SPELL_FAILED_NOT_IN_ARENA = 0x96, + SPELL_FAILED_NOT_ON_SHAPESHIFT = 0x97, + SPELL_FAILED_NOT_ON_STEALTHED = 0x98, + SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 0x99, + SPELL_FAILED_NOT_ON_MOUNTED = 0x9A, + SPELL_FAILED_TOO_SHALLOW = 0x9B, + SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 0x9C, + SPELL_FAILED_TARGET_IS_TRIVIAL = 0x9D, + SPELL_FAILED_BM_OR_INVISGOD = 0x9E, + SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 0x9F, + SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 0xA0, + SPELL_FAILED_NOT_IDLE = 0xA1, + SPELL_FAILED_NOT_INACTIVE = 0xA2, + SPELL_FAILED_PARTIAL_PLAYTIME = 0xA3, + SPELL_FAILED_NO_PLAYTIME = 0xA4, + SPELL_FAILED_NOT_IN_BATTLEGROUND = 0xA5, + SPELL_FAILED_NOT_IN_RAID_INSTANCE = 0xA6, + SPELL_FAILED_ONLY_IN_ARENA = 0xA7, + SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 0xA8, + SPELL_FAILED_ON_USE_ENCHANT = 0xA9, + SPELL_FAILED_NOT_ON_GROUND = 0xAA, + SPELL_FAILED_CUSTOM_ERROR = 0xAB, + SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 0xAC, + SPELL_FAILED_TOO_MANY_SOCKETS = 0xAD, + SPELL_FAILED_INVALID_GLYPH = 0xAE, + SPELL_FAILED_UNIQUE_GLYPH = 0xAF, + SPELL_FAILED_GLYPH_SOCKET_LOCKED = 0xB0, + SPELL_FAILED_NO_VALID_TARGETS = 0xB1, + SPELL_FAILED_ITEM_AT_MAX_CHARGES = 0xB2, + SPELL_FAILED_NOT_IN_BARBERSHOP = 0xB3, + SPELL_FAILED_FISHING_TOO_LOW = 0xB4, + SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 0xB5, + SPELL_FAILED_SUMMON_PENDING = 0xB6, + SPELL_FAILED_MAX_SOCKETS = 0xB7, + SPELL_FAILED_PET_CAN_RENAME = 0xB8, + SPELL_FAILED_UNKNOWN = 0xB9, + + SPELL_CAST_OK = 0xFF // custom value, don't must be send to client }; // Spell aura states enum AuraState { // (C) used in caster aura state (T) used in target aura state // (c) used in caster aura state-not (t) used in target aura state-not + AURA_STATE_NONE = 0, // C | AURA_STATE_DEFENSE = 1, // C | AURA_STATE_HEALTHLESS_20_PERCENT = 2, // CcT | AURA_STATE_BERSERKING = 3, // C T | @@ -907,7 +913,7 @@ enum AuraState //AURA_STATE_UNKNOWN11 = 11, // t| AURA_STATE_FAERIE_FIRE = 12, // c t| AURA_STATE_HEALTHLESS_35_PERCENT = 13, // C T | - AURA_STATE_IMMOLATE = 14, // T | + AURA_STATE_CONFLAGRATE = 14, // T | AURA_STATE_SWIFTMEND = 15, // T | AURA_STATE_DEADLY_POISON = 16, // T | AURA_STATE_ENRAGE = 17, // C | @@ -919,6 +925,9 @@ enum AuraState AURA_STATE_HEALTH_ABOVE_75_PERCENT = 23, // C | }; +#define PER_CASTER_AURA_STATE_MASK ( \ + (1<<(AURA_STATE_CONFLAGRATE-1))|(1<<(AURA_STATE_DEADLY_POISON-1))) + // Spell mechanics enum Mechanics { @@ -965,7 +974,13 @@ enum Mechanics (1<<MECHANIC_SHACKLE )|(1<<MECHANIC_TURN )|(1<<MECHANIC_HORROR)| \ (1<<MECHANIC_DAZE )|(1<<MECHANIC_SAPPED ) ) -// Spell dispel type +// Daze and all croud control spells except polymorph are not removed +#define MECHANIC_NOT_REMOVED_BY_SHAPESHIFT ( \ + (1<<MECHANIC_CHARM )|(1<<MECHANIC_DISORIENTED)|(1<<MECHANIC_FEAR )|(1<<MECHANIC_PACIFY )| \ + (1<<MECHANIC_STUN )|(1<<MECHANIC_FREEZE )|(1<<MECHANIC_BANISH)|(1<<MECHANIC_SHACKLE)| \ + (1<<MECHANIC_HORROR)|(1<<MECHANIC_TURN )|(1<<MECHANIC_DAZE )|(1<<MECHANIC_SAPPED ) ) + +// Spell dispell type enum DispelType { DISPEL_NONE = 0, @@ -1835,6 +1850,7 @@ enum CreatureType CREATURE_TYPE_GAS_CLOUD = 13 }; +uint32 const CREATURE_TYPEMASK_DEMON_OR_UNDEAD = (1 << (CREATURE_TYPE_DEMON-1)) | (1 << (CREATURE_TYPE_UNDEAD-1)); uint32 const CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD = (1 << (CREATURE_TYPE_HUMANOID-1)) | (1 << (CREATURE_TYPE_UNDEAD-1)); uint32 const CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL = (1 << (CREATURE_TYPE_MECHANICAL-1)) | (1 << (CREATURE_TYPE_ELEMENTAL-1)); @@ -2269,7 +2285,9 @@ enum CorpseDynFlags #define SPELL_ID_WEAPON_SWITCH_COOLDOWN_1_0s 6123 #define SPELL_ID_AUTOSHOT 75 // used for checks in other spells interruption #define SPELL_ID_SHADOWMELD 58984 // used for check ignore stealth stance state - +#define SPELL_ID_BLOOD_PRESENCE 48266 // Blood Presence +#define SPELL_ID_FROST_PRESENCE 48263 // Frost Presence +#define SPELL_ID_UNHOLY_PRESENCE 48265 // Unholy Presence enum WeatherType { WEATHER_TYPE_FINE = 0, @@ -2384,20 +2402,23 @@ enum DiminishingGroup { // Common Groups DIMINISHING_NONE, - DIMINISHING_CONTROL_STUN, // Player Controlled stuns - DIMINISHING_TRIGGER_STUN, // By aura proced stuns, usualy chance on hit talents - DIMINISHING_CONTROL_ROOT, // Immobilizing effects from casted spells - DIMINISHING_TRIGGER_ROOT, // Immobilizing effects from triggered spells like Frostbite + DIMINISHING_CONTROL_STUN, // Player Controlled stuns + DIMINISHING_TRIGGER_STUN, // By aura proced stuns, usualy chance on hit talents + DIMINISHING_CONTROL_ROOT, // Immobilizing effects from casted spells + DIMINISHING_TRIGGER_ROOT, // Immobilizing effects from triggered spells like Frostbite DIMINISHING_CHARM, - DIMINISHING_SLEEP_FREEZE, DIMINISHING_POLYMORPH, // Also: Gouge, Sap, Repentance, Hungering Cold - DIMINISHING_CHEAPSHOT_POUNCE, - DIMINISHING_DEATHCOIL, // Death Coil Diminish only with another Death Coil - DIMINISHING_SILENCE, DIMINISHING_KNOCKOUT, // Sap, Knockout mechanics - DIMINISHING_DISARM, DIMINISHING_FEAR_BLIND, // Intimidating Shout, Howl of Terror, Blind - DIMINISHING_FEAR, + // Warlock Specific + DIMINISHING_DEATHCOIL, // Death Coil Diminish only with another Death Coil + // Druid Specific + DIMINISHING_CYCLONE, // From 2.3.0 + // Shared Class Specific + DIMINISHING_CHEAPSHOT_POUNCE, + DIMINISHING_DISARM, // From 2.3.0 + DIMINISHING_SILENCE, // From 2.3.0 + DIMINISHING_FREEZE_SLEEP, // Hunter's Freezing Trap DIMINISHING_BANISH, DIMINISHING_TAUNT, DIMINISHING_LIMITONLY // Don't Diminish, but limit duration to 10s diff --git a/src/game/SkillDiscovery.cpp b/src/game/SkillDiscovery.cpp index 2116e554a9f..686fcf889b9 100644 --- a/src/game/SkillDiscovery.cpp +++ b/src/game/SkillDiscovery.cpp @@ -26,6 +26,7 @@ #include "Util.h" #include "SkillDiscovery.h" #include "SpellMgr.h" +#include "Player.h" #include <map> struct SkillDiscoveryEntry @@ -37,7 +38,7 @@ struct SkillDiscoveryEntry SkillDiscoveryEntry() : spellId(0), reqSkillValue(0), chance(0) {} - SkillDiscoveryEntry(uint16 _spellId, uint32 req_skill_val, float _chance) + SkillDiscoveryEntry(uint32 _spellId, uint32 req_skill_val, float _chance) : spellId(_spellId), reqSkillValue(req_skill_val), chance(_chance) {} }; @@ -105,7 +106,9 @@ void LoadSkillDiscoveryTable() { if (reportedReqSpells.count(reqSkillOrSpell)==0) { - sLog.outErrorDb("Spell (ID: %u) not have have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table",reqSkillOrSpell,spellId); + sLog.outErrorDb("Spell (ID: %u) not have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc" + " and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table", + reqSkillOrSpell,spellId); reportedReqSpells.insert(reqSkillOrSpell); } continue; @@ -144,6 +147,21 @@ void LoadSkillDiscoveryTable() sLog.outString( ">> Loaded %u skill discovery definitions", count ); if(!ssNonDiscoverableEntries.str().empty()) sLog.outErrorDb("Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n%s",ssNonDiscoverableEntries.str().c_str()); + + // report about empty data for explicit discovery spells + for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id) + { + SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell_id); + if(!spellEntry) + continue; + + // skip not explicit discovery spells + if (!IsExplicitDiscoverySpell(spellEntry)) + continue; + + if(SkillDiscoveryStore.find(spell_id)==SkillDiscoveryStore.end()) + sLog.outErrorDb("Spell (ID: %u) is 100%% chance random discovery ability but not have data in `skill_discovery_template` table",spell_id); + } } uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player) diff --git a/src/game/SocialMgr.cpp b/src/game/SocialMgr.cpp index fb0e1574d08..d94cd422f11 100644 --- a/src/game/SocialMgr.cpp +++ b/src/game/SocialMgr.cpp @@ -198,7 +198,7 @@ void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &fri uint32 team = player->GetTeam(); AccountTypes security = player->GetSession()->GetSecurity(); bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); - bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || security > SEC_PLAYER; + AccountTypes gmLevelInWhoList = AccountTypes (sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST)); PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friendGUID); if(itr != player->GetSocial()->m_playerSocialMap.end()) @@ -206,10 +206,10 @@ void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &fri // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if( pFriend && pFriend->GetName() && - ( security > SEC_PLAYER || - ( pFriend->GetTeam() == team || allowTwoSideWhoList ) && - ( pFriend->GetSession()->GetSecurity() == SEC_PLAYER || gmInWhoList && pFriend->IsVisibleGloballyFor(player) ))) + if (pFriend && pFriend->GetName() && + (security > SEC_PLAYER || + (pFriend->GetTeam() == team || allowTwoSideWhoList) && (pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList)) && + pFriend->IsVisibleGloballyFor(player)) { friendInfo.Status = FRIEND_STATUS_ONLINE; if(pFriend->isAFK()) @@ -273,7 +273,7 @@ void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet) uint32 team = player->GetTeam(); AccountTypes security = player->GetSession()->GetSecurity(); uint32 guid = player->GetGUIDLow(); - bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST); + AccountTypes gmLevelInWhoList = AccountTypes(sWorld.getConfig(CONFIG_GM_LEVEL_IN_WHO_LIST)); bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); for(SocialMap::const_iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr) @@ -285,10 +285,10 @@ void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet) // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if( pFriend && pFriend->IsInWorld() && - ( pFriend->GetSession()->GetSecurity() > SEC_PLAYER || - ( pFriend->GetTeam() == team || allowTwoSideWhoList ) && - (security == SEC_PLAYER || gmInWhoList && player->IsVisibleGloballyFor(pFriend) ))) + if (pFriend && pFriend->IsInWorld() && + (pFriend->GetSession()->GetSecurity() > SEC_PLAYER || + (pFriend->GetTeam() == team || allowTwoSideWhoList) && security <= gmLevelInWhoList) && + player->IsVisibleGloballyFor(pFriend)) { pFriend->GetSession()->SendPacket(packet); } diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index ed818d95570..991b525afa7 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -82,7 +82,7 @@ struct PrioritizeMana { int operator()( PrioritizeManaUnitWraper const& x, PrioritizeManaUnitWraper const& y ) const { - return x.getPercent() < y.getPercent(); + return x.getPercent() > y.getPercent(); } }; @@ -106,7 +106,7 @@ struct PrioritizeHealth { int operator()( PrioritizeHealthUnitWraper const& x, PrioritizeHealthUnitWraper const& y ) const { - return x.getPercent() < y.getPercent(); + return x.getPercent() > y.getPercent(); } }; @@ -363,6 +363,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi m_referencedFromCurrentSpell = false; m_executedCurrently = false; m_needComboPoints = NeedsComboPoints(m_spellInfo); + m_comboPointGain = 0; m_delayStart = 0; m_delayAtDamageCount = 0; @@ -370,6 +371,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi m_applyMultiplierMask = 0; m_effectMask = 0; + m_auraScaleMask = 0; // Get data for type of attack switch (m_spellInfo->DmgClass) @@ -700,7 +702,6 @@ void Spell::FillTargetMap() break; } } - if(IsChanneledSpell(m_spellInfo)) { uint8 mask = (1<<i); @@ -713,6 +714,29 @@ void Spell::FillTargetMap() } } } + else if (m_auraScaleMask) + { + bool checkLvl = !m_UniqueTargetInfo.empty(); + for(std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();) + { + // remove targets which did not pass min level check + if(m_auraScaleMask && ihit->effectMask == m_auraScaleMask) + { + // Do not check for selfcast + if (!ihit->scaleAura && ihit->targetGUID != m_caster->GetGUID()) + { + m_UniqueTargetInfo.erase(ihit++); + continue; + } + } + ++ihit; + } + if (checkLvl && m_UniqueTargetInfo.empty()) + { + SendCastResult(SPELL_FAILED_LOWLEVEL); + finish(false); + } + } } if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) @@ -734,6 +758,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura) // Create base triggers flags for Attacker and Victim ( m_procAttacker, m_procVictim and m_procEx) //========================================================================================== + m_procVictim = m_procAttacker = 0; // Get data for type of attack and fill base info for trigger switch (m_spellInfo->DmgClass) { @@ -755,37 +780,15 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura) } break; default: - if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell - { - if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_HEALING_SPELL; - m_procVictim = PROC_FLAG_TAKEN_HEALING_SPELL; - } - else - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL; - m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL; - } - } - else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack + if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && + m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND) + && m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack { m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; m_procVictim = PROC_FLAG_TAKEN_RANGED_HIT; } - else // Negative spell - { - if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT; - m_procVictim = PROC_FLAG_TAKEN_DAMAGING_SPELL_HIT; - } - else - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; - m_procVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT; - } - } + // For other spells trigger procflags are set in Spell::DoAllEffectOnTarget + // Because spell positivity is dependant on target } m_procEx= PROC_EX_NONE; @@ -794,40 +797,34 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura) if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (m_spellInfo->SpellFamilyFlags[1] & 0x00002000 || m_spellInfo->SpellFamilyFlags[0] & 0x1C)) { m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION; + // Trigger only from spells originally casted by hunter(trap activation) to prevent multiple trigger from trap triggered spells + if (m_originalCasterGUID != m_caster->GetGUID() && m_originalCasterGUID) + return; } - else + /* + Effects which are result of aura proc from triggered spell cannot proc + to prevent chain proc of these spells + */ + if ((triggeredByAura && !triggeredByAura->GetParentAura()->GetTarget()->CanProc())) { - /* - Effects which are result of aura proc from triggered spell cannot proc - to prevent chain proc of these spells - */ - if ((triggeredByAura && !triggeredByAura->GetParentAura()->GetTarget()->CanProc()) || !m_caster->CanProc()) - { - m_canTrigger=false; - } + m_canTrigger=false; + } + // Ranged autorepeat attack is set as triggered spell - ignore it + if (!(m_procAttacker & PROC_FLAG_SUCCESSFUL_RANGED_HIT)) + { if (m_IsTriggeredSpell && (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER || m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2)) + m_procEx |= PROC_EX_INTERNAL_CANT_PROC; + else if (m_IsTriggeredSpell) m_procEx |= PROC_EX_INTERNAL_TRIGGERED; - - // Totem casts require spellfamilymask defined in spell_proc_event to proc - if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isTotem() && m_caster->IsControlledByPlayer()) - { - m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; - } - // Check done for judgements to make them not trigger seal effects - else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK1) - { - // Rogue poisons - if (m_spellInfo->SpellFamilyName && m_spellInfo->SpellFamilyFlags) - m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; - else - m_canTrigger=false; - } } - if (m_IsTriggeredSpell || triggeredByAura) - m_procEx |= PROC_EX_INTERNAL_CANT_PROC; + // Totem casts require spellfamilymask defined in spell_proc_event to proc + if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isTotem() && m_caster->IsControlledByPlayer()) + { + m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; + } } void Spell::CleanupTargetList() @@ -858,6 +855,13 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex) { if (!immuned) ihit->effectMask |= 1 << effIndex; // Add only effect mask if not immuned + ihit->scaleAura = false; + if (m_auraScaleMask && ihit->effectMask == m_auraScaleMask && m_caster != pVictim) + { + SpellEntry const * auraSpell = sSpellStore.LookupEntry(spellmgr.GetFirstSpellInChain(m_spellInfo->Id)); + if ((pVictim->getLevel() + 10) >= auraSpell->spellLevel) + ihit->scaleAura = true; + } return; } } @@ -872,6 +876,13 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex) target.alive = pVictim->isAlive(); target.damage = 0; target.crit = false; + target.scaleAura = false; + if (m_auraScaleMask && target.effectMask == m_auraScaleMask && m_caster != pVictim) + { + SpellEntry const * auraSpell = sSpellStore.LookupEntry(spellmgr.GetFirstSpellInChain(m_spellInfo->Id)); + if ((pVictim->getLevel() + 10) >= auraSpell->spellLevel) + target.scaleAura = true; + } // Calculate hit result if(m_originalCaster) @@ -1052,7 +1063,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) if(spellHitTarget) { - SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask); + SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask, target->scaleAura); if(missInfo != SPELL_MISS_NONE) { if(missInfo != SPELL_MISS_MISS) @@ -1067,6 +1078,50 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) if( missInfo != SPELL_MISS_NONE && missInfo != SPELL_MISS_MISS) m_needComboPoints = false; + // Trigger info was not filled in spell::preparedatafortriggersystem - we do it now + if (canEffectTrigger && !procAttacker && !procVictim) + { + bool positive = true; + if (m_damage > 0) + positive = false; + else if (!m_healing) + { + for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + // If at least one effect negative spell is negative hit + if (mask & (1<<i) && !IsPositiveEffect(m_spellInfo->Id, i)) + { + positive = false; + break; + } + } + switch(m_spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_MAGIC: + if (positive) + { + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL; + procVictim |= PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL; + } + else + { + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL; + procVictim |= PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL; + } + break; + case SPELL_DAMAGE_CLASS_NONE: + if (positive) + { + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT; + procVictim |= PROC_FLAG_TAKEN_POSITIVE_SPELL; + } + else + { + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; + procVictim |= PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT; + } + break; + } + } // All calculated do it! // Do healing and triggers if (m_healing > 0) @@ -1109,11 +1164,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) 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_ATTR_STOP_ATTACK_TARGET) == 0 && + (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) + ((Player *)caster)->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx); + } if (m_spellAura) m_spellAura->SetProcDamage(damageInfo.damage); - caster->DealSpellDamage(&damageInfo, true); // Judgement of Blood @@ -1136,11 +1195,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) if( !m_caster->IsFriendlyTo(unit) && !IsPositiveSpell(m_spellInfo->Id)) { - if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) - { - m_caster->CombatStart(unit); - } - else if(m_customAttr & SPELL_ATTR_CU_AURA_CC) + m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO)); + + if(m_customAttr & SPELL_ATTR_CU_AURA_CC) { if(!unit->IsStandState()) unit->SetStandState(UNIT_STAND_STATE_STAND); @@ -1174,7 +1231,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) } } -SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) +SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool scaleAura) { if(!unit || !effectMask) return SPELL_MISS_EVADE; @@ -1242,7 +1299,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) } if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) { - m_caster->SetInCombatState(unit->GetCombatTimer() > 0); + m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit); unit->getHostilRefManager().threatAssist(m_caster, 0.0f); } } @@ -1265,21 +1322,43 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) if (aura_effmask) { + // Select rank for aura with level requirements only in specific cases + // Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target + SpellEntry const * aurSpellInfo = m_spellInfo; + int32 basePoints[3]; + if (scaleAura) + { + aurSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(m_spellInfo,unitTarget->getLevel()); + assert (aurSpellInfo); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + basePoints[i] = aurSpellInfo->EffectBasePoints[i]; + } + } + else + { + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + basePoints[i] = m_currentBasePoints[i]; + } + } + Unit * caster = m_originalCaster ? m_originalCaster : m_caster; - Aura * Aur = new Aura(m_spellInfo, aura_effmask, m_currentBasePoints, unit, m_caster, caster, m_CastItem); + Aura * Aur = new Aura(aurSpellInfo, aura_effmask, basePoints, unit, m_caster, caster, m_CastItem); if (!Aur->IsAreaAura()) { // Now Reduce spell duration using data received at spell hit int32 duration = Aur->GetAuraMaxDuration(); - unit->ApplyDiminishingToDuration(m_diminishGroup,duration,caster,m_diminishLevel); + int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup,aurSpellInfo); + unitTarget->ApplyDiminishingToDuration(m_diminishGroup, duration, caster, m_diminishLevel,limitduration); Aur->setDiminishGroup(m_diminishGroup); - duration = caster->ModSpellDuration(m_spellInfo, unit, duration, Aur->IsPositive()); + duration = caster->ModSpellDuration(aurSpellInfo, unit, duration, Aur->IsPositive()); //mod duration of channeled aura by spell haste if (IsChanneledSpell(m_spellInfo)) - caster->ModSpellCastTime(m_spellInfo, duration, this); + caster->ModSpellCastTime(aurSpellInfo, duration, this); if(duration != Aur->GetAuraMaxDuration()) { @@ -1288,9 +1367,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) } // Prayer of Mending (jump animation), we need formal caster instead original for correct animation - if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST) + if( aurSpellInfo->SpellFamilyName == SPELLFAMILY_PRIEST) { - if(m_spellInfo->SpellFamilyFlags[1] & 0x000020) + if(aurSpellInfo->SpellFamilyFlags[1] & 0x000020) m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID); } } @@ -1337,7 +1416,7 @@ void Spell::DoTriggersOnSpellHit(Unit *unit) if(roll_chance_i(i->second)) { m_caster->CastSpell(unit, i->first, true); - sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first); + sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first->Id); } if (GetSpellDuration(i->first)==-1) { @@ -1651,6 +1730,15 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType) { switch(i_spellST->second.type) { + case SPELL_TARGET_TYPE_CONTROLLED: + for(Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == i_spellST->second.targetEntry && (*itr)->IsWithinDistInMap(m_caster, range)) + { + goScriptTarget = NULL; + range = m_caster->GetDistance(creatureScriptTarget); + creatureScriptTarget = ((Creature *)*itr); + } + break; case SPELL_TARGET_TYPE_GAMEOBJECT: if(i_spellST->second.targetEntry) { @@ -2143,6 +2231,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) case TARGET_UNIT_AREA_ENEMY_DST: case TARGET_UNIT_CONE_ENEMY: case TARGET_UNIT_CONE_ENEMY_UNKNOWN: + case TARGET_UNIT_AREA_PATH: radius = GetSpellRadius(m_spellInfo, i, false); targetType = SPELL_TARGETS_ENEMY; break; @@ -2181,8 +2270,6 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) { case 46584: // Raise Dead { - // TODO: change visual of corpses which gave ghoul? - // Allow corpses to be ghouled only once? m_targets.m_targetMask &= ~TARGET_FLAG_DEST_LOCATION; WorldObject* result = FindCorpseUsing<MaNGOS::RaiseDeadObjectCheck> (); if(result) @@ -2195,6 +2282,45 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) } break; } + // Corpse Explosion + case 49158: + case 51325: + case 51326: + case 51327: + case 51328: + // Search for ghoul if our ghoul or dead body not valid unit target + if (!(m_targets.getUnitTarget() && (m_targets.getUnitTarget()->GetEntry() == 26125 && m_targets.getUnitTarget()->GetOwnerGUID() == m_caster->GetGUID() + || (m_targets.getUnitTarget()->getDeathState() == CORPSE + && m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId() + && m_targets.getUnitTarget()->GetTypeId()== TYPEID_UNIT + && !((Creature*)m_targets.getUnitTarget())->isDeadByDefault() + && !(m_targets.getUnitTarget()->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL)) + && m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId()))) + { + CleanupTargetList(); + + WorldObject* result = FindCorpseUsing <Trinity::ExplodeCorpseObjectCheck> (); + + if(result) + { + switch(result->GetTypeId()) + { + case TYPEID_UNIT: + case TYPEID_PLAYER: + m_targets.setUnitTarget((Unit*)result); + break; + } + } + else + { + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true); + SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW); + finish(false); + } + } + break; + default: sLog.outDebug("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry()); @@ -2213,6 +2339,13 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) { if(i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE) SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry); + else if (i_spellST->second.type == SPELL_TARGET_TYPE_CONTROLLED) + { + for(Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == i_spellST->second.targetEntry && + /*(*itr)->IsWithinDistInMap(m_caster, radius)*/ (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect) + unitList.push_back(*itr); + } } } } @@ -2319,7 +2452,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) case 59725: // Improved Spell Reflection - aoe aura unitList.remove(m_caster); break; - case 57699: //Replenishment (special target selection) 10 targets with lowest mana + case 57669: //Replenishment (special target selection) 10 targets with lowest mana { typedef std::priority_queue<PrioritizeManaUnitWraper, std::vector<PrioritizeManaUnitWraper>, PrioritizeMana> TopMana; TopMana manaUsers; @@ -2380,6 +2513,34 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) healedMembers.pop(); } } + // Death Pact + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) + { + Unit * unit_to_add = NULL; + for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();++itr) + { + if ((*itr)->GetTypeId() == TYPEID_UNIT + && (*itr)->GetOwnerGUID() == m_caster->GetGUID() + && ((Creature*)(*itr))->GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD) + { + unit_to_add = (*itr); + break; + } + } + if (unit_to_add) + { + unitList.clear(); + unitList.push_back(unit_to_add); + } + // Pet not found - remove cooldown + else + { + if (modOwner->GetTypeId()==TYPEID_PLAYER) + modOwner->RemoveSpellCooldown(m_spellInfo->Id,true); + SendCastResult(SPELL_FAILED_NO_PET); + finish(false); + } + } } for(std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) AddUnitTarget(*itr, i); @@ -2414,6 +2575,27 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura } } + // Fill aura scaling information + if (m_caster->IsControlledByPlayer() && !IsPassiveSpell(m_spellInfo->Id) && m_spellInfo->spellLevel && !IsChanneledSpell(m_spellInfo) && !m_IsTriggeredSpell) + { + for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + { + if (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) + { + // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive + if (IsPositiveEffect(m_spellInfo->Id, i)) + { + m_auraScaleMask |= (1<<i); + if (m_currentBasePoints[i] != m_spellInfo->EffectBasePoints[i]) + { + m_auraScaleMask = 0; + break; + } + } + } + } + } + m_spellState = SPELL_STATE_PREPARING; if(triggeredByAura) @@ -2458,8 +2640,12 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura } } - // Fill cost data - m_powerCost = CalculatePowerCost(); + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->SetSpellModTakingSpell(this, true); + // Fill cost data (not use power for item casts + m_powerCost = m_CastItem ? 0 : CalculatePowerCost(m_spellInfo, m_caster, m_spellSchoolMask); + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->SetSpellModTakingSpell(this, false); SpellCastResult result = CheckCast(true); if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering @@ -2500,7 +2686,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura { // stealth must be removed at cast starting (at show channel bar) // skip triggered spell (item equip spell casting and other not explicit character casts/item uses) - if(isSpellBreakStealth(m_spellInfo) ) + if(!m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) ) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST); for(uint32 i = 0; i < 3; ++i) @@ -2593,6 +2779,7 @@ void Spell::cast(bool skipCheck) && !target->IsFriendlyTo(m_caster) && !m_caster->canSeeOrDetect(target, true)) { SendCastResult(SPELL_FAILED_BAD_TARGETS); + SendInterrupted(0); finish(false); return; } @@ -2626,6 +2813,7 @@ void Spell::cast(bool skipCheck) if(castResult != SPELL_CAST_OK) { SendCastResult(castResult); + SendInterrupted(0); finish(false); SetExecutedCurrently(false); return; @@ -2634,6 +2822,14 @@ void Spell::cast(bool skipCheck) FillTargetMap(); + // Spell may be finished after target map check + if(m_spellState == SPELL_STATE_FINISHED) + { + SendInterrupted(0); + SetExecutedCurrently(false); + return; + } + if(m_spellInfo->SpellFamilyName) { if (m_spellInfo->excludeCasterAuraSpell && !IsPositiveSpell(m_spellInfo->excludeCasterAuraSpell)) @@ -2647,8 +2843,18 @@ void Spell::cast(bool skipCheck) { if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages m_preCastSpell = 11196; // Recently Bandaged - else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20) - m_preCastSpell = 23230; // Blood Fury - Healing Reduction + break; + } + case SPELLFAMILY_DRUID: + { + // Faerie Fire (Feral) + if (m_spellInfo->SpellFamilyFlags[0] & 0x00000400) + { + // Trigger only if has correct shapeshift for triggered spell + SpellEntry const * spellInfo = sSpellStore.LookupEntry(60089); + if (GetErrorAtShapeshiftedCast(spellInfo, m_caster->m_form) == SPELL_CAST_OK) + m_preCastSpell = 60089; + } break; } } @@ -2664,7 +2870,13 @@ void Spell::cast(bool skipCheck) ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id); } - // this is related to combo points so must be done before takepower + if(!m_IsTriggeredSpell) + { + // Powers have to be taken before SendSpellGo + TakePower(); + TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot + } + // are there any spells need to be triggered after hit? // handle SPELL_AURA_ADD_TARGET_TRIGGER auras Unit::AuraEffectList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER); @@ -2682,17 +2894,9 @@ void Spell::cast(bool skipCheck) } } - // this is related to combo points so must be done before takepower if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) CalculateDamageDoneForAllTargets(); - if(!m_IsTriggeredSpell) - { - // Powers have to be taken before SendSpellGo - TakePower(); - TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot - } - // CAST SPELL SendSpellCooldown(); //SendCastResult(castResult); @@ -2726,6 +2930,9 @@ void Spell::cast(bool skipCheck) m_immediateHandled = false; m_spellState = SPELL_STATE_DELAYED; SetDelayStart(0); + + if(m_caster->hasUnitState(UNIT_STAT_CASTING) && !m_caster->IsNonMeleeSpellCasted(false, false, true)) + m_caster->clearUnitState(UNIT_STAT_CASTING); } else { @@ -2882,6 +3089,7 @@ void Spell::_handle_immediate_phase() if(!m_originalCaster) return; + uint8 oldEffMask = m_effectMask; // process ground for(uint32 j = 0; j < 3; ++j) { @@ -2898,6 +3106,38 @@ void Spell::_handle_immediate_phase() m_effectMask |= (1<<j); } } + if (oldEffMask != m_effectMask && m_UniqueTargetInfo.empty()) + { + uint32 procAttacker = m_procAttacker; + if (!procAttacker) + { + bool positive = true; + for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + // If at least one effect negative spell is negative hit + if (m_effectMask & (1<<i) && !IsPositiveEffect(m_spellInfo->Id, i)) + { + positive = false; + break; + } + switch(m_spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_MAGIC: + if (positive) + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL; + else + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL; + break; + case SPELL_DAMAGE_CLASS_NONE: + if (positive) + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT; + else + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; + break; + } + } + // Proc damage for spells which have only dest targets (2484 should proc 51486 for example) + m_originalCaster->ProcDamageAndSpell(0, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell); + } } void Spell::_handle_finish_phase() @@ -2906,6 +3146,10 @@ void Spell::_handle_finish_phase() if (m_needComboPoints) ((Player*)m_caster)->ClearComboPoints(); + // Real add combo points from effects + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->GainSpellComboPoints(m_comboPointGain); + // spell log if(m_needSpellLog) SendLogExecute(); @@ -3046,7 +3290,7 @@ void Spell::finish(bool ok) if(IsChanneledSpell(m_spellInfo)) m_caster->UpdateInterruptMask(); - if(!m_caster->IsNonMeleeSpellCasted(false, false, true)) + if(m_caster->hasUnitState(UNIT_STAT_CASTING) && !m_caster->IsNonMeleeSpellCasted(false, false, true)) m_caster->clearUnitState(UNIT_STAT_CASTING); // Unsummon summon as possessed creatures on spell cancel @@ -3103,9 +3347,10 @@ void Spell::finish(bool ok) } // potions disabled by client, send event "not in combat" if need - if (!m_triggeredByAuraSpell && m_caster->GetTypeId() == TYPEID_PLAYER) + if (m_caster->GetTypeId() == TYPEID_PLAYER) { - ((Player*)m_caster)->UpdatePotionCooldown(this); + if (!m_triggeredByAuraSpell) + ((Player*)m_caster)->UpdatePotionCooldown(this); // triggered spell pointer can be not set in some cases // this is needed for proper apply of triggered spell mods @@ -3251,11 +3496,11 @@ void Spell::SendSpellGo() //sLog.outDebug("Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id); uint32 castFlags = CAST_FLAG_UNKNOWN3; - + // triggered spells with spell visual != 0 - if(m_IsTriggeredSpell || m_triggeredByAuraSpell) + if((m_IsTriggeredSpell && !IsAutoRepeatRangedSpell(m_spellInfo)) || m_triggeredByAuraSpell) castFlags |= CAST_FLAG_UNKNOWN0; - + if(m_spellInfo->Attributes & SPELL_ATTR_REQ_AMMO) castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual if ((m_caster->GetTypeId() == TYPEID_PLAYER || @@ -3352,7 +3597,7 @@ void Spell::WriteAmmoToPacket( WorldPacket * data ) ammoInventoryType = pProto->InventoryType; } } - else if(m_caster->GetDummyAura(46699)) // Requires No Ammo + else if(m_caster->HasAura(46699)) // Requires No Ammo { ammoDisplayID = 5996; // normal arrow ammoInventoryType = INVTYPE_AMMO; @@ -3887,6 +4132,7 @@ void Spell::TakeRunePower() if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) { plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec + plr->SetLastUsedRune(RuneType(rune)); runeCost[rune]--; } } @@ -3901,8 +4147,52 @@ void Spell::TakeRunePower() if((plr->GetRuneCooldown(i) == 0) && (rune == RUNE_DEATH)) { plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec + plr->SetLastUsedRune(RuneType(rune)); runeCost[rune]--; + bool auraFound = false; plr->ConvertRune(i, plr->GetBaseRune(i)); + // * * * * * * * * * * * + // update convert rune auras + // * * * * * * * * * * * + // Remove rune from SPELL_AURA_CONVERT_RUNE when rune is used + // To prevent overriding other rune convert effects + Unit::AuraEffectList const& runeconvert = m_caster->GetAurasByType(SPELL_AURA_CONVERT_RUNE); + for(Unit::AuraEffectList::const_iterator itr = runeconvert.begin(); itr != runeconvert.end(); ++itr) + { + // Remove rune of aura if avalible + if ((*itr)->GetAmount() & (1<<i)) + { + (*itr)->SetAmount((*itr)->GetAmount() & ~(1<<i)); + auraFound = true; + } + // All runes from aura used - remove aura + if (!(*itr)->GetAmount()) + plr->RemoveAura((*itr)->GetParentAura(), AURA_REMOVE_BY_EXPIRE); + break; + } + if (!auraFound) + { + // Decrease used rune count for dk talent auras + // To prevent overriding other rune convert effects + Unit::AuraEffectList const& runeconvert = m_caster->GetAurasByType(SPELL_AURA_CONVERT_RUNE); + for(Unit::AuraEffectList::const_iterator itr = runeconvert.begin(); itr != runeconvert.end(); ++itr) + { + if (plr->GetBaseRune(i) != RUNE_DEATH) + { + if ((*itr)->GetSpellProto()->SpellIconID != 2622) + continue; + } + else if ((*itr)->GetSpellProto()->SpellIconID != 3041 && + (*itr)->GetSpellProto()->SpellIconID != 22) + continue; + + // Remove rune of aura if avalible + if ((*itr)->GetAmount() & (1<<i)) + (*itr)->SetAmount((*itr)->GetAmount() & ~(1<<i)); + break; + } + } + if(runeCost[RUNE_DEATH] == 0) break; } @@ -3976,13 +4266,14 @@ void Spell::HandleThreatSpells(uint32 spellId) if(!m_targets.getUnitTarget()->CanHaveThreatList()) return; - SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry<SpellThreatEntry>(spellId); - if(!threatSpell) + uint16 threat = spellmgr.GetSpellThreat(spellId); + + if(!threat) return; - m_targets.getUnitTarget()->AddThreat(m_caster, float(threatSpell->threat)); + m_targets.getUnitTarget()->AddThreat(m_caster, float(threat)); - DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat); + DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threat); } void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i) @@ -4021,15 +4312,19 @@ void Spell::TriggerSpell() SpellCastResult Spell::CheckCast(bool strict) { // check cooldowns to prevent cheating - if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) + if(m_caster->GetTypeId()==TYPEID_PLAYER) { //can cast triggered (by aura only?) spells while have this flag if (!m_IsTriggeredSpell && ((Player*)m_caster)->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY)) return SPELL_FAILED_SPELL_IN_PROGRESS; - if(m_triggeredByAuraSpell) - return SPELL_FAILED_DONT_REPORT; - else - return SPELL_FAILED_NOT_READY; + + if (((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) + { + if(m_triggeredByAuraSpell) + return SPELL_FAILED_DONT_REPORT; + else + return SPELL_FAILED_NOT_READY; + } } // only allow triggered spells if at an ended battleground @@ -4118,7 +4413,12 @@ SpellCastResult Spell::CheckCast(bool strict) if(m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell)) return SPELL_FAILED_TARGET_AURASTATE; - if(target != m_caster) + if(!m_IsTriggeredSpell && target == m_caster && m_spellInfo->AttributesEx & SPELL_ATTR_EX_CANT_TARGET_SELF) + return SPELL_FAILED_BAD_TARGETS; + + bool non_caster_target = target != m_caster && !spellmgr.IsSpellWithCasterSourceTargetsOnly(m_spellInfo); + + if(non_caster_target) { // target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds if(!m_IsTriggeredSpell && m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState), m_spellInfo, m_caster)) @@ -4131,13 +4431,6 @@ SpellCastResult Spell::CheckCast(bool strict) if(!m_IsTriggeredSpell && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) return SPELL_FAILED_LINE_OF_SIGHT; - // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode - // this case can be triggered if rank not found (too low-level target for first rank) - if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) - for(int i=0;i<3;i++) - if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) - if(target->getLevel() + 10 < m_spellInfo->spellLevel) - return SPELL_FAILED_LOWLEVEL; } else if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster { @@ -4173,7 +4466,7 @@ SpellCastResult Spell::CheckCast(bool strict) //check creature type //ignore self casts (including area casts when caster selected as target) - if(target != m_caster) + if(non_caster_target) { if(!CheckTargetCreatureType(target)) { @@ -4186,7 +4479,7 @@ SpellCastResult Spell::CheckCast(bool strict) // TODO: this check can be applied and for player to prevent cheating when IsPositiveSpell will return always correct result. // check target for pet/charmed casts (not self targeted), self targeted cast used for area effects and etc - if(m_caster != target && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID()) + if(non_caster_target && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID()) { // check correctness positive/negative cast target (pet cast real check and cheating check) if(IsPositiveSpell(m_spellInfo->Id)) @@ -4225,7 +4518,7 @@ SpellCastResult Spell::CheckCast(bool strict) } // check if target is in combat - if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) + if (non_caster_target && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) return SPELL_FAILED_TARGET_AFFECTING_COMBAT; } @@ -4442,12 +4735,23 @@ SpellCastResult Spell::CheckCast(bool strict) if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, m_targets.getUnitTarget() )) return SPELL_FAILED_UNIT_NOT_INFRONT; } + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] == 0x2000) // Death Coil (DeathKnight) + { + Unit* target = m_targets.getUnitTarget(); + if (!target || (target->IsFriendlyTo(m_caster) && target->GetCreatureType() != CREATURE_TYPE_UNDEAD)) + return SPELL_FAILED_BAD_TARGETS; + } else if (m_spellInfo->Id == 19938) // Awaken Peon { Unit *unit = m_targets.getUnitTarget(); if(!unit || !unit->HasAura(17743, 0)) return SPELL_FAILED_BAD_TARGETS; } + else if (m_spellInfo->Id == 52264) // Deliver Stolen Horse + { + if(!m_caster->FindNearestCreature(28653,5)) + return SPELL_FAILED_OUT_OF_RANGE; + } break; } case SPELL_EFFECT_LEARN_SPELL: @@ -4492,6 +4796,14 @@ SpellCastResult Spell::CheckCast(bool strict) break; } + case SPELL_EFFECT_APPLY_GLYPH: + { + uint32 glyphId = m_spellInfo->EffectMiscValue[i]; + if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyphId)) + if(m_caster->HasAura(gp->SpellId)) + return SPELL_FAILED_UNIQUE_GLYPH; + break; + } case SPELL_EFFECT_FEED_PET: { if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -4529,9 +4841,14 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_CHARGE: { + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR) + { + // Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process + if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953)) + m_caster->RemoveMovementImpairingAuras(); + } if (m_caster->hasUnitState(UNIT_STAT_ROOT)) return SPELL_FAILED_ROOTED; - break; } case SPELL_EFFECT_SKINNING: @@ -4564,7 +4881,6 @@ SpellCastResult Spell::CheckCast(bool strict) break; } - case SPELL_EFFECT_OPEN_LOCK_ITEM: case SPELL_EFFECT_OPEN_LOCK: { if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT && @@ -4588,7 +4904,7 @@ SpellCastResult Spell::CheckCast(bool strict) uint32 lockId = 0; if (GameObject* go = m_targets.getGOTarget()) { - lockId = go->GetLockId(); + lockId = go->GetGOInfo()->GetLockId(); if (!lockId) return SPELL_FAILED_BAD_TARGETS; } @@ -4762,27 +5078,34 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_CHARM: - //case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_AOE_CHARM: { - if(m_caster->GetPetGUID()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - if(m_caster->GetCharmerGUID()) return SPELL_FAILED_CHARMED; - Unit *target = m_targets.getUnitTarget(); - if(!target || target->GetTypeId() == TYPEID_UNIT - && ((Creature*)target)->isVehicle()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM + || m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS) + { + if(m_caster->GetPetGUID()) + return SPELL_FAILED_ALREADY_HAVE_SUMMON; - if(target->GetCharmerGUID()) - return SPELL_FAILED_CHARMED; + if(m_caster->GetCharmGUID()) + return SPELL_FAILED_ALREADY_HAVE_CHARM; + } + + if(Unit *target = m_targets.getUnitTarget()) + { + if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isVehicle()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + + if(target->GetCharmerGUID()) + return SPELL_FAILED_CHARMED; - if(int32(target->getLevel()) > CalculateDamage(i, target)) - return SPELL_FAILED_HIGHLEVEL; + int32 damage = CalculateDamage(i, target); + if(damage && int32(target->getLevel()) > damage) + return SPELL_FAILED_HIGHLEVEL; + } break; } @@ -4818,14 +5141,15 @@ SpellCastResult Spell::CheckCast(bool strict) break; } - case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED: case SPELL_AURA_FLY: + case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED: { - // not allow cast fly spells at old maps by players (all spells is self target) - if(m_originalCaster && m_originalCaster->GetTypeId()==TYPEID_PLAYER) + // not allow cast fly spells if not have req. skills (all spells is self target) + // allow always ghost flight spells + if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->isAlive()) { - if( !((Player*)m_originalCaster)->IsAllowUseFlyMountsHere() ) - return SPELL_FAILED_NOT_HERE; + if (!((Player*)m_originalCaster)->IsKnowHowFlyIn(m_originalCaster->GetMapId(),m_originalCaster->GetZoneId())) + return m_IsTriggeredSpell ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; } break; } @@ -5092,81 +5416,13 @@ SpellCastResult Spell::CheckRange(bool strict) { if(!m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, max_range)) return SPELL_FAILED_OUT_OF_RANGE; - if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, min_range)) + if(min_range && m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, min_range)) return SPELL_FAILED_TOO_CLOSE; } return SPELL_CAST_OK; } -int32 Spell::CalculatePowerCost() -{ - // item cast not used power - if(m_CastItem) - return 0; - - // Spell drain all exist power on cast (Only paladin lay of Hands) - if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER) - { - // If power type - health drain all - if (m_spellInfo->powerType == POWER_HEALTH) - return m_caster->GetHealth(); - // Else drain all power - if (m_spellInfo->powerType < MAX_POWERS) - return m_caster->GetPower(Powers(m_spellInfo->powerType)); - sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); - return 0; - } - - // Base powerCost - int32 powerCost = m_spellInfo->manaCost; - // PCT cost from total amount - if (m_spellInfo->ManaCostPercentage) - { - switch (m_spellInfo->powerType) - { - // health as power used - case POWER_HEALTH: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateHealth() / 100; - break; - case POWER_MANA: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; - break; - case POWER_RAGE: - case POWER_FOCUS: - case POWER_ENERGY: - case POWER_HAPPINESS: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100; - break; - case POWER_RUNE: - case POWER_RUNIC_POWER: - sLog.outDebug("Spell::CalculateManaCost: Not implemented yet!"); - break; - default: - sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); - return 0; - } - } - SpellSchools school = GetFirstSchoolInMask(m_spellSchoolMask); - // Flat mod from caster auras by spell school - powerCost += m_caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school); - // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) - if ( m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST ) - powerCost += m_caster->GetAttackTime(OFF_ATTACK)/100; - // Apply cost mod by spell - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, powerCost, this); - - if(m_spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) - powerCost = int32(powerCost/ (1.117f* m_spellInfo->spellLevel / m_caster->getLevel() -0.1327f)); - - // PCT mod from user auras by school - powerCost = int32(powerCost * (1.0f+m_caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school))); - if (powerCost < 0) - powerCost = 0; - return powerCost; -} - SpellCastResult Spell::CheckPower() { // item cast not used power @@ -5310,7 +5566,7 @@ SpellCastResult Spell::CheckItems() TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker); CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap()); if(!ok) return SPELL_FAILED_REQUIRES_SPELL_FOCUS; @@ -5567,7 +5823,7 @@ SpellCastResult Spell::CheckItems() if(!ammo) { // Requires No Ammo - if(m_caster->GetDummyAura(46699)) + if(m_caster->HasAura(46699)) break; // skip other checks return SPELL_FAILED_NO_AMMO; @@ -5758,8 +6014,10 @@ bool Spell::CheckTargetCreatureType(Unit* target) const { uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType; - // Curse of Doom : not find another way to fix spell target check :/ - if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags.IsEqual(0,0x02,0)) + // Curse of Doom & Exorcism: not find another way to fix spell target check :/ + if (m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->Category == 1179 || + // TODO: will be removed in 3.2.x + m_spellInfo->SpellFamilyName==SPELLFAMILY_PALADIN && m_spellInfo->Category == 19) { // not allow cast at player if(target->GetTypeId()==TYPEID_PLAYER) @@ -5834,7 +6092,26 @@ bool Spell::CheckTarget(Unit* target, uint32 eff) return false; } - //Do not check LOS for triggered spells + switch(m_spellInfo->EffectApplyAuraName[eff]) + { + case SPELL_AURA_NONE: + default: + break; + case SPELL_AURA_MOD_POSSESS: + case SPELL_AURA_MOD_CHARM: + case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_AOE_CHARM: + if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isVehicle()) + return false; + if(target->GetCharmerGUID()) + return false; + if(int32 damage = CalculateDamage(eff, target)) + if((int32)target->getLevel() > damage) + return false; + break; + } + + //Do not do further checks for triggered spells if(m_IsTriggeredSpell) return true; @@ -6115,7 +6392,7 @@ void Spell::CalculateDamageDoneForAllTargets() if (target.missCondition==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target { - target.damage += CalculateDamageDone(unit, mask, multiplier); + target.damage += CalculateDamageDone(unit, mask, multiplier); target.crit = m_caster->isSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); } else if (target.missCondition == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit) diff --git a/src/game/Spell.h b/src/game/Spell.h index 6aa539808df..b593bf79881 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -263,11 +263,11 @@ class Spell void EffectQuestComplete(uint32 i); void EffectCreateItem(uint32 i); void EffectCreateItem2(uint32 i); + void EffectCreateRandomItem(uint32 i); void EffectPersistentAA(uint32 i); void EffectEnergize(uint32 i); void EffectOpenLock(uint32 i); void EffectSummonChangeItem(uint32 i); - void EffectOpenSecretSafe(uint32 i); void EffectProficiency(uint32 i); void EffectApplyAreaAura(uint32 i); void EffectSummonType(uint32 i); @@ -319,6 +319,7 @@ class Spell void EffectSelfResurrect(uint32 i); void EffectSkinning(uint32 i); void EffectCharge(uint32 i); + void EffectCharge2(uint32 i); void EffectProspecting(uint32 i); void EffectMilling(uint32 i); void EffectRenamePet(uint32 i); @@ -353,6 +354,7 @@ class Spell void EffectActivateRune(uint32 i); void EffectTitanGrip(uint32 i); void EffectEnchantItemPrismatic(uint32 i); + void EffectPlayMusic(uint32 i); typedef std::set<Aura *> UsedSpellMods; @@ -389,7 +391,6 @@ class Spell SpellCastResult CheckCasterAuras() const; int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); } - int32 CalculatePowerCost(); bool HaveTargetsForEffect(uint8 effect) const; void Delayed(); @@ -438,6 +439,7 @@ class Spell uint32 m_glyphIndex; uint32 m_preCastSpell; SpellCastTargets m_targets; + int8 m_comboPointGain; UsedSpellMods m_appliedMods; @@ -567,9 +569,10 @@ class Spell SpellMissInfo reflectResult:8; uint8 effectMask:8; bool processed:1; - bool alive:1; + bool alive:1; + bool crit:1; + bool scaleAura:1; int32 damage; - bool crit; }; std::list<TargetInfo> m_UniqueTargetInfo; uint8 m_needAliveTargetMask; // Mask req. alive targets @@ -596,7 +599,7 @@ class Spell void AddGOTarget(uint64 goGUID, uint32 effIndex); void AddItemTarget(Item* target, uint32 effIndex); void DoAllEffectOnTarget(TargetInfo *target); - SpellMissInfo DoSpellHitOnUnit(Unit *unit, uint32 effectMask); + SpellMissInfo DoSpellHitOnUnit(Unit *unit, uint32 effectMask, bool scaleAura); void DoTriggersOnSpellHit(Unit *unit); void DoAllEffectOnTarget(GOTargetInfo *target); void DoAllEffectOnTarget(ItemTargetInfo *target); @@ -637,6 +640,7 @@ class Spell uint32 m_customAttr; bool m_skipCheck; uint32 m_effectMask; + uint8 m_auraScaleMask; #ifdef MAP_BASED_RAND_GEN int32 irand(int32 min, int32 max) { return int32 (m_caster->GetMap()->mtRand.randInt(max - min)) + min; } diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h index f38bd455896..1a116173135 100644 --- a/src/game/SpellAuraDefines.h +++ b/src/game/SpellAuraDefines.h @@ -250,7 +250,7 @@ enum AuraType SPELL_AURA_IGNORE_COMBAT_RESULT = 202, SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE = 203, SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE = 204, - SPELL_AURA_205 = 205, // school vunderability? + SPELL_AURA_MOD_SCHOOL_CRIT_DMG_TAKEN = 205, SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED = 206, SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED = 207, SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED = 208, @@ -266,7 +266,7 @@ enum AuraType SPELL_AURA_HASTE_RANGED = 218, SPELL_AURA_MOD_MANA_REGEN_FROM_STAT = 219, SPELL_AURA_MOD_RATING_FROM_STAT = 220, - SPELL_AURA_221 = 221, + SPELL_AURA_MOD_DETAUNT = 221, SPELL_AURA_222 = 222, SPELL_AURA_RAID_PROC_FROM_CHARGE = 223, SPELL_AURA_224 = 224, @@ -292,7 +292,7 @@ enum AuraType SPELL_AURA_COMPREHEND_LANGUAGE = 244, SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL = 245, SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK = 246, - SPELL_AURA_247 = 247, + SPELL_AURA_CLONE_CASTER = 247, SPELL_AURA_MOD_COMBAT_RESULT_CHANCE = 248, SPELL_AURA_CONVERT_RUNE = 249, SPELL_AURA_MOD_INCREASE_HEALTH_2 = 250, @@ -324,14 +324,14 @@ enum AuraType SPELL_AURA_276 = 276, // Only "Test Mod Damage % Mechanic" spell, possible mod damage done SPELL_AURA_MOD_MAX_AFFECTED_TARGETS = 277, SPELL_AURA_MOD_DISARM_RANGED = 278, - SPELL_AURA_279 = 279, + SPELL_AURA_INITIALIZE_IMAGES = 279, SPELL_AURA_MOD_ARMOR_PENETRATION_PCT = 280, SPELL_AURA_MOD_HONOR_GAIN_PCT = 281, SPELL_AURA_MOD_BASE_HEALTH_PCT = 282, SPELL_AURA_MOD_HEALING_RECEIVED = 283, // Possibly only for some spell family class spells SPELL_AURA_LINKED = 284, SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR = 285, - SPELL_AURA_286, + SPELL_AURA_ABILITY_PERIODIC_CRIT = 286, SPELL_AURA_DEFLECT_SPELLS, SPELL_AURA_288, SPELL_AURA_289, diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 9c54bf7e27b..c303e5cdb11 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -74,7 +74,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY &Aura::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION &Aura::HandleAuraModTotalHealthPercentRegen, // 20 SPELL_AURA_OBS_MOD_HEALTH - &Aura::HandleAuraModTotalEnergyPercentRegen, // 21 SPELL_AURA_OBS_MOD_ENERGY + &Aura::HandleAuraModTotalEnergyPercentRegen, // 21 SPELL_AURA_OBS_MOD_ENERGY &Aura::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE &Aura::HandlePeriodicTriggerSpell, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL &Aura::HandlePeriodicEnergize, // 24 SPELL_AURA_PERIODIC_ENERGIZE @@ -223,7 +223,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT &Aura::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus &Aura::HandleNoImmediateEffect, //169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS implemented in Unit::DealDamageBySchool, Unit::DoAttackDamage, Unit::SpellCriticalBonus - &Aura::HandleNULL, //170 SPELL_AURA_DETECT_AMORE different spells that ignore transformation effects + &Aura::HandleNULL, //170 SPELL_AURA_DETECT_AMORE various spells that change visual of units for aura target (clientside?) &Aura::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK &Aura::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK &Aura::HandleUnused, //173 unused (3.0.8a) no spells, old SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell @@ -236,7 +236,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus &Aura::HandleUnused, //181 unused (3.0.8a) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS &Aura::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT - &Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746 + &Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746 - miscvalue - spell school &Aura::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &Aura::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &Aura::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult @@ -247,9 +247,9 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED &Aura::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE &Aura::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct) - &Aura::HandleNULL, //194 SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist + &Aura::HandleNoImmediateEffect, //194 SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist &Aura::HandleNoImmediateEffect, //195 SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist - &Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN + &Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN - flat mod of spell cooldowns &Aura::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance &Aura::HandleUnused, //198 unused (3.0.8a) old SPELL_AURA_MOD_ALL_WEAPON_SKILLS &Aura::HandleNoImmediateEffect, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT implemented in Unit::MagicSpellHitResult @@ -258,7 +258,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst &Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage &Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage - &Aura::HandleNULL, //205 vulnerable to school dmg? + &Aura::HandleNULL, //205 SPELL_AURA_MOD_SCHOOL_CRIT_DMG_TAKEN &Aura::HandleAuraModIncreaseFlightSpeed, //206 SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED &Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED &Aura::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED @@ -274,19 +274,19 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED &Aura::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT &Aura::HandleModRatingFromStat, //220 SPELL_AURA_MOD_RATING_FROM_STAT - &Aura::HandleNULL, //221 ignored + &Aura::HandleNULL, //221 SPELL_AURA_MOD_DETAUNT &Aura::HandleUnused, //222 unused (3.0.8a) only for spell 44586 that not used in real spell cast &Aura::HandleNoImmediateEffect, //223 SPELL_AURA_RAID_PROC_FROM_CHARGE &Aura::HandleUnused, //224 unused (3.0.8a) &Aura::HandleNoImmediateEffect, //225 SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE &Aura::HandleAuraPeriodicDummy, //226 SPELL_AURA_PERIODIC_DUMMY &Aura::HandlePeriodicTriggerSpellWithValue, //227 SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE - &Aura::HandleNoImmediateEffect, //228 stealth detection - &Aura::HandleNULL, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE + &Aura::HandleNoImmediateEffect, //228 SPELL_AURA_DETECT_STEALTH stealth detection + &Aura::HandleNoImmediateEffect, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE &Aura::HandleAuraModIncreaseHealth, //230 SPELL_AURA_MOD_INCREASE_HEALTH_2 &Aura::HandleNoImmediateEffect, //231 SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE &Aura::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateSpellDuration - &Aura::HandleNULL, //233 set model id to the one of the creature with id GetMiscValue() + &Aura::HandleUnused, //233 set model id to the one of the creature with id GetMiscValue() - clientside &Aura::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateSpellDuration &Aura::HandleNoImmediateEffect, //235 SPELL_AURA_MOD_DISPEL_RESIST implement in Unit::MagicSpellHitResult &Aura::HandleAuraControlVehicle, //236 SPELL_AURA_CONTROL_VEHICLE @@ -294,18 +294,18 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleModSpellHealingPercentFromAttackPower, //238 SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER implemented in Unit::SpellBaseHealingBonus &Aura::HandleAuraModScale, //239 SPELL_AURA_MOD_SCALE_2 only in Noggenfogger Elixir (16595) before 2.3.0 aura 61 &Aura::HandleAuraModExpertise, //240 SPELL_AURA_MOD_EXPERTISE - &Aura::HandleForceMoveForward, //241 Forces the player to move forward - &Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING + &Aura::HandleForceMoveForward, //241 SPELL_AURA_FORCE_MOVE_FORWARD Forces the player to move forward + &Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING - 2 test spells: 44183 and 44182 &Aura::HandleNULL, //243 faction reaction override spells - &Aura::HandleComprehendLanguage, //244 Comprehend language + &Aura::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE &Aura::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL &Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK implemented in Spell::EffectApplyAura - &Aura::HandleNULL, //247 target to become a clone of the caster + &Aura::HandleAuraCloneCaster, //247 SPELL_AURA_CLONE_CASTER &Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &Aura::HandleAuraConvertRune, //249 SPELL_AURA_CONVERT_RUNE &Aura::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2 &Aura::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE - &Aura::HandleNULL, //252 haste all? + &Aura::HandleModCombatSpeedPct, //252 SPELL_AURA_252 Is there any difference between this and SPELL_AURA_MELEE_SLOW ? maybe not stacking mod? &Aura::HandleNoImmediateEffect, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE implemented in Unit::isBlockCritical &Aura::HandleAuraModDisarm, //254 SPELL_AURA_MOD_DISARM_OFFHAND &Aura::HandleNoImmediateEffect, //255 SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT implemented in Unit::SpellDamageBonus @@ -325,26 +325,26 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNoImmediateEffect, //269 SPELL_AURA_MOD_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage &Aura::HandleNoImmediateEffect, //270 SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage &Aura::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonus - &Aura::HandleNULL, //272 reduce spell cast time? + &Aura::HandleNULL, //272 unknown &Aura::HandleUnused, //273 clientside &Aura::HandleNoImmediateEffect, //274 SPELL_AURA_CONSUME_NO_AMMO implemented in spell::CalculateDamageDoneForAllTargets &Aura::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select &Aura::HandleNULL, //276 mod damage % mechanic? &Aura::HandleNoImmediateEffect, //277 SPELL_AURA_MOD_ABILITY_AFFECTED_TARGETS implemented in spell::settargetmap &Aura::HandleAuraModDisarm, //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon - &Aura::HandleNULL, //279 visual effects? 58836 and 57507 + &Aura::HandleAuraInitializeImages, //279 SPELL_AURA_INITIALIZE_IMAGES &Aura::HandleModArmorPenetrationPct, //280 SPELL_AURA_MOD_ARMOR_PENETRATION_PCT &Aura::HandleNoImmediateEffect, //281 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor &Aura::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT &Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus - &Aura::HandleUnused, //284 not used by any spells (3.08a) + &Aura::HandleNULL, //284 SPELL_AURA_LINKED - probably not sent to client &Aura::HandleAuraModAttackPowerOfArmor, //285 SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR implemented in Player::UpdateAttackPowerAndDamage - &Aura::HandleUnused, //286 not used by any spells (3.08a) + &Aura::HandleNoImmediateEffect, //286 SPELL_AURA_ABILITY_PERIODIC_CRIT implemented in AuraEffect::PeriodicTick &Aura::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult - &Aura::HandleUnused, //288 not used by any spells (3.09) except 1 test spell. + &Aura::HandleUnused, //288 unused &Aura::HandleUnused, //289 unused - &Aura::HandleUnused, //290 unused - &Aura::HandleUnused, //291 unused + &Aura::HandleNULL, //290 mod all critical hit chances? + &Aura::HandleNULL, //291 SPELL_AURA_MOD_XP_QUEST_PCT &Aura::HandleNULL, //292 call stabled pet &Aura::HandleNULL, //293 2 test spells &Aura::HandleNULL //294 2 spells, possible prevent mana regen @@ -354,7 +354,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= Aura::Aura(SpellEntry const* spellproto, uint32 effMask, int32 *currentBasePoints, Unit *target, WorldObject *source, Unit *caster, Item* castItem) : m_caster_guid(0), m_castItemGuid(castItem?castItem->GetGUID():0), m_target(target), m_timeCla(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE), -m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_auraStateMask(0), m_updated(false), m_isRemoved(false) +m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1), m_updated(false), m_isRemoved(false) { assert(target); @@ -369,8 +369,6 @@ m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_aura m_isPassive = IsPassiveSpell(GetId()); - m_auraStateMask = 0; - m_isSingleTargetAura = IsSingleTargetSpell(m_spellProto); m_applyTime = time(NULL); @@ -400,7 +398,7 @@ m_auraSlot(MAX_AURAS), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),m_aura { // Glyph of Thorns if (m_target == caster && m_spellProto->SpellFamilyName==SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x100) - if (AuraEffect * aurEff = m_target->GetDummyAura(57862)) + if (AuraEffect * aurEff = m_target->GetAuraEffect(57862, 0)) m_maxduration += aurEff->GetAmount() * MINUTE * IN_MILISECONDS; modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, m_maxduration); @@ -486,6 +484,9 @@ m_target(parentAura->GetTarget()), m_tickNumber(0) else m_amount = m_currentBasePoints + 1; + if (int32 amount = CalculateCrowdControlAuraAmount(caster)) + m_amount = amount; + if (!m_amount && castItem && castItem->GetItemSuffixFactor()) { ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(castItem->GetItemRandomPropertyId())); @@ -766,7 +767,8 @@ void AreaAuraEffect::Update(uint32 diff) case AREA_AURA_PET: { if(Unit *owner = caster->GetCharmerOrOwner()) - targets.push_back(owner); + if (owner->IsWithinDistInMap(source, m_radius)) + targets.push_back(owner); break; } } @@ -836,7 +838,7 @@ void AreaAuraEffect::Update(uint32 diff) } else if (!source->IsWithinDistInMap(m_target, m_radius)) { - if (needFriendly) + if (needFriendly && source->isMoving()) { m_removeTime -= diff; if (m_removeTime < 0) @@ -940,6 +942,191 @@ void Aura::ApplyAllModifiers(bool apply, bool Real) m_partAuras[i]->ApplyModifier(apply, Real); } +void Aura::HandleAuraSpecificMods(bool apply) +{ + if (apply) + { + if(m_spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT) + { + // Icebound Fortitude + if (m_spellProto->SpellFamilyFlags[0] & 0x00100000) + { + Unit * caster = GetCaster(); + if (caster && caster->GetTypeId() == TYPEID_PLAYER) + { + if(AuraEffect *auraeff = GetPartAura(2)) + { + int32 value = int32((auraeff->GetAmount()*-1)-10); + uint32 defva = uint32(((Player*)caster)->GetSkillValue(SKILL_DEFENSE) + ((Player*)caster)->GetRatingBonusValue(CR_DEFENSE_SKILL)); + + if(defva > 400) + value += int32((defva-400)*0.15); + + // Glyph of Icebound Fortitude + if (AuraEffect *auradummy = caster->GetAuraEffect(58625,0)) + { + uint32 valmax = auradummy->GetAmount(); + if(value < valmax) + value = valmax; + } + auraeff->SetAmount(-value); + } + } + } + } + + if (m_spellProto->SpellFamilyName == SPELLFAMILY_MAGE) + { + if (m_spellProto->SpellFamilyFlags[0] & 0x00000001 && m_spellProto->SpellFamilyFlags[2] & 0x00000008) + { + // Glyph of Fireball + if (Unit * caster = GetCaster()) + if (caster->HasAura(56368)) + SetAuraDuration(0); + } + else if (m_spellProto->SpellFamilyFlags[0] & 0x00000020 && m_spellProto->SpellVisual[0] == 13) + { + // Glyph of Frostbolt + if (Unit * caster = GetCaster()) + if (caster->HasAura(56370)) + SetAuraDuration(0); + } + // Todo: This should be moved to similar function in spell::hit + else if (m_spellProto->SpellFamilyFlags[0] & 0x01000000) + { + Unit * caster = GetCaster(); + if (!caster) + return; + + // Polymorph Sound - Sheep && Penguin + if (m_spellProto->SpellIconID == 82 && m_spellProto->SpellVisual[0] == 12978) + { + // Glyph of the Penguin + if (caster->HasAura(52648)) + caster->CastSpell(m_target,61635,true); + else + caster->CastSpell(m_target,61634,true); + } + } + } + } + + // Aura Mastery Triggered Spell Handler + // If apply Concentration Aura -> trigger -> apply Aura Mastery Immunity + // If remove Concentration Aura -> trigger -> remove Aura Mastery Immunity + // If remove Aura Mastery -> trigger -> remove Aura Mastery Immunity + if (m_spellProto->Id == 19746 || m_spellProto->Id == 31821) + { + if (GetCasterGUID() != m_target->GetGUID()) + return; + if (apply) + { + if ((m_spellProto->Id == 31821 && m_target->HasAura(19746, GetCasterGUID())) || (m_spellProto->Id == 19746 && m_target->HasAura(31821))) + { + m_target->CastSpell(m_target,64364,true); + return; + } + } + else + { + m_target->RemoveAurasDueToSpell(64364, GetCasterGUID()); + return; + } + } + + if (GetSpellSpecific(m_spellProto->Id) == SPELL_PRESENCE) + { + AuraEffect *bloodPresenceAura=0; // healing by damage done + AuraEffect *frostPresenceAura=0; // increased health + AuraEffect *unholyPresenceAura=0; // increased movement speed, faster rune recovery + + // Improved Presences + Unit::AuraEffectList const& vDummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraEffectList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) + { + switch((*itr)->GetId()) + { + // Improved Blood Presence + case 50365: + case 50371: + { + bloodPresenceAura = (*itr); + break; + } + // Improved Frost Presence + case 50384: + case 50385: + { + frostPresenceAura = (*itr); + break; + } + // Improved Unholy Presence + case 50391: + case 50392: + { + unholyPresenceAura = (*itr); + break; + } + } + } + + uint32 presence=GetId(); + if (apply) + { + // Blood Presence bonus + if (presence == SPELL_ID_BLOOD_PRESENCE) + m_target->CastSpell(m_target,63611,true); + else if (bloodPresenceAura) + { + int32 basePoints1=bloodPresenceAura->GetAmount(); + m_target->CastCustomSpell(m_target,63611,NULL,&basePoints1,NULL,true,0,bloodPresenceAura); + } + // Frost Presence bonus + if (presence == SPELL_ID_FROST_PRESENCE) + m_target->CastSpell(m_target,61261,true); + else if (frostPresenceAura) + { + int32 basePoints0=frostPresenceAura->GetAmount(); + m_target->CastCustomSpell(m_target,61261,&basePoints0,NULL,NULL,true,0,frostPresenceAura); + } + // Unholy Presence bonus + if (presence == SPELL_ID_UNHOLY_PRESENCE) + { + if(unholyPresenceAura) + { + // Not listed as any effect, only base points set + int32 basePoints0 = unholyPresenceAura->GetSpellProto()->EffectBasePoints[1]; + //m_target->CastCustomSpell(m_target,63622,&basePoints0 ,NULL,NULL,true,0,unholyPresenceAura); + m_target->CastCustomSpell(m_target,65095,&basePoints0 ,NULL,NULL,true,0,unholyPresenceAura); + } + m_target->CastSpell(m_target,49772, true); + } + else if (unholyPresenceAura) + { + int32 basePoints0=unholyPresenceAura->GetAmount(); + m_target->CastCustomSpell(m_target,49772,&basePoints0,NULL,NULL,true,0,unholyPresenceAura); + } + } + else + { + // Remove passive auras + if (presence == SPELL_ID_BLOOD_PRESENCE || bloodPresenceAura) + m_target->RemoveAurasDueToSpell(63611); + if (presence == SPELL_ID_FROST_PRESENCE || frostPresenceAura) + m_target->RemoveAurasDueToSpell(61261); + if (presence == SPELL_ID_UNHOLY_PRESENCE || unholyPresenceAura) + { + if(presence == SPELL_ID_UNHOLY_PRESENCE && unholyPresenceAura) + { + //m_target->RemoveAurasDueToSpell(63622); + m_target->RemoveAurasDueToSpell(65095); + } + m_target->RemoveAurasDueToSpell(49772); + } + } + } +} + void Aura::SendAuraUpdate() { if (m_auraSlot>=MAX_AURAS) @@ -960,7 +1147,7 @@ void Aura::SendAuraUpdate() data << uint32(GetId()); data << uint8(m_auraFlags); data << uint8(m_auraLevel); - data << uint8(m_stackAmount > 1 ? m_stackAmount : m_procCharges); + data << uint8(m_stackAmount > 1 ? m_stackAmount : (m_procCharges) ? m_procCharges : 1); if(!(m_auraFlags & AFLAG_CASTER)) { @@ -1096,57 +1283,7 @@ void Aura::_AddAura() } } - //***************************************************** - // Update target aura state flag - //***************************************************** - - // Update Seals information - if (IsSealSpell(m_spellProto)) - SetAuraState(AURA_STATE_JUDGEMENT); - - // Conflagrate aura state on Immolate or Shadowflame - if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && (m_spellProto->SpellFamilyFlags[0] & 4 - || m_spellProto->SpellFamilyFlags[2] & 2)) - SetAuraState(AURA_STATE_IMMOLATE); - - // Faerie Fire (druid versions) - if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x400) - SetAuraState(AURA_STATE_FAERIE_FIRE); - - // Victorious - if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags[1] & 0x00040000) - SetAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH); - - // Swiftmend state on Regrowth & Rejuvenation - if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags[0] & 0x50 ) - SetAuraState(AURA_STATE_SWIFTMEND); - - // Deadly poison aura state - if(m_spellProto->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellProto->SpellFamilyFlags[0] & 0x10000) - SetAuraState(AURA_STATE_DEADLY_POISON); - - // Enrage aura state - if(m_spellProto->Dispel == DISPEL_ENRAGE) - SetAuraState(AURA_STATE_ENRAGE); - - // Bleeding aura state - if (GetAllSpellMechanicMask(m_spellProto) & 1<<MECHANIC_BLEED) - SetAuraState(AURA_STATE_BLEEDING); - - if(GetSpellSchoolMask(m_spellProto) & SPELL_SCHOOL_MASK_FROST) - { - for (uint8 i = 0;i<MAX_SPELL_EFFECTS;++i) - { - if (m_spellProto->EffectApplyAuraName[i]==SPELL_AURA_MOD_STUN - || m_spellProto->EffectApplyAuraName[i]==SPELL_AURA_MOD_ROOT) - { - SetAuraState(AURA_STATE_FROZEN); - break; - } - } - } - - m_target->ApplyModFlag(UNIT_FIELD_AURASTATE, GetAuraStateMask(), true); + HandleAuraSpecificMods(true); } bool Aura::SetPartAura(AuraEffect* aurEff, uint8 effIndex) @@ -1192,22 +1329,6 @@ void Aura::_RemoveAura() if (getDiminishGroup() != DIMINISHING_NONE ) m_target->ApplyDiminishingAura(getDiminishGroup(),false); - // Check needed only if aura applies aurastate - if(GetAuraStateMask()) - { - uint32 foundMask = 0; - Unit::AuraMap& Auras = m_target->GetAuras(); - // Get mask of all aurastates from remaining auras - for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i) - { - foundMask|=(*i).second->GetAuraStateMask(); - } - // Remove only aurastates which were not found - foundMask = GetAuraStateMask() &~foundMask; - if (foundMask) - m_target->ApplyModFlag(UNIT_FIELD_AURASTATE, foundMask, false); - } - // since now aura cannot apply/remove it's modifiers m_isRemoved = true; // disable client server communication for removed aura @@ -1262,23 +1383,25 @@ void Aura::_RemoveAura() if (procEx) { uint32 ProcCaster, ProcVictim; - if (IsPositiveSpell(GetId())) + if (IsPositive()) { - ProcCaster = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL; - ProcVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL; + ProcCaster = PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL | PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT; + ProcVictim = PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL | PROC_FLAG_TAKEN_POSITIVE_SPELL; } else { - ProcCaster = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; - ProcVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT; + ProcCaster = PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL | PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; + ProcVictim = PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL | PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT; } caster->ProcDamageAndSpell(m_target,ProcCaster, ProcVictim, procEx, m_procDamage, BASE_ATTACK, m_spellProto); } } + HandleAuraSpecificMods(false); } void Aura::SetStackAmount(uint8 stackAmount, bool applied) { + bool refresh = stackAmount >= m_stackAmount; if (stackAmount != m_stackAmount) { m_stackAmount = stackAmount; @@ -1290,7 +1413,11 @@ void Aura::SetStackAmount(uint8 stackAmount, bool applied) } } } - RefreshAura(); + + if (refresh) + RefreshAura(); + else + SendAuraUpdate(); } bool Aura::modStackAmount(int32 num) @@ -1398,6 +1525,7 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply) { uint32 spellId = 0; uint32 spellId2 = 0; + uint32 spellId3 = 0; uint32 HotWSpellId = 0; switch(GetMiscValue()) @@ -1407,8 +1535,7 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply) HotWSpellId = 24900; break; case FORM_TREE: - spellId = 5420; - spellId2 = 34123; + spellId = 34123; break; case FORM_TRAVEL: spellId = 5419; @@ -1456,14 +1583,15 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply) spellId = 27792; spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation. break; + case FORM_SHADOW: + spellId = 49868; + break; case FORM_GHOUL: case FORM_GHOSTWOLF: case FORM_AMBIENT: - case FORM_SHADOW: case FORM_STEALTH: case FORM_CREATURECAT: case FORM_CREATUREBEAR: - spellId = 0; break; } @@ -1471,8 +1599,20 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply) if(apply) { - if (spellId) m_target->CastSpell(m_target, spellId, true, NULL, this ); - if (spellId2) m_target->CastSpell(m_target, spellId2, true, NULL, this); + // Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell + if (spellId) + { + if(m_target->GetTypeId() == TYPEID_PLAYER) + ((Player *)m_target)->RemoveSpellCooldown(spellId); + m_target->CastSpell(m_target, spellId, true, NULL, this ); + } + + if (spellId2) + { + if(m_target->GetTypeId() == TYPEID_PLAYER) + ((Player *)m_target)->RemoveSpellCooldown(spellId2); + m_target->CastSpell(m_target, spellId2, true, NULL, this); + } if(m_target->GetTypeId() == TYPEID_PLAYER) { @@ -1510,12 +1650,71 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply) } } } + switch(GetMiscValue()) + { + case FORM_CAT: + // Nurturing Instinct + if (AuraEffect const * aurEff = m_target->GetAuraEffect(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT, SPELLFAMILY_DRUID, 2254,0)) + { + uint32 spellId = 0; + switch (aurEff->GetId()) + { + case 33872: + spellId = 47179; + break; + case 33873: + spellId = 47180; + break; + } + m_target->CastSpell(m_target, spellId, true, NULL, this); + } + // Master Shapeshifter - Cat + if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0)) + { + int32 bp = aurEff->GetAmount(); + m_target->CastCustomSpell(m_target, 48420, &bp, NULL, NULL, true); + } + break; + case FORM_DIREBEAR: + case FORM_BEAR: + // Master Shapeshifter - Bear + if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0)) + { + int32 bp = aurEff->GetAmount(); + m_target->CastCustomSpell(m_target, 48418, &bp, NULL, NULL, true); + } + // Survival of the Fittest + if (AuraEffect const * aurEff = m_target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE,SPELLFAMILY_DRUID, 961, 0)) + { + int32 bp = m_target->CalculateSpellDamage(aurEff->GetSpellProto(),2,aurEff->GetSpellProto()->EffectBasePoints[2],m_target); + m_target->CastCustomSpell(m_target, 62069,&bp, NULL, NULL, true, 0, this); + } + break; + case FORM_MOONKIN: + // Master Shapeshifter - Moonkin + if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0)) + { + int32 bp = aurEff->GetAmount(); + m_target->CastCustomSpell(m_target, 48421, &bp, NULL, NULL, true); + } + break; + // Master Shapeshifter - Tree of Life + case FORM_TREE: + if (AuraEffect const * aurEff = m_target->GetDummyAura(SPELLFAMILY_GENERIC, 2851, 0)) + { + int32 bp = aurEff->GetAmount(); + m_target->CastCustomSpell(m_target, 48422, &bp, NULL, NULL, true); + } + break; + } } } else { - m_target->RemoveAurasDueToSpell(spellId); - m_target->RemoveAurasDueToSpell(spellId2); + if (spellId) + m_target->RemoveAurasDueToSpell(spellId); + if (spellId2) + m_target->RemoveAurasDueToSpell(spellId2); Unit::AuraMap& tAuras = m_target->GetAuras(); for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();) @@ -1540,12 +1739,8 @@ bool AuraEffect::isAffectedOnSpell(SpellEntry const *spell) const if (spell->SpellFamilyName != m_spellProto->SpellFamilyName) return false; - // Check EffectClassMask and Spell_Affect table - flag96 const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex); - if (!spellAffect) - spellAffect = &m_spellProto->EffectSpellClassMask[m_effIndex]; - - if (*spellAffect & spell->SpellFamilyFlags) + // Check EffectClassMask + if (m_spellProto->EffectSpellClassMask[m_effIndex] & spell->SpellFamilyFlags) return true; return false; } @@ -1590,10 +1785,7 @@ void AuraEffect::HandleAddModifier(bool apply, bool Real, bool changeAmount) mod->type = SpellModType(m_auraName); // SpellModType value == spell aura types mod->spellId = GetId(); - flag96 const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex); - if (!spellAffect) - spellAffect = &m_spellProto->EffectSpellClassMask[m_effIndex]; - mod->mask = *spellAffect; + mod->mask = m_spellProto->EffectSpellClassMask[m_effIndex]; mod->charges = GetParentAura()->GetAuraCharges(); m_spellmod = mod; @@ -1707,43 +1899,13 @@ void AuraEffect::TriggerSpell() ((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,true); return; } -// // Periodic Mana Burn -// case 812: break; -// // Polymorphic Ray -// case 6965: break; -// // Fire Nova (1-7 ranks) -// case 8350: -// case 8508: -// case 8509: -// case 11312: -// case 11313: -// case 25540: -// case 25544: -// break; // Thaumaturgy Channel case 9712: trigger_spell_id = 21029; break; -// // Egan's Blaster -// case 17368: break; -// // Haunted -// case 18347: break; -// // Ranshalla Waiting -// case 18953: break; -// // Inferno -// case 19695: break; -// // Frostwolf Muzzle DND -// case 21794: break; -// // Alterac Ram Collar DND -// case 21866: break; -// // Celebras Waiting -// case 21916: break; - // Brood Affliction: Bronze case 23170: { m_target->CastSpell(m_target, 23171, true, 0, this); return; } -// // Mark of Frost -// case 23184: break; // Restoration case 23493: { @@ -1758,46 +1920,6 @@ void AuraEffect::TriggerSpell() } return; } -// // Stoneclaw Totem Passive TEST -// case 23792: break; -// // Axe Flurry -// case 24018: break; -// // Mark of Arlokk -// case 24210: break; -// // Restoration -// case 24379: break; -// // Happy Pet -// case 24716: break; -// // Dream Fog -// case 24780: break; -// // Cannon Prep -// case 24832: break; -// // Shadow Bolt Whirl -// case 24834: break; -// // Stink Trap -// case 24918: break; -// // Mark of Nature -// case 25041: break; -// // Agro Drones -// case 25152: break; -// // Consume -// case 25371: break; -// // Pain Spike -// case 25572: break; -// // Rotate 360 -// case 26009: break; -// // Rotate -360 -// case 26136: break; -// // Consume -// case 26196: break; -// // Berserk -// case 26615: break; -// // Defile -// case 27177: break; -// // Teleport: IF/UC -// case 27601: break; -// // Five Fat Finger Exploding Heart Technique -// case 27673: break; // Nitrous Boost case 27746: { @@ -1811,8 +1933,6 @@ void AuraEffect::TriggerSpell() return; } } break; -// // Steam Tank Passive -// case 27747: break; // Frost Blast case 27808: caster->CastCustomSpell(29879, SPELLVALUE_BASE_POINT0, (float)m_target->GetMaxHealth()*0.26f, m_target, true, NULL, this); @@ -1825,49 +1945,13 @@ void AuraEffect::TriggerSpell() m_target->CastCustomSpell(27820, SPELLVALUE_BASE_POINT0, -mana*4, NULL, true, NULL, this, caster->GetGUID()); } return; -// // Controller Timer -// case 28095: break; -// // Stalagg Chain -// case 28096: break; -// // Stalagg Tesla Passive -// case 28097: break; -// // Feugen Tesla Passive -// case 28109: break; -// // Feugen Chain -// case 28111: break; -// // Mark of Didier -// case 28114: break; -// // Communique Timer, camp -// case 28346: break; -// // Icebolt -// case 28522: break; -// // Silithyst -// case 29519: break; // Inoculate Nestlewood Owlkin case 29528: if(target->GetTypeId()!=TYPEID_UNIT)// prevent error reports in case ignored player target return; break; -// // Overload -// case 29768: break; -// // Return Fire -// case 29788: break; -// // Return Fire -// case 29793: break; -// // Return Fire -// case 29794: break; -// // Guardian of Icecrown Passive -// case 29897: break; // Feed Captured Animal case 29917: trigger_spell_id = 29916; break; -// // Flame Wreath -// case 29946: break; -// // Flame Wreath -// case 29947: break; -// // Mind Exhaustion Passive -// case 30025: break; -// // Nether Beam - Serenity -// case 30401: break; // Extract Gas case 30427: { @@ -1890,19 +1974,6 @@ void AuraEffect::TriggerSpell() } // Quake case 30576: trigger_spell_id = 30571; break; -// // Burning Maul -// case 30598: break; -// // Regeneration -// case 30799: -// case 30800: -// case 30801: -// break; -// // Despawn Self - Smoke cloud -// case 31269: break; -// // Time Rift Periodic -// case 31320: break; -// // Corrupt Medivh -// case 31326: break; // Doom case 31347: { @@ -1917,20 +1988,6 @@ void AuraEffect::TriggerSpell() caster->SummonCreature(17870, 0, 0, 0, caster->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); return; } -// // Bloodmyst Tesla -// case 31611: break; -// // Doomfire -// case 31944: break; -// // Teleport Test -// case 32236: break; -// // Earthquake -// case 32686: break; -// // Possess -// case 33401: break; -// // Draw Shadows -// case 33563: break; -// // Murmur's Touch -// case 33711: break; // Flame Quills case 34229: { @@ -1941,82 +1998,8 @@ void AuraEffect::TriggerSpell() caster->CastSpell(m_target,spell_id,true, NULL, this); return; } -// // Gravity Lapse -// case 34480: break; -// // Tornado -// case 34683: break; -// // Frostbite Rotate -// case 34748: break; -// // Arcane Flurry -// case 34821: break; -// // Interrupt Shutdown -// case 35016: break; -// // Interrupt Shutdown -// case 35176: break; -// // Inferno -// case 35268: break; -// // Salaadin's Tesla -// case 35515: break; -// // Ethereal Channel (Red) -// case 35518: break; -// // Nether Vapor -// case 35879: break; -// // Dark Portal Storm -// case 36018: break; -// // Burning Maul -// case 36056: break; -// // Living Grove Defender Lifespan -// case 36061: break; -// // Professor Dabiri Talks -// case 36064: break; -// // Kael Gaining Power -// case 36091: break; -// // They Must Burn Bomb Aura -// case 36344: break; -// // They Must Burn Bomb Aura (self) -// case 36350: break; -// // Stolen Ravenous Ravager Egg -// case 36401: break; -// // Activated Cannon -// case 36410: break; -// // Stolen Ravenous Ravager Egg -// case 36418: break; -// // Enchanted Weapons -// case 36510: break; -// // Cursed Scarab Periodic -// case 36556: break; -// // Cursed Scarab Despawn Periodic -// case 36561: break; -// // Vision Guide -// case 36573: break; -// // Cannon Charging (platform) -// case 36785: break; -// // Cannon Charging (self) -// case 36860: break; // Remote Toy case 37027: trigger_spell_id = 37029; break; -// // Mark of Death -// case 37125: break; -// // Arcane Flurry -// case 37268: break; -// // Spout -// case 37429: break; -// // Spout -// case 37430: break; -// // Karazhan - Chess NPC AI, Snapshot timer -// case 37440: break; -// // Karazhan - Chess NPC AI, action timer -// case 37504: break; -// // Karazhan - Chess: Is Square OCCUPIED aura (DND) -// case 39400: break; -// // Banish -// case 37546: break; -// // Shriveling Gaze -// case 37589: break; -// // Fake Aggro Radius (2 yd) -// case 37815: break; -// // Corrupt Medivh -// case 37853: break; // Eye of Grillok case 38495: { @@ -2036,93 +2019,18 @@ void AuraEffect::TriggerSpell() creatureTarget->ForcedDespawn(); return; } -// // Magic Sucker Device timer -// case 38672: break; -// // Tomb Guarding Charging -// case 38751: break; -// // Murmur's Touch -// case 38794: break; -// // Activate Nether-wraith Beacon (31742 Nether-wraith Beacon item) -// case 39105: break; -// // Drain World Tree Visual -// case 39140: break; -// // Quest - Dustin's Undead Dragon Visual aura -// case 39259: break; -// // Hellfire - The Exorcism, Jules releases darkness, aura -// case 39306: break; -// // Inferno -// case 39346: break; -// // Enchanted Weapons -// case 39489: break; -// // Shadow Bolt Whirl -// case 39630: break; -// // Shadow Bolt Whirl -// case 39634: break; -// // Shadow Inferno -// case 39645: break; // Tear of Azzinoth Summon Channel - it's not really supposed to do anything,and this only prevents the console spam case 39857: trigger_spell_id = 39856; break; -// // Soulgrinder Ritual Visual (Smashed) -// case 39974: break; -// // Simon Game Pre-game timer -// case 40041: break; -// // Knockdown Fel Cannon: The Aggro Check Aura -// case 40113: break; -// // Spirit Lance -// case 40157: break; -// // Demon Transform 2 -// case 40398: break; -// // Demon Transform 1 -// case 40511: break; -// // Ancient Flames -// case 40657: break; -// // Ethereal Ring Cannon: Cannon Aura -// case 40734: break; -// // Cage Trap -// case 40760: break; -// // Random Periodic -// case 40867: break; -// // Prismatic Shield -// case 40879: break; // Aura of Desire case 41350: { - Unit::AuraEffectList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT); - for(Unit::AuraEffectList::const_iterator i = mMod.begin(); i != mMod.end(); ++i) - { - if ((*i)->GetId() == 41350) - { - (*i)->ApplyModifier(false); - (*i)->SetAmount((*i)->GetAmount()-5); - (*i)->ApplyModifier(true); - break; - } - } - }break; -// // Dementia -// case 41404: break; -// // Chaos Form -// case 41629: break; -// // Alert Drums -// case 42177: break; -// // Spout -// case 42581: break; -// // Spout -// case 42582: break; -// // Return to the Spirit Realm -// case 44035: break; -// // Curse of Boundless Agony -// case 45050: break; -// // Earthquake -// case 46240: break; - // Personalized Weather + AuraEffect * aurEff = GetParentAura()->GetPartAura(1); + aurEff->ApplyModifier(false, false, true); + aurEff->SetAmount(aurEff->GetAmount()-5); + aurEff->ApplyModifier(true, false, true); + break; + } case 46736: trigger_spell_id = 46737; break; -// // Stay Submerged -// case 46981: break; -// // Dragonblight Ram -// case 47015: break; -// // Party G.R.E.N.A.D.E. -// case 51510: break; default: break; } @@ -2141,32 +2049,6 @@ void AuraEffect::TriggerSpell() } break; } -// case SPELLFAMILY_WARRIOR: -// { -// switch(auraId) -// { -// // Wild Magic -// case 23410: break; -// // Corrupted Totems -// case 23425: break; -// default: -// break; -// } -// break; -// } -// case SPELLFAMILY_PRIEST: -// { -// switch(auraId) -// { -// // Blue Beam -// case 32930: break; -// // Fury of the Dreghood Elders -// case 35460: break; -// default: -// break; -// } - // break; - // } case SPELLFAMILY_DRUID: { switch(auraId) @@ -2177,8 +2059,6 @@ void AuraEffect::TriggerSpell() return; // Frenzied Regeneration case 22842: - case 22895: - case 22896: case 26999: { int32 LifePerRage = GetAmount(); @@ -2196,42 +2076,42 @@ void AuraEffect::TriggerSpell() } break; } + case SPELLFAMILY_HUNTER: + { + switch (auraId) + { + // Sniper training + case 53302: + case 53303: + case 53304: + if (m_target->GetTypeId() != TYPEID_PLAYER) + return; + + if (((Player*)m_target)->isMoving()) + { + m_amount = m_target->CalculateSpellDamage(m_spellProto,m_effIndex,m_currentBasePoints,m_target); + return; + } + + // We are standing at the moment + if (m_amount > 0) + { + --m_amount; + return; + } -// case SPELLFAMILY_HUNTER: -// { -// switch(auraId) -// { -// //Frost Trap Aura -// case 13810: -// return; -// //Rizzle's Frost Trap -// case 39900: -// return; -// // Tame spells -// case 19597: // Tame Ice Claw Bear -// case 19676: // Tame Snow Leopard -// case 19677: // Tame Large Crag Boar -// case 19678: // Tame Adult Plainstrider -// case 19679: // Tame Prairie Stalker -// case 19680: // Tame Swoop -// case 19681: // Tame Dire Mottled Boar -// case 19682: // Tame Surf Crawler -// case 19683: // Tame Armored Scorpid -// case 19684: // Tame Webwood Lurker -// case 19685: // Tame Nightsaber Stalker -// case 19686: // Tame Strigid Screecher -// case 30100: // Tame Crazed Dragonhawk -// case 30103: // Tame Elder Springpaw -// case 30104: // Tame Mistbat -// case 30647: // Tame Barbed Crawler -// case 30648: // Tame Greater Timberstrider -// case 30652: // Tame Nightstalker -// return; -// default: -// break; -// } -// break; -// } + trigger_spell_id = 64418 + auraId - 53302; + + // If aura is active - no need to continue + if (target->HasAura(trigger_spell_id)) + return; + + break; + default: + break; + } + break; + } case SPELLFAMILY_SHAMAN: { switch(auraId) @@ -2240,15 +2120,8 @@ void AuraEffect::TriggerSpell() case 28820: { // Need remove self if Lightning Shield not active - Unit::AuraMap const& auras = target->GetAuras(); - for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - { - SpellEntry const* spell = itr->second->GetSpellProto(); - if( spell->SpellFamilyName == SPELLFAMILY_SHAMAN && - spell->SpellFamilyFlags[0] & 0x400) - return; - } - target->RemoveAurasDueToSpell(28820); + if (!target->GetAura(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN,0x400)) + target->RemoveAurasDueToSpell(28820); return; } // Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus) @@ -2287,43 +2160,6 @@ void AuraEffect::TriggerSpell() // Spell exist but require custom code switch(auraId) { - // Curse of Idiocy - case 1010: - { - // TODO: spell casted by result in correct way mostly - // BUT: - // 1) target show casting at each triggered cast: target don't must show casting animation for any triggered spell - // but must show affect apply like item casting - // 2) maybe aura must be replace by new with accumulative stat mods instead stacking - - // prevent cast by triggered auras - if(GetCasterGUID() == m_target->GetGUID()) - return; - - // stop triggering after each affected stats lost > 90 - int32 intellectLoss = 0; - int32 spiritLoss = 0; - - Unit::AuraEffectList const& mModStat = m_target->GetAurasByType(SPELL_AURA_MOD_STAT); - for(Unit::AuraEffectList::const_iterator i = mModStat.begin(); i != mModStat.end(); ++i) - { - if ((*i)->GetId() == 1010) - { - switch((*i)->GetMiscValue()) - { - case STAT_INTELLECT: intellectLoss += (*i)->GetAmount(); break; - case STAT_SPIRIT: spiritLoss += (*i)->GetAmount(); break; - default: break; - } - } - } - - if(intellectLoss <= -90 && spiritLoss <= -90) - return; - - caster = target; - break; - } // Mana Tide case 16191: { @@ -2347,6 +2183,10 @@ void AuraEffect::TriggerSpell() case 54835: caster->CastSpell(m_target, trigger_spell_id, true, NULL, this); return; + // Ground Slam + case 33525: + target->CastSpell(target, trigger_spell_id, true); + return; } } @@ -2395,6 +2235,29 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) // AT APPLY if(apply) { + // Overpower + if (caster && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && + m_spellProto->SpellFamilyFlags[0] & 0x4) + { + // Must be casting target + if (!m_target->IsNonMeleeSpellCasted(false, false, true)) + return; + if (AuraEffect * aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARRIOR, 2775, 0)) + { + switch (aurEff->GetId()) + { + // Unrelenting Assault, rank 1 + case 46859: + m_target->CastSpell(m_target,64849,true,NULL,aurEff); + break; + // Unrelenting Assault, rank 2 + case 46860: + m_target->CastSpell(m_target,64850,true,NULL,aurEff); + break; + } + } + return; + } switch(GetId()) { // Haunting Spirits - perdiodic trigger demon @@ -2435,6 +2298,24 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) } return; } + case 37096: // Blood Elf Illusion + { + if(caster) + { + switch(caster->getGender()) + { + case GENDER_FEMALE: + caster->CastSpell(m_target,37095,true,NULL,this); // Blood Elf Disguise + break; + case GENDER_MALE: + caster->CastSpell(m_target,37093,true,NULL,this); + break; + default: + break; + } + } + return; + } case 55198: // Tidal Force { m_target->CastSpell(m_target,55166,true,NULL,this); @@ -2479,8 +2360,9 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) ((Player*)m_target)->RemoveAmmo(); // not use ammo and not allow use return; case 52916: // Honor Among Thieves - if (Unit * target = ObjectAccessor::GetUnit(*m_target, m_target->GetUInt64Value(UNIT_FIELD_TARGET))) - m_target->CastSpell(target, 51699, true); + if(m_target->GetTypeId()==TYPEID_PLAYER) + if (Unit * target = ObjectAccessor::GetUnit(*m_target,((Player*)m_target)->GetComboTarget())) + m_target->CastSpell(target, 51699, true); return; } @@ -2551,7 +2433,11 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) return; case 46308: // Burning Winds casted only at creatures at spawn m_target->CastSpell(m_target,47287,true,NULL,this); - return; + return; + case 52173: // Coyote Spirit Despawn Aura + case 60244: // Blood Parrot Despawn Aura + m_target->CastSpell((Unit*)NULL, GetAmount(), true, NULL, this); + return; } break; case SPELLFAMILY_WARLOCK: @@ -2581,6 +2467,14 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) return; } break; + case SPELLFAMILY_DEATHKNIGHT: + // Summon Gargoyle ( will start feeding gargoyle ) + if(GetId()==61777) + { + m_target->CastSpell(m_target,m_spellProto->EffectTriggerSpell[m_effIndex],true); + return; + } + break; default: break; } @@ -2597,6 +2491,10 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) break; switch(GetId()) { + // Recently Bandaged + case 11196: + m_target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply); + return; // Unstable Power case 24658: { @@ -2763,6 +2661,14 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) return; } } + // Predatory Strikes + if(m_target->GetTypeId()==TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563) + { + ((Player*)m_target)->UpdateAttackPowerAndDamage(); + return; + } + if (!Real) + break; // Lifebloom if ( GetSpellProto()->SpellFamilyFlags[1] & 0x10 ) { @@ -2783,85 +2689,19 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) if(m_target->IsInWorld()) m_target->CastCustomSpell(m_target,33778,&m_amount,NULL,NULL,true,NULL,this,GetCasterGUID()); - /*// have a look if there is still some other Lifebloom dummy aura - Unit::AuraList auras = m_target->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraList::iterator itr = auras.begin(); itr!=auras.end(); ++itr) - if((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID && - (*itr)->GetSpellProto()->SpellFamilyFlags & 0x1000000000LL) - return; - - // final heal - if(m_target->IsInWorld() && m_stackAmount > 0) + // restore mana + if (caster) { - int32 amount = m_amount / m_stackAmount; - m_target->CastCustomSpell(m_target,33778,&amount,NULL,NULL,true,NULL,this,GetCasterGUID()); - }*/ - } - return; - } - - // Predatory Strikes - if(m_target->GetTypeId()==TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563) - { - ((Player*)m_target)->UpdateAttackPowerAndDamage(); - return; - } - break; - } - case SPELLFAMILY_HUNTER: - { - if (!Real) - break; - // Glyph of Aspect of the Monkey - if(m_spellProto->Id==56833) - { - if(apply) - { - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_CHANCE_OF_SUCCESS; - mod->value = 100; - mod->type = SPELLMOD_FLAT; - mod->spellId = GetId(); - mod->mask[2] = 8192; - mod->mask[1] = 0x00000000; - mod->mask[0] = 524288; - m_spellmod = mod; + int32 returnmana = (GetSpellProto()->ManaCostPercentage * caster->GetCreateMana() / 100) * GetParentAura()->GetStackAmount() / 2; + caster->CastCustomSpell(caster, 64372, &returnmana, NULL, NULL, true, NULL, this, GetCasterGUID()); + } } - ((Player*)m_target)->AddSpellMod(m_spellmod, apply); return; } break; } case SPELLFAMILY_SHAMAN: { - if (!Real && !changeAmount) - break; - // Improved Weapon Totems - if( GetSpellProto()->SpellIconID == 57 && m_target->GetTypeId()==TYPEID_PLAYER ) - { - if(apply) - { - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_EFFECT1; - mod->value = m_amount; - mod->type = SPELLMOD_PCT; - mod->spellId = GetId(); - switch (m_effIndex) - { - case 0: - mod->mask[1] = 0x002; // Windfury Totem - break; - case 1: - mod->mask[1] = 0x004; // Flametongue Totem - break; - } - - m_spellmod = mod; - } - - ((Player*)m_target)->AddSpellMod(m_spellmod, apply); - return; - } if (!Real) break; // Sentry Totem @@ -2888,7 +2728,7 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) if (Real) { // pet auras - if(PetAura const* petSpell = spellmgr.GetPetAura(GetId())) + if(PetAura const* petSpell = spellmgr.GetPetAura(GetId(), m_effIndex)) { if(apply) m_target->AddPetAura(petSpell); @@ -3088,6 +2928,8 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun case FORM_AMBIENT: case FORM_SHADOW: case FORM_STEALTH: + case FORM_UNDEAD: + case FORM_SHADOW_DANCE: break; case FORM_TREE: modelid = 864; @@ -3116,13 +2958,37 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun case FORM_FLIGHT_EPIC: case FORM_FLIGHT: case FORM_MOONKIN: + { // remove movement affects m_target->RemoveMovementImpairingAuras(); +/* + m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); + Unit::AuraList const& slowingAuras = m_target->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); + for (Unit::AuraList::const_iterator iter = slowingAuras.begin(); iter != slowingAuras.end();) + { + SpellEntry const* aurSpellInfo = (*iter)->GetSpellProto(); + + // If spell that caused this aura has Croud Control or Daze effect + if((GetAllSpellMechanicMask(aurSpellInfo) & MECHANIC_NOT_REMOVED_BY_SHAPESHIFT) || + // some Daze spells have these parameters instead of MECHANIC_DAZE + (aurSpellInfo->SpellIconID == 15 && aurSpellInfo->Dispel == 0)) + { + ++iter; + continue; + } + + // All OK, remove aura now + m_target->RemoveAurasDueToSpellByCancel(aurSpellInfo->Id); + iter = slowingAuras.begin(); + } +*/ // and polymorphic affects if(m_target->IsPolymorphed()) m_target->RemoveAurasDueToSpell(m_target->getTransForm()); + break; + } default: break; } @@ -3176,28 +3042,6 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun } break; } - case FORM_BATTLESTANCE: - case FORM_DEFENSIVESTANCE: - case FORM_BERSERKERSTANCE: - { - uint32 Rage_val = 0; - // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch) - if(m_target->GetTypeId() == TYPEID_PLAYER) - { - PlayerSpellMap const& sp_list = ((Player *)m_target)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - if(itr->second->state == PLAYERSPELL_REMOVED) continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139) - Rage_val += m_target->CalculateSpellDamage(spellInfo,0,spellInfo->EffectBasePoints[0],m_target) * 10; - } - } - - if (m_target->GetPower(POWER_RAGE) > Rage_val) - m_target->SetPower(POWER_RAGE,Rage_val); - break; - } default: break; } @@ -3222,14 +3066,41 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun case FORM_BEAR: case FORM_DIREBEAR: case FORM_CAT: - if(AuraEffect* dummy = m_target->GetDummyAura(37315) ) + if(AuraEffect* dummy = m_target->GetAuraEffect(37315, 0) ) m_target->CastSpell(m_target,37316,true,NULL,dummy); break; // Nordrassil Regalia - bonus case FORM_MOONKIN: - if(AuraEffect* dummy = m_target->GetDummyAura(37324) ) + if(AuraEffect* dummy = m_target->GetAuraEffect(37324, 0) ) m_target->CastSpell(m_target,37325,true,NULL,dummy); break; + case FORM_BATTLESTANCE: + case FORM_DEFENSIVESTANCE: + case FORM_BERSERKERSTANCE: + { + uint32 Rage_val = 0; + // Defensive Tactics + if (form == FORM_DEFENSIVESTANCE) + { + if (AuraEffect const * aurEff = m_target->IsScriptOverriden(m_spellProto,831)) + Rage_val += aurEff->GetAmount() * 10; + } + // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch) + if(m_target->GetTypeId() == TYPEID_PLAYER) + { + PlayerSpellMap const& sp_list = ((Player *)m_target)->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + { + if(itr->second->state == PLAYERSPELL_REMOVED) continue; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139) + Rage_val += m_target->CalculateSpellDamage(spellInfo,0,spellInfo->EffectBasePoints[0],m_target) * 10; + } + } + if (m_target->GetPower(POWER_RAGE) > Rage_val) + m_target->SetPower(POWER_RAGE,Rage_val); + break; + } default: break; } @@ -3244,8 +3115,9 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun if(m_target->getClass() == CLASS_DRUID) { - if(form == FORM_CAT && apply) // add dash if in cat-from + if(form == FORM_CAT && apply) { + // add dash if in cat-from Unit::AuraMap & auras = m_target->GetAuras(); for (Unit::AuraMap::iterator iter = auras.begin(); iter != auras.end();++iter) { @@ -3364,6 +3236,13 @@ void AuraEffect::HandleAuraTransform(bool apply, bool Real, bool /*changeAmount* // Dragonmaw Illusion (set mount model also) if(GetId()==42016 && m_target->GetMountID() && !m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED).empty()) m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314); + + // Polymorph (sheep) + if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellProto()->SpellIconID == 82 && GetSpellProto()->SpellVisual[0] == 12978) + if (Unit * caster = GetCaster()) + // Glyph of the Penguin + if (caster->HasAura(52648)) + m_target->SetDisplayId(26452); } } @@ -4055,12 +3934,12 @@ void AuraEffect::HandleModThreat(bool apply, bool Real, bool changeAmount) if(!Real && !changeAmount) return; - if(!m_target->isAlive()) + if (!m_target->isAlive()) return; Unit* caster = GetCaster(); - if(!caster || !caster->isAlive()) + if (!caster || !caster->isAlive()) return; int level_diff = 0; @@ -4078,17 +3957,14 @@ void AuraEffect::HandleModThreat(bool apply, bool Real, bool changeAmount) multiplier = 1; break; } + if (level_diff > 0) m_amount += multiplier * level_diff; - for(int8 x=0;x < MAX_SPELL_SCHOOL;x++) - { - if(GetMiscValue() & int32(1<<x)) - { - if(m_target->GetTypeId() == TYPEID_PLAYER) + if (m_target->GetTypeId() == TYPEID_PLAYER) + for(int8 x=0;x < MAX_SPELL_SCHOOL;x++) + if (GetMiscValue() & int32(1<<x)) ApplyPercentModFloatVar(m_target->m_threatModifier[x], m_amount, apply); - } - } } void AuraEffect::HandleAuraModTotalThreat(bool apply, bool Real, bool changeAmount) @@ -4097,19 +3973,15 @@ void AuraEffect::HandleAuraModTotalThreat(bool apply, bool Real, bool changeAmou if(!Real && !changeAmount) return; - if(!m_target->isAlive() || m_target->GetTypeId()!= TYPEID_PLAYER) + if (!m_target->isAlive() || m_target->GetTypeId() != TYPEID_PLAYER) return; Unit* caster = GetCaster(); - if(!caster || !caster->isAlive()) + if (!caster || !caster->isAlive()) return; - float threatMod = 0.0f; - if(apply) - threatMod = float(m_amount); - else - threatMod = float(-m_amount); + float threatMod = apply ? float(m_amount) : float(-m_amount); m_target->getHostilRefManager().threatAssist(caster, threatMod); } @@ -4117,18 +3989,18 @@ void AuraEffect::HandleAuraModTotalThreat(bool apply, bool Real, bool changeAmou void AuraEffect::HandleModTaunt(bool apply, bool Real, bool /*changeAmount*/) { // only at real add/remove aura - if(!Real) + if (!Real) return; - if(!m_target->isAlive() || !m_target->CanHaveThreatList()) + if (!m_target->isAlive() || !m_target->CanHaveThreatList()) return; Unit* caster = GetCaster(); - if(!caster || !caster->isAlive() || caster->GetTypeId() != TYPEID_PLAYER) + if (!caster || !caster->isAlive()) return; - if(apply) + if (apply) m_target->TauntApply(caster); else { @@ -4204,15 +4076,28 @@ void AuraEffect::HandleAuraModIncreaseSwimSpeed(bool /*apply*/, bool Real, bool m_target->UpdateSpeed(MOVE_SWIM, true); } -void AuraEffect::HandleAuraModDecreaseSpeed(bool /*apply*/, bool Real, bool changeAmount) +void AuraEffect::HandleAuraModDecreaseSpeed(bool apply, bool Real, bool changeAmount) { // all applied/removed only at real aura add/remove if(!Real && !changeAmount) return; + if (apply) + { + // Gronn Lord's Grasp, becomes stoned + if (GetId() == 33572) + { + if (GetParentAura()->GetStackAmount() >= 5 && !m_target->HasAura(33652)) + m_target->CastSpell(m_target, 33652, true); + } + } + m_target->UpdateSpeed(MOVE_RUN, true); m_target->UpdateSpeed(MOVE_SWIM, true); m_target->UpdateSpeed(MOVE_FLIGHT, true); + m_target->UpdateSpeed(MOVE_RUN_BACK, true); + m_target->UpdateSpeed(MOVE_SWIM_BACK, true); + m_target->UpdateSpeed(MOVE_FLIGHT_BACK, true); } void AuraEffect::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real, bool changeAmount) @@ -4240,7 +4125,7 @@ void AuraEffect::HandleModStateImmunityMask(bool apply, bool Real, bool /*change if (GetMiscValue() & (1<<7)) immunity_list.push_back(SPELL_AURA_MOD_DISARM); if (GetMiscValue() & (1<<1)) - immunity_list.push_back(SPELL_AURA_MOD_TAUNT); + immunity_list.push_back(SPELL_AURA_TRANSFORM); // These flag can be recognized wrong: if (GetMiscValue() & (1<<6)) @@ -4283,6 +4168,11 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA //immune movement impairment and loss of control if(GetId()==42292 || GetId()==59752) mechanic=IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; + // Forbearance + // in DBC wrong mechanic immune since 3.0.x + else if (GetId() == 25771) + mechanic = 1 << MECHANIC_IMMUNE_SHIELD; + if (!mechanic) return; @@ -4310,23 +4200,18 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,GetMiscValue(),apply); // Bestial Wrath - if ( GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->Id == 19574) + if (GetSpellProto()->Id == 19574) { // The Beast Within cast on owner if talent present if ( Unit* owner = m_target->GetOwner() ) { // Search talent - Unit::AuraEffectList const& m_dummyAuras = owner->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraEffectList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i) + if (owner->GetAuraEffect(34692, 0)) { - if ( (*i)->GetSpellProto()->SpellIconID == 2229 ) - { - if (apply) - owner->CastSpell(owner, 34471, true, 0, this); - else - owner->RemoveAurasDueToSpell(34471); - break; - } + if (apply) + owner->CastSpell(owner, 34471, true, 0, this); + else + owner->RemoveAurasDueToSpell(34471); } } } @@ -4365,7 +4250,7 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,SPELL_AURA_MOD_DECREASE_SPEED,apply); } // Demonic Circle - else if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellProto->SpellIconID == 3221) + else if (GetId() == 48020) { if (m_target->GetTypeId() != TYPEID_PLAYER) return; @@ -4378,7 +4263,6 @@ void AuraEffect::HandleModMechanicImmunity(bool apply, bool Real, bool /*changeA } } -//this method is called whenever we add / remove aura which gives m_target some imunity to some spell effect void AuraEffect::HandleAuraModEffectImmunity(bool apply, bool Real, bool /*changeAmount*/) { // when removing flag aura, handle flag drop @@ -4518,15 +4402,20 @@ void AuraEffect::HandlePeriodicTriggerSpellWithValue(bool apply, bool Real, bool void AuraEffect::HandlePeriodicEnergize(bool apply, bool Real, bool changeAmount) { - if(!Real && !changeAmount) + if(!Real) return; m_isPeriodic = apply; - // Replenishment (0.25% from max) - // Infinite Replenishment - if (m_spellProto->SpellIconID == 3184 && m_spellProto->SpellVisual[0] == 12495) - m_amount = m_target->GetMaxPower(POWER_MANA) * 25 / 10000; + if (apply) + { + // Replenishment (0.25% from max) + // Infinite Replenishment + if (m_spellProto->SpellIconID == 3184 && m_spellProto->SpellVisual[0] == 12495) + m_amount = m_target->GetMaxPower(POWER_MANA) * 25 / 10000; + else if (m_spellProto->Id == 29166) // Innervate + m_amount = m_target->GetCreatePowers(POWER_MANA) * m_amount / (GetTotalTicks() * 100.0f); + } } void AuraEffect::HandleAuraPowerBurn(bool apply, bool Real, bool /*changeAmount*/) @@ -4572,10 +4461,19 @@ void AuraEffect::HandleAuraPeriodicDummy(bool apply, bool Real, bool changeAmoun case SPELLFAMILY_HUNTER: { // Explosive Shot - if (apply && !loading && caster) + if (apply && !loading && caster && spell->SpellFamilyFlags[1] & 0x80000000) m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 14 / 100); break; } + case SPELLFAMILY_DEATHKNIGHT: + { + // Reaping + // Blood of the North + // Death Rune Mastery + if (spell->SpellIconID == 3041 || spell->SpellIconID == 22 || spell->SpellIconID == 2622) + m_amount = 0; + break; + } } m_isPeriodic = apply; @@ -4599,7 +4497,7 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount) // Curse of Doom // This is a hack - this aura should be handled by passive aura and proc doomguard spawn on kill, however there is no such aura in dbcs - if(m_spellProto->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellProto->SpellFamilyFlags.IsEqual(0,0x02,0)) + if(m_spellProto->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellProto->SpellFamilyFlags[1] & 0x02) { if (Real && !apply && GetParentAura()->GetRemoveMode()==AURA_REMOVE_BY_DEATH) { @@ -4621,17 +4519,6 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount) switch (m_spellProto->SpellFamilyName) { - case SPELLFAMILY_GENERIC: - { - // Pounce Bleed - if ( m_spellProto->SpellIconID == 147 && m_spellProto->SpellVisual[0] == 0 ) - { - // $AP*0.18/6 bonus per tick - m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100); - return; - } - break; - } case SPELLFAMILY_WARRIOR: { // Rend @@ -4643,28 +4530,32 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount) float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE); float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE); m_amount+=int32(((mwb_min+mwb_max)/2+ap*mws/14000)*0.2f); + // "If used while your target is above 75% health, Rend does 35% more damage." + // as for 3.1.3 only ranks above 9 (wrong tooltip?) + if (spellmgr.GetSpellRank(m_spellProto->Id) >= 9) + { + if (m_target->HasAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, m_spellProto, caster)) + m_amount += int32(m_amount*0.35); + } return; } break; } - case SPELLFAMILY_DRUID: + // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage + case SPELLFAMILY_WARLOCK: { - // Rake - if (m_spellProto->SpellFamilyFlags[0] & 0x1000) - { - // $AP*0.06 bonus per tick - m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 6 / 100); - return; - } - // Lacerate - if (m_spellProto->SpellFamilyFlags[1] & 0x0000000100) + if (m_spellProto->SpellFamilyFlags[0] & 0x00004000) { - // $AP*0.05/5 bonus per tick - m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - return; + // if victim is below 25% of hp + if (m_target->GetMaxHealth() / 4 > m_target->GetHealth()) + m_amount *= 4; } + break; + } + case SPELLFAMILY_DRUID: + { // Rip - if (m_spellProto->SpellVisual[0] == 3941) + if (m_spellProto->SpellFamilyFlags[0] & 0x00800000) { // 0.01*$AP*cp if (caster->GetTypeId() != TYPEID_PLAYER) @@ -4673,25 +4564,12 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount) uint8 cp = ((Player*)caster)->GetComboPoints(); // Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs - Unit::AuraEffectList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr) - { - if((*itr)->GetId()==34241) - { - m_amount += cp * (*itr)->GetAmount(); - break; - } - } + if (AuraEffect const * aurEff = caster->GetAuraEffect(34241,0)) + m_amount += cp * aurEff->GetAmount(); + m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100); return; } - // Lock Jaw - if (m_spellProto->SpellFamilyFlags[1] & 0x10000000) - { - // 0.15*$AP - m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 15 / 100); - return; - } break; } case SPELLFAMILY_ROGUE: @@ -4712,38 +4590,6 @@ void AuraEffect::HandlePeriodicDamage(bool apply, bool Real, bool changeAmount) m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * AP_per_combo[cp]); return; } - // Garrote - if (m_spellProto->SpellFamilyFlags[0] & 0x100) - { - // $AP*0.07 bonus per tick - m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 7 / 100); - return; - } - // Deadly Poison - if (m_spellProto->SpellFamilyFlags[0] & 0x10000) - { - // 0.08*$AP / 4 * amount of stack - m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 2 * GetParentAura()->GetStackAmount() / 100); - return; - } - break; - } - case SPELLFAMILY_HUNTER: - { - // Serpent Sting - if (m_spellProto->SpellFamilyFlags[0] & 0x4000) - { - // $RAP*0.1/5 bonus per tick - m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500); - return; - } - // Immolation Trap - if (m_spellProto->SpellFamilyFlags[0] & 0x4 && m_spellProto->SpellIconID == 678) - { - // $RAP*0.1/5 bonus per tick - m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500); - return; - } break; } default: @@ -4913,7 +4759,7 @@ void AuraEffect::HandleModSpellDamagePercentFromStat(bool /*apply*/, bool Real, ((Player*)m_target)->UpdateSpellDamageAndHealingBonus(); } -void AuraEffect::HandleModSpellHealingPercentFromStat(bool /*apply*/, bool Real, bool /*changeAmount*/) +void AuraEffect::HandleModSpellHealingPercentFromStat(bool apply, bool Real, bool /*changeAmount*/) { if(m_target->GetTypeId() != TYPEID_PLAYER) return; @@ -5663,6 +5509,7 @@ void AuraEffect::HandleAuraModPacify(bool apply, bool Real, bool /*changeAmount* void AuraEffect::HandleAuraModPacifyAndSilence(bool apply, bool Real, bool changeAmount) { + // Vengeance of the Blue Flight if(m_spellProto->Id == 45839) { if(apply) @@ -5855,7 +5702,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount) { case SPELLFAMILY_PRIEST: // Power Word: Shield - if(m_spellProto->SpellFamilyFlags.IsEqual(0x1, 0, 0x400)) + if(m_spellProto->SpellFamilyFlags[0] & 0x1 && m_spellProto->SpellFamilyFlags[2] & 0x400) { // +80.68% from sp bonus DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.8068f; @@ -5863,7 +5710,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount) break; case SPELLFAMILY_MAGE: // ice barrier - if(m_spellProto->SpellFamilyFlags.IsEqual(0, 0x1, 0x8)) + if(m_spellProto->SpellFamilyFlags[1] & 0x1 && m_spellProto->SpellFamilyFlags[2] & 0x8) { // +80.67% from sp bonus DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.8067f; @@ -5880,7 +5727,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount) break; case SPELLFAMILY_WARLOCK: // shadow ward - if(m_spellProto->SpellFamilyFlags.IsEqual(0, 0, 0x40)) + if(m_spellProto->SpellFamilyFlags[2]& 0x40) { // +30% from sp bonus DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.3f; @@ -5891,7 +5738,7 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount) if (m_spellProto->SpellFamilyFlags[1] & 0x80000) { // 0.75 from sp bonus - DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f; + DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f; } break; default: @@ -5903,6 +5750,38 @@ void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount) m_amount += (int32)DoneActualBenefit; } } + + // Guardian Spirit + if(m_spellProto->Id == 47788 && Real && !apply) + { + Unit *caster = GetCaster(); + if(!caster) + return; + + if(caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *player = ((Player*)caster); + // Glyph of Guardian Spirit + if(AuraEffect * aurEff = player->GetAuraEffect(63231, 0)) + { + if (GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + { + if (!player->HasSpellCooldown(47788)) + return; + + player->RemoveSpellCooldown(m_spellProto->Id, true); + player->AddSpellCooldown(m_spellProto->Id, 0, uint32(time(NULL) + aurEff->GetAmount())); + + WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4); + data << uint64(player->GetGUID()); + data << uint8(0x0); // flags (0x1, 0x2) + data << uint32(m_spellProto->Id); + data << uint32(aurEff->GetAmount()*IN_MILISECONDS); + player->SendDirectMessage(&data); + } + } + } } void AuraEffect::PeriodicTick() @@ -5933,15 +5812,15 @@ void AuraEffect::PeriodicTick() { switch(GetId()) { - case 43093: case 31956: case 38801: - case 35321: case 38363: case 39215: + case 43093: case 31956: case 38801: // Grievous Wound + case 35321: case 38363: case 39215: // Gushing Wound if(m_target->GetHealth() == m_target->GetMaxHealth() ) { m_target->RemoveAurasDueToSpell(GetId()); return; } break; - case 38772: + case 38772: // Grievous Wound { uint32 percent = GetEffIndex() < 2 && GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_DUMMY ? @@ -5954,18 +5833,13 @@ void AuraEffect::PeriodicTick() } break; } - case 41337:// aura of anger + case 41337:// Aura of Anger { - Unit::AuraEffectList const& mMod = m_target->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - for(Unit::AuraEffectList::const_iterator i = mMod.begin(); i != mMod.end(); ++i) + if (AuraEffect * aurEff = GetParentAura()->GetPartAura(1)) { - if ((*i)->GetId() == 41337) - { - (*i)->ApplyModifier(false); - (*i)->SetAmount((*i)->GetAmount()+5); - (*i)->ApplyModifier(true); - break; - } + aurEff->ApplyModifier(false, false, true); + aurEff->SetAmount(aurEff->GetAmount()+5); + aurEff->ApplyModifier(true, false, true); } m_amount = 100 * m_tickNumber; break; @@ -5977,7 +5851,7 @@ void AuraEffect::PeriodicTick() uint32 absorb=0; uint32 resist=0; - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); + CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL ); // ignore non positive values (can be result apply spellmods to aura damage //uint32 amount = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0; @@ -5993,7 +5867,7 @@ void AuraEffect::PeriodicTick() GetEffectMechanic(GetSpellProto(), m_effIndex) != MECHANIC_BLEED) { uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage, GetSpellProto()); - cleanDamage.damage += pdamage - pdamageReductedArmor; + cleanDamage.mitigated_damage += pdamage - pdamageReductedArmor; pdamage = pdamageReductedArmor; } @@ -6013,6 +5887,21 @@ void AuraEffect::PeriodicTick() else pdamage = uint32(m_target->GetMaxHealth()*pdamage/100); + bool crit = false; + Unit::AuraEffectList const& mPeriodicCritAuras= pCaster->GetAurasByType(SPELL_AURA_ABILITY_PERIODIC_CRIT); + for(Unit::AuraEffectList::const_iterator itr = mPeriodicCritAuras.begin(); itr != mPeriodicCritAuras.end(); ++itr) + { + if (!(*itr)->isAffectedOnSpell(m_spellProto)) + continue; + + if (pCaster->isSpellCrit(m_target, m_spellProto, GetSpellSchoolMask(m_spellProto))) + { + crit = true; + pdamage = pCaster->SpellCriticalDamageBonus(m_spellProto, pdamage, m_target); + } + break; + } + //As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit // Reduce dot damage from resilience for players if (m_target->GetTypeId()==TYPEID_PLAYER) @@ -6025,7 +5914,7 @@ void AuraEffect::PeriodicTick() pCaster->DealDamageMods(m_target,pdamage,&absorb); - SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f); + SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f, crit); m_target->SendPeriodicAuraLog(&pInfo); Unit* target = m_target; // aura can be deleted in DealDamage @@ -6062,7 +5951,7 @@ void AuraEffect::PeriodicTick() uint32 absorb=0; uint32 resist=0; - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); + CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL ); //uint32 pdamage = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0; uint32 pdamage = GetAmount() > 0 ? GetAmount() : 0; @@ -6072,7 +5961,7 @@ void AuraEffect::PeriodicTick() if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL) { uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage, GetSpellProto()); - cleanDamage.damage += pdamage - pdamageReductedArmor; + cleanDamage.mitigated_damage += pdamage - pdamageReductedArmor; pdamage = pdamageReductedArmor; } @@ -6156,7 +6045,7 @@ void AuraEffect::PeriodicTick() return; // heal for caster damage (must be alive) - if(m_target != pCaster && GetSpellProto()->SpellVisual[0]==163 && !pCaster->isAlive()) + if(m_target != pCaster && GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_HEALTH_FUNNEL && !pCaster->isAlive()) return; if(GetParentAura()->GetAuraDuration() ==-1 && m_target->GetHealth()==m_target->GetMaxHealth()) @@ -6169,14 +6058,39 @@ void AuraEffect::PeriodicTick() if(m_auraName==SPELL_AURA_OBS_MOD_HEALTH) pdamage = uint32(m_target->GetMaxHealth() * pdamage * GetParentAura()->GetStackAmount() / 100); else + { + // Wild Growth (1/7 - 6 + 2*ramainTicks) % + if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellIconID == 2864) + { + int32 ticks = GetParentAura()->GetAuraMaxDuration()/m_amplitude; + int32 remainingTicks = int32(float(GetParentAura()->GetAuraDuration()) / m_amplitude + 0.5); + pdamage = int32(pdamage) + int32(pdamage)*ticks*(-6+2*remainingTicks)/100; + } + pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetParentAura()->GetStackAmount()); + } + + bool crit = false; + Unit::AuraEffectList const& mPeriodicCritAuras= pCaster->GetAurasByType(SPELL_AURA_ABILITY_PERIODIC_CRIT); + for(Unit::AuraEffectList::const_iterator itr = mPeriodicCritAuras.begin(); itr != mPeriodicCritAuras.end(); ++itr) + { + if (!(*itr)->isAffectedOnSpell(m_spellProto)) + continue; + + if (pCaster->isSpellCrit(m_target, m_spellProto, GetSpellSchoolMask(m_spellProto))) + { + crit = true; + pdamage = pCaster->SpellCriticalHealingBonus(m_spellProto, pdamage, m_target); + } + break; + } sLog.outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u", GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId()); int32 gain = m_target->ModifyHealth(pdamage); - SpellPeriodicAuraLogInfo pInfo(this, pdamage, pdamage - gain, 0, 0, 0.0f); + SpellPeriodicAuraLogInfo pInfo(this, pdamage, pdamage - gain, 0, 0, 0.0f, crit); m_target->SendPeriodicAuraLog(&pInfo); // add HoTs to amount healed in bgs @@ -6192,7 +6106,7 @@ void AuraEffect::PeriodicTick() // Health Funnel // heal for caster damage - if(m_target!=pCaster && spellProto->SpellVisual[0]==163) + if(m_target!=pCaster && GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_HEALTH_FUNNEL) { uint32 dmg = spellProto->manaPerSecond; if(pCaster->GetHealth() <= dmg && pCaster->GetTypeId()==TYPEID_PLAYER) @@ -6217,7 +6131,7 @@ void AuraEffect::PeriodicTick() pCaster->DealDamageMods(pCaster,damage,&absorb); pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, 0, false, 0, false); - CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL ); + CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL ); pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); } } @@ -6291,7 +6205,7 @@ void AuraEffect::PeriodicTick() modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, gain_multiplier); } - SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, gain_multiplier); + SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, gain_multiplier, false); m_target->SendPeriodicAuraLog(&pInfo); int32 gain_amount = int32(drain_amount*gain_multiplier); @@ -6323,6 +6237,20 @@ void AuraEffect::PeriodicTick() GetParentAura()->SetAuraDuration(0); } } + // Mana Feed - Drain Mana + if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK + && m_spellProto->SpellFamilyFlags[0] & 0x00000010) + { + int32 manaFeedVal = 0; + if (AuraEffect const * aurEff = GetParentAura()->GetPartAura(1)) + manaFeedVal = aurEff->GetAmount(); + + if(manaFeedVal > 0) + { + manaFeedVal = manaFeedVal * gain_amount / 100; + pCaster->CastCustomSpell(pCaster, 32554, &manaFeedVal, NULL, NULL, true, NULL, this); + } + } break; } case SPELL_AURA_OBS_MOD_ENERGY: @@ -6346,7 +6274,7 @@ void AuraEffect::PeriodicTick() sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u", GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), amount, GetId()); - SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f); + SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false); m_target->SendPeriodicAuraLog(&pInfo); int32 gain = m_target->ModifyPower(power,amount); @@ -6371,7 +6299,7 @@ void AuraEffect::PeriodicTick() uint32 amount = m_amount; - SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f); + SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false); m_target->SendPeriodicAuraLog(&pInfo); sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u", @@ -6523,6 +6451,7 @@ void AuraEffect::PeriodicDummyTick() case 34291: case 43182: case 43183: + case 43706: case 46755: case 49472: // Drink Coffee case 57073: @@ -6602,165 +6531,10 @@ void AuraEffect::PeriodicDummyTick() // 7053 Forsaken Skill: Shadow return; } -// // Panda -// case 19230: break; -// // Gossip NPC Periodic - Talk -// case 33208: break; -// // Gossip NPC Periodic - Despawn -// case 33209: break; -// // Steal Weapon -// case 36207: break; -// // Simon Game START timer, (DND) -// case 39993: break; -// // Knockdown Fel Cannon: break; The Aggro Burst -// case 40119: break; -// // Old Mount Spell -// case 40154: break; -// // Magnetic Pull -// case 40581: break; -// // Ethereal Ring: break; The Bolt Burst -// case 40801: break; -// // Crystal Prison -// case 40846: break; -// // Copy Weapon -// case 41054: break; -// // Dementia -// case 41404: break; -// // Ethereal Ring Visual, Lightning Aura -// case 41477: break; -// // Ethereal Ring Visual, Lightning Aura (Fork) -// case 41525: break; -// // Ethereal Ring Visual, Lightning Jumper Aura -// case 41567: break; -// // No Man's Land -// case 41955: break; -// // Headless Horseman - Fire -// case 42074: break; -// // Headless Horseman - Visual - Large Fire -// case 42075: break; -// // Headless Horseman - Start Fire, Periodic Aura -// case 42140: break; -// // Ram Speed Boost -// case 42152: break; -// // Headless Horseman - Fires Out Victory Aura -// case 42235: break; -// // Pumpkin Life Cycle -// case 42280: break; -// // Brewfest Request Chick Chuck Mug Aura -// case 42537: break; -// // Squashling -// case 42596: break; -// // Headless Horseman Climax, Head: Periodic -// case 42603: break; -// // Fire Bomb -// case 42621: break; -// // Headless Horseman - Conflagrate, Periodic Aura -// case 42637: break; -// // Headless Horseman - Create Pumpkin Treats Aura -// case 42774: break; -// // Headless Horseman Climax - Summoning Rhyme Aura -// case 42879: break; -// // Tricky Treat -// case 42919: break; -// // Giddyup! -// case 42924: break; -// // Ram - Trot -// case 42992: break; -// // Ram - Canter -// case 42993: break; -// // Ram - Gallop -// case 42994: break; -// // Ram Level - Neutral -// case 43310: break; -// // Headless Horseman - Maniacal Laugh, Maniacal, Delayed 17 -// case 43884: break; -// // Wretched! -// case 43963: break; -// // Headless Horseman - Maniacal Laugh, Maniacal, other, Delayed 17 -// case 44000: break; -// // Energy Feedback -// case 44328: break; -// // Romantic Picnic -// case 45102: break; -// // Romantic Picnic -// case 45123: break; -// // Looking for Love -// case 45124: break; -// // Kite - Lightning Strike Kite Aura -// case 45197: break; -// // Rocket Chicken -// case 45202: break; -// // Copy Offhand Weapon -// case 45205: break; -// // Upper Deck - Kite - Lightning Periodic Aura -// case 45207: break; -// // Kite -Sky Lightning Strike Kite Aura -// case 45251: break; -// // Ribbon Pole Dancer Check Aura -// case 45390: break; -// // Holiday - Midsummer, Ribbon Pole Periodic Visual -// case 45406: break; -// // Parachute -// case 45472: break; -// // Alliance Flag, Extra Damage Debuff -// case 45898: break; -// // Horde Flag, Extra Damage Debuff -// case 45899: break; -// // Ahune - Summoning Rhyme Aura -// case 45926: break; -// // Ahune - Slippery Floor -// case 45945: break; -// // Ahune's Shield -// case 45954: break; -// // Nether Vapor Lightning -// case 45960: break; -// // Darkness -// case 45996: break; -// // Summon Blood Elves Periodic -// case 46041: break; -// // Transform Visual Missile Periodic -// case 46205: break; -// // Find Opening Beam End -// case 46333: break; -// // Ice Spear Control Aura -// case 46371: break; -// // Hailstone Chill -// case 46458: break; -// // Hailstone Chill, Internal -// case 46465: break; -// // Chill, Internal Shifter -// case 46549: break; -// // Summon Ice Spear Knockback Delayer -// case 46878: break; -// // Burninate Effect -// case 47214: break; -// // Fizzcrank Practice Parachute -// case 47228: break; -// // Send Mug Control Aura -// case 47369: break; -// // Direbrew's Disarm (precast) -// case 47407: break; -// // Mole Machine Port Schedule -// case 47489: break; -// case 47941: break; // Crystal Spike -// case 48200: break; // Healer Aura -// case 48630: break; // Summon Gauntlet Mobs Periodic -// case 49313: break; // Proximity Mine Area Aura -// // Mole Machine Portal Schedule -// case 49466: break; -// case 49555: break; // Corpse Explode -// case 49592: break; // Temporal Rift -// case 49957: break; // Cutting Laser -// case 50085: break; // Slow Fall -// // Listening to Music -// case 50493: break; -// // Love Rocket Barrage -// case 50530: break; case 58549: // Tenacity case 59911: // Tenacity (vehicle) GetParentAura()->RefreshAura(); break; -// Exist more after, need add later default: break; } @@ -6768,8 +6542,12 @@ void AuraEffect::PeriodicDummyTick() case SPELLFAMILY_MAGE: { // Mirror Image -// if (spell->Id == 55342) -// return; + if (spell->Id == 55342) + { + // Set name of summons to name of caster + m_target->CastSpell((Unit *)NULL, m_spellProto->EffectTriggerSpell[m_effIndex], true); + m_isPeriodic = false; + } break; } case SPELLFAMILY_WARLOCK: @@ -6881,9 +6659,6 @@ void AuraEffect::PeriodicDummyTick() } switch (spell->Id) { - // Harpooner's Mark - // case 40084: - // return; // Feeding Frenzy Rank 1 case 53511: if ( m_target->GetHealth() * 100 < m_target->GetMaxHealth() * 35 ) @@ -6935,26 +6710,46 @@ void AuraEffect::PeriodicDummyTick() return; } // Summon Gargoyle -// if (spell->SpellFamilyFlags & 0x0000008000000000LL) -// return; + // Being pursuaded by Gargoyle - AI related? + // if (spell->SpellFamilyFlags[1] & 0x00000080) + // break; + // Blood of the North + // Reaping // Death Rune Mastery -// if (spell->SpellFamilyFlags & 0x0000000000004000LL) -// return; - // Bladed Armor - if (spell->SpellIconID == 2653) + if (spell->SpellIconID == 3041 || spell->SpellIconID == 22 || spell->SpellIconID == 2622) { - // Increases your attack power by $s1 for every $s2 armor value you have. - // Calculate AP bonus (from 1 efect of this spell) - int32 apBonus = m_amount * m_target->GetArmor() / m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target); - m_target->CastCustomSpell(m_target, 61217, &apBonus, &apBonus, 0, true, 0, this); + if (m_target->GetTypeId() != TYPEID_PLAYER) + return; + // Aura not used - prevent removing death runes from other effects + if (!GetAmount()) + return; + if(((Player*)m_target)->getClass() != CLASS_DEATH_KNIGHT) + return; + + // Remove death rune added on proc + for (uint8 i=0;i<MAX_RUNES && m_amount;++i) + { + if (m_spellProto->SpellIconID == 2622) + { + if (((Player*)m_target)->GetCurrentRune(i) != RUNE_DEATH || + ((Player*)m_target)->GetBaseRune(i) == RUNE_BLOOD ) + continue; + } + else + { + if (((Player*)m_target)->GetCurrentRune(i) != RUNE_DEATH || + ((Player*)m_target)->GetBaseRune(i) != RUNE_BLOOD ) + continue; + } + + if (!(m_amount & (1<<i))) + continue; + + ((Player*)m_target)->ConvertRune(i,((Player*)m_target)->GetBaseRune(i)); + } + m_amount = 0; return; } - // Reaping -// if (spell->SpellIconID == 22) -// return; - // Blood of the North -// if (spell->SpellIconID == 30412) -// return; break; } default: @@ -6992,7 +6787,7 @@ void AuraEffect::HandleManaShield(bool apply, bool Real, bool changeAmount) switch(m_spellProto->SpellFamilyName) { case SPELLFAMILY_MAGE: - if(m_spellProto->SpellFamilyFlags[0] & 0x8000) + if(m_spellProto->SpellFamilyFlags[0] & 0x8000 && m_spellProto->SpellFamilyFlags[2] & 0x8) { // Mana Shield // +50% from +spd bonus @@ -7075,26 +6870,32 @@ void AuraEffect::HandleAuraConvertRune(bool apply, bool Real, bool /*changeAmoun if(plr->getClass() != CLASS_DEATH_KNIGHT) return; - // how to determine what rune need to be converted? - for(uint32 i = 0; i < MAX_RUNES; ++i) + uint32 runes = 0; + // convert number of runes specified in aura amount of rune type in miscvalue to runetype in miscvalueb + for(uint32 i = 0; i < MAX_RUNES && m_amount; ++i) { if(apply) { + if (GetMiscValue() != plr->GetCurrentRune(i)) + continue; if(!plr->GetRuneCooldown(i)) { plr->ConvertRune(i, GetSpellProto()->EffectMiscValueB[m_effIndex]); - break; + runes |= 1<<i; + --m_amount; } } else { if(plr->GetCurrentRune(i) == GetSpellProto()->EffectMiscValueB[m_effIndex]) { - plr->ConvertRune(i, plr->GetBaseRune(i)); - break; + if (m_amount & (1<<i)) + plr->ConvertRune(i, plr->GetBaseRune(i)); } } } + if (apply) + m_amount = runes; } // Control Auras @@ -7130,12 +6931,7 @@ void AuraEffect::HandleModPossess(bool apply, bool Real, bool /*changeAmount*/) } if(apply) - { - if(m_target->getLevel() > m_amount) - return; - m_target->SetCharmedBy(caster, CHARM_TYPE_POSSESS); - } else m_target->RemoveCharmedBy(caster); } @@ -7153,7 +6949,6 @@ void AuraEffect::HandleModPossessPet(bool apply, bool Real, bool /*changeAmount* { if(caster->GetGuardianPet() != m_target) return; - m_target->SetCharmedBy(caster, CHARM_TYPE_POSSESS); } else @@ -7164,7 +6959,7 @@ void AuraEffect::HandleModPossessPet(bool apply, bool Real, bool /*changeAmount* ((Player*)caster)->PetSpellInitialize(); if(!m_target->getVictim()) { - m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + m_target->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, m_target->GetFollowAngle()); m_target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW); } } @@ -7178,12 +6973,7 @@ void AuraEffect::HandleModCharm(bool apply, bool Real, bool /*changeAmount*/) Unit* caster = GetCaster(); if(apply) - { - if(m_amount && int32(m_target->getLevel()) > m_amount) - return; - m_target->SetCharmedBy(caster, CHARM_TYPE_CHARM); - } else m_target->RemoveCharmedBy(caster); } @@ -7196,12 +6986,7 @@ void AuraEffect::HandleCharmConvert(bool apply, bool Real, bool /*changeAmount*/ Unit* caster = GetCaster(); if(apply) - { - if(m_amount && int32(m_target->getLevel()) > m_amount) - return; - m_target->SetCharmedBy(caster, CHARM_TYPE_CONVERT); - } else m_target->RemoveCharmedBy(caster); } @@ -7268,7 +7053,7 @@ void AuraEffect::HandleAuraSafeFall( bool Apply, bool Real , bool /*changeAmount { // implemented in WorldSession::HandleMovementOpcodes - // only special case + // Buffeting Winds of Susurrus - only special case if(Apply && Real && GetId()==32474 && m_target->GetTypeId()==TYPEID_PLAYER) ((Player*)m_target)->ActivateTaxiPathTo(506,GetId()); } @@ -7286,12 +7071,13 @@ void AuraEffect::HandleReflectSpells( bool Apply, bool Real , bool /*changeAmoun // implemented in Unit::SpellHitResult // only special case - if(!Apply && Real && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags[1] & 0x2) + if(!Apply && Real && GetParentAura()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT + && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags[1] & 0x2) { if (Unit * caster = GetCaster()) { // Improved Spell Reflection - if (caster->GetDummyAura(SPELLFAMILY_WARRIOR,1935)) + if (caster->GetDummyAura(SPELLFAMILY_WARRIOR,1935, 1)) { // aura remove - remove auras from all party members std::list<Unit*> PartyMembers; @@ -7305,4 +7091,98 @@ void AuraEffect::HandleReflectSpells( bool Apply, bool Real , bool /*changeAmoun } } } +void AuraEffect::HandleAuraInitializeImages( bool Apply, bool Real , bool /*changeAmount*/) +{ + if (!Real) + return; + if (Apply) + { + Unit * caster = GetCaster(); + if (!caster) + return; + // Set item visual + if (caster->GetTypeId()== TYPEID_PLAYER) + { + if (Item const * item = ((Player *)caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) + m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, item->GetProto()->ItemId); + if (Item const * item = ((Player *)caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND)) + m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, item->GetProto()->ItemId); + } + else // TYPEID_UNIT + { + m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID)); + m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1)); + m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2)); + } + } + else + { + // Remove equipment visual + if (m_target->GetTypeId() == TYPEID_PLAYER) + { + for (uint8 i = 0; i < 3; ++i) + m_target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0); + } + else // TYPEID_UNIT + { + ((Creature*)m_target)->LoadEquipment(((Creature*)m_target)->GetEquipmentId()); + } + } +} + +void AuraEffect::HandleAuraCloneCaster( bool Apply, bool Real , bool /*changeAmount*/) +{ + if (!Real) + return; + + if (Apply) + { + Unit * caster = GetCaster(); + if (!caster) + return; + // Set display id (probably for portrait?) + m_target->SetDisplayId(caster->GetDisplayId()); + m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE); + } + else + { + m_target->SetDisplayId(m_target->GetNativeDisplayId()); + m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE); + } +} + +int32 AuraEffect::CalculateCrowdControlAuraAmount(Unit * caster) +{ + // Damage cap for CC effects + if (!m_spellProto->procFlags) + return 0; + + if (m_auraName !=SPELL_AURA_MOD_CONFUSE && + m_auraName !=SPELL_AURA_MOD_FEAR && + m_auraName !=SPELL_AURA_MOD_STUN && + m_auraName !=SPELL_AURA_MOD_ROOT && + m_auraName !=SPELL_AURA_TRANSFORM) + return 0; + + int32 damageCap = (int32)(m_target->GetMaxHealth()*0.10f); + + if (!caster) + return damageCap; + + // Glyphs increasing damage cap + Unit::AuraEffectList const& overrideClassScripts = caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(Unit::AuraEffectList::const_iterator itr = overrideClassScripts.begin();itr != overrideClassScripts.end(); ++itr) + { + if((*itr)->isAffectedOnSpell(m_spellProto)) + { + // Glyph of Fear, Glyph of Frost nova and similar auras + if ((*itr)->GetMiscValue() == 7801) + { + damageCap += (int32)(damageCap*(*itr)->GetAmount()/100.0f); + break; + } + } + } + return damageCap; +} diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 987c8b0db25..6a1c11e49c9 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -84,8 +84,6 @@ class TRINITY_DLL_SPEC Aura int8 GetStackAmount() const {return m_stackAmount;} void SetStackAmount(uint8 num, bool applied = true); bool modStackAmount(int32 num); // return true if last charge dropped - uint32 GetAuraStateMask(){return m_auraStateMask;} - void SetAuraState(uint8 num){m_auraStateMask |= 1<<(num-1);} //modifies auras' aura state (not unit!) void SetRemoveMode(AuraRemoveMode mode) { m_removeMode = mode; } uint8 GetRemoveMode() const {return m_removeMode;} @@ -119,6 +117,7 @@ class TRINITY_DLL_SPEC Aura m_target->HandleAuraEffect(m_partAuras[i], apply); } void ApplyAllModifiers(bool apply, bool Real=false); + void HandleAuraSpecificMods(bool apply); void Update(uint32 diff); @@ -153,7 +152,6 @@ class TRINITY_DLL_SPEC Aura uint8 m_auraLevel; // Aura level (store caster level for correct show level dep amount) uint8 m_procCharges; // Aura charges (0 for infinite) uint8 m_stackAmount; // Aura stack amount - uint32 m_auraStateMask; AuraEffect * m_partAuras[3]; uint32 m_procDamage; // used in aura proc code @@ -334,6 +332,10 @@ class TRINITY_DLL_SPEC AuraEffect void HandleCharmConvert(bool apply, bool Real, bool changeAmount); void HandleReflectSpells( bool Apply, bool Real , bool changeAmount); void HandleModArmorPenetrationPct(bool Apply, bool Real, bool changeAmount); + void HandleAuraInitializeImages(bool Apply, bool Real, bool changeAmount); + void HandleAuraCloneCaster(bool Apply, bool Real, bool changeAmount); + + int32 CalculateCrowdControlAuraAmount(Unit * caster); // add/remove SPELL_AURA_MOD_SHAPESHIFT (36) linked auras void HandleShapeshiftBoosts(bool apply); @@ -348,9 +350,12 @@ class TRINITY_DLL_SPEC AuraEffect uint32 GetEffIndex() const { return m_effIndex; } int32 GetBasePoints() const { return m_currentBasePoints; } int32 GetAuraAmplitude(){return m_amplitude;} + void ResetPeriodicTimer(){m_periodicTimer = m_amplitude;} + virtual void Update(uint32 diff); uint32 GetTickNumber() const { return m_tickNumber; } + int32 GetTotalTicks () const { return m_amplitude ? (GetParentAura()->GetAuraMaxDuration() / m_amplitude) : 1;} bool IsAreaAura() const { return m_isAreaAura; } bool IsPeriodic() const { return m_isPeriodic; } bool IsPersistent() const { return m_isPersistent; } diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 6d1c986d7b2..f68488e538b 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -123,7 +123,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE - &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM + &Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN @@ -196,7 +196,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY &Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells - &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc) + &Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc) &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET @@ -213,7 +213,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused - &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop + &Spell::EffectCharge2, //149 SPELL_EFFECT_CHARGE2 swoop &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend @@ -221,7 +221,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //154 unused &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal. &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC - &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession + &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling &Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again &Spell::EffectNULL, //160 SPELL_EFFECT_160 unused @@ -315,18 +315,14 @@ void Spell::EffectSchoolDMG(uint32 effect_idx) void Spell::SpellDamageSchoolDmg(uint32 effect_idx) { + bool apply_direct_bonus=true; + if( unitTarget && unitTarget->isAlive()) { switch(m_spellInfo->SpellFamilyName) { case SPELLFAMILY_GENERIC: { - //Gore - if(m_spellInfo->SpellIconID == 2269 ) - { - damage += (rand()%2 ? damage : 0); - } - // Meteor like spells (divided damage to targets) if(m_customAttr & SPELL_ATTR_CU_SHARE_DAMAGE) { @@ -390,13 +386,6 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage = 200; break; } - // Intercept (warrior spell trigger) - case 20253: - case 61491: - { - damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f); - break; - } // arcane charge. must only affect demons (also undead?) case 45072: { @@ -430,9 +419,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) { // Bloodthirst if(m_spellInfo->SpellFamilyFlags[1] & 0x400) - { damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); - } // Shield Slam else if(m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->Category==1209) damage += int32(m_caster->GetShieldBlockValue()); @@ -442,12 +429,6 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false); } - // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207} - else if(m_spellInfo->SpellFamilyFlags[0] & 0x400) - damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f); - // Heroic Throw ${$m1+$AP*.50} - else if(m_spellInfo->SpellFamilyFlags[1] & 0x00000001) - damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f); // Shockwave ${$m3/100*$AP} else if(m_spellInfo->SpellFamilyFlags[1] & 0x00008000) { @@ -456,12 +437,6 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100); break; } - // Thunder Clap - else if(m_spellInfo->SpellFamilyFlags[0] & 0x80) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 12 / 100); - break; - } break; } case SPELLFAMILY_WARLOCK: @@ -469,26 +444,51 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) // Incinerate Rank 1 & 2 if((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID==2128) { - // Incinerate does more dmg (dmg*0.25) if the target is Immolated. - if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE, m_spellInfo, m_caster)) - damage += int32(damage*0.25f); + // Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff. + // Check aura state for speed but aura state set not only for Immolate spell + if(unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE)) + { + if (unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4)) + damage += damage/4; + } } - // Conflagrate - consumes immolate - else if (m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE) + // Conflagrate - consumes Immolate or Shadowflame + else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE) { - // Glyph of Conflagrate - if (m_caster->HasAura(56235)) - break; - // for caster applied auras only + AuraEffect const* aura = NULL; // found req. aura for damage calculation + Unit::AuraEffectList const &mPeriodic = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); for(Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i) { - if( (*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 4 || (*i)->GetSpellProto()->SpellFamilyFlags[2] & 2) && - (*i)->GetCasterGUID()==m_caster->GetGUID() ) + // for caster applied auras only + if ((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_WARLOCK || + (*i)->GetCasterGUID()!=m_caster->GetGUID()) + continue; + + // Immolate + if ((*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x4) { - unitTarget->RemoveAurasDueToSpell((*i)->GetId(), m_caster->GetGUID()); + aura = *i; // it selected always if exist break; } + + // Shadowflame + if ((*i)->GetSpellProto()->SpellFamilyFlags[2] & 0x00000002) + aura = *i; // remember but wait possible Immolate as primary priority + } + + // found Immolate or Shadowflame + if (aura) + { + uint32 pdamage = aura->GetAmount() > 0 ? aura->GetAmount() : 0; + pdamage = m_caster->SpellDamageBonus(unitTarget, aura->GetSpellProto(), pdamage, DOT, aura->GetParentAura()->GetStackAmount()); + damage += pdamage * 4; // 4 ticks of 3 seconds = 12 secs + apply_direct_bonus = false; + // Glyph of Conflagrate + if (!m_caster->HasAura(56235)) + unitTarget->RemoveAurasDueToSpell(aura->GetId(), m_caster->GetGUID()); + + break; } } // Shadow Bite @@ -517,31 +517,9 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) // converts each extra point of energy into ($f1+$AP/410) additional damage float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx]; - damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple); + int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -30)); + damage += int32(energy * multiple); damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100); - m_caster->SetPower(POWER_ENERGY,0); - } - // Rake - else if(m_spellInfo->SpellFamilyFlags[0] & 0x1000) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100); - } - // Swipe - else if(m_spellInfo->SpellFamilyFlags[1] & 0x00100000) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f); - } - //Mangle Bonus for the initial damage of Lacerate and Rake - if((m_spellInfo->SpellFamilyFlags.IsEqual(0x1000,0,0) && m_spellInfo->SpellIconID==494) || - (m_spellInfo->SpellFamilyFlags.IsEqual(0,0x100,0) && m_spellInfo->SpellIconID==2246)) - { - Unit::AuraEffectList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - if((*i)->GetSpellProto()->SpellFamilyFlags[1] & 0x00000440 && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID) - { - damage = int32(damage*(100.0f+(*i)->GetAmount())/100.0f); - break; - } } break; } @@ -553,22 +531,13 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) // consume from stack dozes not more that have combo-points if(uint32 combo = ((Player*)m_caster)->GetComboPoints()) { - Aura *poison = 0; // Lookup for Deadly poison (only attacker applied) - Unit::AuraEffectList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE); - for(Unit::AuraEffectList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) - if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && - (*itr)->GetSpellProto()->SpellFamilyFlags[0] & 0x10000 && - (*itr)->GetCasterGUID()==m_caster->GetGUID() ) - { - poison = (*itr)->GetParentAura(); - break; - } - // count consumed deadly poison doses at target - if (poison) + if (AuraEffect const * aurEff = unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0, 0, m_caster->GetGUID())) { - uint32 spellId = poison->GetId(); - uint32 doses = poison->GetStackAmount(); + // count consumed deadly poison doses at target + Aura *poison = 0; + uint32 spellId = aurEff->GetId(); + uint32 doses = aurEff->GetParentAura()->GetStackAmount(); if (doses > combo) doses = combo; for (int i=0; i< doses; i++) @@ -577,7 +546,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses); } // Eviscerate and Envenom Bonus Damage (item set effect) - if(m_caster->GetDummyAura(37169)) + if(m_caster->HasAura(37169)) damage += ((Player*)m_caster)->GetComboPoints()*40; } } @@ -590,52 +559,24 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f)); // Eviscerate and Envenom Bonus Damage (item set effect) - if(m_caster->GetDummyAura(37169)) + if(m_caster->HasAura(37169)) damage += combo*40; } } - // Gouge - else if(m_spellInfo->SpellFamilyFlags[0] & 0x8) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.21f); - } - // Instant Poison - else if(m_spellInfo->SpellFamilyFlags[0] & 0x2000) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f); - } - // Wound Poison - else if(m_spellInfo->SpellFamilyFlags[0] & 0x10000000) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f); - } break; } case SPELLFAMILY_HUNTER: { - // Mongoose Bite - if((m_spellInfo->SpellFamilyFlags[0] & 0x2) && m_spellInfo->SpellVisual[0]==342) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); - } - // Counterattack - else if(m_spellInfo->SpellFamilyFlags[1] & 0x00080000) - { - damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); - } - // Arcane Shot - else if((m_spellInfo->SpellFamilyFlags[0] & 0x00000800) && m_spellInfo->maxLevel > 0) + //Gore + if (m_spellInfo->SpellIconID == 1578) { - damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f); + if (m_caster->HasAura(57627)) // Charge 6 sec post-affect + damage *= 2; } // Steady Shot else if(m_spellInfo->SpellFamilyFlags[1] & 0x1) { - int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE)); - damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f); - bool found = false; - // check dazed affect Unit::AuraEffectList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); for(Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter) @@ -651,29 +592,12 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) if(found) damage += m_spellInfo->EffectBasePoints[1]; } - // Explosive Trap Effect - else if(m_spellInfo->SpellFamilyFlags[0] & 0x00000004) - { - damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f); - } break; } case SPELLFAMILY_PALADIN: { - // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - if(m_spellInfo->SpellFamilyFlags[0] & 0x4000) - { - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - damage += int32(ap * 0.07f); - } - // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - else if(m_spellInfo->SpellFamilyFlags[1] & 0x00000080) - { - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - damage += int32(ap * 0.15f); - } // Hammer of the Righteous - else if(m_spellInfo->SpellFamilyFlags[1]&0x00040000) + if(m_spellInfo->SpellFamilyFlags[1]&0x00040000) { // Add main hand dps * effect[2] amount float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; @@ -683,13 +607,23 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) // Shield of Righteousness else if(m_spellInfo->SpellFamilyFlags[1]&0x00100000) { - damage+=int32(m_caster->GetShieldBlockValue()); + damage += int32(m_caster->GetShieldBlockValue() * 1.3f); + } + break; + } + case SPELLFAMILY_DEATHKNIGHT: + { + // Blood Boil - bonus for diseased targets + if (m_spellInfo->SpellFamilyFlags[0] & 0x00040000 && unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x00000002, m_caster->GetGUID())) + { + damage += m_damage / 2; + damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)* 0.035f); } break; } } - if(m_originalCaster && damage > 0) + if(m_originalCaster && damage > 0 && apply_direct_bonus) damage = m_originalCaster->SpellDamageBonus(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE); m_damage += damage; @@ -740,14 +674,11 @@ void Spell::EffectDummy(uint32 i) { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet()) return; - Creature* creatureTarget = (Creature*)unitTarget; GameObject* pGameObj = new GameObject; - if (!creatureTarget || !pGameObj) return; - - if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 181574, creatureTarget->GetMap(), creatureTarget->GetPhaseMask(), - creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), - creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) + if (!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 181574, unitTarget->GetMap(), unitTarget->GetPhaseMask(), + unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), + unitTarget->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) { delete pGameObj; return; @@ -758,7 +689,7 @@ void Spell::EffectDummy(uint32 i) //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); pGameObj->SetSpellId(m_spellInfo->Id); - MapManager::Instance().GetMap(creatureTarget->GetMapId(), pGameObj)->Add(pGameObj); + unitTarget->GetMap()->Add(pGameObj); WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); data << uint64(pGameObj->GetGUID()); @@ -841,15 +772,24 @@ void Spell::EffectDummy(uint32 i) switch (m_spellInfo->Id) { - case 12850: damage *= 0.2f; break; - case 12162: damage *= 0.4f; break; - case 12868: damage *= 0.6f; break; + case 12162: damage *= 0.16f; break; // Rank 1 + case 12850: damage *= 0.32f; break; // Rank 2 + case 12868: damage *= 0.48f; break; // Rank 3 default: sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id); return; }; - int32 deepWoundsDotBasePoints0 = int32(damage / 4); + // get remaining damage of old Deep Wound aura + AuraEffect* deepWound = unitTarget->GetAuraEffect(12721, 0); + if(deepWound) + { + int32 remainingTicks = deepWound->GetParentAura()->GetAuraDuration() / deepWound->GetAuraAmplitude(); + damage += remainingTicks * deepWound->GetAmount(); + } + + // 1 tick/sec * 6 sec = 6 ticks + int32 deepWoundsDotBasePoints0 = int32(damage / 6); m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL); return; } @@ -895,9 +835,7 @@ void Spell::EffectDummy(uint32 i) if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) return; - Creature* creatureTarget = (Creature*)unitTarget; - - creatureTarget->ForcedDespawn(); + ((Creature*)unitTarget)->ForcedDespawn(); return; } case 16589: // Noggenfogger Elixir @@ -934,7 +872,9 @@ void Spell::EffectDummy(uint32 i) if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER) return; - uint32 spell_id = roll_chance_i(50) ? 17269 : 17270; + uint32 spell_id = roll_chance_i(50) + ? 17269 // Create Resonating Skull + : 17270; // Create Bone Dust m_caster->CastSpell(m_caster, spell_id, true, NULL); return; @@ -949,8 +889,6 @@ void Spell::EffectDummy(uint32 i) return; Creature* creatureTarget = (Creature*)unitTarget; - if(creatureTarget->isPet()) - return; GameObject* Crystal_Prison = m_caster->SummonGameObject(179644, creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(), creatureTarget->GetOrientation(), 0, 0, 0, 0, creatureTarget->GetRespawnTime()-time(NULL)); sLog.outDebug("SummonGameObject at SpellEfects.cpp EffectDummy for Spell 23019"); @@ -979,25 +917,25 @@ void Spell::EffectDummy(uint32 i) if (!m_CastItem) return; m_caster->CastSpell(m_caster, 13166, true, m_CastItem); return; - case 23448: // Ultrasafe Transporter: Gadgetzan - backfires + case 23448: // Transporter Arrival - Ultrasafe Transporter: Gadgetzan - backfires { int32 r = irand(0, 119); - if ( r < 20 ) // 1/6 polymorph + if ( r < 20 ) // Transporter Malfunction - 1/6 polymorph m_caster->CastSpell(m_caster, 23444, true); - else if ( r < 100 ) // 4/6 evil twin + else if ( r < 100 ) // Evil Twin - 4/6 evil twin m_caster->CastSpell(m_caster, 23445, true); - else // 1/6 miss the target + else // Transporter Malfunction - 1/6 miss the target m_caster->CastSpell(m_caster, 36902, true); return; } - case 23453: // Ultrasafe Transporter: Gadgetzan - if ( roll_chance_i(50) ) // success + case 23453: // Gnomish Transporter - Ultrasafe Transporter: Gadgetzan + if ( roll_chance_i(50) ) // Gadgetzan Transporter - success m_caster->CastSpell(m_caster, 23441, true); - else // failure + else // Gadgetzan Transporter Failure - failure m_caster->CastSpell(m_caster, 23446, true); return; case 23645: // Hourglass Sand - m_caster->RemoveAurasDueToSpell(23170); + m_caster->RemoveAurasDueToSpell(23170); // Brood Affliction: Bronze return; case 23725: // Gift of Life (warrior bwl trinket) m_caster->CastSpell(m_caster, 23782, true); @@ -1015,23 +953,30 @@ void Spell::EffectDummy(uint32 i) //5 different spells used depending on mounted speed and if mount can fly or not if (flyspeed >= 4.1f) + // Flying Reindeer m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer else if (flyspeed >= 3.8f) + // Flying Reindeer m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer else if (flyspeed >= 1.6f) + // Flying Reindeer m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer else if (speed >= 2.0f) + // Reindeer m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer else + // Reindeer m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer return; } - //case 26074: // Holiday Cheer - // return; -- implemented at client side + case 26074: // Holiday Cheer + // implemented at client side + return; case 28006: // Arcane Cloaking { if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER ) + // Naxxramas Entry Flag Effect DND m_caster->CastSpell(unitTarget, 29294, true); return; } @@ -1050,7 +995,9 @@ void Spell::EffectDummy(uint32 i) if( m_caster->GetTypeId() != TYPEID_PLAYER ) return; - uint32 spell_id = roll_chance_i(50) ? 29277 : 29278; + uint32 spell_id = roll_chance_i(50) + ? 29277 // Summon Purified Helboar Meat + : 29278; // Summon Toxic Helboar Meat m_caster->CastSpell(m_caster,spell_id,true,NULL); return; @@ -1062,26 +1009,19 @@ void Spell::EffectDummy(uint32 i) return; case 30458: // Nigh Invulnerability if (!m_CastItem) return; - if(roll_chance_i(86)) // success + if(roll_chance_i(86)) // Nigh-Invulnerability - success m_caster->CastSpell(m_caster, 30456, true, m_CastItem); - else // backfire in 14% casts + else // Complete Vulnerability - backfire in 14% casts m_caster->CastSpell(m_caster, 30457, true, m_CastItem); return; case 30507: // Poultryizer if (!m_CastItem) return; - if(roll_chance_i(80)) // success + if(roll_chance_i(80)) // Poultryized! - success m_caster->CastSpell(unitTarget, 30501, true, m_CastItem); - else // backfire 20% + else // Poultryized! - backfire 20% m_caster->CastSpell(unitTarget, 30504, true, m_CastItem); return; - case 55004: //Nitro Boosts - if(!m_CastItem) return; - if(roll_chance_i(95)) //success - m_caster->CastSpell(m_caster, 54861, true, m_CastItem); - else //backfire 5% - m_caster->CastSpell(m_caster, 46014, true, m_CastItem); - return; - case 33060: // Make a Wish + case 33060: // Make a Wish { if(m_caster->GetTypeId()!=TYPEID_PLAYER) return; @@ -1090,23 +1030,23 @@ void Spell::EffectDummy(uint32 i) switch(urand(1,5)) { - case 1: spell_id = 33053; break; - case 2: spell_id = 33057; break; - case 3: spell_id = 33059; break; - case 4: spell_id = 33062; break; - case 5: spell_id = 33064; break; + case 1: spell_id = 33053; break; // Mr Pinchy's Blessing + case 2: spell_id = 33057; break; // Summon Mighty Mr. Pinchy + case 3: spell_id = 33059; break; // Summon Furious Mr. Pinchy + case 4: spell_id = 33062; break; // Tiny Magical Crawdad + case 5: spell_id = 33064; break; // Mr. Pinchy's Gift } m_caster->CastSpell(m_caster, spell_id, true, NULL); return; } - case 35745: + case 35745: // Socrethar's Stone { uint32 spell_id; switch(m_caster->GetAreaId()) { - case 3900: spell_id = 35743; break; - case 3742: spell_id = 35744; break; + case 3900: spell_id = 35743; break; // Socrethar Portal + case 3742: spell_id = 35744; break; // Socrethar Portal default: return; } @@ -1171,9 +1111,7 @@ void Spell::EffectDummy(uint32 i) if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) return; - Creature* creatureTarget = (Creature*)unitTarget; - - creatureTarget->ForcedDespawn(); + ((Creature*)unitTarget)->ForcedDespawn(); //cast spell Raptor Capture Credit m_caster->CastSpell(m_caster, 42337, true, NULL); @@ -1181,33 +1119,15 @@ void Spell::EffectDummy(uint32 i) } case 34665: //Administer Antidote { - if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER ) + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT + || unitTarget->GetEntry() != 16880 || ((Creature*)unitTarget)->isPet()) return; - if(!unitTarget) - return; - - TempSummon* tempSummon = dynamic_cast<TempSummon*>(unitTarget); - if(!tempSummon) - return; - - uint32 health = tempSummon->GetHealth(); + ((Creature*)unitTarget)->UpdateEntry(16992); + ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992, unitTarget); - float x = tempSummon->GetPositionX(); - float y = tempSummon->GetPositionY(); - float z = tempSummon->GetPositionZ(); - float o = tempSummon->GetOrientation(); - tempSummon->UnSummon(); - - Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000); - if (!pCreature) - return; - - pCreature->SetHealth(health); - ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992, pCreature); - - if (pCreature->IsAIEnabled) - pCreature->AI()->AttackStart(m_caster); + if (unitTarget->IsAIEnabled) + ((Creature*)unitTarget)->AI()->AttackStart(m_caster); return; } @@ -1223,6 +1143,13 @@ void Spell::EffectDummy(uint32 i) m_caster->CastSpell(m_caster, 45088, true); return; } + case 55004: // Nitro Boosts + if(!m_CastItem) return; + if(roll_chance_i(95)) // Nitro Boosts - success + m_caster->CastSpell(m_caster, 54861, true, m_CastItem); + else // Knocked Up - backfire 5% + m_caster->CastSpell(m_caster, 46014, true, m_CastItem); + return; case 50243: // Teach Language { if(m_caster->GetTypeId() != TYPEID_PLAYER) @@ -1260,13 +1187,11 @@ void Spell::EffectDummy(uint32 i) if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) return; - Creature* creatureTarget = (Creature*)unitTarget; - - creatureTarget->ForcedDespawn(); + ((Creature*)unitTarget)->ForcedDespawn(); return; } - case 52308: + case 52308: // Take Sputum Sample { switch(i) { @@ -1289,15 +1214,31 @@ void Spell::EffectDummy(uint32 i) return; m_caster->CastCustomSpell(unitTarget, 52752, &damage, NULL, NULL, true); return; - case 53341: - case 53343: + case 53341: // Rune of Cinderglacier + case 53343: // Rune of Razorice { + // Runeforging Credit m_caster->CastSpell(m_caster, 54586, true); return; } case 58418: // Portal to Orgrimmar case 58420: // Portal to Stormwind return; // implemented in EffectScript[0] + case 59640: // Underbelly Elixir + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id = 0; + switch(urand(1,3)) + { + case 1: spell_id = 59645; break; + case 2: spell_id = 59831; break; + case 3: spell_id = 59843; break; + } + m_caster->CastSpell(m_caster,spell_id,true,NULL); + return; + } } //All IconID Check in there @@ -1334,30 +1275,35 @@ void Spell::EffectDummy(uint32 i) return; // immediately finishes the cooldown on Frost spells - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap(); + for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) { - if (itr->second->state == PLAYERSPELL_REMOVED) - continue; - - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 ) { - ((Player*)m_caster)->RemoveSpellCooldown(classspell, true); + ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first, true); } + else + ++itr; } return; } - case 32826: + case 32826: // Polymorph Cast Visual { if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT ) { //Polymorph Cast Visual Rank 1 - const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820}; + const uint32 spell_list[6] = { + 32813, // Squirrel Form + 32816, // Giraffe Form + 32817, // Serpent Form + 32818, // Dragonhawk Form + 32819, // Worgen Form + 32820 // Sheep Form + }; unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true); } return; @@ -1387,7 +1333,7 @@ void Spell::EffectDummy(uint32 i) uint32 rage=0; // Glyph of Execution bonus - if (AuraEffect *aura = m_caster->GetDummyAura(58367)) + if (AuraEffect *aura = m_caster->GetAuraEffect(58367, 0)) rage+=aura->GetAmount(); spell_id = 20647; @@ -1407,7 +1353,7 @@ void Spell::EffectDummy(uint32 i) } bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] + - m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); + m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); break; } // Concussion Blow @@ -1484,7 +1430,10 @@ void Spell::EffectDummy(uint32 i) for(Unit::AuraEffectList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr) { if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982) - manaFeedVal+= (*itr)->GetAmount(); + { + manaFeedVal = (*itr)->GetAmount(); + break; + } } if(manaFeedVal > 0) { @@ -1517,9 +1466,9 @@ void Spell::EffectDummy(uint32 i) return; } if (m_caster->IsFriendlyTo(unitTarget)) - m_caster->CastSpell(unitTarget, heal, true, 0); + m_caster->CastSpell(unitTarget, heal, false, 0); else - m_caster->CastSpell(unitTarget, hurt, true, 0); + m_caster->CastSpell(unitTarget, hurt, false, 0); return; } break; @@ -1587,20 +1536,21 @@ void Spell::EffectDummy(uint32 i) m_caster->CastSpell(unitTarget, 5940, true); return; } - case 14185: // Preparation Rogue + case 14185: // Preparation { if(m_caster->GetTypeId()!=TYPEID_PLAYER) return; //immediately finishes the cooldown on certain Rogue abilities - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + const SpellCooldowns& cm = ((Player *)m_caster)->GetSpellCooldownMap(); + for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) { - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags[1] & 0x00000240 || spellInfo->SpellFamilyFlags[0] & 0x00000860)) - ((Player*)m_caster)->RemoveSpellCooldown(classspell,true); + ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true); + else + ++itr; } return; } @@ -1614,20 +1564,21 @@ void Spell::EffectDummy(uint32 i) case SPELLFAMILY_HUNTER: switch(m_spellInfo->Id) { - case 23989: //Readiness talent + case 23989: // Readiness talent { if(m_caster->GetTypeId()!=TYPEID_PLAYER) return; - //immediately finishes the cooldown for hunter abilities - const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) + // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath + const SpellCooldowns& cm = ((Player*)m_caster)->GetSpellCooldownMap(); + for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) { - uint32 classspell = itr->first; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 ) - ((Player*)m_caster)->RemoveSpellCooldown(classspell,true); + ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true); + else + ++itr; } return; } @@ -1645,15 +1596,15 @@ void Spell::EffectDummy(uint32 i) } break; case SPELLFAMILY_PALADIN: + // Divine Storm + if (m_spellInfo->SpellFamilyFlags[1] & 0x20000 && i == 1) + { + int32 dmg= m_damage * damage /100; + m_caster->CastCustomSpell(unitTarget, 54172, &dmg , 0, 0, true); + return; + } switch(m_spellInfo->SpellIconID) { - // Divine Storm - if (m_spellInfo->SpellFamilyFlags[1] & 0x20000) - { - int32 damage=m_currentBasePoints[0] * damage /100; - m_caster->CastCustomSpell(unitTarget, 54172, &damage , 0, 0, true); - return; - } case 156: // Holy Shock { if(!unitTarget) @@ -1771,8 +1722,8 @@ void Spell::EffectDummy(uint32 i) } break; case SPELLFAMILY_SHAMAN: - //Shaman Rockbiter Weapon - if (m_spellInfo->SpellFamilyFlags.IsEqual(0x400000)) + // Rockbiter Weapon + if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) { // TODO: use expect spell for enchant (if exist talent) // In 3.0.3 no mods present for rockbiter @@ -1820,10 +1771,12 @@ void Spell::EffectDummy(uint32 i) } return; } - // Cleansing Totem + // Cleansing Totem Pulse if(m_spellInfo->SpellFamilyFlags[0] & 0x04000000 && m_spellInfo->SpellIconID==1673) { - m_caster->CastSpell(unitTarget, 52025, true, 0, 0, m_originalCasterGUID); + int32 bp1 = 1; + // Cleansing Totem Effect + m_caster->CastCustomSpell(unitTarget, 52025, NULL, &bp1, NULL, true, NULL, NULL, m_originalCasterGUID); return; } // Healing Stream Totem @@ -1845,9 +1798,8 @@ void Spell::EffectDummy(uint32 i) if(!unitTarget || unitTarget->getPowerType() != POWER_MANA) return; // Glyph of Mana Tide - Unit *owner = m_caster->GetOwner(); - if (owner) - if (AuraEffect *dummy = owner->GetDummyAura(55441)) + if(Unit *owner = m_caster->GetOwner()) + if (AuraEffect *dummy = owner->GetAuraEffect(55441, 0)) damage+=dummy->GetAmount(); // Regenerate 6% of Total Mana Every 3 secs int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100; @@ -1862,6 +1814,7 @@ void Spell::EffectDummy(uint32 i) Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); if (item) { + // Damage is increased by 25% if your off-hand weapon is enchanted with Flametongue. if (m_caster->GetAura(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0x200000)) { m_damage += m_damage * damage / 100; @@ -1871,12 +1824,27 @@ void Spell::EffectDummy(uint32 i) } break; case SPELLFAMILY_DEATHKNIGHT: - // Death strike dummy aura apply - // Used to proc healing later + // Death strike if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010) { - spell_id=45469; - m_caster->CastSpell(m_caster,spell_id,true); + uint32 count = 0; + Unit::AuraMap const& auras = unitTarget->GetAuras(); + for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr) + { + if(itr->second->GetSpellProto()->Dispel == DISPEL_DISEASE && + itr->second->GetCasterGUID() == m_caster->GetGUID()) + { + ++count; + // max. 15% + if(count == 3) + break; + } + } + int32 bp = count * m_caster->GetMaxHealth() * m_spellInfo->DmgMultiplier[0] / 100; + // Improved Death Strike + if (AuraEffect const * aurEff = m_caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2751, 0)) + bp = bp * (m_caster->CalculateSpellDamage(aurEff->GetSpellProto(), 2, aurEff->GetSpellProto()->EffectBasePoints[2], m_caster) + 100.0f) / 100.0f; + m_caster->CastCustomSpell(m_caster, 45470, &bp, NULL, NULL, true); return; } // Scourge Strike @@ -1890,9 +1858,6 @@ void Spell::EffectDummy(uint32 i) { if(m_caster->IsFriendlyTo(unitTarget)) { - if(unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD) - return; - int32 bp = damage * 1.5f; m_caster->CastCustomSpell(unitTarget, 47633, &bp, NULL, NULL, true); } @@ -1912,7 +1877,10 @@ void Spell::EffectDummy(uint32 i) // Death Grip if(m_spellInfo->Id == 49560) { - unitTarget->CastSpell(m_caster, damage, true); + if (unitTarget->m_Vehicle) + unitTarget->m_Vehicle->CastSpell(m_caster, damage, true); + else + unitTarget->CastSpell(m_caster, damage, true); return; } else if(m_spellInfo->Id == 46584) // Raise dead @@ -1950,6 +1918,48 @@ void Spell::EffectDummy(uint32 i) spell_id = m_currentBasePoints[0]; } + // Corpse Explosion + else if(m_spellInfo->SpellIconID == 1737) + { + // Dummy effect 1 is used only for targeting and damage amount + if (i!=0) + return; + int32 bp = 0; + // Living ghoul as a target + if (unitTarget->isAlive()) + { + bp = unitTarget->GetMaxHealth()*0.25f; + } + // Some corpse + else + { + bp = damage; + } + m_caster->CastCustomSpell(unitTarget,m_spellInfo->CalculateSimpleValue(1),&bp,NULL,NULL,true); + // Corpse Explosion (Suicide) + unitTarget->CastCustomSpell(unitTarget,43999,&bp,NULL,NULL,true); + // Set corpse look + unitTarget->SetDisplayId(25537+urand(0,3)); + } + // Runic Power Feed ( keeping Gargoyle alive ) + else if (m_spellInfo->Id == 50524) + { + // No power, dismiss Gargoyle + if (m_caster->GetPower(POWER_RUNIC_POWER)<30) + m_caster->CastSpell((Unit*)NULL,50515,true); + else + m_caster->ModifyPower(POWER_RUNIC_POWER,-30); + + return; + } + // Dismiss Gargoyle + else if (m_spellInfo->Id == 50515) + { + // FIXME: gargoyle should fly away + unitTarget->setDeathState(JUST_DIED); + m_caster->RemoveAurasDueToSpell(50514); + return; + } break; } @@ -1971,7 +1981,7 @@ void Spell::EffectDummy(uint32 i) } // pet auras - if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id)) + if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id,i)) { m_caster->AddPetAura(petSpell); return; @@ -2043,7 +2053,10 @@ void Spell::EffectForceCast(uint32 i) return; } - unitTarget->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID); + if (damage) + unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID); + else + unitTarget->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID); } void Spell::EffectTriggerSpell(uint32 i) @@ -2053,7 +2066,16 @@ void Spell::EffectTriggerSpell(uint32 i) // special cases switch(triggered_spell_id) { - // Vanish + // Mirror Image + case 58832: + { + // Glyph of Mirror Image + if (m_caster->HasAura(63093)) + m_caster->CastSpell(m_caster, 65047, true); // Mirror Image + + break; + } + // Vanish (not exist) case 18461: { m_caster->RemoveMovementImpairingAuras(); @@ -2114,7 +2136,8 @@ void Spell::EffectTriggerSpell(uint32 i) // Brittle Armor - (need add max stack of 24575 Brittle Armor) case 29284: { - const SpellEntry *spell = sSpellStore.LookupEntry(24575); + // Brittle Armor + SpellEntry const* spell = sSpellStore.LookupEntry(24575); if (!spell) return; @@ -2125,7 +2148,8 @@ void Spell::EffectTriggerSpell(uint32 i) // Mercurial Shield - (need add max stack of 26464 Mercurial Shield) case 29286: { - const SpellEntry *spell = sSpellStore.LookupEntry(26464); + // Mercurial Shield + SpellEntry const* spell = sSpellStore.LookupEntry(26464); if (!spell) return; @@ -2140,7 +2164,7 @@ void Spell::EffectTriggerSpell(uint32 i) return; } // Cloak of Shadows - case 35729 : + case 35729: { uint32 dispelMask = GetDispellMask(DISPEL_ALL); Unit::AuraMap& Auras = m_caster->GetAuras(); @@ -2436,7 +2460,7 @@ void Spell::EffectUnlearnSpecialization( uint32 i ) _player->removeSpell(spellToUnlearn); - sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() ); + sLog.outDebug( "Spell: Player %u has unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() ); } void Spell::EffectPowerDrain(uint32 i) @@ -2495,7 +2519,7 @@ void Spell::EffectSendEvent(uint32 EffectIndex) we do not handle a flag dropping or clicking on flag in battleground by sendevent system */ sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id); - sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject); + m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject); } void Spell::EffectPowerBurn(uint32 i) @@ -2569,12 +2593,11 @@ void Spell::SpellDamageHeal(uint32 /*i*/) { // Amount of heal - depends from stacked Holy Energy int damageAmount = 0; - Unit::AuraEffectList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraEffectList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) - if((*i)->GetId() == 45062) - damageAmount+=(*i)->GetAmount(); - if (damageAmount) + if (AuraEffect const * aurEff = m_caster->GetAuraEffect(45062, 0)) + { + damageAmount+= aurEff->GetAmount(); m_caster->RemoveAurasDueToSpell(45062); + } addhealth += damageAmount; } @@ -2587,7 +2610,7 @@ void Spell::SpellDamageHeal(uint32 /*i*/) for(Unit::AuraEffectList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) { if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID - && ((*i)->GetSpellProto()->SpellFamilyFlags.IsEqual(0x40) || (*i)->GetSpellProto()->SpellFamilyFlags.IsEqual(0x10)) ) + && (*i)->GetSpellProto()->SpellFamilyFlags[0] & 0x50) { if(!targetAura || (*i)->GetParentAura()->GetAuraDuration() < targetAura->GetParentAura()->GetAuraDuration()) targetAura = *i; @@ -2607,18 +2630,17 @@ void Spell::SpellDamageHeal(uint32 /*i*/) //It is said that talent bonus should not be included int32 tickcount = 0; - if(targetAura->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID) - { - switch(targetAura->GetSpellProto()->SpellFamilyFlags[0]) - { - case 0x10: tickcount = 4; break; // Rejuvenation - case 0x40: tickcount = 6; break; // Regrowth - } - } + // Rejuvenation + if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x10) + tickcount = 4; + // Regrowth + else // if (targetAura->GetSpellProto()->SpellFamilyFlags[0] & 0x40) + tickcount = 6; + addhealth += tickheal * tickcount; // Glyph of Swiftmend - if(!caster->GetDummyAura(54824)) + if(!caster->HasAura(54824)) unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID()); //addhealth += tickheal * tickcount; @@ -2635,6 +2657,11 @@ void Spell::SpellDamageHeal(uint32 /*i*/) unitTarget->RemoveAura(aurEff->GetParentAura()); } } + // Death Pact - return pct of max health to caster + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) + { + addhealth = int32(caster->GetMaxHealth()*damage/100.0f); + } else addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL); @@ -2827,27 +2854,34 @@ void Spell::EffectCreateItem2(uint32 i) Player* player = (Player*)m_caster; uint32 item_id = m_spellInfo->EffectItemType[i]; - if(item_id) - DoCreateItem(i, item_id); + + DoCreateItem(i, item_id); // special case: fake item replaced by generate using spell_loot_template if(IsLootCraftingSpell(m_spellInfo)) { - if(item_id) - { - if(!player->HasItemCount(item_id, 1)) - return; + if(!player->HasItemCount(item_id, 1)) + return; - // remove reagent - uint32 count = 1; - player->DestroyItemCount(item_id, count, true); - } + // remove reagent + uint32 count = 1; + player->DestroyItemCount(item_id, count, true); // create some random items player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); } } +void Spell::EffectCreateRandomItem(uint32 i) +{ + if(m_caster->GetTypeId()!=TYPEID_PLAYER) + return; + Player* player = (Player*)m_caster; + + // create some random items + player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); +} + void Spell::EffectPersistentAA(uint32 i) { float radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); @@ -2880,31 +2914,31 @@ void Spell::EffectEnergize(uint32 i) Powers power = Powers(m_spellInfo->EffectMiscValue[i]); // Some level depends spells - int multiplier = 0; + int level_multiplier = 0; int level_diff = 0; switch (m_spellInfo->Id) { - // Restore Energy - case 9512: + case 9512: // Restore Energy level_diff = m_caster->getLevel() - 40; - multiplier = 2; + level_multiplier = 2; break; - // Blood Fury - case 24571: + case 24571: // Blood Fury level_diff = m_caster->getLevel() - 60; - multiplier = 10; + level_multiplier = 10; break; - // Burst of Energy - case 24532: + case 24532: // Burst of Energy level_diff = m_caster->getLevel() - 60; - multiplier = 4; + level_multiplier = 4; break; + case 31930: // Judgements of the Wise + case 63375: // Improved Stormstrike + damage = damage * unitTarget->GetCreateMana() / 100; default: break; } if (level_diff > 0) - damage -= multiplier * level_diff; + damage -= level_multiplier * level_diff; if(damage < 0) return; @@ -2912,6 +2946,12 @@ void Spell::EffectEnergize(uint32 i) if(unitTarget->GetMaxPower(power) == 0) return; + // Spells which use pct of max mana, but have wrong effect + if (m_spellInfo->Id == 48542) + { + damage = damage * unitTarget->GetMaxPower(power) / 100; + } + m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); // Mad Alchemist's Potion @@ -2993,7 +3033,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: gameObjTarget->UseDoorOrButton(); - sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); + player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); return; case GAMEOBJECT_TYPE_QUESTGIVER: @@ -3013,7 +3053,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) if (gameObjTarget->GetGOInfo()->goober.eventId) { sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow()); - sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget); + player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget); gameObjTarget->EventInform(gameObjTarget->GetGOInfo()->goober.eventId); } @@ -3024,7 +3064,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) return; Script->GOHello(player, gameObjTarget); - sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); + gameObjTarget->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget); gameObjTarget->AddUniqueUse(player); gameObjTarget->SetLootState(GO_JUST_DEACTIVATED); @@ -3046,7 +3086,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) if (gameObjTarget->GetGOInfo()->chest.eventId) { sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow()); - sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget); + player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget); } // triggering linked GO @@ -3109,7 +3149,7 @@ void Spell::EffectOpenLock(uint32 effIndex) // these objects must have been spawned by outdoorpvp! else if(gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr.HandleOpenGo(player, gameObjTarget->GetGUID())) return; - lockId = gameObjTarget->GetLockId(); + lockId = goInfo->GetLockId(); guid = gameObjTarget->GetGUID(); } else if(itemTarget) @@ -3255,11 +3295,6 @@ void Spell::EffectSummonChangeItem(uint32 i) delete pNewItem; } -void Spell::EffectOpenSecretSafe(uint32 i) -{ - EffectOpenLock(i); //no difference for now -} - void Spell::EffectProficiency(uint32 /*i*/) { if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) @@ -3327,6 +3362,11 @@ void Spell::EffectSummonType(uint32 i) switch(properties->Category) { default: + if (properties->Flags & 512) + { + SummonGuardian(entry, properties); + break; + } switch(properties->Type) { case SUMMON_TYPE_PET: @@ -3409,7 +3449,12 @@ void Spell::EffectSummonType(uint32 i) TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; - m_originalCaster->SummonCreature(entry,px,py,pz,m_caster->GetOrientation(),summonType,duration); + TempSummon * summon = m_originalCaster->SummonCreature(entry,px,py,pz,m_caster->GetOrientation(),summonType,duration); + if (!summon) + continue; + summon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_originalCaster->GetGUID()); + if (properties->Category == SUMMON_CATEGORY_ALLY) + summon->setFaction(m_originalCaster->getFaction()); } break; } @@ -3464,7 +3509,7 @@ void Spell::EffectLearnSpell(uint32 i) uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i]; player->learnSpell(spellToLearn,false); - sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() ); + sLog.outDebug( "Spell: Player %u has learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() ); } void Spell::EffectDispel(uint32 i) @@ -3554,26 +3599,12 @@ void Spell::EffectDispel(uint32 i) } m_caster->SendMessageToSet(&dataSuccess, true); - // On succes dispel + // On success dispel // Devour Magic if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC) { - uint32 heal_spell = 0; - switch (m_spellInfo->Id) - { - case 19505: heal_spell = 19658; break; - case 19731: heal_spell = 19732; break; - case 19734: heal_spell = 19733; break; - case 19736: heal_spell = 19735; break; - case 27276: heal_spell = 27278; break; - case 27277: heal_spell = 27279; break; - case 48011: heal_spell = 48010; break; - default: - sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id); - break; - } - if (heal_spell) - m_caster->CastSpell(m_caster, heal_spell, true); + int32 heal_amount = m_spellInfo->CalculateSimpleValue(1); + m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true); } } } @@ -3992,7 +4023,7 @@ void Spell::EffectTameCreature(uint32 /*i*/) if(!unitTarget) return; - if(unitTarget->GetTypeId() == TYPEID_PLAYER) + if(unitTarget->GetTypeId() != TYPEID_UNIT) return; Creature* creatureTarget = (Creature*)unitTarget; @@ -4068,7 +4099,6 @@ void Spell::EffectSummonPet(uint32 i) return; OldSummon->GetMap()->Remove((Creature*)OldSummon,false); - OldSummon->SetMapId(owner->GetMapId()); float px, py, pz; owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); @@ -4211,11 +4241,11 @@ void Spell::SpellDamageWeaponDmg(uint32 i) SpellEntry const *spellInfo = NULL; uint32 stack = 0; - if (AuraEffect * aur = unitTarget->GetAura(SPELL_AURA_MOD_RESISTANCE,SPELLFAMILY_WARRIOR,SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR, 0, 0, m_caster->GetGUID())) + if (Aura * aur = unitTarget->GetAura(58567, m_caster->GetGUID())) { - aur->GetParentAura()->RefreshAura(); + aur->RefreshAura(); spellInfo = aur->GetSpellProto(); - stack = aur->GetParentAura()->GetStackAmount(); + stack = aur->GetStackAmount(); } for(uint8 j = 0; j < 3; j++) @@ -4254,7 +4284,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i) break; int32 count = 1; // Glyph of Devastate - if (AuraEffect * aurEff = m_caster->GetDummyAura(58388)) + if (AuraEffect * aurEff = m_caster->GetAuraEffect(58388, 0)) count += aurEff->GetAmount(); for (;count>0;count--) m_caster->CastSpell(unitTarget, spellInfo, true); @@ -4269,7 +4299,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i) if(m_spellInfo->SpellFamilyFlags[0] & 0x2000000) { if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddComboPoints(unitTarget, 1); + ((Player*)m_caster)->AddComboPoints(unitTarget, 1, this); } // Fan of Knives else if(m_spellInfo->SpellFamilyFlags[1] & 0x40000) @@ -4326,19 +4356,8 @@ void Spell::SpellDamageWeaponDmg(uint32 i) { // Skyshatter Harness item set bonus // Stormstrike - if(m_spellInfo->SpellFamilyFlags[1] & 0x0010) - { - Unit::AuraEffectList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); - for(Unit::AuraEffectList::const_iterator citr = m_OverrideClassScript.begin(); citr != m_OverrideClassScript.end(); ++citr) - { - // Stormstrike AP Buff - if ( (*citr)->GetMiscValue() == 5634 ) - { - m_caster->CastSpell(m_caster, 38430, true, NULL, *citr); - break; - } - } - } + if (AuraEffect * aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634)) + m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff); break; } case SPELLFAMILY_DRUID: @@ -4347,18 +4366,60 @@ void Spell::SpellDamageWeaponDmg(uint32 i) if(m_spellInfo->SpellFamilyFlags.IsEqual(0,0x00000400)) { if(m_caster->GetTypeId()==TYPEID_PLAYER) - ((Player*)m_caster)->AddComboPoints(unitTarget,1); + ((Player*)m_caster)->AddComboPoints(unitTarget,1, this); + } + // Shred, Maul - Rend and Tear + else if (m_spellInfo->SpellFamilyFlags[0] & 0x00008800 && unitTarget->HasAuraState(AURA_STATE_BLEEDING, m_spellInfo, m_caster)) + { + if (AuraEffect const* rendAndTear = m_caster->GetDummyAura(SPELLFAMILY_DRUID, 2859, 0)) + { + totalDamagePercentMod *= float((rendAndTear->GetAmount() + 100.0f) / 100.0f); + } } break; } case SPELLFAMILY_DEATHKNIGHT: { + // Plague Strike + if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001) + { + // Glyph of Plague Strike + if (AuraEffect * aurEff = m_caster->GetAuraEffect(58657,0)) + totalDamagePercentMod *= float((aurEff->GetAmount() + 100.0f) / 100.0f); + } + // Blood Strike + else if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) + { + totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f; + + // Glyph of Blood Strike + if (AuraEffect * aurEff = m_caster->GetAuraEffect(59332,0)) + { + if(unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED)) + totalDamagePercentMod *= float((20 + 100.0f) / 100.0f); + } + } + // Death Strike + else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000010) + { + // Glyph of Death Strike + if (AuraEffect * aurEff = m_caster->GetAuraEffect(59336,0)) + { + if(uint32 runic = m_caster->GetPower(POWER_RUNIC_POWER)) + { + if (runic > 25) + runic = 25; + + totalDamagePercentMod *= float((runic + 100.0f) / 100.0f); + } + } + } // Obliterate (12.5% more damage per disease) - if (m_spellInfo->SpellFamilyFlags[1] & 0x20000) + else if (m_spellInfo->SpellFamilyFlags[1] & 0x20000) { bool consumeDiseases = true; // Annihilation - if (AuraEffect * aurEff = m_caster->GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2710)) + if (AuraEffect * aurEff = m_caster->GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2710, 0)) { // Do not consume diseases if roll sucesses if (roll_chance_i(aurEff->GetAmount())) @@ -4366,8 +4427,8 @@ void Spell::SpellDamageWeaponDmg(uint32 i) } totalDamagePercentMod *= (float(CalculateDamage(2, unitTarget) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), consumeDiseases) / 2) + 100.0f) / 100.0f; } - // Blood-Caked Strike - Blood-Caked Blade // Blood Strike - else if (m_spellInfo->SpellIconID == 1736 || m_spellInfo->SpellFamilyFlags[0] & 0x400000) + // Blood-Caked Strike - Blood-Caked Blade + else if (m_spellInfo->SpellIconID == 1736) totalDamagePercentMod *= (float(unitTarget->GetDiseasesByCaster(m_caster->GetGUID())) * 12.5f + 100.0f) / 100.0f; break; } @@ -4536,44 +4597,45 @@ void Spell::EffectSummonObjectWild(uint32 i) } int32 duration = GetSpellDuration(m_spellInfo); + pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0); pGameObj->SetSpellId(m_spellInfo->Id); - if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)... - m_caster->AddGameObject(pGameObj); + // Wild object not have owner and check clickable by players map->Add(pGameObj); - if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS + if(pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP && m_caster->GetTypeId() == TYPEID_PLAYER) { - if(m_caster->GetTypeId() == TYPEID_PLAYER) + Player *pl = (Player*)m_caster; + BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); + + switch(pGameObj->GetMapId()) { - Player *pl = (Player*)m_caster; - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS) + case 489: //WS { - uint32 team = ALLIANCE; + if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS) + { + uint32 team = ALLIANCE; - if(pl->GetTeam() == team) - team = HORDE; + if(pl->GetTeam() == team) + team = HORDE; - ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team); + ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team); + } + break; } - } - } - - if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY - { - if(m_caster->GetTypeId() == TYPEID_PLAYER) - { - BattleGround* bg = ((Player *)m_caster)->GetBattleGround(); - if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS) + case 566: //EY { - ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID()); + if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS) + { + ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID()); + } + break; } } } - if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) + if(uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) { GameObject* linkedGO = new GameObject; if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, @@ -4582,7 +4644,7 @@ void Spell::EffectSummonObjectWild(uint32 i) linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0); linkedGO->SetSpellId(m_spellInfo->Id); - m_caster->AddGameObject(linkedGO); + // Wild object not have owner and check clickable by players map->Add(linkedGO); } else @@ -4604,6 +4666,31 @@ void Spell::EffectScriptEffect(uint32 effIndex) { switch(m_spellInfo->Id) { + // Dispelling Analysis + case 37028: + { + if (unitTarget->HasAura(36904)) + unitTarget->RemoveAurasDueToSpell(36904); + + return; + } + case 45204: // Clone Me! + case 41055: // Copy Weapon + case 45206: // Copy Off-hand Weapon + unitTarget->CastSpell(m_caster, damage, false); + break; + case 45205: // Copy Offhand Weapon + case 41054: // Copy Weapon + m_caster->CastSpell(unitTarget, damage, false); + break; + // Despawn Horse + case 52267: + { + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + ((Creature*)unitTarget)->ForcedDespawn(); + return; + } // PX-238 Winter Wondervolt TRAP case 26275: { @@ -4695,7 +4782,7 @@ void Spell::EffectScriptEffect(uint32 effIndex) return; // Onyxia Scale Cloak - if(unitTarget->GetDummyAura(22683)) + if(unitTarget->HasAura(22683)) return; // Shadow Flame @@ -4964,6 +5051,11 @@ void Spell::EffectScriptEffect(uint32 effIndex) } break; } + case 52173: // Coyote Spirit Despawn + case 60243: // Blood Parrot Despawn + if (unitTarget->GetTypeId() == TYPEID_UNIT && ((Creature*)unitTarget)->isSummon()) + ((TempSummon*)unitTarget)->UnSummon(); + return; // Sky Darkener Assault case 52124: if(unitTarget) @@ -5039,6 +5131,24 @@ void Spell::EffectScriptEffect(uint32 effIndex) } } return; + case 58983: // Big Blizzard Bear + { + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // Prevent stacking of mounts + unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED); + + // Triggered spell id dependent of riding skill + if(uint16 skillval = ((Player*)unitTarget)->GetSkillValue(SKILL_RIDING)) + { + if (skillval >= 150) + unitTarget->CastSpell(unitTarget, 58999, true); + else + unitTarget->CastSpell(unitTarget, 58997, true); + } + return; + } case 59317: // Teleporting if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; @@ -5056,6 +5166,7 @@ void Spell::EffectScriptEffect(uint32 effIndex) case 61177: // Northrend Inscription Research case 61288: // Minor Inscription Research case 61756: // Northrend Inscription Research (FAST QA VERSION) + case 64323: // Book of Glyph Mastery { if(m_caster->GetTypeId() != TYPEID_PLAYER) return; @@ -5176,6 +5287,14 @@ void Spell::EffectScriptEffect(uint32 effIndex) } return; } + // Guarded by The Light + case 63521: + { + // Divine Plea + if(Aura *AuraDivinePlea = m_caster->GetAura(54428)) + AuraDivinePlea->RefreshAura(); + return; + } } break; } @@ -5193,16 +5312,6 @@ void Spell::EffectScriptEffect(uint32 effIndex) aur->GetParentAura()->RefreshAura(); return; } - // Divine Hymn - case 47951: - { - if (!unitTarget) - return; - Unit * target=NULL; - unitTarget->CastSpell(target, 59600, false); - unitTarget->CastSpell(target, 47953, false); - return; - } default: break; } @@ -5215,7 +5324,7 @@ void Spell::EffectScriptEffect(uint32 effIndex) // Invigoration case 53412: { - if (AuraEffect * aurEff = unitTarget->GetDummyAura(SPELLFAMILY_HUNTER, 3487)) + if (AuraEffect * aurEff = unitTarget->GetDummyAura(SPELLFAMILY_HUNTER, 3487, 0)) { if (roll_chance_i(aurEff->GetAmount())) unitTarget->CastSpell(unitTarget, 53398, true); @@ -5246,6 +5355,8 @@ void Spell::EffectScriptEffect(uint32 effIndex) flag96 familyFlag = aura->GetSpellProto()->SpellFamilyFlags; if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000)) continue; + if (!aura->GetPartAura(0)) + continue; // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting. if (familyFlag[0] & 0x4000) @@ -5290,8 +5401,8 @@ void Spell::EffectScriptEffect(uint32 effIndex) } case SPELLFAMILY_PALADIN: { - // Judgement - if (m_spellInfo->SpellFamilyFlags[0] & 0x800000 || m_spellInfo->SpellFamilyFlags[2] & 0x8) + // Judgement (seal trigger) + if (m_spellInfo->Category == SPELLCATEGORY_JUDGEMENT) { if(!unitTarget || !unitTarget->isAlive()) return; @@ -5301,12 +5412,12 @@ void Spell::EffectScriptEffect(uint32 effIndex) // Judgement self add switch switch (m_spellInfo->Id) { - case 41467: break; // Judgement case 53407: spellId1 = 20184; break; // Judgement of Justice case 20271: // Judgement of Light case 57774: spellId1 = 20185; break; // Judgement of Light case 53408: spellId1 = 20186; break; // Judgement of Wisdom default: + sLog.outError("Unsupported Judgement (seal trigger) spell (Id: %u) in Spell::EffectScriptEffect",m_spellInfo->Id); return; } // all seals have aura dummy in 2 effect @@ -5349,6 +5460,43 @@ void Spell::EffectScriptEffect(uint32 effIndex) { switch(m_spellInfo->Id) { + // Death Knight Initiate Visual + case 51519: + { + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) + return; + + uint32 iTmpSpellId = 0; + switch (unitTarget->GetDisplayId()) + { + case 25369: iTmpSpellId = 51552; break; // bloodelf female + case 25373: iTmpSpellId = 51551; break; // bloodelf male + case 25363: iTmpSpellId = 51542; break; // draenei female + case 25357: iTmpSpellId = 51541; break; // draenei male + case 25361: iTmpSpellId = 51537; break; // dwarf female + case 25356: iTmpSpellId = 51538; break; // dwarf male + case 25372: iTmpSpellId = 51550; break; // forsaken female + case 25367: iTmpSpellId = 51549; break; // forsaken male + case 25362: iTmpSpellId = 51540; break; // gnome female + case 25359: iTmpSpellId = 51539; break; // gnome male + case 25355: iTmpSpellId = 51534; break; // human female + case 25354: iTmpSpellId = 51520; break; // human male + case 25360: iTmpSpellId = 51536; break; // nightelf female + case 25358: iTmpSpellId = 51535; break; // nightelf male + case 25368: iTmpSpellId = 51544; break; // orc female + case 25364: iTmpSpellId = 51543; break; // orc male + case 25371: iTmpSpellId = 51548; break; // tauren female + case 25366: iTmpSpellId = 51547; break; // tauren male + case 25370: iTmpSpellId = 51545; break; // troll female + case 25365: iTmpSpellId = 51546; break; // troll male + default: return; + } + + unitTarget->CastSpell(unitTarget, iTmpSpellId, true); + Creature* npc = (Creature*)unitTarget; + npc->LoadEquipment(npc->GetEquipmentId()); + return; + } // Dreaming Glory case 28698: { @@ -5413,11 +5561,24 @@ void Spell::EffectScriptEffect(uint32 effIndex) } break; } + case SPELLFAMILY_WARRIOR: + { + // Shattering Throw + if ( m_spellInfo->SpellFamilyFlags[1] & 0x1 ) + { + if(!unitTarget) + return; + // remove shields, will still display immune to damage part + unitTarget->RemoveAurasWithMechanic(1<<MECHANIC_IMMUNE_SHIELD); + return; + } + break; + } } // normal DB scripted effect sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id); - sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); + m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget); } void Spell::EffectSanctuary(uint32 /*i*/) @@ -5464,7 +5625,7 @@ void Spell::EffectAddComboPoints(uint32 /*i*/) if(damage <= 0) return; - ((Player*)m_caster)->AddComboPoints(unitTarget, damage); + ((Player*)m_caster)->AddComboPoints(unitTarget, damage, this); } void Spell::EffectDuel(uint32 i) @@ -5571,8 +5732,10 @@ void Spell::EffectStuck(uint32 /*i*/) if(pTarget->isInFlight()) return; + PlayerInfo const *info = objmgr.GetPlayerInfo(pTarget->getRace(), pTarget->getClass()); + pTarget->TeleportTo(info->mapId, info->positionX, info->positionY, info->positionZ, pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0)); // homebind location is loaded always - pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0)); + // pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0)); // Stuck spell trigger Hearthstone cooldown SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690); @@ -5588,7 +5751,7 @@ void Spell::EffectSummonPlayer(uint32 /*i*/) return; // Evil Twin (ignore player summon, but hide this for summoner) - if(unitTarget->GetDummyAura(23445)) + if(unitTarget->HasAura(23445)) return; float x, y, z; @@ -5619,7 +5782,7 @@ void Spell::EffectActivateObject(uint32 effect_idx) int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx]; - sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); + gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); } void Spell::EffectApplyGlyph(uint32 i) @@ -5802,7 +5965,7 @@ void Spell::EffectSummonObject(uint32 i) // Recast case - null spell id to make auras not be removed on object remove from world if (m_spellInfo->Id == obj->GetSpellId()) obj->SetSpellId(0); - obj->Delete(); + m_caster->RemoveGameObject(obj, true); } m_caster->m_ObjectSlot[slot] = 0; } @@ -5955,23 +6118,23 @@ void Spell::EffectMomentMove(uint32 i) dist = sqrt((x-destx)*(x-destx) + (y-desty)*(y-desty)); step = dist/10.0f; } - + int j = 0; for(j; j<10 ;j++) { - if(fabs(z - destz) > 6) - { - destx -= step * cos(orientation); - desty -= step * sin(orientation); - ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true); - floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true); - destz = fabs(ground - z) <= fabs(floor - z) ? ground:floor; - }else - break; + if(fabs(z - destz) > 6) + { + destx -= step * cos(orientation); + desty -= step * sin(orientation); + ground = unitTarget->GetMap()->GetHeight(destx,desty,MAX_HEIGHT,true); + floor = unitTarget->GetMap()->GetHeight(destx,desty,z, true); + destz = fabs(ground - z) <= fabs(floor - z) ? ground:floor; + }else + break; } if(j == 9) { - return; + return; } unitTarget->NearTeleportTo(destx, desty, destz + 0.07531, orientation, unitTarget==m_caster); @@ -6087,6 +6250,28 @@ void Spell::EffectCharge(uint32 /*i*/) m_caster->Attack(target, true); } +void Spell::EffectCharge2(uint32 /*i*/) +{ + float x, y, z; + if(m_targets.HasDst()) + { + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + } + else if(Unit *target = m_targets.getUnitTarget()) + { + target->GetContactPoint(m_caster, x, y, z); + // not all charge effects used in negative spells + if(!IsPositiveSpell(m_spellInfo->Id) && m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->Attack(target, true); + } + else + return; + + m_caster->GetMotionMaster()->MoveCharge(x, y, z); +} + void Spell::EffectKnockBack(uint32 i) { if(!unitTarget) @@ -6330,7 +6515,7 @@ void Spell::EffectTransmitted(uint32 effIndex) if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE) { - if ( !cMap->IsInWater(fx, fy, fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole + if ( !cMap->IsInWater(fx, fy, fz-0.5f, 0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole { // but this is not proper, we really need to ignore not materialized objects SendCastResult(SPELL_FAILED_NOT_HERE); SendChannelUpdate(0); @@ -6390,16 +6575,14 @@ void Spell::EffectTransmitted(uint32 effIndex) case GAMEOBJECT_TYPE_FISHINGHOLE: case GAMEOBJECT_TYPE_CHEST: default: - { break; - } } pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0); - pGameObj->SetOwnerGUID(m_caster->GetGUID() ); + pGameObj->SetOwnerGUID(m_caster->GetGUID()); - //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); + //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); pGameObj->SetSpellId(m_spellInfo->Id); DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted"); @@ -6412,16 +6595,16 @@ void Spell::EffectTransmitted(uint32 effIndex) data << uint64(pGameObj->GetGUID()); m_caster->SendMessageToSet(&data,true); - if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry()) + if(uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) { GameObject* linkedGO = new GameObject; if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0); - //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); + //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); linkedGO->SetSpellId(m_spellInfo->Id); - linkedGO->SetOwnerGUID(m_caster->GetGUID() ); + linkedGO->SetOwnerGUID(m_caster->GetGUID()); linkedGO->GetMap()->Add(linkedGO); } @@ -6700,6 +6883,7 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties switch(m_spellInfo->Id) { case 1122: // Inferno + amount = 1; break; } int32 duration = GetSpellDuration(m_spellInfo); @@ -6714,11 +6898,12 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties TempSummon *summon = map->SummonCreature(entry, px, py, pz, m_caster->GetOrientation(), properties, duration, caster); if(!summon) return; - if(summon->HasSummonMask(SUMMON_MASK_GUARDIAN)) ((Guardian*)summon)->InitStatsForLevel(level); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); + if(summon->HasSummonMask(SUMMON_MASK_MINION) && m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + ((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon)); summon->AI()->EnterEvadeMode(); } @@ -6769,4 +6954,23 @@ void Spell::EffectRenamePet(uint32 /*eff_idx*/) return; unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED); -}
\ No newline at end of file +} + +void Spell::EffectPlayMusic(uint32 i) +{ + if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 soundid = m_spellInfo->EffectMiscValue[i]; + + if (!sSoundEntriesStore.LookupEntry(soundid)) + { + sLog.outError("EffectPlayMusic: Sound (Id: %u) not exist in spell %u.",soundid,m_spellInfo->Id); + return; + } + + WorldPacket data(SMSG_PLAY_MUSIC, 4); + data << uint32(soundid); + ((Player*)unitTarget)->GetSession()->SendPacket(&data); +} + diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 74313eaa38b..dd88ef8e50a 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -537,3 +537,79 @@ void WorldSession::HandleSpellClick( WorldPacket & recv_data ) if(unit->isVehicle()) _player->EnterVehicle((Vehicle*)unit); } + +void WorldSession::HandleMirrrorImageDataRequest( WorldPacket & recv_data ) +{ + sLog.outDebug("WORLD: CMSG_GET_MIRRORIMAGE_DATA"); + CHECK_PACKET_SIZE(recv_data, 8); + uint64 guid; + recv_data >> guid; + + // Get unit for which data is needed by client + Unit *unit = ObjectAccessor::GetObjectInWorld(guid, (Unit*)NULL); + if(!unit) + return; + // Get creator of the unit + Unit *creator = ObjectAccessor::GetObjectInWorld(unit->GetCreatorGUID(),(Unit*)NULL); + if (!creator) + return; + WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68); + data << (uint64)guid; + data << (uint32)creator->GetDisplayId(); + if (creator->GetTypeId()==TYPEID_PLAYER) + { + Player * pCreator = (Player *)creator; + data << (uint8)pCreator->getRace(); + data << (uint8)pCreator->getGender(); + data << (uint8)pCreator->getClass(); + data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 0); // skin + + data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 1); // face + data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 2); // hair + data << (uint8)pCreator->GetByteValue(PLAYER_BYTES, 3); // haircolor + data << (uint8)pCreator->GetByteValue(PLAYER_BYTES_2, 0); // facialhair + + data << (uint32)0; // unk + static const EquipmentSlots ItemSlots[] = + { + EQUIPMENT_SLOT_HEAD, + EQUIPMENT_SLOT_SHOULDERS, + EQUIPMENT_SLOT_BODY, + EQUIPMENT_SLOT_CHEST, + EQUIPMENT_SLOT_WAIST, + EQUIPMENT_SLOT_LEGS, + EQUIPMENT_SLOT_FEET, + EQUIPMENT_SLOT_WRISTS, + EQUIPMENT_SLOT_HANDS, + EQUIPMENT_SLOT_BACK, + EQUIPMENT_SLOT_TABARD, + EQUIPMENT_SLOT_END + }; + // Display items in visible slots + for (EquipmentSlots const* itr = &ItemSlots[0];*itr!=EQUIPMENT_SLOT_END;++itr) + if (Item const *item = pCreator->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr)) + data << (uint32)item->GetProto()->DisplayInfoID; + else + data << (uint32)0; + } + else + { + // Skip player data for creatures + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + data << (uint32)0; + } + SendPacket( &data ); +} + diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 513075ea2b6..ca01f4422b7 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -147,6 +147,7 @@ SpellMgr::SpellMgr() case TARGET_UNIT_CONE_ALLY: case TARGET_UNIT_CONE_ENTRY: case TARGET_UNIT_CONE_ENEMY_UNKNOWN: + case TARGET_UNIT_AREA_PATH: SpellTargetType[i] = TARGET_TYPE_AREA_CONE; break; case TARGET_DST_CASTER: @@ -226,6 +227,7 @@ SpellMgr::SpellMgr() case TARGET_UNIT_CONE_ENEMY: case TARGET_UNIT_CONE_ALLY: case TARGET_UNIT_CONE_ENEMY_UNKNOWN: + case TARGET_UNIT_AREA_PATH: case TARGET_UNIT_RAID_CASTER: IsAreaEffectTarget[i] = true; break; @@ -236,6 +238,7 @@ SpellMgr::SpellMgr() } } + SpellMgr::~SpellMgr() { } @@ -246,6 +249,16 @@ SpellMgr& SpellMgr::Instance() return spellMgr; } +bool SpellMgr::IsSrcTargetSpell(SpellEntry const *spellInfo) const +{ + for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + { + if(SpellTargetType[spellInfo->EffectImplicitTargetA[i]] == TARGET_TYPE_AREA_SRC || SpellTargetType[spellInfo->EffectImplicitTargetB[i]] == TARGET_TYPE_AREA_SRC) + return true; + } + return false; +} + int32 GetSpellDuration(SpellEntry const *spellInfo) { if(!spellInfo) @@ -307,8 +320,6 @@ bool IsPassiveSpell(uint32 spellId) return false; if(spellInfo->Attributes & SPELL_ATTR_PASSIVE) return true; - if(spellInfo->activeIconID == 2158) //flight - return true; return false; } @@ -319,8 +330,6 @@ bool IsAutocastableSpell(uint32 spellId) return false; if(spellInfo->Attributes & SPELL_ATTR_PASSIVE) return false; - if(spellInfo->activeIconID == 2158) - return false; if(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET) return false; return true; @@ -331,6 +340,127 @@ bool IsHigherHankOfSpell(uint32 spellId_1, uint32 spellId_2) return spellmgr.GetSpellRank(spellId_1)<spellmgr.GetSpellRank(spellId_2); } +uint32 CalculatePowerCost(SpellEntry const * spellInfo, Unit const * caster, SpellSchoolMask schoolMask) +{ + // Spell drain all exist power on cast (Only paladin lay of Hands) + if (spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER) + { + // If power type - health drain all + if (spellInfo->powerType == POWER_HEALTH) + return caster->GetHealth(); + // Else drain all power + if (spellInfo->powerType < MAX_POWERS) + return caster->GetPower(Powers(spellInfo->powerType)); + sLog.outError("CalculateManaCost: Unknown power type '%d' in spell %d", spellInfo->powerType, spellInfo->Id); + return 0; + } + + // Base powerCost + int32 powerCost = spellInfo->manaCost; + // PCT cost from total amount + if (spellInfo->ManaCostPercentage) + { + switch (spellInfo->powerType) + { + // health as power used + case POWER_HEALTH: + powerCost += spellInfo->ManaCostPercentage * caster->GetCreateHealth() / 100; + break; + case POWER_MANA: + powerCost += spellInfo->ManaCostPercentage * caster->GetCreateMana() / 100; + break; + case POWER_RAGE: + case POWER_FOCUS: + case POWER_ENERGY: + case POWER_HAPPINESS: + powerCost += spellInfo->ManaCostPercentage * caster->GetMaxPower(Powers(spellInfo->powerType)) / 100; + break; + case POWER_RUNE: + case POWER_RUNIC_POWER: + sLog.outDebug("CalculateManaCost: Not implemented yet!"); + break; + default: + sLog.outError("CalculateManaCost: Unknown power type '%d' in spell %d", spellInfo->powerType, spellInfo->Id); + return 0; + } + } + SpellSchools school = GetFirstSchoolInMask(schoolMask); + // Flat mod from caster auras by spell school + 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 ( spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST ) + powerCost += caster->GetAttackTime(OFF_ATTACK)/100; + // Apply cost mod by spell + if(Player* modOwner = caster->GetSpellModOwner()) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, powerCost); + + if(spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) + powerCost = int32(powerCost/ (1.117f* spellInfo->spellLevel / caster->getLevel() -0.1327f)); + + // PCT mod from user auras by school + powerCost = int32(powerCost * (1.0f+caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school))); + if (powerCost < 0) + powerCost = 0; + return powerCost; +} + +AuraState GetSpellAuraState(SpellEntry const * spellInfo) +{ + // Seals + if (IsSealSpell(spellInfo)) + return (AURA_STATE_JUDGEMENT); + + // Conflagrate aura state on Immolate and Shadowflame + if (spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && + // Immolate + ((spellInfo->SpellFamilyFlags[0] & 4) || + // Shadowflame + (spellInfo->SpellFamilyFlags[2] & 2))) + return (AURA_STATE_CONFLAGRATE); + + // Faerie Fire (druid versions) + if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && spellInfo->SpellFamilyFlags[0] & 0x400) + return (AURA_STATE_FAERIE_FIRE); + + // Sting (hunter's pet ability) + if (spellInfo->Category == 1133) + return (AURA_STATE_FAERIE_FIRE); + + // Victorious + if (spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellFamilyFlags[1] & 0x00040000) + return (AURA_STATE_WARRIOR_VICTORY_RUSH); + + // Swiftmend state on Regrowth & Rejuvenation + if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && spellInfo->SpellFamilyFlags[0] & 0x50 ) + return (AURA_STATE_SWIFTMEND); + + // Deadly poison aura state + if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags[0] & 0x10000) + return (AURA_STATE_DEADLY_POISON); + + // Enrage aura state + if(spellInfo->Dispel == DISPEL_ENRAGE) + return (AURA_STATE_ENRAGE); + + // Bleeding aura state + if (GetAllSpellMechanicMask(spellInfo) & 1<<MECHANIC_BLEED) + return (AURA_STATE_BLEEDING); + + if(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) + { + for (uint8 i = 0;i<MAX_SPELL_EFFECTS;++i) + { + if (spellInfo->EffectApplyAuraName[i]==SPELL_AURA_MOD_STUN + || spellInfo->EffectApplyAuraName[i]==SPELL_AURA_MOD_ROOT) + { + return (AURA_STATE_FROZEN); + break; + } + } + } + return AURA_STATE_NONE; +} + SpellSpecific GetSpellSpecific(uint32 spellId) { SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); @@ -428,8 +558,8 @@ SpellSpecific GetSpellSpecific(uint32 spellId) if (spellInfo->Dispel == DISPEL_POISON) return SPELL_STING; - // only hunter aspects have this - if( spellInfo->SpellFamilyFlags[1] & 0x00440000 || spellInfo->SpellFamilyFlags[0] & 0x00380000 || spellInfo->SpellFamilyFlags[2] & 0x00001010) + // only hunter aspects have this (but not all aspects in hunter family) + if( spellInfo->SpellFamilyFlags.HasFlag(0x00380000, 0x00440000, 0x00001010)) return SPELL_ASPECT; break; @@ -442,15 +572,17 @@ SpellSpecific GetSpellSpecific(uint32 spellId) if (spellInfo->SpellFamilyFlags[0] & 0x11010002) return SPELL_BLESSING; - if ((spellInfo->SpellFamilyFlags[1] & 0x000008 || spellInfo->SpellFamilyFlags[0] & 0x20180400) && (spellInfo->AttributesEx3 & 0x200)) + if (spellInfo->SpellFamilyFlags[0] & 0x00002190) + return SPELL_HAND; + + // Judgement of Wisdom, Judgement of Light, Judgement of Justice + if (spellInfo->Id == 20184 || spellInfo->Id == 20185 || spellInfo->Id == 20186) return SPELL_JUDGEMENT; - for (int i = 0; i < 3; ++i) - { - // only paladin auras have this (for palaldin class family) - if (spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID) - return SPELL_AURA; - } + // only paladin auras have this (for palaldin class family) + if( spellInfo->SpellFamilyFlags[2] & 0x00000020 ) + return SPELL_AURA; + break; } case SPELLFAMILY_SHAMAN: @@ -465,7 +597,8 @@ SpellSpecific GetSpellSpecific(uint32 spellId) return spellmgr.GetSpellElixirSpecific(spellInfo->Id); case SPELLFAMILY_DEATHKNIGHT: - if ((spellInfo->Attributes & 0x10) && (spellInfo->AttributesEx2 & 0x10) && (spellInfo->AttributesEx4 & 0x200000)) + if (spellInfo->Id == SPELL_ID_BLOOD_PRESENCE || spellInfo->Id == SPELL_ID_FROST_PRESENCE || spellInfo->Id == SPELL_ID_UNHOLY_PRESENCE) + //if (spellInfo->Category == 47) return SPELL_PRESENCE; break; } @@ -501,6 +634,7 @@ bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1,uint32 spellSpec2) { case SPELL_SEAL: case SPELL_BLESSING: + case SPELL_HAND: case SPELL_AURA: case SPELL_STING: case SPELL_CURSE: @@ -569,13 +703,16 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB) return true; } -bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) +bool SpellMgr::_isPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) const { SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); if (!spellproto) return false; switch(spellId) { + case 1852: // Silenced (GM) + case 46392: // Focused Assault + case 46393: // Brutal Assault case 28441: // not positive dummy spell case 37675: // Chaos Blast case 41519: // Mark of Stormrage @@ -584,6 +721,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) case 31719: // Suspension case 61987: // Avenging Wrath Marker case 11196: // Recently Bandadged + case 50524: // Runic Power Feed return false; case 12042: // Arcane Power return true; @@ -631,6 +769,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) case 38637: // Nether Exhaustion (red) case 38638: // Nether Exhaustion (green) case 38639: // Nether Exhaustion (blue) + case 11196: // Recently Bandaged return false; // some spells have unclear target modes for selection, so just make effect positive case 27184: @@ -673,7 +812,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) continue; // if non-positive trigger cast targeted to positive target this main cast is non-positive // this will place this spell auras as debuffs - if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !IsPositiveEffect(spellTriggeredId,i, true)) + if(IsPositiveTarget(spellTriggeredProto->EffectImplicitTargetA[effIndex],spellTriggeredProto->EffectImplicitTargetB[effIndex]) && !_isPositiveEffect(spellTriggeredId,i, true)) return false; } } @@ -759,7 +898,7 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) for (uint8 i=0;i<MAX_SPELL_EFFECTS;++i) { if (i != effIndex) - if (IsPositiveEffect(spellId, i, true)) + if (_isPositiveEffect(spellId, i, true)) { negative = false; break; @@ -806,14 +945,30 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) if (!deep && spellproto->EffectTriggerSpell[effIndex] && !spellproto->EffectApplyAuraName[effIndex] && IsPositiveTarget(spellproto->EffectImplicitTargetA[effIndex],spellproto->EffectImplicitTargetB[effIndex]) - && !IsPositiveSpell(spellproto->EffectTriggerSpell[effIndex], true)) + && !_isPositiveSpell(spellproto->EffectTriggerSpell[effIndex], true)) return false; // ok, positive return true; } -bool IsPositiveSpell(uint32 spellId, bool deep) +bool IsPositiveSpell(uint32 spellId) +{ + return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE); +} + +bool IsPositiveEffect(uint32 spellId, uint32 effIndex) +{ + switch(effIndex) + { + default: + case 0: return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE_EFF0); + case 1: return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE_EFF1); + case 2: return !(spellmgr.GetSpellCustomAttr(spellId) & SPELL_ATTR_CU_NEGATIVE_EFF2); + } +} + +bool SpellMgr::_isPositiveSpell(uint32 spellId, bool deep) const { SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); if (!spellproto) return false; @@ -821,7 +976,7 @@ bool IsPositiveSpell(uint32 spellId, bool deep) // spells with at least one negative effect are considered negative // some self-applied spells have negative effects but in self casting case negative check ignored. for (int i = 0; i < 3; ++i) - if (!IsPositiveEffect(spellId, i, deep)) + if (!_isPositiveEffect(spellId, i, deep)) return false; return true; } @@ -875,17 +1030,6 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI return false; } -bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId) -{ - SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); - if (!spellproto) return false; - - for (int i = 0; i < 3; ++i) - if (spellproto->EffectApplyAuraName[i] == auraType) - return true; - return false; -} - SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) { // talents that learn spells can have stance requirements that need ignore @@ -1062,77 +1206,6 @@ void SpellMgr::LoadSpellTargetPositions() sLog.outString( ">> Loaded %u spell teleport coordinates", count ); } -void SpellMgr::LoadSpellAffects() -{ - mSpellAffectMap.clear(); // need for reload case - - uint32 count = 0; - - // 0 1 2 3 4 - QueryResult *result = WorldDatabase.Query("SELECT entry, effectId, SpellClassMask0, SpellClassMask1, SpellClassMask2 FROM spell_affect"); - if( !result ) - { - - barGoLink bar( 1 ); - - bar.step(); - - sLog.outString(); - sLog.outString( ">> Loaded %u spell affect definitions", count ); - return; - } - - barGoLink bar( result->GetRowCount() ); - - do - { - Field *fields = result->Fetch(); - - bar.step(); - - uint16 entry = fields[0].GetUInt16(); - uint8 effectId = fields[1].GetUInt8(); - - SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry); - - if (!spellInfo) - { - sLog.outErrorDb("Spell %u listed in `spell_affect` does not exist", entry); - continue; - } - - if (effectId >= 3) - { - sLog.outErrorDb("Spell %u listed in `spell_affect` have invalid effect index (%u)", entry,effectId); - continue; - } - - flag96 affect(fields[2].GetUInt32(), fields[3].GetUInt32(), fields[4].GetUInt32()); - - // Spell.dbc have own data - if (effectId>3) - continue; - - flag96 dbc_affect; - dbc_affect = spellInfo->EffectSpellClassMask[effectId]; - if(dbc_affect[0] == affect[0] && dbc_affect[1] == affect[1] && dbc_affect[2] == affect[2]) - { - char text[]="ABC"; - sLog.outErrorDb("Spell %u listed in `spell_affect` have redundant (same with EffectSpellClassMask%c) data for effect index (%u) and not needed, skipped.", entry, text[effectId], effectId); - continue; - } - - mSpellAffectMap[(entry<<8) + effectId] = affect; - - ++count; - } while( result->NextRow() ); - - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded %u custom spell affect definitions", count ); -} - bool SpellMgr::IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod) const { // false for spellInfo == NULL @@ -1225,8 +1298,8 @@ void SpellMgr::LoadSpellBonusess() { mSpellBonusMap.clear(); // need for reload case uint32 count = 0; - // 0 1 2 3 - QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus FROM spell_bonus_data"); + // 0 1 2 3 4 + QueryResult *result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data"); if( !result ) { barGoLink bar( 1 ); @@ -1255,8 +1328,10 @@ void SpellMgr::LoadSpellBonusess() sbe.direct_damage = fields[1].GetFloat(); sbe.dot_damage = fields[2].GetFloat(); sbe.ap_bonus = fields[3].GetFloat(); + sbe.ap_dot_bonus = fields[4].GetFloat(); mSpellBonusMap[entry] = sbe; + ++count; } while( result->NextRow() ); delete result; @@ -1265,7 +1340,7 @@ void SpellMgr::LoadSpellBonusess() sLog.outString( ">> Loaded %u extra spell bonus data", count); } -bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra) +bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active) { // No extra req need uint32 procEvent_procEx = PROC_EX_NONE; @@ -1278,42 +1353,52 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellPr /* Check Periodic Auras - * Both hots and dots can trigger if spell has no PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT - nor PROC_FLAG_SUCCESSFUL_HEALING_SPELL + *Dots can trigger if spell has no PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL + nor PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL + + *Only Hots can trigger if spell has PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL - *Only Hots can trigger if spell has PROC_FLAG_SUCCESSFUL_HEALING_SPELL + *Only dots can trigger if spell has both positivity flags or PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL - *Only dots can trigger if spell has both positivity flags or PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT + *Aura has to have PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL or spellfamily specified to trigger from Hot */ if (procFlags & PROC_FLAG_ON_DO_PERIODIC) { - if (EventProcFlag & PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT) + if (EventProcFlag & PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL) { if (!(procExtra & PROC_EX_INTERNAL_DOT)) return false; } - else if (EventProcFlag & PROC_FLAG_SUCCESSFUL_HEALING_SPELL + else if (EventProcFlag & PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL && !(procExtra & PROC_EX_INTERNAL_HOT)) return false; + else if (procExtra & PROC_EX_INTERNAL_HOT) + procExtra |= PROC_EX_INTERNAL_REQ_FAMILY; } if (procFlags & PROC_FLAG_ON_TAKE_PERIODIC) { - if (EventProcFlag & PROC_FLAG_TAKEN_DAMAGING_SPELL_HIT) + if (EventProcFlag & PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL) { if (!(procExtra & PROC_EX_INTERNAL_DOT)) return false; } - else if (EventProcFlag & PROC_FLAG_TAKEN_HEALING_SPELL + else if (EventProcFlag & PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL && !(procExtra & PROC_EX_INTERNAL_HOT)) return false; + else if (procExtra & PROC_EX_INTERNAL_HOT) + procExtra |= PROC_EX_INTERNAL_REQ_FAMILY; } + // Trap casts are active by default + if (procFlags & PROC_FLAG_ON_TRAP_ACTIVATION) + active = true; // Always trigger for this - if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_ON_TRAP_ACTIVATION)) + if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH)) return true; + if (spellProcEvent) // Exist event data { // Store extra req @@ -1342,11 +1427,14 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellPr if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags ) == 0) return false; hasFamilyMask = true; + // Some spells are not considered as active even with have spellfamilyflags + if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)) + active = true; } } } - if (procExtra & PROC_EX_INTERNAL_REQ_FAMILY) + if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY)) { if (!hasFamilyMask) return false; @@ -1355,15 +1443,27 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellPr // Check for extra req (if none) and hit/crit if (procEvent_procEx == PROC_EX_NONE) { - // No extra req, so can trigger only for hit/crit - if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT))) + // No extra req, so can trigger only for hit/crit - spell has to be active + if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active) return true; } else // Passive spells hits here only if resist/reflect/immune/evade { - // Exist req for PROC_EX_EX_TRIGGER_ALWAYS - if ((procExtra & AURA_SPELL_PROC_EX_MASK) && (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)) - return true; + if (procExtra & AURA_SPELL_PROC_EX_MASK) + { + // if spell marked as procing only from not active spells + if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL) + return false; + // if spell marked as procing only from active spells + if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL) + return false; + // Exist req for PROC_EX_EX_TRIGGER_ALWAYS + if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS) + return true; + // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before + if ((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK | AURA_REMOVE_PROC_EX_MASK)) == 0)) + return true; + } // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other) if (procEvent_procEx & procExtra) return true; @@ -1399,7 +1499,7 @@ void SpellMgr::LoadSpellElixirs() bar.step(); - uint16 entry = fields[0].GetUInt16(); + uint32 entry = fields[0].GetUInt32(); uint8 mask = fields[1].GetUInt8(); SpellEntry const* spellInfo = sSpellStore.LookupEntry(entry); @@ -1423,12 +1523,50 @@ void SpellMgr::LoadSpellElixirs() void SpellMgr::LoadSpellThreats() { - sSpellThreatStore.Free(); // for reload + mSpellThreatMap.clear(); // need for reload case - sSpellThreatStore.Load(); + uint32 count = 0; + + // 0 1 + QueryResult *result = WorldDatabase.Query("SELECT entry, Threat FROM spell_threat"); + if( !result ) + { + + barGoLink bar( 1 ); + + bar.step(); + + sLog.outString(); + sLog.outString( ">> Loaded %u aggro generating spells", count ); + return; + } + + barGoLink bar( result->GetRowCount() ); + + do + { + Field *fields = result->Fetch(); + + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + uint16 Threat = fields[1].GetUInt16(); + + if (!sSpellStore.LookupEntry(entry)) + { + sLog.outErrorDb("Spell %u listed in `spell_threat` does not exist", entry); + continue; + } + + mSpellThreatMap[entry] = Threat; + + ++count; + } while( result->NextRow() ); + + delete result; - sLog.outString( ">> Loaded %u aggro generating spells", sSpellThreatStore.RecordCount ); sLog.outString(); + sLog.outString( ">> Loaded %u aggro generating spells", count ); } bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const @@ -1666,7 +1804,13 @@ void SpellMgr::LoadSpellLearnSpells() if(!sSpellStore.LookupEntry(node.spell)) { - sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",node.spell); + sLog.outErrorDb("Spell %u listed in `spell_learn_spell` learning not existed spell %u",spell_id,node.spell); + continue; + } + + if(GetTalentSpellCost(node.spell)) + { + sLog.outErrorDb("Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped",spell_id,node.spell); continue; } @@ -1807,6 +1951,9 @@ void SpellMgr::LoadSpellScriptTarget() } break; } + case SPELL_TARGET_TYPE_CONTROLLED: + if( targetEntry==0 ) + sLog.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.",targetEntry); default: { //players @@ -1892,8 +2039,8 @@ void SpellMgr::LoadSpellPetAuras() uint32 count = 0; - // 0 1 2 - QueryResult *result = WorldDatabase.Query("SELECT spell, pet, aura FROM spell_pet_auras"); + // 0 1 2 3 + QueryResult *result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras"); if( !result ) { @@ -1914,11 +2061,12 @@ void SpellMgr::LoadSpellPetAuras() bar.step(); - uint16 spell = fields[0].GetUInt16(); - uint16 pet = fields[1].GetUInt16(); - uint16 aura = fields[2].GetUInt16(); + uint32 spell = fields[0].GetUInt32(); + uint8 eff = fields[1].GetUInt8(); + uint32 pet = fields[2].GetUInt32(); + uint32 aura = fields[3].GetUInt32(); - SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find(spell); + SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell<<8) + eff); if(itr != mSpellPetAuraMap.end()) { itr->second.AddAura(pet, aura); @@ -1931,14 +2079,9 @@ void SpellMgr::LoadSpellPetAuras() sLog.outErrorDb("Spell %u listed in `spell_pet_auras` does not exist", spell); continue; } - int i = 0; - for(; i < 3; ++i) - if((spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA && - spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DUMMY) || - spellInfo->Effect[i] == SPELL_EFFECT_DUMMY) - break; - - if(i == 3) + if (spellInfo->Effect[eff] != SPELL_EFFECT_DUMMY && + (spellInfo->Effect[eff] != SPELL_EFFECT_APPLY_AURA || + spellInfo->EffectApplyAuraName[eff] != SPELL_AURA_DUMMY)) { sLog.outError("Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell); continue; @@ -1951,8 +2094,8 @@ void SpellMgr::LoadSpellPetAuras() continue; } - PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_PET, spellInfo->CalculateSimpleValue(i)); - mSpellPetAuraMap[spell] = pa; + PetAura pa(pet, aura, spellInfo->EffectImplicitTargetA[eff] == TARGET_UNIT_PET, spellInfo->CalculateSimpleValue(eff)); + mSpellPetAuraMap[(spell<<8) + eff] = pa; } ++count; @@ -2159,8 +2302,9 @@ bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg) case 0: continue; - // craft spell for crafting non-existed item (break client recipes list show) + // craft spell for crafting non-existed item (break client recipes list show) case SPELL_EFFECT_CREATE_ITEM: + case SPELL_EFFECT_CREATE_ITEM_2: { if(!ObjectMgr::GetItemPrototype( spellInfo->EffectItemType[i] )) { @@ -2339,10 +2483,15 @@ void SpellMgr::LoadSpellAreas() continue; } - if(spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_DUMMY && spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_PHASE) + switch(spellInfo->EffectApplyAuraName[0]) { - sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy/phase aura in effect 0", spell,abs(spellArea.auraSpell)); - continue; + case SPELL_AURA_DUMMY: + case SPELL_AURA_PHASE: + case SPELL_AURA_GHOST: + break; + default: + sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy/phase/ghost aura in effect 0", spell,abs(spellArea.auraSpell)); + continue; } if(abs(spellArea.auraSpell)==spellArea.spellId) @@ -2435,8 +2584,12 @@ void SpellMgr::LoadSpellAreas() SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) { + // allow in GM-mode + if (player && player->isGameMaster()) + return SPELL_CAST_OK; + // normal case - if( spellInfo->AreaGroupId > 0) + if (spellInfo->AreaGroupId > 0) { bool found = false; AreaGroupEntry const* groupEntry = sAreaGroupStore.LookupEntry(spellInfo->AreaGroupId); @@ -2455,9 +2608,18 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell return SPELL_FAILED_INCORRECT_AREA; } + // continent limitation (virtual continent) + if (spellInfo->AttributesEx4 & SPELL_ATTR_EX4_CAST_ONLY_IN_OUTLAND) + { + uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id); + MapEntry const* mapEntry = sMapStore.LookupEntry(v_map); + if(!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent()) + return SPELL_FAILED_INCORRECT_AREA; + } + // DB base check (if non empty then must fit at least single for allow) SpellAreaMapBounds saBounds = spellmgr.GetSpellAreaMapBounds(spellInfo->Id); - if(saBounds.first != saBounds.second) + if (saBounds.first != saBounds.second) { for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { @@ -2484,21 +2646,21 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell case 44535: // Spirit Heal (mana) { MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); - if(!mapEntry) + if (!mapEntry) return SPELL_FAILED_INCORRECT_AREA; return mapEntry->IsBattleGround() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 44521: // Preparation { - if(!player) + if (!player) return SPELL_FAILED_REQUIRES_AREA; MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); - if(!mapEntry) + if (!mapEntry) return SPELL_FAILED_INCORRECT_AREA; - if(!mapEntry->IsBattleGround()) + if (!mapEntry->IsBattleGround()) return SPELL_FAILED_REQUIRES_AREA; BattleGround* bg = player->GetBattleGround(); @@ -2510,14 +2672,14 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell case 35775: // Green Team (Horde) { MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); - if(!mapEntry) + if (!mapEntry) return SPELL_FAILED_INCORRECT_AREA; return mapEntry->IsBattleArena() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 32727: // Arena Preparation { - if(!player) + if (!player) return SPELL_FAILED_REQUIRES_AREA; MapEntry const* mapEntry = sMapStore.LookupEntry(map_id); @@ -2562,13 +2724,25 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto // Explicit Diminishing Groups switch(spellproto->SpellFamilyName) { + case SPELLFAMILY_GENERIC: + // some generic arena related spells have by some strange reason MECHANIC_TURN + if (spellproto->Mechanic == MECHANIC_TURN) + return DIMINISHING_NONE; + break; + case SPELLFAMILY_MAGE: + { + // Frostbite 0x80000000 + if (spellproto->SpellFamilyFlags[1] & 0x80000000) + return DIMINISHING_TRIGGER_ROOT; + // Frost Nova / Freeze (Water Elemental) + else if (spellproto->SpellIconID == 193) + return DIMINISHING_CONTROL_ROOT; + break; + } case SPELLFAMILY_ROGUE: { - // Sap - if (spellproto->SpellFamilyFlags[0] & 0x80) - return DIMINISHING_POLYMORPH; - // Gouge - else if (spellproto->SpellFamilyFlags[0] & 0x8) + // Sap 0x80 Gouge 0x8 + if (spellproto->SpellFamilyFlags[0] & 0x88) return DIMINISHING_POLYMORPH; // Blind else if (spellproto->SpellFamilyFlags[0] & 0x1000000) @@ -2576,6 +2750,9 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto // Cheap Shot else if (spellproto->SpellFamilyFlags[0] & 0x400) return DIMINISHING_CHEAPSHOT_POUNCE; + // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags) + else if (spellproto->SpellIconID == 163) + return DIMINISHING_LIMITONLY; break; } case SPELLFAMILY_WARLOCK: @@ -2596,17 +2773,15 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto // Pounce if (spellproto->SpellFamilyFlags[0] & 0x20000) return DIMINISHING_CHEAPSHOT_POUNCE; - + // Cyclone + else if (spellproto->SpellFamilyFlags[1] & 0x20) + return DIMINISHING_CYCLONE; //Entangling Roots: to force natures grasp proc to be control root else if (spellproto->SpellFamilyFlags[0] & 0x00000200) return DIMINISHING_CONTROL_ROOT; - break; - } - case SPELLFAMILY_MAGE: - { - // Frostbite - if (spellproto->SpellFamilyFlags[1] & 0x80000000) - return DIMINISHING_TRIGGER_ROOT; + // Faerie Fire + else if (spellproto->SpellFamilyFlags[0] & 0x400) + return DIMINISHING_LIMITONLY; break; } case SPELLFAMILY_WARRIOR: @@ -2617,8 +2792,8 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto // Intimidating Shout else if (spellproto->SpellFamilyFlags[0] & 0x40000) return DIMINISHING_FEAR_BLIND; - // Charge - else if (spellproto->SpellFamilyFlags[0] & 0x1) + // Charge Stun + else if (spellproto->SpellFamilyFlags[0] & 0x01000000) return DIMINISHING_NONE; break; } @@ -2629,9 +2804,16 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto return DIMINISHING_POLYMORPH; break; } + case SPELLFAMILY_PRIEST: + { + // Vampiric Embrace + if ((spellproto->SpellFamilyFlags[0] & 0x4) && spellproto->SpellIconID == 150) + return DIMINISHING_LIMITONLY; + break; + } case SPELLFAMILY_DEATHKNIGHT: { - // Hungering Cold + // Hungering Cold (no flags) if (spellproto->SpellIconID == 2797) return DIMINISHING_POLYMORPH; break; @@ -2643,15 +2825,20 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto // Get by mechanic uint32 mechanic = GetAllSpellMechanicMask(spellproto); if (mechanic == MECHANIC_NONE) return DIMINISHING_NONE; - if (mechanic & (1<<MECHANIC_STUN)) return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN; - if (mechanic & ((1<<MECHANIC_SLEEP) | (1<<MECHANIC_FREEZE))) return DIMINISHING_SLEEP_FREEZE; + if (mechanic & ((1<<MECHANIC_STUN) | + (1<<MECHANIC_SHACKLE))) return triggered ? DIMINISHING_TRIGGER_STUN : DIMINISHING_CONTROL_STUN; + if (mechanic & ((1<<MECHANIC_SLEEP) | + (1<<MECHANIC_FREEZE))) return DIMINISHING_FREEZE_SLEEP; if (mechanic & (1<<MECHANIC_POLYMORPH)) return DIMINISHING_POLYMORPH; if (mechanic & (1<<MECHANIC_ROOT)) return triggered ? DIMINISHING_TRIGGER_ROOT : DIMINISHING_CONTROL_ROOT; - if (mechanic & (1<<MECHANIC_FEAR)) return DIMINISHING_FEAR; + if (mechanic & ((1<<MECHANIC_FEAR) | + (1<<MECHANIC_TURN))) return DIMINISHING_FEAR_BLIND; if (mechanic & (1<<MECHANIC_CHARM)) return DIMINISHING_CHARM; if (mechanic & (1<<MECHANIC_SILENCE)) return DIMINISHING_SILENCE; if (mechanic & (1<<MECHANIC_DISARM)) return DIMINISHING_DISARM; - if (mechanic & ((1<<MECHANIC_KNOCKOUT) | (1<<MECHANIC_SAPPED))) return DIMINISHING_KNOCKOUT; + if (mechanic & (1<<MECHANIC_FREEZE)) return DIMINISHING_FREEZE_SLEEP; + if (mechanic & ((1<<MECHANIC_KNOCKOUT) | + (1<<MECHANIC_SAPPED))) return DIMINISHING_KNOCKOUT; if (mechanic & (1<<MECHANIC_BANISH)) return DIMINISHING_BANISH; if (mechanic & (1<<MECHANIC_HORROR)) return DIMINISHING_DEATHCOIL; @@ -2664,20 +2851,63 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto return DIMINISHING_NONE; } +int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellEntry const* spellproto) +{ + if(!IsDiminishingReturnsGroupDurationLimited(group)) + return 0; + + // Explicit diminishing duration + switch(spellproto->SpellFamilyName) + { + case SPELLFAMILY_HUNTER: + { + // Wyvern Sting + if (spellproto->SpellFamilyFlags[1] & 0x1000) + return 6000; + break; + } + case SPELLFAMILY_PALADIN: + { + // Repentance - limit to 6 seconds in PvP + if (spellproto->SpellFamilyFlags[0] & 0x4) + return 6000; + break; + } + case SPELLFAMILY_DRUID: + { + // Faerie Fire - limit to 40 seconds in PvP (3.1) + if (spellproto->SpellFamilyFlags[0] & 0x400) + return 40000; + break; + } + case SPELLFAMILY_PRIEST: + { + // Vampiric Embrace - limit to 60 seconds in PvP (3.1) + if ((spellproto->SpellFamilyFlags[0] & 0x4) && spellproto->SpellIconID == 150) + return 60000; + break; + } + default: + break; + } + + return 10000; +} + bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group) { switch(group) { case DIMINISHING_CONTROL_STUN: case DIMINISHING_TRIGGER_STUN: - case DIMINISHING_SLEEP_FREEZE: + case DIMINISHING_FREEZE_SLEEP: case DIMINISHING_CONTROL_ROOT: case DIMINISHING_TRIGGER_ROOT: - case DIMINISHING_FEAR: case DIMINISHING_FEAR_BLIND: case DIMINISHING_CHARM: case DIMINISHING_POLYMORPH: case DIMINISHING_KNOCKOUT: + case DIMINISHING_CYCLONE: case DIMINISHING_BANISH: case DIMINISHING_LIMITONLY: case DIMINISHING_CHEAPSHOT_POUNCE: @@ -2696,18 +2926,18 @@ DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group) case DIMINISHING_CONTROL_STUN: case DIMINISHING_TRIGGER_STUN: case DIMINISHING_CHEAPSHOT_POUNCE: - case DIMINISHING_FEAR_BLIND: + case DIMINISHING_CYCLONE: return DRTYPE_ALL; - case DIMINISHING_BANISH: + case DIMINISHING_FEAR_BLIND: case DIMINISHING_CONTROL_ROOT: case DIMINISHING_TRIGGER_ROOT: - case DIMINISHING_FEAR: case DIMINISHING_CHARM: case DIMINISHING_POLYMORPH: case DIMINISHING_SILENCE: case DIMINISHING_DISARM: case DIMINISHING_DEATHCOIL: - case DIMINISHING_SLEEP_FREEZE: + case DIMINISHING_FREEZE_SLEEP: + case DIMINISHING_BANISH: case DIMINISHING_KNOCKOUT: return DRTYPE_PLAYER; default: @@ -2784,7 +3014,7 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool SpellSpecific spellId_spec_2 = GetSpellSpecific(spellId_2); if (spellId_spec_1 && spellId_spec_2) if (IsSingleFromSpellSpecificPerTarget(spellId_spec_1, spellId_spec_2) - ||(IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2) && sameCaster)) + ||(sameCaster && IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2))) return true; if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName) @@ -2795,6 +3025,11 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool for(uint32 i = 0; i < 3; ++i) if (spellInfo_1->Effect[i] == SPELL_EFFECT_APPLY_AURA || spellInfo_1->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA) + { + // not channeled AOE effects can stack + if(IsAreaEffectTarget[spellInfo_1->EffectImplicitTargetA[i]] || IsAreaEffectTarget[spellInfo_1->EffectImplicitTargetB[i]] + && !IsChanneledSpell(spellInfo_1)) + continue; // not area auras (shaman totem) switch(spellInfo_1->EffectApplyAuraName[i]) { @@ -2808,17 +3043,19 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool case SPELL_AURA_POWER_BURN_MANA: case SPELL_AURA_OBS_MOD_ENERGY: case SPELL_AURA_OBS_MOD_HEALTH: + case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: return false; default: break; } + } } spellId_2 = GetLastSpellInChain(spellId_2); spellId_1 = GetLastSpellInChain(spellId_1); // Hack for Incanter's Absorption - if (spellId_1 == spellId_2 && spellId_1 == 44413) + if (spellId_1 == spellId_2 && (spellId_1 == 44413 || (!sameCaster && spellInfo_1->AttributesEx3 & SPELL_ATTR_EX3_STACKS_FOR_DIFFERENT_CASTERS))) return false; if (spellId_1 == spellId_2) @@ -2852,7 +3089,7 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool || spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura return false; // need itemtype check? need an example to add that check - return true; + return (!(!sameCaster && spellInfo_1->AttributesEx3 & SPELL_ATTR_EX3_STACKS_FOR_DIFFERENT_CASTERS)); } bool IsDispelableBySpell(SpellEntry const * dispelSpell, uint32 spellId, bool def) @@ -3167,7 +3404,7 @@ void SpellMgr::LoadSpellChains() for (itr2 = RankErrorMap.lower_bound(err_entry);itr2!=RankErrorMap.upper_bound(err_entry);itr2++) { sLog.outDebug("There is a duplicate rank entry (%s) for spell: %u",itr2->first,itr2->second->second.Id); - if (!(itr2->second->second.Id==52375 || itr2->second->second.Id==45902)) + if (!(itr2->second->second.Id==47541 || itr2->second->second.Id==45902 || itr2->second->second.Id==7620)) { sLog.outDebug("Spell %u removed from chain data.",itr2->second->second.Id); RankMap.erase(itr2->second); @@ -3248,7 +3485,7 @@ void SpellMgr::LoadSpellChains() } } -//uncomment these two lines to print yourself list of spell_chains on startup + //uncomment these two lines to print yourself list of spell_chains on startup //for (UNORDERED_MAP<uint32, SpellChainNode>::iterator itr=mSpellChains.begin();itr!=mSpellChains.end();itr++) //sLog.outString( "Id: %u, Rank: %d , %s, %u, %u, %u, %u",itr->first,itr->second.rank, sSpellStore.LookupEntry(itr->first)->Rank[sWorld.GetDefaultDbcLocale()], itr->second.first, itr->second.last,itr->second.next ,itr->second.prev); @@ -3362,13 +3599,30 @@ void SpellMgr::LoadSpellCustomAttr() mSpellCustomAttr[i] &= ~SPELL_ATTR_CU_MOVEMENT_IMPAIR; break; } - } + } + + if(!_isPositiveEffect(i, 0, false)) + mSpellCustomAttr[i] |= SPELL_ATTR_CU_NEGATIVE_EFF0; + if(!_isPositiveEffect(i, 1, false)) + mSpellCustomAttr[i] |= SPELL_ATTR_CU_NEGATIVE_EFF1; + if(!_isPositiveEffect(i, 2, false)) + mSpellCustomAttr[i] |= SPELL_ATTR_CU_NEGATIVE_EFF2; if(spellInfo->SpellVisual[0] == 3879) mSpellCustomAttr[i] |= SPELL_ATTR_CU_CONE_BACK; + if(spellInfo->activeIconID == 2158) //flight + spellInfo->Attributes |= SPELL_ATTR_PASSIVE; + switch(i) { + // Heart of the Crusader + case 20335: + case 20336: + case 20337: + // Entries were not updated after spell effect change, we have to do that manually:/ + spellInfo->AttributesEx3 |= SPELL_ATTR_EX3_CAN_PROC_TRIGGERED; + break; case 16007: // Draco-Incarcinatrix 900 // was 46, but effect is aura effect spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_NEARBY_ENTRY; @@ -3388,6 +3642,7 @@ void SpellMgr::LoadSpellCustomAttr() case 40810: case 43267: case 43268: // Saber Lash case 42384: // Brutal Swipe case 45150: // Meteor Slash + case 64422: case 64688: // Sonic Screech mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE; break; case 59725: // Improved Spell Reflection - aoe aura @@ -3446,10 +3701,6 @@ void SpellMgr::LoadSpellCustomAttr() case 54098: // Poison Bolt Volly - Faerlina (H) spellInfo->MaxAffectedTargets = 10; break; - case 8122: case 8124: case 10888: case 10890: // Psychic Scream - case 12494: // Frostbite - spellInfo->Attributes |= SPELL_ATTR_BREAKABLE_BY_DAMAGE; - break; case 38794: case 33711: //Murmur's Touch spellInfo->MaxAffectedTargets = 1; spellInfo->EffectTriggerSpell[0] = 33760; @@ -3465,10 +3716,12 @@ void SpellMgr::LoadSpellCustomAttr() case 57761: // Fireball! case 39805: // Lightning Overload case 52437: // Sudden Death + case 64823: // Item - Druid T8 Balance 4P Bonus spellInfo->procCharges=1; break; case 44544: // Fingers of Frost spellInfo->procCharges=2; + spellInfo->EffectSpellClassMask[0] = flag96(685904631,1151048,0); break; case 28200: // Ascendance (Talisman of Ascendance trinket) spellInfo->procCharges=6; @@ -3479,6 +3732,20 @@ void SpellMgr::LoadSpellCustomAttr() case 51904: // Summon Ghouls On Scarlet Crusade (core does not know the triggered spell is summon spell) spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_CASTER; break; + case 29809: // Desecration Arm - 36 instead of 37 - typo? :/ + spellInfo->EffectRadiusIndex[0] = 37; + break; + // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data + // To prevent aura staying on target after talent unlearned + case 48420: + spellInfo->Stances = 1 << (FORM_CAT - 1); + break; + case 48421: + spellInfo->Stances = 1 << (FORM_MOONKIN - 1); + break; + case 48422: + spellInfo->Stances = 1 << (FORM_TREE - 1); + break; default: break; } diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 9871930a8fd..e651283fa48 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -25,7 +25,9 @@ // For more high level function for sSpellStore data #include "SharedDefines.h" +#include "SpellAuraDefines.h" #include "DBCStructure.h" +#include "DBCStores.h" #include "Database/SQLStorage.h" #include "Utilities/UnorderedMap.h" @@ -36,14 +38,14 @@ class Player; class Spell; - -extern SQLStorage sSpellThreatStore; +struct SpellModifier; // only used in code enum SpellCategories { SPELLCATEGORY_HEALTH_MANA_POTIONS = 4, - SPELLCATEGORY_DEVOUR_MAGIC = 12 + SPELLCATEGORY_DEVOUR_MAGIC = 12, + SPELLCATEGORY_JUDGEMENT = 1210, // Judgement (seal trigger) }; enum SpellDisableTypes @@ -120,6 +122,7 @@ enum SpellSpecific SPELL_MAGE_ARCANE_BRILLANCE = 24, SPELL_WARRIOR_ENRAGE = 25, SPELL_PRIEST_DIVINE_SPIRIT = 26, + SPELL_HAND = 27, }; #define SPELL_LINKED_MAX_SPELLS 200000 @@ -133,6 +136,7 @@ enum SpellLinkedType }; SpellSpecific GetSpellSpecific(uint32 spellId); +AuraState GetSpellAuraState(SpellEntry const * spellInfo); // Different spell properties inline float GetSpellRadiusForHostile(SpellRadiusEntry const *radius) { return (radius ? radius->radiusHostile : 0); } @@ -193,6 +197,14 @@ inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect) return false; } +inline bool IsSpellHaveAura(SpellEntry const *spellInfo, AuraType aura) +{ + for(int i= 0; i < 3; ++i) + if(AuraType(spellInfo->EffectApplyAuraName[i])==aura) + return true; + return false; +} + //bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2); inline bool IsSealSpell(SpellEntry const *spellInfo) @@ -213,15 +225,16 @@ inline bool IsElementalShield(SpellEntry const *spellInfo) inline bool IsExplicitDiscoverySpell(SpellEntry const *spellInfo) { - return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && spellInfo->Effect[1]==SPELL_EFFECT_SCRIPT_EFFECT; + return spellInfo->Effect[0] == SPELL_EFFECT_CREATE_RANDOM_ITEM + && spellInfo->Effect[1] == SPELL_EFFECT_SCRIPT_EFFECT + || spellInfo->Id == 64323; // Book of Glyph Mastery (Effect0==SPELL_EFFECT_SCRIPT_EFFECT without any other data) } inline bool IsLootCraftingSpell(SpellEntry const *spellInfo) { - return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && ( - spellInfo->Effect[1]==SPELL_EFFECT_SCRIPT_EFFECT || // see IsExplicitDiscoverySpell - !spellInfo->EffectItemType[0] || // result item not provided - spellInfo->TotemCategory[0] == 121); // different random cards from Inscription (121==Virtuoso Inking Set category) + return spellInfo->Effect[0]==SPELL_EFFECT_CREATE_RANDOM_ITEM || + // different random cards from Inscription (121==Virtuoso Inking Set category) + spellInfo->Effect[0]==SPELL_EFFECT_CREATE_ITEM_2 && spellInfo->TotemCategory[0] == 121; } bool IsHigherHankOfSpell(uint32 spellId_1,uint32 spellId_2); @@ -230,6 +243,8 @@ bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1, uint32 spellSpec2); bool IsPassiveSpell(uint32 spellId); bool IsAutocastableSpell(uint32 spellId); +uint32 CalculatePowerCost(SpellEntry const * spellInfo, Unit const * caster, SpellSchoolMask schoolMask); + inline bool IsPassiveSpellStackableWithRanks(SpellEntry const* spellProto) { if(!IsPassiveSpell(spellProto->Id)) @@ -249,15 +264,14 @@ inline bool IsNonCombatSpell(SpellEntry const *spellInfo) return (spellInfo->Attributes & SPELL_ATTR_CANT_USED_IN_COMBAT) != 0; } -bool IsPositiveSpell(uint32 spellId, bool deep = false); -bool IsPositiveEffect(uint32 spellId, uint32 effIndex, bool deep = false); +bool IsPositiveSpell(uint32 spellId); +bool IsPositiveEffect(uint32 spellId, uint32 effIndex); bool IsPositiveTarget(uint32 targetA, uint32 targetB); bool IsDispelableBySpell(SpellEntry const * dispelSpell, uint32 spellId, bool def = false); bool IsSingleTargetSpell(SpellEntry const *spellInfo); bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2); -bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId); extern bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS]; @@ -317,7 +331,7 @@ inline bool IsAutoRepeatRangedSpell(SpellEntry const* spellInfo) inline bool IsRangedWeaponSpell(SpellEntry const* spellInfo) { //spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED should be checked outside - return (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER) // for 53352, cannot find better way + return (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && !(spellInfo->SpellFamilyFlags[1] & 0x10000000)) // for 53352, cannot find better way || (spellInfo->EquippedItemSubClassMask & ITEM_SUBCLASS_MASK_WEAPON_RANGED); } @@ -381,55 +395,53 @@ inline uint32 GetDispellMask(DispelType dispel) DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered); bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group); DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group); - -// Spell affects related declarations (accessed using SpellMgr functions) -typedef UNORDERED_MAP<uint32, flag96> SpellAffectMap; +int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellEntry const* spellproto); // Spell proc event related declarations (accessed using SpellMgr functions) enum ProcFlags { - PROC_FLAG_NONE = 0x00000000, + PROC_FLAG_NONE = 0x00000000, - PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor - PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward) + PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor + PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward) - PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee auto attack - PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee auto attack hit + PROC_FLAG_SUCCESSFUL_MELEE_HIT = 0x00000004, // 02 Successful melee auto attack + PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee auto attack hit - PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon - PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon + PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon + PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon - PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged auto attack - PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged auto attack + PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged auto attack + PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged auto attack - PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon - PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon + PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon + PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon - PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL = 0x00000400, // 10 Successful Positive spell hit - PROC_FLAG_TAKEN_POSITIVE_SPELL = 0x00000800, // 11 Taken Positive spell hit + PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT = 0x00000400, // 10 Successful Positive spell hit + PROC_FLAG_TAKEN_POSITIVE_SPELL = 0x00000800, // 11 Taken Positive spell hit - PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT = 0x00001000, // 12 Successful Negative spell hit - PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT = 0x00002000, // 13 Taken Negative spell hit + PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT = 0x00001000, // 12 Successful Negative spell hit + PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT = 0x00002000, // 13 Taken Negative spell hit - PROC_FLAG_SUCCESSFUL_HEALING_SPELL = 0x00004000, // 14 Successful Direct Heal spell hit - PROC_FLAG_TAKEN_HEALING_SPELL = 0x00008000, // 15 Taken Direct Heal spell hit + PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL = 0x00004000, // 14 Successful Positive Magic spell hit + PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL = 0x00008000, // 15 Taken Positive Magic spell hit - PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT = 0x00010000, // 16 Successful Direct Damage spell hit - PROC_FLAG_TAKEN_DAMAGING_SPELL_HIT = 0x00020000, // 17 Taken Direct Damage spell hit + PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL = 0x00010000, // 16 Successful Negative Magic spell hit + PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL = 0x00020000, // 17 Taken Negative Magic spell hit - PROC_FLAG_ON_DO_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing, determined from 14,16 flags) - PROC_FLAG_ON_TAKE_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing, determined from 15,17 flags) + PROC_FLAG_ON_DO_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing, determined from 14,16 flags) + PROC_FLAG_ON_TAKE_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing, determined from 15,17 flags) - PROC_FLAG_TAKEN_ANY_DAMAGE = 0x00100000, // 20 Taken any damage - PROC_FLAG_ON_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation + PROC_FLAG_TAKEN_ANY_DAMAGE = 0x00100000, // 20 Taken any damage + PROC_FLAG_ON_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation (possibly needs name change to ON_GAMEOBJECT_CAST or USE) - PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks(not used) - PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000, // 23 Successful off-hand melee attacks ( this is probably wrong ) + PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks ( this is probably wrong ) + PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000, // 23 Successful off-hand melee attacks ( this is probably wrong ) - PROC_FLAG_DEATH = 0x01000000 // 24 Died in any way + PROC_FLAG_DEATH = 0x01000000 // 24 Died in any way }; -#define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MILEE_HIT | \ +#define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MELEE_HIT | \ PROC_FLAG_TAKEN_MELEE_HIT | \ PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT | \ PROC_FLAG_TAKEN_MELEE_SPELL_HIT | \ @@ -454,15 +466,19 @@ enum ProcFlagsEx PROC_EX_ABSORB = 0x0000400, PROC_EX_REFLECT = 0x0000800, PROC_EX_INTERRUPT = 0x0001000, // Melee hit result can be Interrupt (not used) - PROC_EX_AURA_REMOVE_DESTROY = 0x0002000, // aura absorb destroy or dispel - PROC_EX_AURA_REMOVE_EXPIRE = 0x0004000, // aura remove by default and by cancel - PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always ( no matter another flags) used for drop charges - PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not used) + PROC_EX_AURA_REMOVE_DESTROY = 0x0002000, // Aura absorb destroy or dispel + PROC_EX_AURA_REMOVE_EXPIRE = 0x0004000, // Aura remove by default and by cancel + PROC_EX_NOT_ACTIVE_SPELL = 0x0008000, // Spell mustn't do damage/heal to proc + PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always no matter of hit result + PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000, // If set trigger always but only one time (not implemented yet) + PROC_EX_ONLY_ACTIVE_SPELL = 0x0040000, // Spell has to do damage/heal to proc + + // Flags for internal use - do not use these in db! PROC_EX_INTERNAL_CANT_PROC = 0x0800000, - PROC_EX_INTERNAL_DOT = 0x1000000, // Only for internal use - PROC_EX_INTERNAL_HOT = 0x2000000, // Only for internal use - PROC_EX_INTERNAL_TRIGGERED = 0x4000000, // Only for internal use - PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 // Only for internal use + PROC_EX_INTERNAL_DOT = 0x1000000, + PROC_EX_INTERNAL_HOT = 0x2000000, + PROC_EX_INTERNAL_TRIGGERED = 0x4000000, + PROC_EX_INTERNAL_REQ_FAMILY = 0x8000000 }; #define AURA_REMOVE_PROC_EX_MASK \ (PROC_EX_AURA_REMOVE_DESTROY | PROC_EX_AURA_REMOVE_EXPIRE) @@ -490,6 +506,7 @@ struct SpellBonusEntry float direct_damage; float dot_damage; float ap_bonus; + float ap_dot_bonus; }; typedef UNORDERED_MAP<uint32, SpellProcEventEntry> SpellProcEventMap; @@ -511,16 +528,18 @@ typedef UNORDERED_MAP<uint32, SpellBonusEntry> SpellBonusMap; #define ELIXIR_SHATTRATH_MASK 0x8 typedef std::map<uint32, uint8> SpellElixirMap; +typedef std::map<uint32, uint16> SpellThreatMap; // Spell script target related declarations (accessed using SpellMgr functions) enum SpellScriptTargetType { SPELL_TARGET_TYPE_GAMEOBJECT = 0, SPELL_TARGET_TYPE_CREATURE = 1, - SPELL_TARGET_TYPE_DEAD = 2 + SPELL_TARGET_TYPE_DEAD = 2, + SPELL_TARGET_TYPE_CONTROLLED = 3, }; -#define MAX_SPELL_TARGET_TYPE 3 +#define MAX_SPELL_TARGET_TYPE 4 struct SpellTargetEntry { @@ -552,28 +571,24 @@ class PetAura auras.clear(); } - PetAura(uint16 petEntry, uint16 aura, bool _removeOnChangePet, int _damage) : + PetAura(uint32 petEntry, uint32 aura, bool _removeOnChangePet, int _damage) : removeOnChangePet(_removeOnChangePet), damage(_damage) { auras[petEntry] = aura; } - uint16 GetAura(uint16 petEntry) const + uint32 GetAura(uint32 petEntry) const { - std::map<uint16, uint16>::const_iterator itr = auras.find(petEntry); + std::map<uint32, uint32>::const_iterator itr = auras.find(petEntry); if(itr != auras.end()) return itr->second; - else - { - std::map<uint16, uint16>::const_iterator itr2 = auras.find(0); - if(itr2 != auras.end()) - return itr2->second; - else - return 0; - } + std::map<uint32, uint32>::const_iterator itr2 = auras.find(0); + if(itr2 != auras.end()) + return itr2->second; + return 0; } - void AddAura(uint16 petEntry, uint16 aura) + void AddAura(uint32 petEntry, uint32 aura) { auras[petEntry] = aura; } @@ -589,11 +604,11 @@ class PetAura } private: - std::map<uint16, uint16> auras; + std::map<uint32, uint32> auras; bool removeOnChangePet; int32 damage; }; -typedef std::map<uint16, PetAura> SpellPetAuraMap; +typedef std::map<uint32, PetAura> SpellPetAuraMap; struct SpellArea { @@ -688,7 +703,6 @@ inline bool IsProfessionSkill(uint32 skill) return IsPrimaryProfessionSkill(skill) || skill == SKILL_FISHING || skill == SKILL_COOKING || skill == SKILL_FIRST_AID; } -//#define SPELL_ATTR_CU_PLAYERS_ONLY 0x00000001 #define SPELL_ATTR_CU_CONE_BACK 0x00000002 #define SPELL_ATTR_CU_CONE_LINE 0x00000004 #define SPELL_ATTR_CU_SHARE_DAMAGE 0x00000008 @@ -704,7 +718,10 @@ inline bool IsProfessionSkill(uint32 skill) #define SPELL_ATTR_CU_LINK_REMOVE 0x00002000 #define SPELL_ATTR_CU_MOVEMENT_IMPAIR 0x00004000 #define SPELL_ATTR_CU_EXCLUDE_SELF 0x00008000 - +#define SPELL_ATTR_CU_NEGATIVE_EFF0 0x00010000 +#define SPELL_ATTR_CU_NEGATIVE_EFF1 0x00020000 +#define SPELL_ATTR_CU_NEGATIVE_EFF2 0x00040000 +#define SPELL_ATTR_CU_NEGATIVE 0x00070000 typedef std::vector<uint32> SpellCustomAttribute; typedef std::vector<bool> EnchantCustomAttribute; @@ -725,14 +742,6 @@ class SpellMgr // Accessors (const or static functions) public: - // Spell affects - flag96 const*GetSpellAffect(uint16 spellId, uint8 effectId) const - { - SpellAffectMap::const_iterator itr = mSpellAffectMap.find((spellId<<8) + effectId); - if( itr != mSpellAffectMap.end( ) ) - return &itr->second; - return 0; - } bool IsAffectedByMod(SpellEntry const *spellInfo, SpellModifier *mod) const; @@ -760,6 +769,15 @@ class SpellMgr return SPELL_NORMAL; } + uint16 GetSpellThreat(uint32 spellid) const + { + SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellid); + if(itr==mSpellThreatMap.end()) + return 0; + + return itr->second; + } + // Spell proc events SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const { @@ -769,7 +787,7 @@ class SpellMgr return NULL; } - bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra); + bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active); SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const { @@ -850,8 +868,6 @@ class SpellMgr SpellsRequiringSpellMap const& GetSpellsRequiringSpell() const { return mSpellsReqSpell; } - // Note: not use rank for compare to spell ranks: spell chains isn't linear order - // Use IsHighRankOfSpell instead uint8 GetSpellRank(uint32 spell_id) const { if(SpellChainNode const* node = GetSpellChainNode(spell_id)) @@ -965,9 +981,9 @@ class SpellMgr return mSkillLineAbilityMap.upper_bound(spell_id); } - PetAura const* GetPetAura(uint16 spell_id) + PetAura const* GetPetAura(uint32 spell_id, uint8 eff) { - SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find(spell_id); + SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find((spell_id<<8) + eff); if(itr != mSpellPetAuraMap.end()) return &itr->second; else @@ -1039,6 +1055,30 @@ class SpellMgr return SpellAreaForAreaMapBounds(mSpellAreaForAreaMap.lower_bound(area_id),mSpellAreaForAreaMap.upper_bound(area_id)); } + bool IsSrcTargetSpell(SpellEntry const *spellInfo) const; + + inline bool IsCasterSourceTarget(uint32 target) + { + switch (SpellTargetType[target]) + { + case TARGET_TYPE_UNIT_TARGET: + case TARGET_TYPE_DEST_TARGET: + return false; + default: + break; + } + return true; + } + + inline bool IsSpellWithCasterSourceTargetsOnly(SpellEntry const* spellInfo) + { + for(int i = 0; i < 3; ++i) + if(uint32 target = spellInfo->EffectImplicitTargetA[i]) + if(!IsCasterSourceTarget(target)) + return false; + return true; + } + // Modifiers public: static SpellMgr& Instance(); @@ -1049,7 +1089,6 @@ class SpellMgr void LoadSpellLearnSkills(); void LoadSpellLearnSpells(); void LoadSpellScriptTarget(); - void LoadSpellAffects(); void LoadSpellElixirs(); void LoadSpellProcEvents(); void LoadSpellBonusess(); @@ -1068,6 +1107,9 @@ class SpellMgr bool CheckDB() const; private: + bool _isPositiveSpell(uint32 spellId, bool deep) const; + bool _isPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) const; + SpellScriptTarget mSpellScriptTarget; SpellChainMap mSpellChains; SpellsRequiringSpellMap mSpellsReqSpell; @@ -1075,8 +1117,8 @@ class SpellMgr SpellLearnSkillMap mSpellLearnSkills; SpellLearnSpellMap mSpellLearnSpells; SpellTargetPositionMap mSpellTargetPositions; - SpellAffectMap mSpellAffectMap; SpellElixirMap mSpellElixirs; + SpellThreatMap mSpellThreatMap; SpellProcEventMap mSpellProcEventMap; SpellBonusMap mSpellBonusMap; SkillLineAbilityMap mSkillLineAbilityMap; diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp index bb7b1273ac0..36d88e065a6 100644 --- a/src/game/StatSystem.cpp +++ b/src/game/StatSystem.cpp @@ -881,10 +881,9 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType) float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); - //float base_value = GetModifierValue(unitMod, BASE_VALUE) - // + (weapon_mindamage + weapon_maxdamage) - // * GetTotalAttackPowerValue(attType) / (getLevel() * 30); - float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType); + /* difference in AP between current attack power and base value from DB */ + float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower; + float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f); float base_pct = GetModifierValue(unitMod, BASE_PCT); float total_value = GetModifierValue(unitMod, TOTAL_VALUE); float total_pct = GetModifierValue(unitMod, TOTAL_PCT); diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp index c40568318d4..c1c601921b3 100644 --- a/src/game/TargetedMovementGenerator.cpp +++ b/src/game/TargetedMovementGenerator.cpp @@ -53,7 +53,7 @@ template<class T> bool TargetedMovementGenerator<T>::_setTargetLocation(T &owner) { - if( !i_target.isValid() || !&owner ) + if (!i_target.isValid() || !i_target->IsInWorld()) return false; if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) ) @@ -170,7 +170,7 @@ template<class T> bool TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff) { - if(!i_target.isValid()) + if (!i_target.isValid() || !i_target->IsInWorld()) return false; if( !&owner || !owner.isAlive()) diff --git a/src/game/TaxiHandler.cpp b/src/game/TaxiHandler.cpp index 0928b8ba96a..5655bfd57bb 100644 --- a/src/game/TaxiHandler.cpp +++ b/src/game/TaxiHandler.cpp @@ -253,13 +253,11 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& /*recv_data*/) SendDoFlight( mountDisplayId, path, 1 ); // skip start fly node else GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next + return; } - GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node - GetPlayer()->Unmount(); - GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + GetPlayer()->CleanupAfterTaxiFlight(); GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); - GetPlayer()->getHostilRefManager().setOnlineOfflineState(true); if(GetPlayer()->pvpInfo.inHostileArea) GetPlayer()->CastSpell(GetPlayer(), 2479, true); } diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp index 724d68c568b..434750c8744 100644 --- a/src/game/TemporarySummon.cpp +++ b/src/game/TemporarySummon.cpp @@ -224,13 +224,18 @@ void TempSummon::SetTempSummonType(TempSummonType type) void TempSummon::UnSummon() { - assert(!isPet()); + //assert(!isPet()); + if(isPet()) + { + ((Pet*)this)->Remove(PET_SAVE_NOT_IN_SLOT); + assert(!IsInWorld()); + return; + } Unit* owner = GetSummoner(); if(owner && owner->GetTypeId() == TYPEID_UNIT && ((Creature*)owner)->IsAIEnabled) ((Creature*)owner)->AI()->SummonedCreatureDespawn(this); - CleanupsBeforeDelete(); AddObjectToRemoveList(); } @@ -266,6 +271,7 @@ Minion::Minion(SummonPropertiesEntry const *properties, Unit *owner) : TempSummo { assert(m_owner); m_summonMask |= SUMMON_MASK_MINION; + m_followAngle = PET_FOLLOW_ANGLE; } void Minion::InitStats(uint32 duration) @@ -287,7 +293,7 @@ void Minion::InitSummon() if(m_owner->GetTypeId() == TYPEID_PLAYER && m_owner->GetMinionGUID() == GetGUID() && !m_owner->GetCharmGUID()) - ((Player*)m_owner)->CharmSpellInitialize(); + ((Player*)m_owner)->CharmSpellInitialize(); } void Minion::RemoveFromWorld() @@ -303,7 +309,11 @@ Guardian::Guardian(SummonPropertiesEntry const *properties, Unit *owner) : Minio , m_bonusdamage(0) { m_summonMask |= SUMMON_MASK_GUARDIAN; - InitCharmInfo(); + if (properties && properties->Type == SUMMON_TYPE_PET) + { + m_summonMask |= SUMMON_MASK_CONTROLABLE_GUARDIAN; + InitCharmInfo(); + } } void Guardian::InitStats(uint32 duration) @@ -312,7 +322,7 @@ void Guardian::InitStats(uint32 duration) InitStatsForLevel(m_owner->getLevel()); - if(m_owner->GetTypeId() == TYPEID_PLAYER) + if(m_owner->GetTypeId() == TYPEID_PLAYER && HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN)) m_charmInfo->InitCharmCreateSpells(); SetReactState(REACT_AGGRESSIVE); @@ -335,7 +345,8 @@ void Puppet::InitStats(uint32 duration) void Puppet::InitSummon() { Minion::InitSummon(); - SetCharmedBy(m_owner, CHARM_TYPE_POSSESS); + if (!SetCharmedBy(m_owner, CHARM_TYPE_POSSESS)) + assert(false); } void Puppet::Update(uint32 time) diff --git a/src/game/TemporarySummon.h b/src/game/TemporarySummon.h index 47961d714ec..aa4650a02c9 100644 --- a/src/game/TemporarySummon.h +++ b/src/game/TemporarySummon.h @@ -54,9 +54,12 @@ class Minion : public TempSummon void InitSummon(); void RemoveFromWorld(); Unit *GetOwner() { return m_owner; } + float GetFollowAngle() const { return m_followAngle; } + void SetFollowAngle(float angle) { m_followAngle = angle; } bool IsPetGhoul() const {return GetEntry() == 26125;} // Ghoul may be guardian or pet protected: Unit * const m_owner; + float m_followAngle; }; class Guardian : public Minion diff --git a/src/game/ThreatManager.cpp b/src/game/ThreatManager.cpp index a0459aa81dc..60c46c2307d 100644 --- a/src/game/ThreatManager.cpp +++ b/src/game/ThreatManager.cpp @@ -34,11 +34,9 @@ // The pHatingUnit is not used yet float ThreatCalcHelper::calcThreat(Unit* pHatedUnit, Unit* pHatingUnit, float pThreat, SpellSchoolMask schoolMask, SpellEntry const *pThreatSpell) { - if(pThreatSpell) - { - if( Player* modOwner = pHatingUnit->GetSpellModOwner() ) + if (pThreatSpell) + if (Player* modOwner = pHatedUnit->GetSpellModOwner()) modOwner->ApplySpellMod(pThreatSpell->Id, SPELLMOD_THREAT, pThreat); - } float threat = pHatedUnit->ApplyTotalThreatModifier(pThreat, schoolMask); return threat; @@ -346,7 +344,7 @@ HostilReference* ThreatContainer::selectNextVictim(Creature* pAttacker, HostilRe //=================== ThreatManager ========================== //============================================================ -ThreatManager::ThreatManager(Unit* owner) : iCurrentVictim(NULL), iOwner(owner) +ThreatManager::ThreatManager(Unit* owner) : iCurrentVictim(NULL), iOwner(owner), iUpdateTimer(THREAT_UPDATE_INTERVAL) { } @@ -357,6 +355,7 @@ void ThreatManager::clearReferences() iThreatContainer.clearReferences(); iThreatOfflineContainer.clearReferences(); iCurrentVictim = NULL; + iUpdateTimer = THREAT_UPDATE_INTERVAL; } //============================================================ @@ -470,6 +469,10 @@ void ThreatManager::tauntFadeOut(Unit *pTaunter) void ThreatManager::setCurrentVictim(HostilReference* pHostilReference) { + if (pHostilReference && pHostilReference != iCurrentVictim) + { + iOwner->SendChangeCurrentVictimOpcode(pHostilReference); + } iCurrentVictim = pHostilReference; } @@ -515,6 +518,7 @@ void ThreatManager::processThreatEvent(ThreatRefStatusChangeEvent* threatRefStat setCurrentVictim(NULL); setDirty(true); } + iOwner->SendRemoveFromThreatListOpcode(hostilReference); if(hostilReference->isOnline()) iThreatContainer.remove(hostilReference); else @@ -523,3 +527,16 @@ void ThreatManager::processThreatEvent(ThreatRefStatusChangeEvent* threatRefStat } } +bool ThreatManager::isNeedUpdateToClient(uint32 time) +{ + if (isThreatListEmpty()) + return false; + if (time >= iUpdateTimer) + { + iUpdateTimer = THREAT_UPDATE_INTERVAL; + return true; + } + iUpdateTimer -= time; + return false; +} + diff --git a/src/game/ThreatManager.h b/src/game/ThreatManager.h index aa84cb7d52c..1dba6277cfc 100644 --- a/src/game/ThreatManager.h +++ b/src/game/ThreatManager.h @@ -35,6 +35,8 @@ class Creature; class ThreatManager; struct SpellEntry; +#define THREAT_UPDATE_INTERVAL 1 * IN_MILISECONDS // Server should send threat update to client periodically each second + //============================================================== // Class to calculate the real threat based @@ -187,6 +189,8 @@ class TRINITY_DLL_SPEC ThreatManager void processThreatEvent(ThreatRefStatusChangeEvent* threatRefStatusChangeEvent); + bool isNeedUpdateToClient(uint32 time); + HostilReference* getCurrentVictim() { return iCurrentVictim; } Unit* getOwner() { return iOwner; } @@ -211,6 +215,7 @@ class TRINITY_DLL_SPEC ThreatManager HostilReference* iCurrentVictim; Unit* iOwner; + uint32 iUpdateTimer; ThreatContainer iThreatContainer; ThreatContainer iThreatOfflineContainer; }; diff --git a/src/game/Totem.cpp b/src/game/Totem.cpp index 67fa0281d91..d35ba9e30b9 100644 --- a/src/game/Totem.cpp +++ b/src/game/Totem.cpp @@ -57,9 +57,9 @@ void Totem::InitStats(uint32 duration) Minion::InitStats(duration); CreatureInfo const *cinfo = GetCreatureInfo(); - if (m_owner->GetTypeId()==TYPEID_PLAYER && cinfo) + if(m_owner->GetTypeId() == TYPEID_PLAYER && cinfo) { - uint32 display_id = objmgr.ChooseDisplayId(((Player*)m_owner)->GetTeam(),cinfo); + uint32 display_id = objmgr.ChooseDisplayId(((Player*)m_owner)->GetTeam(), cinfo); CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id); if (minfo) display_id = minfo->modelid; @@ -91,6 +91,9 @@ void Totem::InitSummon() if(m_type == TOTEM_PASSIVE) CastSpell(this, GetSpell(), true); + // Some totems can have both instant effect and passive spell + if (GetSpell(1)) + CastSpell(this, GetSpell(1), true); } void Totem::UnSummon() @@ -129,13 +132,12 @@ void Totem::UnSummon() } } - CleanupsBeforeDelete(); AddObjectToRemoveList(); } bool Totem::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) const { - // TODO: possibly all negative auras immuned? + // TODO: possibly all negative auras immune? switch(spellInfo->EffectApplyAuraName[index]) { case SPELL_AURA_PERIODIC_DAMAGE: @@ -148,4 +150,3 @@ bool Totem::IsImmunedToSpellEffect(SpellEntry const* spellInfo, uint32 index) co } return Creature::IsImmunedToSpellEffect(spellInfo, index); } - diff --git a/src/game/Totem.h b/src/game/Totem.h index 134ca6d6d3f..9975cd4deae 100644 --- a/src/game/Totem.h +++ b/src/game/Totem.h @@ -40,7 +40,7 @@ class Totem : public Minion void InitStats(uint32 duration); void InitSummon(); void UnSummon(); - uint32 GetSpell() const { return m_spells[0]; } + uint32 GetSpell(uint8 slot=0) const { return m_spells[slot]; } uint32 GetTotemDuration() const { return m_duration; } TotemType GetTotemType() const { return m_type; } diff --git a/src/game/Transports.cpp b/src/game/Transports.cpp index 11089f053d1..25248b7b9d2 100644 --- a/src/game/Transports.cpp +++ b/src/game/Transports.cpp @@ -106,8 +106,9 @@ void MapManager::LoadTransports() m_TransportsByMap[*i].insert(t); //If we someday decide to use the grid to track transports, here: - //MapManager::Instance().LoadGrid(mapid,x,y,true); - //MapManager::Instance().GetMap(t->GetMapId())->Add<GameObject>((GameObject *)t); + t->SetMap(MapManager::Instance().CreateMap(mapid, t, 0)); + + //t->GetMap()->Add<GameObject>((GameObject *)t); ++count; } while(result->NextRow()); delete result; @@ -142,8 +143,6 @@ Transport::Transport() : GameObject() bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags) { Relocate(x,y,z,ang); - - SetMapId(mapid); // instance id and phaseMask isn't set to values different from std. if(!IsPositionValid()) @@ -439,7 +438,6 @@ Transport::WayPointMap::const_iterator Transport::GetNextWayPoint() void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) { Map const* oldMap = GetMap(); - SetMapId(newMapid); Relocate(x, y, z); for(PlayerSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end();) @@ -458,7 +456,15 @@ void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) //plr->GetSession()->SendPacket(&data); } - Map const* newMap = GetMap(); + //we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference... + //player far teleport would try to create same instance, but we need it NOW for transport... + //correct me if I'm wrong O.o + //yes, you're right + + ResetMap(); + Map * newMap = MapManager::Instance().CreateMap(newMapid, this, 0); + SetMap(newMap); + assert (GetMap()); if(oldMap != newMap) { @@ -485,7 +491,7 @@ void Transport::CheckForEvent(uint32 entry, uint32 wp_id) { uint32 key = entry*100+wp_id; if(objmgr.TransportEventMap.find(key) != objmgr.TransportEventMap.end()) - sWorld.ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL); + GetMap()->ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL); } void Transport::Update(uint32 /*p_time*/) diff --git a/src/game/Transports.h b/src/game/Transports.h index d72fa3b2124..e05a6006971 100644 --- a/src/game/Transports.h +++ b/src/game/Transports.h @@ -56,24 +56,11 @@ class TransportPath std::vector<PathNode> i_nodes; }; -class Transport : protected GameObject +class Transport : public GameObject { public: explicit Transport(); - // prevent using Transports as normal GO, but allow call some inherited functions - using GameObject::IsTransport; - using GameObject::GetEntry; - using GameObject::GetGUID; - using GameObject::GetGUIDLow; - using GameObject::GetMapId; - using GameObject::GetPositionX; - using GameObject::GetPositionY; - using GameObject::GetPositionZ; - using GameObject::BuildCreateUpdateBlockForPlayer; - using GameObject::BuildOutOfRangeUpdateBlock; - using GameObject::GetPackGUID; - bool Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags); bool GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids); void Update(uint32 p_time); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index e107eb90f55..74eda6482d0 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -60,7 +60,7 @@ float baseMoveSpeed[MAX_MOVE_TYPE] = { 2.5f, // MOVE_WALK 7.0f, // MOVE_RUN - 1.25f, // MOVE_RUN_BACK + 3.0f, // MOVE_RUN_BACK 4.722222f, // MOVE_SWIM 4.5f, // MOVE_SWIM_BACK 3.141594f, // MOVE_TURN_RATE @@ -211,13 +211,20 @@ void Unit::Update( uint32 p_time ) m_Events.Update( p_time ); _UpdateSpells( p_time ); - // update combat timer only for players and pets - if (isInCombat() && IsControlledByPlayer()) + // If this is set during update SetCantProc(false) call is missing somewhere in the code + // Having this would prevent spells from being proced, so let's crash + assert(!m_procDeep); + + if (CanHaveThreatList() && getThreatManager().isNeedUpdateToClient(p_time)) + SendThreatListUpdate(); + + // update combat timer only for players and pets (only pets with PetAI) + if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || (((Creature *)this)->isPet() && IsControlledByPlayer()))) { // Check UNIT_STAT_MELEE_ATTACKING or UNIT_STAT_CHASE (without UNIT_STAT_FOLLOW in this case) so pets can reach far away // targets without stopping half way there and running off. // These flags are reset after target dies or another command is given. - if( m_HostilRefManager.isEmpty() ) + if( m_HostilRefManager.isEmpty()) { // m_CombatTimer set at aura start and it will be freeze until aura removing if ( m_CombatTimer <= p_time ) @@ -546,6 +553,22 @@ void Unit::RemoveAurasWithFamily(uint32 family, uint32 familyFlag1, uint32 famil } } +void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, uint32 except) +{ + for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) + { + if (!except || iter->second->GetId() != except) + { + if(GetAllSpellMechanicMask(iter->second->GetSpellProto()) & mechanic_mask) + { + RemoveAura(iter, AURA_REMOVE_BY_ENEMY_SPELL); + continue; + } + } + ++iter; + } +} + void Unit::UpdateInterruptMask() { m_interruptMask = 0; @@ -570,29 +593,6 @@ bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint return false; } -/* Called by DealDamage for auras that have a chance to be dispelled on damage taken. */ -void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell) -{ - // The chance to dispel an aura depends on the damage taken with respect to the casters level. - uint32 max_dmg = getLevel() > 8 ? 25 * getLevel() - 150 : 50; - float chance = float(damage) / max_dmg * 100.0f; - - std::queue < std::pair < uint32, uint64 > > remove_list; - - for (AuraList::iterator iter = m_ccAuras.begin(); iter != m_ccAuras.end();++iter) - { - if((!spell || (*iter)->GetId() != spell) && roll_chance_f(chance)) - { - remove_list.push(std::make_pair((*iter)->GetId(), (*iter)->GetCasterGUID() ) ); - } - } - - for(;remove_list.size();remove_list.pop()) - { - RemoveAura(remove_list.front().first, remove_list.front().second, AURA_REMOVE_BY_ENEMY_SPELL); - } -} - void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb) { if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) @@ -605,10 +605,10 @@ void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb) //You don't lose health from damage taken from another player while in a sanctuary //You still see it in the combat log though - if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer()) { const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); - if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary + if(area && area->IsSanctuary()) //sanctuary { if(absorb) absorb += damage; @@ -639,14 +639,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa { // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras) pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto ? spellProto->Id : 0); - pVictim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0); } if(!damage) { - // Rage from physical damage received . - if(cleanDamage && cleanDamage->damage && (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) && pVictim->GetTypeId() == TYPEID_PLAYER && (pVictim->getPowerType() == POWER_RAGE)) - ((Player*)pVictim)->RewardRage(cleanDamage->damage, 0, false); + // Rage from absorbed damage + if(cleanDamage && cleanDamage->absorbed_damage && pVictim->getPowerType() == POWER_RAGE) + pVictim->RewardRage(cleanDamage->absorbed_damage, 0, false); return 0; } @@ -666,7 +665,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa // some critters required for quests if(GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->KilledMonster(pVictim->GetEntry(),pVictim->GetGUID()); + ((Player*)this)->KilledMonster(cInfo ,pVictim->GetGUID()); } else pVictim->ModifyHealth(- (int32)damage); @@ -691,9 +690,10 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa } // Rage from Damage made (only from direct weapon damage) - if( cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && GetTypeId() == TYPEID_PLAYER && (getPowerType() == POWER_RAGE)) + if(cleanDamage && damagetype==DIRECT_DAMAGE && this != pVictim && getPowerType() == POWER_RAGE) { uint32 weaponSpeedHitFactor; + uint32 rage_damage = damage + cleanDamage->absorbed_damage; switch(cleanDamage->attackType) { @@ -704,7 +704,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa else weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 3.5f); - ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); + RewardRage(rage_damage, weaponSpeedHitFactor, true); break; } @@ -715,7 +715,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa else weaponSpeedHitFactor = uint32(GetAttackTime(cleanDamage->attackType)/1000.0f * 1.75f); - ((Player*)this)->RewardRage(damage, weaponSpeedHitFactor, true); + RewardRage(rage_damage, weaponSpeedHitFactor, true); break; } @@ -865,7 +865,11 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa if(!cVictim->isPet()) { cVictim->DeleteThreatList(); - cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + // only lootable if it has loot or can drop gold + if(cVictim->GetCreatureInfo()->lootid || cVictim->GetCreatureInfo()->maxgold > 0) + cVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + else + cVictim->lootForBody = true; // needed for skinning } // Call creature just died function if (cVictim->AI()) @@ -949,13 +953,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa } else // victim is a player { - // Rage from damage received - if(this != pVictim && pVictim->getPowerType() == POWER_RAGE) - { - uint32 rage_damage = damage + (cleanDamage ? cleanDamage->damage : 0); - ((Player*)pVictim)->RewardRage(rage_damage, 0, false); - } - // random durability for items (HIT TAKEN) if (roll_chance_f(sWorld.getRate(RATE_DURABILITY_LOSS_DAMAGE))) { @@ -964,6 +961,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa } } + // Rage from damage received + if(this != pVictim && pVictim->getPowerType() == POWER_RAGE) + { + uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0); + pVictim->RewardRage(rage_damage, 0, false); + } + if(GetTypeId()==TYPEID_PLAYER) { // random durability for items (HIT DONE) @@ -1200,7 +1204,7 @@ void Unit::CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* } // used for scripting -void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster) +void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster, Unit* OriginalVictim) { SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); @@ -1220,6 +1224,8 @@ void Unit::CastSpell(float x, float y, float z, uint32 spellId, bool triggered, SpellCastTargets targets; targets.setDestination(x, y, z); + if(OriginalVictim) + targets.setUnitTarget(OriginalVictim); spell->m_CastItem = castItem; spell->prepare(&targets, triggeredByAura); } @@ -1276,6 +1282,9 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama if (damage < 0) return; + if(spellInfo->AttributesEx4 & SPELL_ATTR_EX4_FIXED_DAMAGE) + return; + Unit *pVictim = damageInfo->target; if(!pVictim || !pVictim->isAlive()) return; @@ -1380,7 +1389,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) Unit *pVictim = damageInfo->target; - if(!this || !pVictim) + if(!pVictim) return; if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) @@ -1395,15 +1404,15 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss) //You don't lose health from damage taken from another player while in a sanctuary //You still see it in the combat log though - if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer()) { const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); - if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary + if(area && area->IsSanctuary()) // sanctuary return; } // Call default DealDamage - CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL); + CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL); DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); } @@ -1427,7 +1436,7 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da damageInfo->procEx = PROC_EX_NONE; damageInfo->hitOutCome = MELEE_HIT_EVADE; - if(!this || !pVictim) + if(!pVictim) return; if(!this->isAlive() || !pVictim->isAlive()) return; @@ -1436,12 +1445,12 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da switch (attackType) { case BASE_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT; + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT; damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT; damageInfo->HitInfo = HITINFO_NORMALSWING2; break; case OFF_ATTACK: - damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT; + damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT; damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used damageInfo->HitInfo = HITINFO_LEFTSWING; break; @@ -1623,7 +1632,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) if (damageInfo==0) return; Unit *pVictim = damageInfo->target; - if(!this || !pVictim) + if(!pVictim) return; if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) @@ -1631,10 +1640,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) //You don't lose health from damage taken from another player while in a sanctuary //You still see it in the combat log though - if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + if(pVictim != this && IsControlledByPlayer() && pVictim->IsControlledByPlayer()) { const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); - if(area && area->flags & AREA_FLAG_SANCTUARY) // sanctuary + if(area && area->IsSanctuary()) // sanctuary return; } @@ -1681,7 +1690,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) } // Call default DealDamage - CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome); + CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->absorb,damageInfo->attackType,damageInfo->hitOutCome); DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss); // If this is a creature and it attacks from behind it has a probability to daze it's victim @@ -1709,34 +1718,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) CastSpell(pVictim, 1604, true); } - if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive()) - { - for(uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) - { - // If usable, try to cast item spell - if (Item * item = ((Player*)this)->GetUseableItemByPos(INVENTORY_SLOT_BAG_0,i)) - if(!item->IsBroken()) - if (ItemPrototype const *proto = item->GetProto()) - { - // Additional check for weapons - if (proto->Class==ITEM_CLASS_WEAPON) - { - // offhand item cannot proc from main hand hit etc - EquipmentSlots slot; - switch (damageInfo->attackType) - { - case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break; - case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break; - case RANGED_ATTACK: slot = EQUIPMENT_SLOT_RANGED; break; - default: slot = EQUIPMENT_SLOT_END; break; - } - if (slot != i) - continue; - } - ((Player*)this)->CastItemCombatSpell(item, damageInfo, proto); - } - } - } + if(GetTypeId() == TYPEID_PLAYER) + ((Player *)this)->CastItemCombatSpell(pVictim, damageInfo->attackType, damageInfo->procVictim, damageInfo->procEx); // Do effect if any damage done to target if (damageInfo->damage) @@ -1903,6 +1886,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe // Reflect damage spells (not cast any damage spell in aura lookup) uint32 reflectSpell = 0; int32 reflectDamage = 0; + AuraEffect* reflectTriggeredBy = NULL; // expected as not expired at reflect as in current cases uint32 healSpell = 0; int32 healAmount = 0; Unit * healCaster = NULL; @@ -1968,6 +1952,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe else reflectDamage = currentAbsorb / 2; reflectSpell = 33619; + reflectTriggeredBy = *i; break; } if (spellProto->Id == 39228 || // Argussian Compass @@ -2037,13 +2022,13 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe { case 5065: // Rank 1 case 5064: // Rank 2 - case 5063: // Rank 3 { if(RemainingDamage >= currentAbsorb) reflectDamage = (*k)->GetAmount() * currentAbsorb/100; else reflectDamage = (*k)->GetAmount() * RemainingDamage/100; reflectSpell = 33619; + reflectTriggeredBy = *i; } break; } } @@ -2064,9 +2049,20 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe } case SPELLFAMILY_DEATHKNIGHT: { - // Shadow of Death - if (spellProto->Id == 49157) + // Unbreakable Armor + if (spellProto->Id == 51271) { + Unit* caster = (*i)->GetCaster(); + if (!caster) + continue; + + uint32 absorbed = uint32( currentAbsorb * caster->GetArmor() * 0.01f ); + + // Glyph of Unbreakable Armor + if (AuraEffect *aurEff = caster->GetAuraEffect(58635, 0)) + absorbed += uint32( absorbed * aurEff->GetAmount() / 100 ); + + RemainingDamage -= absorbed; continue; } // Anti-Magic Shell (on self) @@ -2146,7 +2142,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe // Cast back reflect damage spell if (reflectSpell) - pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true); + pVictim->CastCustomSpell(this, reflectSpell, &reflectDamage, NULL, NULL, true, NULL, reflectTriggeredBy); // absorb by mana cost AuraEffectList const& vManaShield = pVictim->GetAurasByType(SPELL_AURA_MANA_SHIELD); @@ -2217,7 +2213,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false); - CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); + CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); } @@ -2244,7 +2240,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false); - CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); + CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL); DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); } } @@ -2364,6 +2360,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex // Send log damage message to client DealDamageMods(pVictim,damageInfo.damage,&damageInfo.absorb); SendAttackStateUpdate(&damageInfo); + ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType); DealMeleeDamage(&damageInfo,true); @@ -2795,6 +2792,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) bool canDodge = true; bool canParry = true; + bool canBlock = spell->AttributesEx3 & SPELL_ATTR_EX3_BLOCKABLE_SPELL; // Same spells cannot be parry/dodge if (spell->Attributes & SPELL_ATTR_IMPOSSIBLE_DODGE_PARRY_BLOCK) @@ -2805,11 +2803,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) tmp += resist_chance; if (roll < tmp) return SPELL_MISS_RESIST; - - // Ranged attack cannot be parry/dodge only deflect - // Check damage class instead of attack type to correctly handle judgements - // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class - if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED) + + // Ranged attacks can only miss, resist and deflect + if (attType == RANGED_ATTACK) { // only if in front if (pVictim->HasInArc(M_PI,this)) @@ -2826,10 +2822,11 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) if (!pVictim->HasInArc(M_PI,this)) { // Can`t dodge from behind in PvP (but its possible in PvE) - if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + if (pVictim->GetTypeId() == TYPEID_PLAYER) canDodge = false; - // Can`t parry + // Can`t parry or block canParry = false; + canBlock = false; } // Check creatures flags_extra for disable parry if(pVictim->GetTypeId()==TYPEID_UNIT) @@ -2837,6 +2834,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) uint32 flagEx = ((Creature*)pVictim)->GetCreatureInfo()->flags_extra; if( flagEx & CREATURE_FLAG_EXTRA_NO_PARRY ) canParry = false; + // Check creatures flags_extra for disable block + if( flagEx & CREATURE_FLAG_EXTRA_NO_BLOCK ) + canBlock = false; } // Ignore combat result aura AuraEffectList const& ignore = GetAurasByType(SPELL_AURA_IGNORE_COMBAT_RESULT); @@ -2847,7 +2847,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) switch((*i)->GetMiscValue()) { case MELEE_HIT_DODGE: canDodge = false; break; - case MELEE_HIT_BLOCK: break; // Block check in hit step + case MELEE_HIT_BLOCK: canBlock = false; break; case MELEE_HIT_PARRY: canParry = false; break; default: DEBUG_LOG("Spell %u SPELL_AURA_IGNORE_COMBAT_RESULT have unhandled state %d", (*i)->GetId(), (*i)->GetMiscValue()); @@ -2888,6 +2888,17 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) return SPELL_MISS_PARRY; } + if (canBlock) + { + int32 blockChance = int32(pVictim->GetUnitBlockChance()*100.0f) - skillDiff * 4; + if ( blockChance < 0 ) + blockChance = 0; + tmp += blockChance; + + if (roll < tmp) + return SPELL_MISS_BLOCK; + } + return SPELL_MISS_NONE; } @@ -3002,7 +3013,7 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool if (reflectchance > 0 && roll_chance_i(reflectchance)) { // Start triggers for remove charges if need (trigger only for victim, and mark as active spell) - ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 0, BASE_ATTACK, spell); + ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL, PROC_EX_REFLECT , 1, BASE_ATTACK, spell); return SPELL_MISS_REFLECT; } } @@ -3491,8 +3502,8 @@ void Unit::InterruptSpell(uint32 spellType, bool withDelayed, bool withInstant) // send autorepeat cancel message for autorepeat spells if (spellType == CURRENT_AUTOREPEAT_SPELL) { - if(GetTypeId()==TYPEID_PLAYER) - ((Player*)this)->SendAutoRepeatCancel(); + if(GetTypeId() == TYPEID_PLAYER) + ((Player*)this)->SendAutoRepeatCancel(this); } if (spell->getState() != SPELL_STATE_FINISHED) @@ -3510,15 +3521,17 @@ bool Unit::IsNonMeleeSpellCasted(bool withDelayed, bool skipChanneled, bool skip if ( m_currentSpells[CURRENT_GENERIC_SPELL] && (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) + { if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT)) return(true); - + } // channeled spells may be delayed, but they are still considered casted else 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_ATTR_EX2_NOT_RESET_AUTOSHOT)) return(true); - + } // autorepeat spells may be finished or delayed, but they are still considered casted else if ( !skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL] ) return(true); @@ -3549,6 +3562,13 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const return NULL; } +int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const +{ + if (Spell const * spell = FindCurrentSpellBySpellId(spell_id)) + return spell->GetCastTime(); + return 0; +} + bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const { return IsWithinDistInMap(target, distance) && HasInArc( arc, target ); @@ -3779,8 +3799,11 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects) return false; } + SpellEntry const* aurSpellInfo = Aur->GetSpellProto(); + // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load) - if( !isAlive() && Aur->GetId() != 20584 && Aur->GetId() != 8326 && Aur->GetId() != 2584 && + if( !isAlive() && !IsDeathPersistentSpell(aurSpellInfo) && + //Aur->GetId() != 2584 && // Waiting to Resurrect (not have death persistence flag) (GetTypeId()!=TYPEID_PLAYER || !((Player*)this)->GetSession()->PlayerLoading()) ) { delete Aur; @@ -3796,7 +3819,6 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects) return false; } - SpellEntry const* aurSpellInfo = Aur->GetSpellProto(); uint32 aurId = aurSpellInfo->Id; // passive and persistent and Incanter's Absorption auras can stack with themselves any number of times @@ -3890,6 +3912,16 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects) // add aura, register in lists and arrays Aur->_AddAura(); + + //***************************************************** + // Update target aura state flag + //***************************************************** + if(AuraState aState = GetSpellAuraState(Aur->GetSpellProto())) + { + m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, Aur)); + ModifyAuraState(aState, true); + } + m_Auras.insert(AuraMap::value_type(aurId, Aur)); if(aurSpellInfo->AuraInterruptFlags) @@ -3897,12 +3929,6 @@ bool Unit::AddAura(Aura *Aur, bool handleEffects) m_interruptableAuras.push_back(Aur); AddInterruptMask(aurSpellInfo->AuraInterruptFlags); } - if((aurSpellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE - && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable - || ((GetAllSpellMechanicMask(aurSpellInfo) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN))) - { - m_ccAuras.push_back(Aur); - } if (handleEffects) Aur->HandleEffects(true); @@ -4173,13 +4199,24 @@ void Unit::RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell) } } -void Unit::RemoveNotOwnSingleTargetAuras() +void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase) { // single target auras from other casters for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); ) { if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto())) - RemoveAura(iter); + { + if(!newPhase) + RemoveAura(iter); + else + { + Unit* caster = iter->second->GetCaster(); + if(!caster || !caster->InSamePhase(newPhase)) + RemoveAura(iter); + else + ++iter; + } + } else ++iter; } @@ -4188,12 +4225,12 @@ void Unit::RemoveNotOwnSingleTargetAuras() AuraList& scAuras = GetSingleCastAuras(); for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();) { - Aura * aur=*iter; + Aura * aura=*iter; ++iter; - if (aur->GetTarget()!=this) + if (aura->GetTarget() != this && !aura->GetTarget()->InSamePhase(newPhase)) { uint32 removedAuras = m_removedAurasCount; - aur->GetTarget()->RemoveAura(aur->GetId(),aur->GetCasterGUID()); + aura->GetTarget()->RemoveAura(aura->GetId(),aura->GetCasterGUID()); if (removedAuras+1<m_removedAurasCount) iter=scAuras.begin(); } @@ -4217,13 +4254,6 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) UpdateInterruptMask(); } - if((Aur->GetSpellProto()->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE - && !Aur->IsAuraType(SPELL_AURA_MOD_POSSESS)) //only dummy aura is breakable - || ((GetAllSpellMechanicMask(Aur->GetSpellProto()) & 1<<MECHANIC_KNOCKOUT) && Aur->IsAuraType(SPELL_AURA_MOD_STUN))) - { - m_ccAuras.remove(Aur); - } - Aur->SetRemoveMode(mode); sLog.outDebug("Aura %u now is remove mode %d", Aur->GetId(), mode); @@ -4234,8 +4264,30 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) Aur->_RemoveAura(); + bool auraStateFound = false; + if (AuraState auraState = GetSpellAuraState(Aur->GetSpellProto())) + { + bool canBreak = false; + // Get mask of all aurastates from remaining auras + for(AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);) + { + if (itr->second == Aur) + { + m_auraStateAuras.erase(itr); + itr = m_auraStateAuras.lower_bound(auraState); + canBreak = true; + continue; + } + auraStateFound = true; + ++itr; + } + // Remove only aurastates which were not found + if (!auraStateFound) + ModifyAuraState(auraState, false); + } + // Remove totem at next update if totem looses its aura - if (GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()&& ((TempSummon*)this)->GetSummonerGUID()==Aur->GetCasterGUID()) + if (Aur->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()&& ((TempSummon*)this)->GetSummonerGUID()==Aur->GetCasterGUID()) { if (((Totem*)this)->GetSpell()==Aur->GetId() && ((Totem*)this)->GetTotemType()==TOTEM_PASSIVE) ((Totem*)this)->setDeathState(JUST_DIED); @@ -4401,6 +4453,18 @@ AuraEffect* Unit::GetAura(AuraType type, uint32 family, uint32 familyFlag1, uint return NULL; } +AuraEffect * Unit::IsScriptOverriden(SpellEntry const * spell, int32 script) const +{ + AuraEffectList const& auras = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); + for(AuraEffectList::const_iterator i = auras.begin();i != auras.end(); ++i) + { + if ((*i)->GetMiscValue() == script) + if ((*i)->isAffectedOnSpell(spell)) + return (*i); + } + return NULL; +} + uint32 Unit::GetDiseasesByCaster(uint64 casterGUID, bool remove) { static const AuraType diseaseAuraTypes[] = @@ -4685,13 +4749,13 @@ void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo) data << uint32(GetSpellSchoolMask(aura->GetSpellProto())); data << uint32(pInfo->absorb); // absorb data << uint32(pInfo->resist); // resist - data << uint8(0); // new 3.1.2 + data << uint8(pInfo->critical); // new 3.1.2 critical tick break; case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_OBS_MOD_HEALTH: data << uint32(pInfo->damage); // damage data << uint32(pInfo->overDamage); // overheal? - data << uint8(0); // new 3.1.2 + data << uint8(pInfo->critical); // new 3.1.2 critical tick break; case SPELL_AURA_OBS_MOD_ENERGY: case SPELL_AURA_PERIODIC_ENERGIZE: @@ -4827,7 +4891,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger case 33735: { target = SelectNearbyTarget(); - if(!target) + if(!target || target == pVictim) return false; basepoints0 = damage; triggered_spell_id = 22482; @@ -4851,7 +4915,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } // default case - if(!target || target!=this && !target->isAlive()) + if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive())) return false; if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) @@ -4880,6 +4944,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger uint32 triggered_spell_id = 0; Unit* target = pVictim; int32 basepoints0 = 0; + uint64 originalCaster = 0; // Master of subtlety (checked here because ranks have different spellfamilynames) if (dummySpell->Id == 31223 || dummySpell->Id == 31221 || dummySpell->Id == 31222) @@ -4898,6 +4963,18 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger { switch (dummySpell->Id) { + // BloodWorms Health Leech + case 50453: + { + if (Unit *owner = this->GetOwner()) + { + basepoints0 = int32(damage*1.50); + target = owner; + triggered_spell_id = 50454; + break; + } + return false; + } // Improved Divine Spirit case 33174: case 33182: @@ -4939,14 +5016,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger break; } // Sweeping Strikes - case 12328: case 18765: case 35429: { - // prevent chain of triggered spell from same triggered spell - if(procSpell && procSpell->Id==26654) - return false; - target = SelectNearbyTarget(); if(!target) return false; @@ -5411,11 +5483,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } switch(dummySpell->Id) { + // Glyph of Polymorph + case 56375: + { + target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE); + target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); + return true; + } // Glyph of Icy Veins case 56374: + { RemoveAurasByType(SPELL_AURA_MOD_HASTE, 0, 0, true, false); RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); - return true; + return true; + } // Ignite case 11119: case 11120: @@ -5474,6 +5555,28 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } case SPELLFAMILY_WARRIOR: { + switch(dummySpell->Id) + { + // Sweeping Strikes + case 12328: + { + target = SelectNearbyTarget(); + if(!target) + return false; + + triggered_spell_id = 26654; + break; + } + // Improved Spell Reflection + case 59088: + case 59089: + { + triggered_spell_id = 59725; + target = this; + break; + } + } + // Retaliation if(dummySpell->SpellFamilyFlags.IsEqual(0, 0x8, 0)) { @@ -5484,14 +5587,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 22858; break; } - // Improved Spell Reflection - if(dummySpell->Id==59088 - || dummySpell->Id==59089) - { - triggered_spell_id = 59725; - target = this; - break; - } // Second Wind if (dummySpell->SpellIconID == 1697) { @@ -5613,6 +5708,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger { if ((*i)->GetId()==54117 || (*i)->GetId()==54118) { + if ((*i)->GetEffIndex() != 0) + continue; basepoints0 = int32((*i)->GetAmount()); if (target = GetGuardianPet()) { @@ -5621,6 +5718,15 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } // regen mana for caster CastCustomSpell(this,59117,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + // Get second aura of spell for replenishment effect on party + if (AuraEffect const * aurEff = (*i)->GetParentAura()->GetPartAura(1)) + { + // Replenishment - roll chance + if (roll_chance_i(aurEff->GetAmount())) + { + CastSpell(this,57669,true, castItem, triggeredByAura); + } + } break; } } @@ -5806,22 +5912,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } break; } - // Psychic Horror - case 47571: - { - if(!pVictim || !pVictim->isAlive()) - return false; - pVictim->CastSpell(pVictim, 59980,true, castItem, triggeredByAura); - return true; - } - // Psychic Horror (Rank 2) - case 47572: - { - if(!pVictim || !pVictim->isAlive()) - return false; - pVictim->CastSpell(pVictim, 59981,true, castItem, triggeredByAura); - return true; - } // Glyph of Dispel Magic case 55677: { @@ -5884,10 +5974,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger basepoints0 = triggerAmount * GetMaxHealth() / 100; target = this; triggered_spell_id = 34299; - if (triggeredByAura->GetCaster() != this) + if (triggeredByAura->GetCasterGUID() != GetGUID()) break; int32 basepoints1 = triggerAmount * 2; - CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura); + // Improved Leader of the Pack + // Check cooldown of heal spell cooldown + if (GetTypeId()==TYPEID_PLAYER && !((Player *)this)->HasSpellCooldown(34299)) + CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura); break; } // Healing Touch (Dreamwalker Raiment set) @@ -5940,7 +6033,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 40446; chance = 25.0f; } - // Mangle (cat/bear) + // Mangle (Bear) and Mangle (Cat) else if( procSpell->SpellFamilyFlags[1] & 0x00000440) { triggered_spell_id = 40452; @@ -5998,6 +6091,30 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger basepoints0 = triggerAmount * damage / 100; break; } + // King of the Jungle + else if (dummySpell->SpellIconID == 2850) + { + // Effect 0 - mod damage while having Enrage + if (effIndex==0) + { + if (!(procSpell->SpellFamilyFlags[0] & 0x00080000)) + return false; + triggered_spell_id = 51185; + basepoints0 = triggerAmount; + target = this; + break; + } + // Effect 1 - Tiger's Fury restore energy + else if (effIndex==1) + { + if (!(procSpell->SpellFamilyFlags[2] & 0x00000800)) + return false; + triggered_spell_id = 51178; + basepoints0 = triggerAmount; + target = this; + break; + } + } break; } case SPELLFAMILY_ROGUE: @@ -6114,36 +6231,26 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Light's Beacon - Beacon of Light if ( dummySpell->Id == 53651 ) { - if (Unit * caster = triggeredByAura->GetCaster()) + if (Unit * source = triggeredByAura->GetSource()) { // do not proc when target of beacon of light is healed - if (caster == pVictim) + if (source == this) return false; - if (Aura const* aur = caster->GetAura(53563)) + if (Unit * caster = triggeredByAura->GetCaster()) { - if (Unit * paladin = aur->GetCaster()) - { - if (paladin != this) - return false; - basepoints0 = damage; - triggered_spell_id = 53654; - target = caster; - break; - } - else - { - pVictim->RemoveAura(triggeredByAura->GetParentAura()); + if (caster != pVictim) return false; - } + basepoints0 = damage; + triggered_spell_id = 53654; + target = source; + break; } } - else return false; + return false; } // Judgements of the Wise if (dummySpell->SpellIconID == 3017) { - // hardcoded amount - basepoints0 = 15 * GetCreatePowers(POWER_MANA)/100; target = this; triggered_spell_id = 31930; // replenishment @@ -6184,17 +6291,19 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } switch(dummySpell->Id) { + // Heart of the Crusader + case 20335: // rank 1 + triggered_spell_id = 21183; + break; + case 20336: // rank 2 + triggered_spell_id = 54498; + break; + case 20337: // rank 3 + triggered_spell_id = 54499; + break; // Judgement of Light case 20185: { - // Get judgement caster - Unit *caster = triggeredByAura->GetCaster(); - if (!caster) - return false; - float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK); - int32 holy = caster->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_HOLY) + - caster->SpellBaseDamageBonusForVictim(SPELL_SCHOOL_MASK_HOLY, this); - basepoints0 = int32(ap*0.10f + 0.10f*holy); pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura); return true; } @@ -6269,7 +6378,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // heal amount basepoints0 = triggerAmount*damage/100; target = this; - triggered_spell_id = 31786; + + if(basepoints0) + triggered_spell_id = 31786; break; } // Seal of Blood do damage trigger @@ -6320,8 +6431,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 40471; chance = 15.0f; } - // Judgement - else if( procSpell->SpellFamilyFlags[0] & 0x800000 ) + // Judgement (any) + else if (GetSpellSpecific(procSpell->Id)==SPELL_JUDGEMENT) { triggered_spell_id = 40472; chance = 50.0f; @@ -6433,6 +6544,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) return false; + if(triggeredByAura->GetParentAura() && castItem->GetGUID() != triggeredByAura->GetParentAura()->GetCastItemGUID()) + return false; + // Now amount of extra power stored in 1 effect of Enchant spell // Get it by item enchant id uint32 spellId; @@ -6463,20 +6577,21 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry, 1, windfurySpellEntry->EffectBasePoints[1], pVictim); - // Off-Hand case - if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK) ) - { - // Value gained from additional AP - basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2); - triggered_spell_id = 33750; - } // Main-Hand case - else if ( isAttackReady(BASE_ATTACK) ) + if ( castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK) ) { // Value gained from additional AP basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000); triggered_spell_id = 25504; } + // Off-Hand case + else if ( castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK) ) + { + // Value gained from additional AP + basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2); + triggered_spell_id = 33750; + } + else return false; @@ -6543,6 +6658,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 58879; break; } + // Shaman T8 Elemental 4P Bonus + case 64928: + { + basepoints0 = int32( triggerAmount * damage / 100 ); + triggered_spell_id = 64930; // Electrified + break; + } } // Storm, Earth and Fire if (dummySpell->SpellIconID == 3063) @@ -6569,6 +6691,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Earth Shield if(dummySpell->SpellFamilyFlags[1] & 0x00000400) { + // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal. + originalCaster = triggeredByAura->GetCasterGUID(); basepoints0 = triggerAmount; target = this; triggered_spell_id = 379; @@ -6816,13 +6940,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 50526; break; } - // Death Strike healing effect - if (dummySpell->Id == 45469) - { - int32 heal=pVictim->GetDiseasesByCaster(GetGUID()) * GetMaxHealth()* 5 /100; - CastCustomSpell(this,45470,&heal,NULL,NULL,true); - return true; - } // Sudden Doom if (dummySpell->SpellIconID == 1939 && GetTypeId() == TYPEID_PLAYER) { @@ -6925,23 +7042,22 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } // default case - if(!target || target!=this && !target->isAlive()) + if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive())) return false; if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) return false; if(basepoints0) - CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura, originalCaster); else - CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura); + CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura, originalCaster); if( cooldown && GetTypeId()==TYPEID_PLAYER ) ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); return true; } - bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) { SpellEntry const *dummySpell = triggeredByAura->GetSpellProto (); @@ -6964,7 +7080,6 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* { uint32 maxmana = GetMaxPower(POWER_MANA); basepoints0 = maxmana* GetAttackTime(RANGED_ATTACK)/1000.0f/100.0f; - target = this; triggered_spell_id = 34075; break; @@ -6978,6 +7093,7 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); + // Try handle unknown trigger spells if(!triggerEntry) { sLog.outError("Unit::HandleObsModEnergyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id); @@ -6985,12 +7101,11 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* } // default case - if(!target || target!=this && !target->isAlive()) + if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive())) return false; if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) return false; - if(basepoints0) CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); else @@ -6998,10 +7113,8 @@ bool Unit::HandleObsModEnergyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* if( cooldown && GetTypeId()==TYPEID_PLAYER ) ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); - return true; } - bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) { SpellEntry const *dummySpell = triggeredByAura->GetSpellProto (); @@ -7025,8 +7138,6 @@ bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEff switch (getPowerType()) { case POWER_MANA: triggered_spell_id = 57319; break; - case POWER_RAGE: triggered_spell_id = 57320; break; - case POWER_RUNIC_POWER: triggered_spell_id = 57321; break; default: return false; } @@ -7047,7 +7158,7 @@ bool Unit::HandleModDamagePctTakenAuraProc(Unit *pVictim, uint32 damage, AuraEff } // default case - if(!target || target!=this && !target->isAlive()) + if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive())) return false; if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) @@ -7074,12 +7185,66 @@ bool Unit::HandleAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, S { case SPELLFAMILY_DEATHKNIGHT: { + // Blood of the North + // Reaping + // Death Rune Mastery + if (dummySpell->SpellIconID == 3041 || dummySpell->SpellIconID == 22 || dummySpell->SpellIconID == 2622) + { + *handled = true; + // Convert recently used Blood Rune to Death Rune + if (GetTypeId() == TYPEID_PLAYER) + { + if(((Player*)this)->getClass() != CLASS_DEATH_KNIGHT) + return false; + RuneType rune = ((Player*)this)->GetLastUsedRune(); + // can't proc from death rune use + if (rune == RUNE_DEATH) + return false; + AuraEffect * aurEff = triggeredByAura->GetPartAura(0); + if (!aurEff) + return false; + // Reset amplitude - set death rune remove timer to 30s + aurEff->ResetPeriodicTimer(); + uint32 runesLeft; + + if (dummySpell->SpellIconID == 2622) + runesLeft = 2; + else + runesLeft = 1; + + for (uint8 i=0;i<MAX_RUNES && runesLeft;++i) + { + if (dummySpell->SpellIconID == 2622) + { + if (((Player*)this)->GetCurrentRune(i) == RUNE_DEATH || + ((Player*)this)->GetBaseRune(i) == RUNE_BLOOD ) + continue; + } + else + { + if (((Player*)this)->GetCurrentRune(i) == RUNE_DEATH || + ((Player*)this)->GetBaseRune(i) != RUNE_BLOOD ) + continue; + } + if (((Player*)this)->GetRuneCooldown(i) != RUNE_COOLDOWN) + continue; + + --runesLeft; + // Mark aura as used + aurEff->SetAmount(aurEff->GetAmount() | (1<<i)); + ((Player*)this)->ConvertRune(i,RUNE_DEATH); + } + return true; + } + return false; + } + switch(dummySpell->Id) { // Hungering Cold aura drop case 51209: *handled = true; - // Drop only in disease case + // Drop only in not disease case if (procSpell && procSpell->Dispel == DISPEL_DISEASE) return false; return true; @@ -7273,38 +7438,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig break; case SPELLFAMILY_WARLOCK: { - // Pyroclasm - if (auraSpellInfo->SpellIconID == 1137) - { - if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL) - return false; - // Calculate spell tick count for spells - uint32 tick; - - // Hellfire have 15 tick - if (procSpell->SpellFamilyFlags[0]&0x40) - tick = 15; - // Rain of Fire have 4 tick - else if (procSpell->SpellFamilyFlags[0]&0x20) - tick = 4; - else - tick = 1; - - // Calculate chance = baseChance / tick - float chance = 0; - switch (auraSpellInfo->Id) - { - case 18096: chance = 13.0f / tick; break; - case 18073: chance = 26.0f / tick; break; - } - // Roll chance - if (!roll_chance_f(chance)) - return false; - - trigger_spell_id = 18093; - } // Improved Drain Soul - else if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000) + if (auraSpellInfo->SpellFamilyFlags[0] & 0x4000) { Unit::AuraEffectList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_DUMMY); for(Unit::AuraEffectList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i) @@ -7387,7 +7522,28 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig break; } case SPELLFAMILY_HUNTER: + { + if (auraSpellInfo->SpellIconID == 3247) // Piercing Shots + { + switch (auraSpellInfo->Id) + { + case 53234: // Rank 1 + case 53237: // Rank 2 + case 53238: // Rank 3 + trigger_spell_id = 63468; + break; + default: + sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Piercing Shots",auraSpellInfo->Id); + return false; + } + SpellEntry const *TriggerPS = sSpellStore.LookupEntry(trigger_spell_id); + if(!TriggerPS) + return false; + basepoints0 = int32(damage * triggerAmount / 100 / (GetSpellMaxDuration(TriggerPS) / TriggerPS->EffectAmplitude[0])); + target = pVictim; + } break; + } case SPELLFAMILY_PALADIN: { /* @@ -7462,9 +7618,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig // stacking CastSpell(this, 37658, true, NULL, triggeredByAura); - AuraEffect * dummy = GetDummyAura(37658); + Aura * dummy = GetAura(37658); // release at 3 aura in stack (cont contain in basepoint of trigger aura) - if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount) + if(!dummy || dummy->GetStackAmount() < triggerAmount) return false; RemoveAurasDueToSpell(37658); @@ -7480,9 +7636,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig CastSpell(this, 54842, true, NULL, triggeredByAura); // counting - AuraEffect * dummy = GetDummyAura(54842); + Aura * dummy = GetAura(54842); // release at 3 aura in stack (cont contain in basepoint of trigger aura) - if(!dummy || dummy->GetParentAura()->GetStackAmount() < triggerAmount) + if(!dummy || dummy->GetStackAmount() < triggerAmount) return false; RemoveAurasDueToSpell(54842); @@ -7580,8 +7736,8 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig return false; } } - // Blood Presence - else if (auraSpellInfo->Id == 48266) + // Blood Presence (Improved) + else if (auraSpellInfo->Id == 63611) { if (GetTypeId() != TYPEID_PLAYER) return false; @@ -7761,7 +7917,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig case 22959: { // Glyph of Improved Scorch - if (AuraEffect * aurEff = GetDummyAura(56371)) + if (AuraEffect * aurEff = GetAuraEffect(56371,0)) { for (int32 count = aurEff->GetAmount();count>0;count--) CastSpell(pVictim, 22959, true); @@ -7795,10 +7951,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig if (GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet()) if (Unit * owner = GetOwner()) { - if (AuraEffect * aurEff = owner->GetDummyAura(SPELLFAMILY_WARLOCK, 3220)) + if (AuraEffect * aurEff = owner->GetDummyAura(SPELLFAMILY_WARLOCK, 3220, 0)) { - if (owner->GetTypeId() == TYPEID_PLAYER) - basepoints0 = (aurEff->GetAmount() * ((Player*)owner)->GetBaseSpellDamageBonus() + 100.0f) / 100; + basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonus(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f); CastCustomSpell(this,trigger_spell_id,&basepoints0,&basepoints0,NULL,true,castItem,triggeredByAura); return true; } @@ -7808,14 +7963,20 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig // Sword and Board case 50227: { - // remove cooldown of Shield Slam + // Remove cooldown on Shield Slam if (GetTypeId()==TYPEID_PLAYER) - ((Player*)this)->RemoveCategoryCooldown(1209); + ((Player*)this)->RemoveSpellCategoryCooldown(1209, true); break; } - case 63375: // Improved Stormstrike + // Maelstrom Weapon + case 53817: { - basepoints0 = GetCreateMana() * 0.20f; + // have rank dependent proc chance, ignore too often cases + // PPM = 2.5 * (rank of talent), + uint32 rank = spellmgr.GetSpellRank(auraSpellInfo->Id); + // 5 rank -> 100% 4 rank -> 80% and etc from full rate + if(!roll_chance_i(20*rank)) + return false; break; } // Brain Freeze @@ -7867,7 +8028,15 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig case 56453: { // Proc only from trap activation (from periodic proc another aura of this spell) - if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION)) + if (!(procFlags & PROC_FLAG_ON_TRAP_ACTIVATION) || !roll_chance_i(triggerAmount)) + return false; + break; + } + // Glyph of Death's Embrace + case 58679: + { + // Proc only from healing part of Death Coil. Check is essential as all Death Coil spells have 0x2000 mask in SpellFamilyFlags + if (!procSpell || !(procSpell->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && procSpell->SpellFamilyFlags[0] == 0x80002000)) return false; break; } @@ -7879,6 +8048,12 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig ((Player*)this)->RemoveCategoryCooldown(82); return true; } + // Savage Defense + case 62606: + { + basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100.0f); + break; + } } if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id)) @@ -7886,16 +8061,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig // try detect target manually if not set if ( target == NULL ) - target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(trigger_spell_id) ? this : pVictim; + target = !(procFlags & (PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL | PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT)) && IsPositiveSpell(trigger_spell_id) ? this : pVictim; // default case - if(!target || target!=this && !target->isAlive()) + if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive())) return false; if(basepoints0) CastCustomSpell(target,trigger_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); - //else if(spellmgr.GetSpellCustomAttr(trigger_spell_id) & SPELL_ATTR_CU_AURA_SPELL) - // AddAura(trigger_spell_id, target); else CastSpell(target,trigger_spell_id,true,castItem,triggeredByAura); @@ -7982,6 +8155,21 @@ bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, AuraE CastCustomSpell(this, 47762, &basepoints0, 0, 0, true, 0, triggeredByAura); return true; } + case 7010: // Revitalize - can proc on full hp target + case 7011: + case 7012: + { + if (!roll_chance_i(triggeredByAura->GetAmount())) + return false; + switch(pVictim->getPowerType()) + { + case POWER_MANA: triggered_spell_id = 48542; break; + case POWER_RAGE: triggered_spell_id = 48541; break; + case POWER_ENERGY: triggered_spell_id = 48540; break; + case POWER_RUNIC_POWER: triggered_spell_id = 48543; break; + } + break; + } } // not processed @@ -8329,7 +8517,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) return false; // dead units can neither attack nor be attacked - if(!isAlive() || !victim->isAlive()) + if(!isAlive() || !victim->IsInWorld() || !victim->isAlive()) return false; // player cannot attack in mount state @@ -8388,7 +8576,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) //if(GetTypeId()==TYPEID_UNIT) // ((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); - if(GetTypeId()==TYPEID_UNIT && !IsControlledByPlayer()) + if(GetTypeId()==TYPEID_UNIT) { // should not let player enter combat by right clicking target SetInCombatWith(victim); @@ -8529,14 +8717,6 @@ void Unit::ModifyAuraState(AuraState flag, bool apply) SpellEntry const* spellProto = (*itr).second->GetSpellProto(); if (spellProto->CasterAuraState == flag) { - // exceptions (applied at state but not removed at state change) - // Rampage - if(spellProto->SpellIconID==2006 && spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && spellProto->SpellFamilyFlags[0]==0x100000) - { - ++itr; - continue; - } - RemoveAura(itr); } else @@ -8547,15 +8727,42 @@ void Unit::ModifyAuraState(AuraState flag, bool apply) } } +uint32 Unit::BuildAuraStateUpdateForTarget(Unit * target) const +{ + uint32 auraStates = GetUInt32Value(UNIT_FIELD_AURASTATE) &~(PER_CASTER_AURA_STATE_MASK); + for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end();++itr) + { + if ((1<<(itr->first-1)) & PER_CASTER_AURA_STATE_MASK) + { + if (itr->second->GetCasterGUID() == target->GetGUID()) + auraStates |= (1<<(itr->first-1)); + } + } + return auraStates; +} + bool Unit::HasAuraState(AuraState flag, SpellEntry const *spellProto, Unit * Caster) const { - if (Caster && spellProto) + if (Caster) { - AuraEffectList const& stateAuras = Caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); - for(AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j) - if((*j)->isAffectedOnSpell(spellProto)) - return true; + if(spellProto) + { + AuraEffectList const& stateAuras = Caster->GetAurasByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE); + for(AuraEffectList::const_iterator j = stateAuras.begin();j != stateAuras.end(); ++j) + if((*j)->isAffectedOnSpell(spellProto)) + return true; + } + // Check per caster aura state + // If aura with aurastate by caster not found return false + if ((1<<(flag-1)) & PER_CASTER_AURA_STATE_MASK) + { + for(AuraStateAurasMap::const_iterator itr = m_auraStateAuras.lower_bound(flag); itr != m_auraStateAuras.upper_bound(flag);++itr) + if (itr->second->GetCasterGUID() == Caster->GetGUID()) + return true; + return false; + } } + return HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)); } @@ -8741,13 +8948,13 @@ void Unit::SetMinion(Minion *minion, bool apply) assert((*itr)->GetOwnerGUID() == GetGUID()); assert((*itr)->GetTypeId() == TYPEID_UNIT); - if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN)) + if(!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN)) continue; if(AddUInt64Value(UNIT_FIELD_SUMMON, (*itr)->GetGUID())) { //show another pet bar if there is no charm bar - if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_GUARDIAN)) + if(GetTypeId() == TYPEID_PLAYER && !GetCharmGUID() && ((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN)) { if(((Creature*)(*itr))->isPet()) ((Player*)this)->PetSpellInitialize(); @@ -8835,19 +9042,24 @@ int32 Unit::DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellPro { int32 gain = pVictim->ModifyHealth(int32(addhealth)); - if (GetTypeId()==TYPEID_PLAYER) + Unit* unit = this; + + if( GetTypeId()==TYPEID_UNIT && ((Creature*)this)->isTotem()) + unit = GetOwner(); + + if (unit->GetTypeId()==TYPEID_PLAYER) { // overheal = addhealth - gain - SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth > gain ? addhealth - gain : 0, critical); + unit->SendHealSpellLog(pVictim, spellProto->Id, addhealth, addhealth - gain, critical); - if (BattleGround *bg = ((Player*)this)->GetBattleGround()) - bg->UpdatePlayerScore((Player*)this, SCORE_HEALING_DONE, gain); + if (BattleGround *bg = ((Player*)unit)->GetBattleGround()) + bg->UpdatePlayerScore((Player*)unit, SCORE_HEALING_DONE, gain); // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria) if (gain) - ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim); + ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, pVictim); - ((Player*)this)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth); + ((Player*)unit)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED, addhealth); } if (pVictim->GetTypeId()==TYPEID_PLAYER) @@ -8926,9 +9138,7 @@ void Unit::RemoveAllControlled() && target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->HasSummonMask(SUMMON_MASK_SUMMON)) { - - if(!((TempSummon*)target)->isPet()) - ((TempSummon*)target)->UnSummon(); + ((TempSummon*)target)->UnSummon(); } else { @@ -9073,7 +9283,7 @@ void Unit::EnergizeBySpell(Unit *pVictim, uint32 SpellID, uint32 Damage, Powers { SendEnergizeSpellLog(pVictim, SpellID, Damage, powertype); // needs to be called after sending spell log - ModifyPower(powertype, Damage); + pVictim->ModifyPower(powertype, Damage); } uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) @@ -9202,7 +9412,8 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 } else // Tundra Stalker { - if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT,0, 0x4000000,0)) + // Frost Fever (target debuff) + if (pVictim->GetAura(SPELL_AURA_MOD_HASTE, SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x2)) DoneTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f; break; } @@ -9265,13 +9476,12 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 } } break; - // Glyph of Shadow Word: Pain case SPELLFAMILY_PRIEST: if (spellProto->SpellFamilyFlags[0] & 0x800000) { // Increase Mind Flay damage - if (AuraEffect * aurEff = GetDummyAura(55687)) + if (AuraEffect * aurEff = GetAuraEffect(55687, 0)) // if Shadow Word: Pain present if (pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0,0, GetGUID())) DoneTotalMod *= (aurEff->GetAmount() + 100.0f) / 100.f; @@ -9300,17 +9510,17 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 // Improved Icy Touch if (spellProto->SpellFamilyFlags[0] & 0x2) { - if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2721)) + if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 2721, 0)) DoneTotalMod *= (100.0f + aurEff->GetAmount()) / 100.0f ; } // Glacier Rot if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6) { - if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 196)) + if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DEATHKNIGHT, 196, 0)) DoneTotalMod *= (100.0f + aurEff->GetAmount()) / 100.0f; } // This is not a typo - Impurity has SPELLFAMILY_DRUID - if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986)) + if (AuraEffect * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986, 0)) ApCoeffMod *= (100.0f + aurEff->GetAmount()) / 100.0f; break; } @@ -9325,7 +9535,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 if (pVictim->GetTypeId() == TYPEID_PLAYER) { //Cheat Death - if (AuraEffect *dummy = pVictim->GetDummyAura(45182)) + if (AuraEffect *dummy = pVictim->GetAuraEffect(45182, 0)) { float mod = -((Player*)pVictim)->GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2*4; if (mod < dummy->GetAmount()) @@ -9341,14 +9551,11 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f; // Mod damage from spell mechanic - uint32 mechanicMask = GetAllSpellMechanicMask(spellProto); - if (mechanicMask) + if (uint32 mechanicMask = GetAllSpellMechanicMask(spellProto)) { AuraEffectList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT); for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i) - if((mechanicMask & uint32(1<<((*i)->GetMiscValue()))) - // Shred - "Effects which increase Bleed damage also increase Shred damage" - || ((*i)->GetMiscValue() == MECHANIC_BLEED && spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x8000)) + if(mechanicMask & uint32(1<<((*i)->GetMiscValue()))) TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f; } @@ -9361,21 +9568,29 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 DoneAdvertisedBenefit += ((Guardian*)this)->GetBonusDamage(); // Check for table values - float coeff; + float coeff = 0; SpellBonusEntry const* bonus = spellmgr.GetSpellBonusData(spellProto->Id); if (bonus) { if (damagetype == DOT) + { coeff = bonus->dot_damage; + if (bonus->ap_dot_bonus > 0) + DoneTotal+=bonus->ap_dot_bonus * stack * ApCoeffMod * GetTotalAttackPowerValue( + (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK); + } else + { coeff = bonus->direct_damage; - if (bonus->ap_bonus) - DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack * ApCoeffMod; + if (bonus->ap_bonus > 0) + DoneTotal+=bonus->ap_bonus * stack * ApCoeffMod * GetTotalAttackPowerValue( + (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK); + } } // Default calculation if (DoneAdvertisedBenefit || TakenAdvertisedBenefit) { - if(!bonus) + if(!bonus || coeff < 0) { // Damage Done from spell damage bonus int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); @@ -9520,8 +9735,9 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM float crit_chance = 0.0f; switch(spellProto->DmgClass) { - case SPELL_DAMAGE_CLASS_NONE: - return false; + case SPELL_DAMAGE_CLASS_NONE: // Exception for earth shield + if (spellProto->Id != 379) // We need more spells to find a general way (if there is any) + return false; case SPELL_DAMAGE_CLASS_MAGIC: { if (schoolMask & SPELL_SCHOOL_MASK_NORMAL) @@ -9590,11 +9806,18 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM // Sacred Shield if (spellProto->SpellFamilyFlags[0] & 0x40000000) { - AuraEffect const* aura = pVictim->GetDummyAura(58597); + AuraEffect const* aura = pVictim->GetAuraEffect(58597,1); if (aura && aura->GetCasterGUID() == GetGUID()) crit_chance+=aura->GetAmount(); break; } + // Exorcism + else if (spellProto->Category == 19) + { + if (pVictim->GetCreatureTypeMask() & CREATURE_TYPEMASK_DEMON_OR_UNDEAD) + return true; + break; + } break; case SPELLFAMILY_SHAMAN: // Lava Burst @@ -9616,12 +9839,30 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM break; } case SPELL_DAMAGE_CLASS_MELEE: + if (pVictim) + { + // Custom crit by class + switch(spellProto->SpellFamilyName) + { + case SPELLFAMILY_DRUID: + // Rend and Tear - bonus crit chance for bleeding targets of Ferocious Bite + if (spellProto->SpellFamilyFlags[0] & 0x00800000 && pVictim->HasAuraState(AURA_STATE_BLEEDING, spellProto, this)) + { + if (AuraEffect const* rendAndTear = GetDummyAura(SPELLFAMILY_DRUID, 2859, 1)) + { + crit_chance += rendAndTear->GetAmount(); + } + break; + } + break; + } + } case SPELL_DAMAGE_CLASS_RANGED: { if (pVictim) { - crit_chance = GetUnitCriticalChance(attackType, pVictim); - crit_chance+= GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); + crit_chance += GetUnitCriticalChance(attackType, pVictim); + crit_chance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, schoolMask); } break; } @@ -9801,16 +10042,24 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint // Check for table values SpellBonusEntry const* bonus = !scripted ? spellmgr.GetSpellBonusData(spellProto->Id) : NULL; - float coeff; + float coeff = 0; float factorMod = 1.0f; if (bonus) { if (damagetype == DOT) + { coeff = bonus->dot_damage; + if (bonus->ap_dot_bonus > 0) + DoneTotal+=bonus->ap_dot_bonus * stack * GetTotalAttackPowerValue( + (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK); + } else + { coeff = bonus->direct_damage; - if (bonus->ap_bonus) - DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack; + if (bonus->ap_bonus > 0) + DoneTotal+=bonus->ap_bonus * stack * GetTotalAttackPowerValue( + (IsRangedWeaponSpell(spellProto) && spellProto->DmgClass !=SPELL_DAMAGE_CLASS_MELEE)? RANGED_ATTACK : BASE_ATTACK); + } } else // scripted bonus { @@ -9836,6 +10085,7 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint // No heal coeff for SPELL_DAMAGE_CLASS_NONE class spells by default else if (scripted || spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE) { + scripted = true; coeff = 0.0f; } } @@ -9843,7 +10093,7 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint // Default calculation if (DoneAdvertisedBenefit || TakenAdvertisedBenefit) { - if(!bonus && !scripted) + if((!bonus && !scripted) || coeff < 0) { // Damage Done from spell damage bonus int32 CastingTime = !IsChanneledSpell(spellProto) ? GetSpellCastTime(spellProto) : GetSpellDuration(spellProto); @@ -10204,6 +10454,9 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT } } } + // This is not a typo - Impurity has SPELLFAMILY_DRUID + if (AuraEffect const * aurEff = GetDummyAura(SPELLFAMILY_DRUID, 1986, 0)) + APbonus *= (100.0f + aurEff->GetAmount()) / 100.0f; DoneFlatBenefit += int32(APbonus/14.0f * GetAPMultiplier(attType,normalized)); } @@ -10238,6 +10491,22 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT if((*i)->GetMiscValue() & GetMeleeDamageSchoolMask()) TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f; + // .. taken pct (special attacks) + if (spellProto) + { + // Mod damage from spell mechanic + uint32 mechanicMask = GetAllSpellMechanicMask(spellProto); + if (mechanicMask) + { + AuraEffectList const& mDamageDoneMechanic = pVictim->GetAurasByType(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT); + for(AuraEffectList::const_iterator i = mDamageDoneMechanic.begin();i != mDamageDoneMechanic.end(); ++i) + if((mechanicMask & uint32(1<<((*i)->GetMiscValue()))) + // Shred - "Effects which increase Bleed damage also increase Shred damage" + || ((*i)->GetMiscValue() == MECHANIC_BLEED && spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x8000)) + TakenTotalMod *= ((*i)->GetAmount()+100.0f)/100.0f; + } + } + // .. taken pct: dummy auras AuraEffectList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY); for(AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) @@ -10256,14 +10525,6 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT TakenTotalMod *= (mod+100.0f)/100.0f; } break; - //Mangle - case 2312: - if(spellProto==NULL) - break; - // Should increase Shred (initial Damage of Lacerate and Rake handled in Spell::EffectSchoolDMG) - if(spellProto->SpellFamilyName==SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags.IsEqual (0x00008000,0,0)) - TakenTotalMod *= (100.0f+(*i)->GetAmount())/100.0f; - break; } } @@ -10394,8 +10655,7 @@ float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, const SpellEntry * s if(Player* modOwner = GetSpellModOwner()) modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_PROC_PER_MINUTE,PPM); - uint32 result = uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) - return result; + return uint32((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60)) } void Unit::Mount(uint32 mount) @@ -10471,20 +10731,22 @@ void Unit::SetInCombatWith(Unit* enemy) SetInCombatState(false,enemy); } -void Unit::CombatStart(Unit* target) +void Unit::CombatStart(Unit* target, bool initialAggro) { - if(!target->IsStandState()/* && !target->hasUnitState(UNIT_STAT_STUNNED)*/) - target->SetStandState(UNIT_STAND_STATE_STAND); - - if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER - && !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->IsAIEnabled) + if (initialAggro) { - ((Creature*)target)->AI()->AttackStart(this); - } + if(!target->IsStandState()/* && !target->hasUnitState(UNIT_STAT_STUNNED)*/) + target->SetStandState(UNIT_STAND_STATE_STAND); - SetInCombatWith(target); - target->SetInCombatWith(this); + if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER + && !((Creature*)target)->HasReactState(REACT_PASSIVE) && ((Creature*)target)->IsAIEnabled) + { + ((Creature*)target)->AI()->AttackStart(this); + } + SetInCombatWith(target); + target->SetInCombatWith(this); + } Unit *who = target->GetCharmerOrOwnerOrSelf(); if(who->GetTypeId() == TYPEID_PLAYER) SetContestedPvP((Player*)who); @@ -10515,8 +10777,10 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy) if(GetTypeId() != TYPEID_PLAYER) { - //if(GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != IDLE_MOTION_TYPE) - ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); + // Set home position at place of engaging combat for escorted creatures + if(((Creature*)this)->IsAIEnabled) + if (((Creature *)this)->AI()->IsEscorted()) + ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); if(enemy) { if(((Creature*)this)->IsAIEnabled) @@ -10581,6 +10845,9 @@ bool Unit::canAttack(Unit const* target, bool force) const else if(!IsHostileTo(target)) return false; + //if(m_Vehicle && m_Vehicle == target->m_Vehicle) + // return true; + if(!target->isAttackableByAOE() || target->hasUnitState(UNIT_STAT_DIED)) return false; @@ -10782,6 +11049,7 @@ bool Unit::canDetectStealthOf(Unit const* target, float distance) const //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) //based on wowwiki every 5 mod we have 1 more level diff in calculation visibleDistance += (float)(GetTotalAuraModifier(SPELL_AURA_MOD_DETECT) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL)) / 5.0f; + visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance; return distance < visibleDistance; } @@ -10823,6 +11091,11 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) switch(mtype) { + // Only apply debuffs + case MOVE_FLIGHT_BACK: + case MOVE_RUN_BACK: + case MOVE_SWIM_BACK: + break; case MOVE_WALK: return; case MOVE_RUN: @@ -10841,15 +11114,11 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) } break; } - case MOVE_RUN_BACK: - return; case MOVE_SWIM: { main_speed_mod = GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_SWIM_SPEED); break; } - case MOVE_SWIM_BACK: - return; case MOVE_FLIGHT: { if (GetTypeId()==TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet @@ -10881,14 +11150,13 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) vehicle->UpdateSpeed(MOVE_FLIGHT, true); break; } - case MOVE_FLIGHT_BACK: - return; default: sLog.outError("Unit::UpdateSpeed: Unsupported move type (%d)", mtype); return; } float bonus = non_stack_bonus > stack_bonus ? non_stack_bonus : stack_bonus; + // now we ready for speed calculation float speed = main_speed_mod ? bonus*(100.0f + main_speed_mod)/100.0f : bonus; @@ -10898,6 +11166,10 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) case MOVE_SWIM: case MOVE_FLIGHT: { + // Set creature speed rate from CreatureInfo + if (GetTypeId() == TYPEID_UNIT) + speed *= ((Creature*)this)->GetCreatureInfo()->speed; + // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need // TODO: possible affect only on MOVE_RUN if(int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED)) @@ -11089,6 +11361,8 @@ void Unit::setDeathState(DeathState s) if (m_deathState != ALIVE && s == ALIVE) { //_ApplyAllAuraMods(); + // Reset display id on resurection - needed by corpse explosion to cleanup after display change + SetDisplayId(GetNativeDisplayId()); } m_deathState = s; } @@ -11116,8 +11390,8 @@ bool Unit::CanHaveThreatList() const //if( ((Creature*)this)->isVehicle() ) // return false; - // pets can not have a threat list, unless they are controlled by a creature - if( ((Creature*)this)->isPet() && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) ) + // summons can not have a threat list, unless they are controlled by a creature + if( ((Creature*)this)->HasSummonMask(SUMMON_MASK_MINION | SUMMON_MASK_GUARDIAN | SUMMON_MASK_CONTROLABLE_GUARDIAN) && IS_PLAYER_GUID(((Pet*)this)->GetOwnerGUID()) ) return false; return true; @@ -11148,6 +11422,8 @@ void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, Sp void Unit::DeleteThreatList() { + if(CanHaveThreatList() && !m_ThreatManager.isThreatListEmpty()) + SendClearThreatListOpcode(); m_ThreatManager.clearReferences(); } @@ -11222,10 +11498,6 @@ Unit* Creature::SelectVictim() //next-victim-selection algorithm and evade mode are called //threat list sorting etc. - //This should not be called by unit who does not have a threatlist - //or who does not have threat (totem/pet/critter) - //otherwise enterevademode every update - Unit* target = NULL; // First checking if we have some taunt on us const AuraEffectList& tauntAuras = GetAurasByType(SPELL_AURA_MOD_TAUNT); @@ -11258,9 +11530,38 @@ Unit* Creature::SelectVictim() target = getVictim(); } - if ( !target && !m_ThreatManager.isThreatListEmpty() ) - // No taunt aura or taunt aura caster is dead standart target selection - target = m_ThreatManager.getHostilTarget(); + if (CanHaveThreatList()) + { + if ( !target && !m_ThreatManager.isThreatListEmpty() ) + // No taunt aura or taunt aura caster is dead standart target selection + target = m_ThreatManager.getHostilTarget(); + } + else if(!HasReactState(REACT_PASSIVE)) + { + // We have player pet probably + target = getAttackerForHelper(); + if (!target && isSummon()) + { + if (Unit * owner = ((TempSummon*)this)->GetOwner()) + { + if (owner->isInCombat()) + target = owner->getAttackerForHelper(); + if (!target) + { + for(ControlList::const_iterator itr = owner->m_Controlled.begin(); itr != owner->m_Controlled.end(); ++itr) + { + if ((*itr)->isInCombat()) + { + target = (*itr)->getAttackerForHelper(); + if (target) break; + } + } + } + } + } + } + else + return NULL; if(target) { @@ -11273,16 +11574,11 @@ Unit* Creature::SelectVictim() // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list // for example at owner command to pet attack some far away creature // Note: creature not have targeted movement generator but have attacker in this case - if(m_attackers.size()) - return NULL; - /*if( GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE ) + for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) { - for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) - { - if( (*itr)->IsInMap(this) && canAttack(*itr) && (*itr)->isInAccessiblePlaceFor((Creature*)this) ) - return NULL; - } - }*/ + if( (*itr)->IsInMap(this) && canAttack(*itr) && (*itr)->isInAccessiblePlaceFor((Creature*)this) && ((*itr)->GetTypeId() != TYPEID_PLAYER && (!((Creature*)(*itr))->HasSummonMask(SUMMON_MASK_CONTROLABLE_GUARDIAN)))) + return NULL; + } // search nearby enemy before enter evade mode if(HasReactState(REACT_AGGRESSIVE)) @@ -11368,8 +11664,8 @@ int32 Unit::CalculateSpellDamage(SpellEntry const* spellProto, uint8 effect_inde spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_INCREASE_SPEED && spellProto->EffectApplyAuraName[effect_index] != SPELL_AURA_MOD_DECREASE_SPEED) //there are many more: slow speed, -healing pct - //value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f)); - value = int32(value * (int32)getLevel() / (int32)(spellProto->spellLevel ? spellProto->spellLevel : 1)); + value = int32(value*0.25f*exp(getLevel()*(70-spellProto->spellLevel)/1000.0f)); + //value = int32(value * (int32)getLevel() / (int32)(spellProto->spellLevel ? spellProto->spellLevel : 1)); return value; } @@ -11509,29 +11805,29 @@ void Unit::IncrDiminishing(DiminishingGroup group) m_Diminishing.push_back(DiminishingReturn(group,getMSTime(),DIMINISHING_LEVEL_2)); } -void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level) +void Unit::ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster,DiminishingLevels Level, int32 limitduration) { if(duration == -1 || group == DIMINISHING_NONE || caster->IsFriendlyTo(this) ) return; - // test pet/charm masters instead pets/charmeds + // test pet/charm masters instead pets/charmeds Unit const* targetOwner = GetCharmerOrOwner(); Unit const* casterOwner = caster->GetCharmerOrOwner(); // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0) - if(duration > 10000 && IsDiminishingReturnsGroupDurationLimited(group)) + if(limitduration > 0 && duration > limitduration) { Unit const* target = targetOwner ? targetOwner : this; Unit const* source = casterOwner ? casterOwner : caster; if(target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() == TYPEID_PLAYER) - duration = 10000; + duration = limitduration; } float mod = 1.0f; // Some diminishings applies to mobs too (for example, Stun) - if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && (targetOwner ? targetOwner->GetTypeId():GetTypeId()) == TYPEID_PLAYER) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL) + if((GetDiminishingReturnsGroupType(group) == DRTYPE_PLAYER && (targetOwner ? (targetOwner->GetTypeId() == TYPEID_PLAYER) : (GetTypeId() == TYPEID_PLAYER))) || GetDiminishingReturnsGroupType(group) == DRTYPE_ALL) { DiminishingLevels diminish = Level; switch(diminish) @@ -11884,6 +12180,8 @@ void Unit::SetHealth(uint32 val) void Unit::SetMaxHealth(uint32 val) { + if(!val) val = 1; + uint32 health = GetHealth(); SetUInt32Value(UNIT_FIELD_MAXHEALTH, val); @@ -12066,7 +12364,7 @@ void Unit::RemoveFromWorld() if(m_NotifyListPos >= 0) { - GetMap()->RemoveUnitFromNotify(m_NotifyListPos); + GetMap()->RemoveUnitFromNotify(this, m_NotifyListPos); m_NotifyListPos = -1; } @@ -12148,11 +12446,9 @@ void Unit::DeleteCharmInfo() CharmInfo::CharmInfo(Unit* unit) : m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_petnumber(0), m_barInit(false) { - for(uint8 i =0; i<MAX_SPELL_CHARM; ++i) - { - m_charmspells[i].spellId = 0; - m_charmspells[i].active = ACT_DISABLED; - } + for(uint8 i = 0; i < MAX_SPELL_CHARM; ++i) + m_charmspells[i].SetActionAndType(0,ACT_DISABLED); + if(m_unit->GetTypeId() == TYPEID_UNIT) { m_oldReactState = ((Creature*)m_unit)->GetReactState(); @@ -12229,18 +12525,21 @@ void CharmInfo::InitCharmCreateSpells() if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD) spellId = 0; - m_charmspells[x].spellId = spellId; - if(!spellId) + { + m_charmspells[x].SetActionAndType(spellId,ACT_DISABLED); continue; + } if (IsPassiveSpell(spellId)) { m_unit->CastSpell(m_unit, spellId, true); - m_charmspells[x].active = ACT_PASSIVE; + m_charmspells[x].SetActionAndType(spellId,ACT_PASSIVE); } else { + m_charmspells[x].SetActionAndType(spellId,ACT_DISABLED); + ActiveStates newstate; if(spellInfo) { @@ -12275,11 +12574,11 @@ bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate) // new spell rank can be already listed for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) { - if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + if (uint32 action = PetActionBar[i].GetAction()) { - if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id) + if (PetActionBar[i].IsActionBarForSpell() && spellmgr.GetFirstSpellInChain(action) == first_id) { - PetActionBar[i].SpellOrAction = spell_id; + PetActionBar[i].SetAction(spell_id); return true; } } @@ -12288,7 +12587,7 @@ bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate) // or use empty slot in other case for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) { - if (!PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + if (!PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell()) { SetActionBar(i,spell_id,newstate == ACT_DECIDE ? IsAutocastableSpell(spell_id) ? ACT_DISABLED : ACT_PASSIVE : newstate); return true; @@ -12303,9 +12602,9 @@ bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id) for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) { - if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + if (uint32 action = PetActionBar[i].GetAction()) { - if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id) + if (PetActionBar[i].IsActionBarForSpell() && spellmgr.GetFirstSpellInChain(action) == first_id) { SetActionBar(i,0,ACT_PASSIVE); return true; @@ -12322,12 +12621,8 @@ void CharmInfo::ToggleCreatureAutocast(uint32 spellid, bool apply) return; for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x) - { - if(spellid == m_charmspells[x].spellId) - { - m_charmspells[x].active = apply ? ACT_ENABLED : ACT_DISABLED; - } - } + if(spellid == m_charmspells[x].GetAction()) + m_charmspells[x].SetType(apply ? ACT_ENABLED : ACT_DISABLED); } void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow) @@ -12353,17 +12648,19 @@ void CharmInfo::LoadPetActionBar(const std::string& data ) for(iter = tokens.begin(), index = ACTION_BAR_INDEX_PET_SPELL_START; index < ACTION_BAR_INDEX_PET_SPELL_END; ++iter, ++index ) { // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion - PetActionBar[index].Type = atol((*iter).c_str()); + uint8 type = atol((*iter).c_str()); ++iter; - PetActionBar[index].SpellOrAction = atol((*iter).c_str()); + uint32 action = atol((*iter).c_str()); + + PetActionBar[index].SetActionAndType(action,ActiveStates(type)); // check correctness if(PetActionBar[index].IsActionBarForSpell()) { - if(!sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction)) + if(!sSpellStore.LookupEntry(PetActionBar[index].GetAction())) SetActionBar(index,0,ACT_PASSIVE); - else if(!IsAutocastableSpell(PetActionBar[index].SpellOrAction)) - SetActionBar(index,PetActionBar[index].SpellOrAction,ACT_PASSIVE); + else if(!IsAutocastableSpell(PetActionBar[index].GetAction())) + SetActionBar(index,PetActionBar[index].GetAction(),ACT_PASSIVE); } } } @@ -12371,19 +12668,16 @@ void CharmInfo::LoadPetActionBar(const std::string& data ) void CharmInfo::BuildActionBar( WorldPacket* data ) { for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) - { - *data << uint16(PetActionBar[i].SpellOrAction); - *data << uint16(PetActionBar[i].Type); - } + *data << uint32(PetActionBar[i].packedData); } void CharmInfo::SetSpellAutocast( uint32 spell_id, bool state ) { for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i) { - if(spell_id == PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell()) + if(spell_id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell()) { - PetActionBar[i].Type = state ? ACT_ENABLED : ACT_DISABLED; + PetActionBar[i].SetType(state ? ACT_ENABLED : ACT_DISABLED); break; } } @@ -12427,8 +12721,10 @@ bool InitTriggerAuraData() isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true; isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true; isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true; - isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; // Aura not have charges but need remove him on trigger + isTriggerAura[SPELL_AURA_MOD_STEALTH] = true; + isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura not have charges but need remove him on trigger isTriggerAura[SPELL_AURA_MOD_ROOT] = true; + isTriggerAura[SPELL_AURA_TRANSFORM] = true; isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true; isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true; isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true; @@ -12499,8 +12795,11 @@ uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missC void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage , SpellEntry const * procAura) { - // For melee/ranged based attack need update skills and set some Aura states - if (procFlag & MELEE_BASED_TRIGGER_MASK) + // Player is loaded now - do not allow passive spell casts to proc + if (GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetSession()->PlayerLoading()) + return; + // For melee/ranged based attack need update skills and set some Aura states if victim present + if (procFlag & MELEE_BASED_TRIGGER_MASK && pTarget) { // Update skills here for players if (GetTypeId() == TYPEID_PLAYER) @@ -12616,6 +12915,9 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag if (GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown) cooldown = i->spellProcEvent->cooldown; + if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DISABLE_PROC) + SetCantProc(true); + // This bool is needed till separate aura effect procs are still here bool handled = false; if (HandleAuraProc(pTarget, damage, i->aura, procSpell, procFlag, procExtra, cooldown, &handled)) @@ -12640,8 +12942,8 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag { sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); // Don`t drop charge or add cooldown for not started trigger - if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - continue; + if (HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges=true; break; } case SPELL_AURA_PROC_TRIGGER_DAMAGE: @@ -12653,53 +12955,64 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb); SendSpellNonMeleeDamageLog(&damageInfo); DealSpellDamage(&damageInfo, true); + takeCharges=true; break; } case SPELL_AURA_MANA_SHIELD: case SPELL_AURA_DUMMY: { sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (!HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - continue; - if (procDebug & 1) - sLog.outError("Dummy aura of spell %d procs twice from one effect!",spellInfo->Id); - procDebug |= 1; + if (HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + takeCharges=true; + if (procDebug & 1) + sLog.outError("Dummy aura of spell %d procs twice from one effect!",spellInfo->Id); + procDebug |= 1; + } break; } case SPELL_AURA_OBS_MOD_ENERGY: sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (!HandleObsModEnergyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - continue; - if (procDebug & 2) - sLog.outError("ObsModEnergy aura of spell %d procs twice from one effect!",spellInfo->Id); - procDebug |= 2; + if (HandleObsModEnergyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + takeCharges=true; + if (procDebug & 2) + sLog.outError("ObsModEnergy aura of spell %d procs twice from one effect!",spellInfo->Id); + procDebug |= 2; + } break; case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (!HandleModDamagePctTakenAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - continue; - if (procDebug & 16) - sLog.outError("ModDamagePctTaken aura of spell %d procs twice from one effect!",spellInfo->Id); - procDebug |= 16; + if (HandleModDamagePctTakenAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + takeCharges=true; + if (procDebug & 16) + sLog.outError("ModDamagePctTaken aura of spell %d procs twice from one effect!",spellInfo->Id); + procDebug |= 16; + } break; case SPELL_AURA_MOD_HASTE: { sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (!HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - continue; - if (procDebug & 4) - sLog.outError("Haste aura of spell %d procs twice from one effect!",spellInfo->Id); - procDebug |= 4; + if (HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + takeCharges=true; + if (procDebug & 4) + sLog.outError("Haste aura of spell %d procs twice from one effect!",spellInfo->Id); + procDebug |= 4; + } break; } case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: { sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (!HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown)) - continue; - if (procDebug & 8) - sLog.outError("OverrideClassScripts aura of spell %d procs twice from one effect!",spellInfo->Id); - procDebug |= 8; + if (HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown)) + { + takeCharges=true; + if (procDebug & 8) + sLog.outError("OverrideClassScripts aura of spell %d procs twice from one effect!",spellInfo->Id); + procDebug |= 8; + } break; } case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE: @@ -12708,6 +13021,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); HandleAuraRaidProcFromChargeWithValue(triggeredByAura); + takeCharges=true; break; } case SPELL_AURA_RAID_PROC_FROM_CHARGE: @@ -12716,68 +13030,92 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); HandleAuraRaidProcFromCharge(triggeredByAura); + takeCharges=true; break; } case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: { sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - continue; + if (HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges=true; break; } case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: // Skip melee hits or instant cast spells - if (procSpell == NULL || GetSpellCastTime(procSpell) == 0) - continue; + if (procSpell && GetSpellCastTime(procSpell) != 0) + takeCharges=true; break; case SPELL_AURA_REFLECT_SPELLS_SCHOOL: // Skip Melee hits and spells ws wrong school - if (procSpell == NULL || (triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0) - continue; + if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check + takeCharges=true; break; case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: case SPELL_AURA_MOD_POWER_COST_SCHOOL: // Skip melee hits and spells ws wrong school or zero cost - if (procSpell == NULL || - (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check + if (procSpell && + (procSpell->manaCost != 0 || procSpell->ManaCostPercentage != 0) && // Cost check (triggeredByAura->GetMiscValue() & procSpell->SchoolMask) == 0) // School check - continue; + takeCharges=true; break; case SPELL_AURA_MECHANIC_IMMUNITY: // Compare mechanic - if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue()) - continue; + if (procSpell && procSpell->Mechanic == triggeredByAura->GetMiscValue()) + takeCharges=true; break; case SPELL_AURA_MOD_MECHANIC_RESISTANCE: // Compare mechanic - if (procSpell==NULL || procSpell->Mechanic != triggeredByAura->GetMiscValue()) - continue; + if (procSpell && procSpell->Mechanic == triggeredByAura->GetMiscValue()) + takeCharges=true; break; case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: // Compare casters - if (triggeredByAura->GetCasterGUID() != pTarget->GetGUID()) - continue; + if (triggeredByAura->GetCasterGUID() == pTarget->GetGUID()) + takeCharges=true; break; case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: - if (!procSpell) - continue; + if (procSpell) + takeCharges=true; break; - /*case SPELL_AURA_ADD_FLAT_MODIFIER: - case SPELL_AURA_ADD_PCT_MODIFIER: + // CC Auras which use their amount amount to drop + // Are there any more auras which need this? + case SPELL_AURA_MOD_CONFUSE: + case SPELL_AURA_MOD_FEAR: + case SPELL_AURA_MOD_STUN: + case SPELL_AURA_MOD_ROOT: + case SPELL_AURA_TRANSFORM: + if (isVictim && damage) + { + // Damage is dealt after proc system - lets ignore auras which wasn't updated yet + // to make spell not remove its own aura + if (i->aura->GetAuraDuration() == i->aura->GetAuraMaxDuration()) + break; + int32 damageLeft = triggeredByAura->GetAmount(); + // No damage left + if (damageLeft < damage ) + RemoveAura(i->aura); + else + triggeredByAura->SetAmount(damageLeft-damage); + } + break; + //case SPELL_AURA_ADD_FLAT_MODIFIER: + //case SPELL_AURA_ADD_PCT_MODIFIER: // HandleSpellModAuraProc - break;*/ + //break; default: // nothing do, just charges counter + takeCharges=true; break; } - takeCharges=true; } // Remove charge (aura can be removed by triggers) if(useCharges && takeCharges) { i->aura->DropAuraCharge(); } + if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DISABLE_PROC) + SetCantProc(false); } // Cleanup proc requirements @@ -12845,33 +13183,6 @@ void Unit::SendPetTalk (uint32 pettalk) ((Player*)owner)->GetSession()->SendPacket(&data); } -void Unit::SendPetSpellCooldown (uint32 spellid, time_t cooltime) -{ - Unit* owner = GetOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4); - data << uint64(GetGUID()); - data << uint8(0x0); // flags (0x1, 0x2) - data << uint32(spellid); - data << uint32(cooltime); - - ((Player*)owner)->GetSession()->SendPacket(&data); -} - -void Unit::SendPetClearCooldown (uint32 spellid) -{ - Unit* owner = GetOwner(); - if(!owner || owner->GetTypeId() != TYPEID_PLAYER) - return; - - WorldPacket data(SMSG_CLEAR_COOLDOWN, 4+8); - data << uint32(spellid); - data << uint64(GetGUID()); - ((Player*)owner)->GetSession()->SendPacket(&data); -} - void Unit::SendPetAIReaction(uint64 guid) { Unit* owner = GetOwner(); @@ -13312,21 +13623,13 @@ float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) } } -AuraEffect* Unit::GetDummyAura( uint32 spell_id ) const -{ - Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); - for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) - if ((*itr)->GetId() == spell_id) - return *itr; - - return NULL; -} - -AuraEffect* Unit::GetDummyAura(SpellFamilyNames name, uint32 iconId) const +AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const { - Unit::AuraEffectList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); + Unit::AuraEffectList const& mDummy = GetAurasByType(type); for(Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) { + if (effIndex != (*itr)->GetEffIndex()) + continue; SpellEntry const * spell = (*itr)->GetSpellProto(); if (spell->SpellIconID == iconId && spell->SpellFamilyName == name && !spell->SpellFamilyFlags) @@ -13368,12 +13671,6 @@ void Unit::AddPetAura(PetAura const* petSpell) if(GetTypeId() != TYPEID_PLAYER) return; - // Aura already added - not need to add it twice - // This check is to prevent existing pet having aura applied twice (passive auras can stack) - // if aura has more than 1 dummy effect - if (m_petAuras.find(petSpell)!= m_petAuras.end()) - return; - m_petAuras.insert(petSpell); if(Pet* pet = ((Player*)this)->GetPet()) pet->CastPetAura(petSpell); @@ -13445,15 +13742,15 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co if (!EventProcFlag) return false; - // Additional checks for triggered spells - if (procExtra & PROC_EX_INTERNAL_TRIGGERED) + // Additional checks for triggered spells (ignore trap casts) + if (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_ON_TRAP_ACTIVATION)) { if (!(spellProto->AttributesEx3 & SPELL_ATTR_EX3_CAN_PROC_TRIGGERED)) return false; } // Check spellProcEvent data requirements - if(!spellmgr.IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra)) + if(!spellmgr.IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active)) return false; // In most cases req get honor or XP from kill if (EventProcFlag & PROC_FLAG_KILL && GetTypeId() == TYPEID_PLAYER) @@ -13465,7 +13762,7 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co if (!allow) return false; } - // Aura added by spell can`t trogger from self (prevent drop charges/do triggers) + // Aura added by spell can`t trigger from self (prevent drop charges/do triggers) // But except periodic and kill triggers (can triggered from self) if(procSpell && procSpell->Id == spellProto->Id && !(spellProto->procFlags&(PROC_FLAG_ON_TAKE_PERIODIC | PROC_FLAG_KILL))) @@ -13504,10 +13801,18 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry co if(spellProcEvent && spellProcEvent->customChance) chance = spellProcEvent->customChance; // If PPM exist calculate chance from PPM - if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0) + if(spellProcEvent && spellProcEvent->ppmRate != 0) { - uint32 WeaponSpeed = GetAttackTime(attType); - chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto); + if(!isVictim) + { + uint32 WeaponSpeed = GetAttackTime(attType); + chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto); + } + else + { + uint32 WeaponSpeed = pVictim->GetAttackTime(attType); + chance = pVictim->GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate, spellProto); + } } // Apply chance modifer aura if(Player* modOwner = GetSpellModOwner()) @@ -13583,7 +13888,7 @@ bool Unit::HandleAuraRaidProcFromCharge( AuraEffect* triggeredByAura ) damageSpellId=43594; break; default: - sLog.outDebug("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id); + sLog.outError("Unit::HandleAuraRaidProcFromCharge, received not handled spell: %u", spellProto->Id); return false; } @@ -13664,6 +13969,9 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss) player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0); } + // Proc auras on death - must be before aura/combat remove + pVictim->ProcDamageAndSpell(NULL, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, BASE_ATTACK, 0); + // if talent known but not triggered (check priest class for speedup check) bool SpiritOfRedemption = false; if(pVictim->GetTypeId()==TYPEID_PLAYER && pVictim->getClass()==CLASS_PRIEST ) @@ -13705,10 +14013,10 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss) ((Player*)pVictim)->SetPvPDeath(player!=NULL); // only if not player and not controlled by player pet. And not at BG - if (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) + if ( (durabilityLoss && !player && !((Player*)pVictim)->InBattleGround()) || ( player && sWorld.getConfig(CONFIG_DURABILITY_LOSS_IN_PVP) ) ) { - DEBUG_LOG("We are dead, loosing 10 percents durability"); - ((Player*)pVictim)->DurabilityLossAll(0.10f,false); + DEBUG_LOG("We are dead, losing %u percent durability", sWorld.getRate(RATE_DURABILITY_LOSS_ON_DEATH)); + ((Player*)pVictim)->DurabilityLossAll(sWorld.getRate(RATE_DURABILITY_LOSS_ON_DEATH),false); // durability lost message WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0); ((Player*)pVictim)->GetSession()->SendPacket(&data); @@ -13912,27 +14220,22 @@ void Unit::SetRooted(bool apply) { AddUnitMovementFlag(MOVEMENTFLAG_ROOT); - if(GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10); - data.append(GetPackGUID()); - data << (uint32)2; - SendMessageToSet(&data,true); - } - else + WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10); + data.append(GetPackGUID()); + data << (uint32)2; + SendMessageToSet(&data,true); + + if(GetTypeId() != TYPEID_PLAYER) ((Creature *)this)->StopMoving(); } else { if(!hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect { - if(GetTypeId() == TYPEID_PLAYER) - { - WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10); - data.append(GetPackGUID()); - data << (uint32)2; - SendMessageToSet(&data,true); - } + WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10); + data.append(GetPackGUID()); + data << (uint32)2; + SendMessageToSet(&data,true); RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT); } @@ -13990,22 +14293,28 @@ void Unit::SetConfused(bool apply) ((Player*)this)->SetClientControl(this, !apply); } -void Unit::SetCharmedBy(Unit* charmer, CharmType type) +bool Unit::SetCharmedBy(Unit* charmer, CharmType type) { if(!charmer) - return; + return false; assert(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER); assert(type != CHARM_TYPE_VEHICLE || GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isVehicle()); + sLog.outDebug("SetCharmedBy: charmer %u, charmed %u, type %u.", charmer->GetEntry(), GetEntry(), (uint32)type); + if(this == charmer) - return; + return false; - if(hasUnitState(UNIT_STAT_UNATTACKABLE)) - return; + //if(hasUnitState(UNIT_STAT_UNATTACKABLE)) + // return false; if(GetTypeId() == TYPEID_PLAYER && ((Player*)this)->GetTransport()) - return; + return false; + + // Already charmed + if(GetCharmerGUID()) + return false; CastStop(); CombatStop(); //TODO: CombatStop(true) may cause crash (interrupt spells) @@ -14027,7 +14336,7 @@ void Unit::SetCharmedBy(Unit* charmer, CharmType type) // StopCastingCharm may remove a possessed pet? if(!IsInWorld()) - return; + return false; // Set charmed setFaction(charmer->getFaction()); @@ -14096,7 +14405,8 @@ void Unit::SetCharmedBy(Unit* charmer, CharmType type) case CHARM_TYPE_CONVERT: break; } - } + } + return true; } void Unit::RemoveCharmedBy(Unit *charmer) @@ -14106,8 +14416,13 @@ void Unit::RemoveCharmedBy(Unit *charmer) if(!charmer) charmer = GetCharmer(); - else if(charmer != GetCharmer()) // one aura overrides another? + if(charmer != GetCharmer()) // one aura overrides another? + { +// sLog.outCrash("Unit::RemoveCharmedBy: this: " UI64FMTD " true charmer: " UI64FMTD " false charmer: " UI64FMTD, +// GetGUID(), GetCharmerGUID(), charmer->GetGUID()); +// assert(false); return; + } CharmType type; if(hasUnitState(UNIT_STAT_POSSESSED)) @@ -14525,6 +14840,12 @@ float Unit::MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) { + if(newPhaseMask==GetPhaseMask()) + return; + + if(IsInWorld()) + RemoveNotOwnSingleTargetAuras(newPhaseMask); // we can lost access to caster or target + WorldObject::SetPhaseMask(newPhaseMask,update); if(!IsInWorld()) @@ -14626,7 +14947,6 @@ void Unit::EnterVehicle(Vehicle *vehicle, int8 seatId) return; } - addUnitState(UNIT_STAT_ONVEHICLE); SetControlled(true, UNIT_STAT_ROOT); //movementInfo is set in AddPassenger //packets are sent in AddPassenger @@ -14671,7 +14991,6 @@ void Unit::ExitVehicle() Vehicle *vehicle = m_Vehicle; m_Vehicle = NULL; - clearUnitState(UNIT_STAT_ONVEHICLE); SetControlled(false, UNIT_STAT_ROOT); RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); @@ -14682,6 +15001,8 @@ void Unit::ExitVehicle() m_movementInfo.t_time = 0; m_movementInfo.t_seat = 0; + Relocate(vehicle->GetPositionX(), vehicle->GetPositionY(), vehicle->GetPositionZ(), GetOrientation()); + //Send leave vehicle, not correct if(GetTypeId() == TYPEID_PLAYER) { @@ -14830,3 +15151,89 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca //SendMessageToSet(&data, false); } } + +void Unit::SendThreatListUpdate() +{ + if (uint32 count = getThreatManager().getThreatList().size()) + { + sLog.outDebug( "WORLD: Send SMSG_THREAT_UPDATE Message" ); + WorldPacket data(SMSG_THREAT_UPDATE, 8 + count * 8); + data.append(GetPackGUID()); + data << uint32(count); + std::list<HostilReference*>& tlist = getThreatManager().getThreatList(); + for (std::list<HostilReference*>::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) + { + data.appendPackGUID((*itr)->getUnitGuid()); + data << uint32((*itr)->getThreat()); + } + SendMessageToSet(&data, false); + } +} + + +void Unit::SendChangeCurrentVictimOpcode(HostilReference* pHostilReference) +{ + if (uint32 count = getThreatManager().getThreatList().size()) + { + sLog.outDebug( "WORLD: Send SMSG_HIGHEST_THREAT_UPDATE Message" ); + WorldPacket data(SMSG_HIGHEST_THREAT_UPDATE, 8 + 8 + count * 8); + data.append(GetPackGUID()); + data.appendPackGUID(pHostilReference->getUnitGuid()); + data << uint32(count); + std::list<HostilReference*>& tlist = getThreatManager().getThreatList(); + for (std::list<HostilReference*>::const_iterator itr = tlist.begin(); itr != tlist.end(); ++itr) + { + data.appendPackGUID((*itr)->getUnitGuid()); + data << uint32((*itr)->getThreat()); + } + SendMessageToSet(&data, false); + } +} + +void Unit::SendClearThreatListOpcode() +{ + sLog.outDebug( "WORLD: Send SMSG_THREAT_CLEAR Message" ); + WorldPacket data(SMSG_THREAT_CLEAR, 8); + data.append(GetPackGUID()); + SendMessageToSet(&data, false); +} + +void Unit::SendRemoveFromThreatListOpcode(HostilReference* pHostilReference) +{ + sLog.outDebug( "WORLD: Send SMSG_THREAT_REMOVE Message" ); + WorldPacket data(SMSG_THREAT_REMOVE, 8 + 8); + data.append(GetPackGUID()); + data.appendPackGUID(pHostilReference->getUnitGuid()); + SendMessageToSet(&data, false); +} + +void Unit::RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ) +{ + float addRage; + + float rageconversion = ((0.0091107836 * getLevel()*getLevel())+3.225598133*getLevel())+4.2652911; + + // Unknown if correct, but lineary adjust rage conversion above level 70 + if (getLevel() > 70) + rageconversion += 13.27f*(getLevel()-70); + + if(attacker) + { + addRage = ((damage/rageconversion*7.5 + weaponSpeedHitFactor)/2); + + // talent who gave more rage on attack + addRage *= 1.0f + GetTotalAuraModifier(SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT) / 100.0f; + } + else + { + addRage = damage/rageconversion*2.5; + + // Berserker Rage effect + if(HasAura(18499)) + addRage *= 2.0; + } + + addRage *= sWorld.getRate(RATE_POWER_RAGE_INCOME); + + ModifyPower(POWER_RAGE, uint32(addRage*10)); +} diff --git a/src/game/Unit.h b/src/game/Unit.h index 03a02f0c512..0c96f6a17e6 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -56,6 +56,7 @@ enum SpellChannelInterruptFlags CHANNEL_FLAG_MOVEMENT = 0x0008, CHANNEL_FLAG_TURNING = 0x0010, CHANNEL_FLAG_DAMAGE2 = 0x0080, + CHANNEL_FLAG_ONLY_IN_WATER = 0x0100, CHANNEL_FLAG_DELAY = 0x4000 }; @@ -196,6 +197,7 @@ enum ShapeshiftForm FORM_AMBIENT = 0x06, FORM_GHOUL = 0x07, FORM_DIREBEAR = 0x08, + FORM_SHADOW_DANCE = 0x0D, FORM_CREATUREBEAR = 0x0E, FORM_CREATURECAT = 0x0F, FORM_GHOSTWOLF = 0x10, @@ -205,6 +207,7 @@ enum ShapeshiftForm FORM_TEST = 0x14, FORM_ZOMBIE = 0x15, FORM_METAMORPHOSIS = 0x16, + FORM_UNDEAD = 0x19, FORM_FLIGHT_EPIC = 0x1B, FORM_SHADOW = 0x1C, FORM_FLIGHT = 0x1D, @@ -580,6 +583,7 @@ enum UnitFlags2 UNIT_FLAG2_FEIGN_DEATH = 0x00000001, UNIT_FLAG2_UNK1 = 0x00000002, // Hide unit model (show only player equip) UNIT_FLAG2_COMPREHEND_LANG = 0x00000008, + UNIT_FLAG2_MIRROR_IMAGE = 0x00000010, UNIT_FLAG2_FORCE_MOVE = 0x00000040, UNIT_FLAG2_DISARM_OFFHAND = 0x00000080, UNIT_FLAG2_DISARM_RANGED = 0x00000400, //this does not disable ranged weapon display (maybe additional flag needed?) @@ -768,10 +772,12 @@ enum MeleeHitOutcome struct CleanDamage { - CleanDamage(uint32 _damage, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome) : - damage(_damage), attackType(_attackType), hitOutCome(_hitOutCome) {} + CleanDamage(uint32 mitigated, uint32 absorbed, WeaponAttackType _attackType, MeleeHitOutcome _hitOutCome) : + mitigated_damage(mitigated), absorbed_damage(absorbed), attackType(_attackType), hitOutCome(_hitOutCome) {} + + uint32 absorbed_damage; + uint32 mitigated_damage; - uint32 damage; WeaponAttackType attackType; MeleeHitOutcome hitOutCome; }; @@ -823,8 +829,8 @@ struct SpellNonMeleeDamage{ struct SpellPeriodicAuraLogInfo { - SpellPeriodicAuraLogInfo(AuraEffect *_auraEff, uint32 _damage, uint32 _overDamage, uint32 _absorb, uint32 _resist, float _multiplier) - : auraEff(_auraEff), damage(_damage), overDamage(_overDamage), absorb(_absorb), resist(_resist), multiplier(_multiplier) {} + SpellPeriodicAuraLogInfo(AuraEffect *_auraEff, uint32 _damage, uint32 _overDamage, uint32 _absorb, uint32 _resist, float _multiplier, bool _critical) + : auraEff(_auraEff), damage(_damage), overDamage(_overDamage), absorb(_absorb), resist(_resist), multiplier(_multiplier), critical(_critical){} AuraEffect *auraEff; uint32 damage; @@ -832,6 +838,7 @@ struct SpellPeriodicAuraLogInfo uint32 resist; uint32 overDamage; // overkill/overheal float multiplier; + bool critical; }; uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition); @@ -855,12 +862,12 @@ enum CurrentSpellTypes enum ActiveStates { - ACT_PASSIVE = 0x0100, // 0x0100 - passive - ACT_DISABLED = 0x8100, // 0x8000 - castable - ACT_ENABLED = 0xC100, // 0x4000 | 0x8000 - auto cast + castable - ACT_COMMAND = 0x0700, // 0x0100 | 0x0200 | 0x0400 - ACT_REACTION = 0x0600, // 0x0200 | 0x0400 - ACT_DECIDE = 0x0001 // what is it? + ACT_PASSIVE = 0x01, // 0x01 - passive + ACT_DISABLED = 0x81, // 0x80 - castable + ACT_ENABLED = 0xC1, // 0x40 | 0x80 - auto cast + castable + ACT_COMMAND = 0x07, // 0x01 | 0x02 | 0x04 + ACT_REACTION = 0x06, // 0x02 | 0x04 + ACT_DECIDE = 0x00 // custom }; enum ReactStates @@ -878,24 +885,40 @@ enum CommandStates COMMAND_ABANDON = 3 }; +#define UNIT_ACTION_BUTTON_ACTION(X) (uint32(X) & 0x00FFFFFF) +#define UNIT_ACTION_BUTTON_TYPE(X) ((uint32(X) & 0xFF000000) >> 24) +#define MAX_UNIT_ACTION_BUTTON_ACTION_VALUE (0x00FFFFFF+1) +#define MAKE_UNIT_ACTION_BUTTON(A,T) (uint32(A) | (uint32(T) << 24)) + struct UnitActionBarEntry { - UnitActionBarEntry() : SpellOrAction(0), Type(ACT_DISABLED) {} + UnitActionBarEntry() : packedData(uint32(ACT_DISABLED) << 24) {} - uint16 SpellOrAction; - uint16 Type; + uint32 packedData; // helper + ActiveStates GetType() const { return ActiveStates(UNIT_ACTION_BUTTON_TYPE(packedData)); } + uint32 GetAction() const { return UNIT_ACTION_BUTTON_ACTION(packedData); } bool IsActionBarForSpell() const { + ActiveStates Type = GetType(); return Type == ACT_DISABLED || Type == ACT_ENABLED || Type == ACT_PASSIVE; } -}; -struct CharmSpellEntry -{ - uint16 spellId; - uint16 active; + void SetActionAndType(uint32 action, ActiveStates type) + { + packedData = MAKE_UNIT_ACTION_BUTTON(action,type); + } + + void SetType(ActiveStates type) + { + packedData = MAKE_UNIT_ACTION_BUTTON(UNIT_ACTION_BUTTON_ACTION(packedData),type); + } + + void SetAction(uint32 action) + { + packedData = (packedData & 0xFF000000) | UNIT_ACTION_BUTTON_ACTION(action); + } }; typedef std::list<Player*> SharedVisionList; @@ -908,6 +931,8 @@ enum CharmType CHARM_TYPE_CONVERT, }; +typedef UnitActionBarEntry CharmSpellEntry; + enum ActionBarIndex { ACTION_BAR_INDEX_START = 0, @@ -946,8 +971,7 @@ struct CharmInfo void SetSpellAutocast(uint32 spell_id, bool state); void SetActionBar(uint8 index, uint32 spellOrAction,ActiveStates type) { - PetActionBar[index].Type = type; - PetActionBar[index].SpellOrAction = spellOrAction; + PetActionBar[index].SetActionAndType(spellOrAction,type); } UnitActionBarEntry const* GetActionBarEntry(uint8 index) const { return &(PetActionBar[index]); } @@ -988,6 +1012,7 @@ enum ReactiveType // delay time next attack to prevent client attack animation problems #define ATTACK_DISPLAY_DELAY 200 +#define MAX_PLAYER_STEALTH_DETECT_RANGE 45.0f // max distance for detection targets by player struct SpellProcEventEntry; // used only privately @@ -998,6 +1023,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject typedef std::set<Unit*> ControlList; typedef std::pair<uint32, uint8> spellEffectPair; typedef std::multimap<uint32, Aura*> AuraMap; + typedef std::multimap<AuraState, Aura*> AuraStateAurasMap; typedef std::list<AuraEffect *> AuraEffectList; typedef std::list<Aura *> AuraList; typedef std::list<DiminishingReturn> Diminishing; @@ -1014,7 +1040,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject DiminishingLevels GetDiminishing(DiminishingGroup group); void IncrDiminishing(DiminishingGroup group); - void ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster, DiminishingLevels Level); + void ApplyDiminishingToDuration(DiminishingGroup group, int32 &duration,Unit* caster, DiminishingLevels Level, int32 limitduration); void ApplyDiminishingAura(DiminishingGroup group, bool apply); void ClearDiminishings() { m_Diminishing.clear(); } @@ -1177,7 +1203,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void Unmount(); uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } - void RemoveSpellbyDamageTaken(uint32 damage, uint32 spell); void DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb); uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *spellProto = NULL, bool durabilityLoss = true); void Kill(Unit *pVictim, bool durabilityLoss = true); @@ -1258,7 +1283,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject bool isInFlight() const { return hasUnitState(UNIT_STAT_IN_FLIGHT); } bool isInCombat() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); } - void CombatStart(Unit* target); + void CombatStart(Unit* target, bool initialAggro = true); void SetInCombatState(bool PvP, Unit* enemy = NULL); void SetInCombatWith(Unit* enemy); void ClearInCombat(); @@ -1288,7 +1313,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject uint32 SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage); void CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0); void CastSpell(Unit* Victim, SpellEntry const *spellInfo, bool triggered, Item *castItem= NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0); - void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0); + void CastSpell(float x, float y, float z, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0, Unit* originalVictim = 0); void CastCustomSpell(Unit* Victim, uint32 spellId, int32 const* bp0, int32 const* bp1, int32 const* bp2, bool triggered, Item *castItem= NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0); void CastCustomSpell(uint32 spellId, SpellValueMod mod, int32 value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0); void CastCustomSpell(uint32 spellId, CustomSpellValues const &value, Unit* Victim = NULL, bool triggered = true, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0); @@ -1325,6 +1350,11 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); void SendMovementFlagUpdate(); + void SendChangeCurrentVictimOpcode(HostilReference* pHostilReference); + void SendClearThreatListOpcode(); + void SendRemoveFromThreatListOpcode(HostilReference* pHostilReference); + void SendThreatListUpdate(); + void BuildHeartBeatMsg(WorldPacket *data) const; void OutMovementInfo() const; @@ -1374,7 +1404,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SetMinion(Minion *minion, bool apply); void SetCharm(Unit* target, bool apply); Unit* GetNextRandomRaidMemberOrPet(float radius); - void SetCharmedBy(Unit* charmer, CharmType type); + bool SetCharmedBy(Unit* charmer, CharmType type); void RemoveCharmedBy(Unit* charmer); void RestoreFaction(); @@ -1420,11 +1450,15 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId); void RemoveAurasByType(AuraType auraType, uint64 casterGUID = 0, Aura * except=NULL, bool negative = true, bool positive = true); void RemoveAurasByTypeWithDispel(AuraType auraType, Spell * spell = NULL); - void RemoveNotOwnSingleTargetAuras(); + void RemoveNotOwnSingleTargetAuras(uint32 newPhase = 0x0); + + void RemoveSpellsCausingAura(AuraType auraType); + void RemoveRankAurasDueToSpell(uint32 spellId); bool RemoveNoStackAurasDueToAura(Aura *Aur); void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = NULL); void RemoveAurasWithFamily(uint32 family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID); void RemoveMovementImpairingAuras(); + void RemoveAurasWithMechanic(uint32 mechanic_mask, uint32 except=0); void RemoveAllAuras(); void RemoveArenaAuras(bool onleave = false); void RemoveAllAurasOnDeath(); @@ -1469,6 +1503,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true); Spell* FindCurrentSpellBySpellId(uint32 spell_id) const; + int32 GetCurrentSpellCastTime(uint32 spell_id) const; Spell* m_currentSpells[CURRENT_MAX_SPELL]; @@ -1572,14 +1607,15 @@ class TRINITY_DLL_SPEC Unit : public WorldObject AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, uint64 casterGUID = 0) const; Aura * GetAura(uint32 spellId, uint64 casterGUID = 0) const; - AuraEffect* GetAura(AuraType type, uint32 family, uint32 familyFlag1 , uint32 familyFlag2=0, uint32 familyFlag3=0, uint64 casterGUID=0); + AuraEffect * GetAura(AuraType type, uint32 family, uint32 familyFlag1 , uint32 familyFlag2=0, uint32 familyFlag3=0, uint64 casterGUID=0); + AuraEffect * IsScriptOverriden(SpellEntry const * spell, int32 script) const; bool HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster = 0) const; bool HasAura(uint32 spellId, uint64 caster = 0) const; bool HasAura(Aura * aur) const; bool HasAuraType(AuraType auraType) const; bool HasAuraTypeWithMiscvalue(AuraType auratype, uint32 miscvalue) const; - AuraEffect* GetDummyAura(uint32 spell_id) const; - AuraEffect* GetDummyAura(SpellFamilyNames name, uint32 iconId) const; + inline AuraEffect* GetDummyAura(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const { return GetAuraEffect(SPELL_AURA_DUMMY, name, iconId, effIndex);} + AuraEffect* GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const; uint32 GetDiseasesByCaster(uint64 casterGUID, bool remove = false); uint32 GetDoTsByCaster(uint64 casterGUID) const; @@ -1625,6 +1661,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject uint32 CalculateDamage(WeaponAttackType attType, bool normalized); float GetAPMultiplier(WeaponAttackType attType, bool normalized); void ModifyAuraState(AuraState flag, bool apply); + uint32 BuildAuraStateUpdateForTarget(Unit * target) const; bool HasAuraState(AuraState flag, SpellEntry const *spellProto = NULL, Unit * Caster = NULL) const ; void UnsummonAllTotems(); Unit* SelectMagnetTarget(Unit *victim, SpellEntry const *spellInfo = NULL); @@ -1705,8 +1742,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SendPetCastFail(uint32 spellid, SpellCastResult msg); void SendPetActionFeedback (uint8 msg); void SendPetTalk (uint32 pettalk); - void SendPetSpellCooldown (uint32 spellid, time_t cooltime); - void SendPetClearCooldown (uint32 spellid); void SendPetAIReaction(uint64 guid); ///----------End of Pet responses methods---------- @@ -1780,6 +1815,10 @@ class TRINITY_DLL_SPEC Unit : public WorldObject bool canFly() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLY_MODE); } bool IsFlying() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLYING); } void SetFlying(bool apply); + + void RewardRage( uint32 damage, uint32 weaponSpeedHitFactor, bool attacker ); + + virtual float GetFollowAngle() const { return M_PI/2; } protected: explicit Unit (); @@ -1819,14 +1858,13 @@ class TRINITY_DLL_SPEC Unit : public WorldObject AuraEffectList m_modAuras[TOTAL_AURAS]; AuraList m_scAuras; // casted singlecast auras AuraList m_interruptableAuras; - AuraList m_ccAuras; AuraList m_removedAuras; + AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove uint32 m_interruptMask; float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END]; float m_weaponDamage[MAX_ATTACK][2]; bool m_canModifyStats; - //std::list< spellEffectPair > AuraSpells[TOTAL_AURAS]; // TODO: use this if ok for mem VisibleAuraMap m_visibleAuras; float m_speed_rate[MAX_MOVE_TYPE]; diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp index c159861697c..a41ad894097 100644 --- a/src/game/UnitAI.cpp +++ b/src/game/UnitAI.cpp @@ -325,6 +325,10 @@ void UnitAI::FillAISpellInfo() } } } + AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime; + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex); + if (srange) + AIInfo->maxRange = srange->maxRangeHostile * 3 / 4; } } @@ -348,7 +352,7 @@ void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) } if(!charmer->isInCombat()) - me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle()); Unit *target = me->getVictim(); if(!target || !charmer->canAttack(target)) diff --git a/src/game/UnitAI.h b/src/game/UnitAI.h index 9530405ed4d..3e6ce4f4a6f 100644 --- a/src/game/UnitAI.h +++ b/src/game/UnitAI.h @@ -23,6 +23,7 @@ #include "Platform/Define.h" #include <list> +#include "Unit.h" class Unit; class Player; @@ -47,7 +48,7 @@ class TRINITY_DLL_SPEC UnitAI virtual void AttackStart(Unit *); virtual void UpdateAI(const uint32 diff) = 0; - virtual void InitializeAI() { Reset(); } + virtual void InitializeAI() { if(!me->isDead()) Reset(); } virtual void Reset() {}; diff --git a/src/game/UpdateData.cpp b/src/game/UpdateData.cpp index a3192b74b0e..e461d63e248 100644 --- a/src/game/UpdateData.cpp +++ b/src/game/UpdateData.cpp @@ -128,7 +128,7 @@ bool UpdateData::BuildPacket(WorldPacket *packet) if (pSize > 100 ) // compress large packets { - uint32 destsize = pSize; + uint32 destsize = compressBound(pSize); packet->resize( destsize + sizeof(uint32) ); packet->put<uint32>(0, pSize); diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp index 0aa0d48a24c..3cad7963d0b 100644 --- a/src/game/Vehicle.cpp +++ b/src/game/Vehicle.cpp @@ -65,9 +65,9 @@ void Vehicle::AddToWorld() } } + Unit::AddToWorld(); InstallAllAccessories(); - Unit::AddToWorld(); AIM_Initialize(); } } @@ -90,9 +90,11 @@ void Vehicle::InstallAllAccessories() InstallAccessory(33139,7); break; case 33114: - InstallAccessory(33143,1); - //InstallAccessory(33142,0); - InstallAccessory(33142,2); + InstallAccessory(33142,0); + //InstallAccessory(33143,1); + //InstallAccessory(33142,2); + InstallAccessory(33143,2); + InstallAccessory(33142,1); break; } } @@ -266,8 +268,7 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId) if(!accessory) return; - accessory->m_Vehicle = this; - AddPassenger(accessory, seatId); + accessory->EnterVehicle(this, seatId); // This is not good, we have to send update twice accessory->SendMovementFlagUpdate(); } @@ -310,6 +311,9 @@ bool Vehicle::AddPassenger(Unit *unit, int8 seatId) RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); } + if(!(seat->second.seatInfo->m_flags & 0x4000)) + unit->addUnitState(UNIT_STAT_ONVEHICLE); + //SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); @@ -321,11 +325,15 @@ bool Vehicle::AddPassenger(Unit *unit, int8 seatId) unit->m_movementInfo.t_time = 0; // 1 for player unit->m_movementInfo.t_seat = seat->first; - if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->IsUsable()) // not right - SetCharmedBy(unit, CHARM_TYPE_VEHICLE); + if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->m_flags & 0x800) // not right + if (!SetCharmedBy(unit, CHARM_TYPE_VEHICLE)) + assert(false); if(IsInWorld()) + { unit->SendMonsterMoveTransport(this); + GetMap()->CreatureRelocation(this, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); + } //if(unit->GetTypeId() == TYPEID_PLAYER) // ((Player*)unit)->SendTeleportAckMsg(); @@ -341,27 +349,27 @@ void Vehicle::RemovePassenger(Unit *unit) SeatMap::iterator seat; for(seat = m_Seats.begin(); seat != m_Seats.end(); ++seat) - { if(seat->second.passenger == unit) - { - seat->second.passenger = NULL; - if(seat->second.seatInfo->IsUsable()) - { - if(!m_usableSeatNum) - SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - ++m_usableSeatNum; - } break; - } - } assert(seat != m_Seats.end()); - sLog.outDebug("Unit %s exit vehicle entry %u id %u dbguid %u", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow()); + sLog.outDebug("Unit %s exit vehicle entry %u id %u dbguid %u seat %d", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow(), (int32)seat->first); + + seat->second.passenger = NULL; + if(seat->second.seatInfo->IsUsable()) + { + if(!m_usableSeatNum) + SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + ++m_usableSeatNum; + } + + if(!(seat->second.seatInfo->m_flags & 0x4000)) + unit->clearUnitState(UNIT_STAT_ONVEHICLE); //SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->IsUsable()) + if(unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->m_flags & 0x800) RemoveCharmedBy(unit); // only for flyable vehicles? @@ -382,7 +390,6 @@ void Vehicle::Dismiss() RemoveAllPassengers(); SendObjectDeSpawnAnim(GetGUID()); CombatStop(); - CleanupsBeforeDelete(); AddObjectToRemoveList(); } diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index 34be9d3179b..92fd9bca2d7 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -198,7 +198,7 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff) //note: disable "start" for mtmap if(node->event_id && rand()%100 < node->event_chance) - sWorld.ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL, false); + unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/); MovementInform(unit); unit.UpdateWaypointID(i_currentNode); diff --git a/src/game/World.cpp b/src/game/World.cpp index 608aaec01d5..f7cc552342a 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -63,7 +63,6 @@ #include "GridNotifiersImpl.h" #include "CellImpl.h" #include "InstanceSaveMgr.h" -#include "WaypointManager.h" #include "Util.h" #include "Language.h" #include "CreatureGroups.h" @@ -83,14 +82,6 @@ float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE; float World::m_VisibleUnitGreyDistance = 0; float World::m_VisibleObjectGreyDistance = 0; -struct ScriptAction -{ - uint64 sourceGUID; - uint64 targetGUID; - uint64 ownerGUID; // owner of source if source is item - ScriptInfo const* script; // pointer to static script data -}; - /// World constructor World::World() { @@ -102,8 +93,11 @@ World::World() m_startTime=m_gameTime; m_maxActiveSessionCount = 0; m_maxQueuedSessionCount = 0; + m_PlayerCount = 0; + m_MaxPlayerCount = 0; m_resultQueue = NULL; m_NextDailyQuestReset = 0; + m_scheduledScripts = 0; m_defaultDbcLocale = LOCALE_enUS; m_availableDbcLocaleMask = 0; @@ -266,7 +260,7 @@ World::AddSession_ (WorldSession* s) float popu = GetActiveSessionCount (); //updated number of users on the server popu /= pLimit; popu *= 2; - LoginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID); + loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID); sLog.outDetail ("Server Population (%f).", popu); } } @@ -475,6 +469,12 @@ void World::LoadConfigSettings(bool reload) rate_values[RATE_XP_KILL] = sConfig.GetFloatDefault("Rate.XP.Kill", 1.0f); rate_values[RATE_XP_QUEST] = sConfig.GetFloatDefault("Rate.XP.Quest", 1.0f); rate_values[RATE_XP_EXPLORE] = sConfig.GetFloatDefault("Rate.XP.Explore", 1.0f); + rate_values[RATE_REPAIRCOST] = sConfig.GetFloatDefault("Rate.RepairCost", 1.0f); + if(rate_values[RATE_REPAIRCOST] < 0.0f) + { + sLog.outError("Rate.RepairCost (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_REPAIRCOST]); + rate_values[RATE_REPAIRCOST] = 0.0f; + } rate_values[RATE_REPUTATION_GAIN] = sConfig.GetFloatDefault("Rate.Reputation.Gain", 1.0f); rate_values[RATE_REPUTATION_LOWLEVEL_KILL] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Kill", 1.0f); rate_values[RATE_REPUTATION_LOWLEVEL_QUEST] = sConfig.GetFloatDefault("Rate.Reputation.LowLevel.Quest", 1.0f); @@ -526,6 +526,19 @@ void World::LoadConfigSettings(bool reload) rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = NOMINAL_MELEE_RANGE; } + rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = sConfig.GetFloatDefault("DurabilityLoss.OnDeath", 10.0f); + if(rate_values[RATE_DURABILITY_LOSS_ON_DEATH] < 0.0f) + { + sLog.outError("DurabilityLoss.OnDeath (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]); + rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = 0.0f; + } + if(rate_values[RATE_DURABILITY_LOSS_ON_DEATH] > 100.0f) + { + sLog.outError("DurabilityLoss.OnDeath (%f) must be <=100. Using 100.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]); + rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = 0.0f; + } + rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = rate_values[RATE_DURABILITY_LOSS_ON_DEATH] / 100.0f; + rate_values[RATE_DURABILITY_LOSS_DAMAGE] = sConfig.GetFloatDefault("DurabilityLossChance.Damage",0.5f); if(rate_values[RATE_DURABILITY_LOSS_DAMAGE] < 0.0f) { @@ -553,6 +566,8 @@ void World::LoadConfigSettings(bool reload) ///- Read other configuration items from the config file + m_configs[CONFIG_DURABILITY_LOSS_IN_PVP] = sConfig.GetBoolDefault("DurabilityLoss.InPvP", false); + m_configs[CONFIG_COMPRESSION] = sConfig.GetIntDefault("Compression", 1); if(m_configs[CONFIG_COMPRESSION] < 1 || m_configs[CONFIG_COMPRESSION] > 9) { @@ -639,6 +654,27 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault ("StrictCharterNames", 0); m_configs[CONFIG_STRICT_PET_NAMES] = sConfig.GetIntDefault ("StrictPetNames", 0); + m_configs[CONFIG_MIN_PLAYER_NAME] = sConfig.GetIntDefault ("MinPlayerName", 2); + if(m_configs[CONFIG_MIN_PLAYER_NAME] < 1 || m_configs[CONFIG_MIN_PLAYER_NAME] > MAX_PLAYER_NAME) + { + sLog.outError("MinPlayerName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_PLAYER_NAME],MAX_PLAYER_NAME); + m_configs[CONFIG_MIN_PLAYER_NAME] = 2; + } + + m_configs[CONFIG_MIN_CHARTER_NAME] = sConfig.GetIntDefault ("MinCharterName", 2); + if(m_configs[CONFIG_MIN_CHARTER_NAME] < 1 || m_configs[CONFIG_MIN_CHARTER_NAME] > MAX_CHARTER_NAME) + { + sLog.outError("MinCharterName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_CHARTER_NAME],MAX_CHARTER_NAME); + m_configs[CONFIG_MIN_CHARTER_NAME] = 2; + } + + m_configs[CONFIG_MIN_PET_NAME] = sConfig.GetIntDefault ("MinPetName", 2); + if(m_configs[CONFIG_MIN_PET_NAME] < 1 || m_configs[CONFIG_MIN_PET_NAME] > MAX_PET_NAME) + { + sLog.outError("MinPetName (%i) must be in range 1..%u. Set to 2.",m_configs[CONFIG_MIN_PET_NAME],MAX_PET_NAME); + m_configs[CONFIG_MIN_PET_NAME] = 2; + } + m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault ("CharactersCreatingDisabled", 0); m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10); @@ -790,8 +826,9 @@ void World::LoadConfigSettings(bool reload) //m_configs[CONFIG_GM_ACCEPT_TICKETS] = sConfig.GetIntDefault("GM.AcceptTickets", 2); m_configs[CONFIG_GM_CHAT] = sConfig.GetIntDefault("GM.Chat", 2); m_configs[CONFIG_GM_WISPERING_TO] = sConfig.GetIntDefault("GM.WhisperingTo", 2); - m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList", false); - m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList", false); + + m_configs[CONFIG_GM_LEVEL_IN_GM_LIST] = sConfig.GetIntDefault("GM.InGMList.Level", SEC_ADMINISTRATOR); + m_configs[CONFIG_GM_LEVEL_IN_WHO_LIST] = sConfig.GetIntDefault("GM.InWhoList.Level", SEC_ADMINISTRATOR); m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false); m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1); m_configs[CONFIG_ALLOW_GM_GROUP] = sConfig.GetBoolDefault("GM.AllowInvite", false); @@ -1156,7 +1193,7 @@ void World::SetInitialWorldSettings() // not send custom type REALM_FFA_PVP to realm list uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_GAME_TYPE); uint32 realm_zone = getConfig(CONFIG_REALM_ZONE); - LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID); + loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID); ///- Remove the bones after a restart CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0'"); @@ -1340,9 +1377,6 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Spell target coordinates..." ); spellmgr.LoadSpellTargetPositions(); - sLog.outString( "Loading SpellAffect definitions..." ); - spellmgr.LoadSpellAffects(); - sLog.outString( "Loading spell pet auras..." ); spellmgr.LoadSpellPetAuras(); @@ -1514,9 +1548,11 @@ void World::SetInitialWorldSettings() sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d", local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec); - LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%s', 0)", + loginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%s', 0)", realmID, uint64(m_startTime), isoDate); + static uint32 abtimer = 0; + abtimer = sConfig.GetIntDefault("AutoBroadcast.Timer", 60000); m_timers[WUPDATE_OBJECTS].SetInterval(IN_MILISECONDS/2); m_timers[WUPDATE_SESSIONS].SetInterval(0); m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILISECONDS); @@ -1527,6 +1563,7 @@ void World::SetInitialWorldSettings() //erase corpses every 20 minutes m_timers[WUPDATE_CLEANDB].SetInterval(m_configs[CONFIG_LOGDB_CLEARINTERVAL]*MINUTE*IN_MILISECONDS); // clean logs table every 14 days by default + m_timers[WUPDATE_AUTOBROADCAST].SetInterval(abtimer); //to set mailtimer to return mails every day between 4 and 5 am //mailtimer is increased when updating auctions @@ -1565,7 +1602,7 @@ void World::SetInitialWorldSettings() objmgr.LoadTransportEvents(); sLog.outString("Deleting expired bans..." ); - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); sLog.outString("Calculate next daily quest reset time..." ); InitDailyQuestResetTime(); @@ -1574,7 +1611,7 @@ void World::SetInitialWorldSettings() poolhandler.Initialize(); sLog.outString("Initialize AuctionHouseBot..."); - AuctionHouseBotInit(); + auctionbot.Initialize(); // possibly enable db logging; avoid massive startup spam by doing it here. if (sLog.GetLogDBLater()) @@ -1700,7 +1737,7 @@ void World::Update(uint32 diff) /// <ul><li> Handle auctions when the timer has passed if (m_timers[WUPDATE_AUCTIONS].Passed()) { - AuctionHouseBot(); + auctionbot.Update(); m_timers[WUPDATE_AUCTIONS].Reset(); ///- Update mails (return old mails with item, or delete them) @@ -1748,7 +1785,7 @@ void World::Update(uint32 diff) uint32 maxClientsNum = GetMaxActiveSessionCount(); m_timers[WUPDATE_UPTIME].Reset(); - LoginDatabase.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD, tmpDiff, maxClientsNum, realmID, uint64(m_startTime)); + loginDatabase.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD, tmpDiff, maxClientsNum, realmID, uint64(m_startTime)); } /// <li> Clean logs table @@ -1760,7 +1797,7 @@ void World::Update(uint32 diff) uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount(); m_timers[WUPDATE_CLEANDB].Reset(); - LoginDatabase.PExecute("DELETE FROM logs WHERE (time + %u) < "UI64FMTD";", + loginDatabase.PExecute("DELETE FROM logs WHERE (time + %u) < "UI64FMTD";", sWorld.getConfig(CONFIG_LOGDB_CLEARTIME), uint64(time(0))); } } @@ -1775,12 +1812,15 @@ void World::Update(uint32 diff) MapManager::Instance().DoDelayedMovesAndRemoves(); }*/ - ///- Process necessary scripts - if (!m_scriptSchedule.empty()) + static uint32 autobroadcaston = 0; + autobroadcaston = sConfig.GetIntDefault("AutoBroadcast.On", 0); + if(autobroadcaston == 1) { - RecordTimeDiff(NULL); - ScriptsProcess(); - RecordTimeDiff("UpdateScriptsProcess"); + if (m_timers[WUPDATE_AUTOBROADCAST].Passed()) + { + m_timers[WUPDATE_AUTOBROADCAST].Reset(); + SendRNDBroadcast(); + } } sBattleGroundMgr.Update(diff); @@ -1827,831 +1867,6 @@ void World::ForceGameEventUpdate() m_timers[WUPDATE_EVENTS].Reset(); } -/// Put scripts in the execution queue -void World::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target, bool start) -{ - ///- Find the script map - ScriptMapMap::const_iterator s = scripts.find(id); - if (s == scripts.end()) - return; - - // prepare static data - uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; //some script commands doesn't have source - uint64 targetGUID = target ? target->GetGUID() : (uint64)0; - uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; - - ///- Schedule script execution for all scripts in the script map - ScriptMap const *s2 = &(s->second); - bool immedScript = false; - for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter) - { - ScriptAction sa; - sa.sourceGUID = sourceGUID; - sa.targetGUID = targetGUID; - sa.ownerGUID = ownerGUID; - - sa.script = &iter->second; - m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + iter->first, sa)); - if (iter->first == 0) - immedScript = true; - } - ///- If one of the effects should be immediate, launch the script execution - if (start && immedScript) - ScriptsProcess(); -} - -void World::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target) -{ - // NOTE: script record _must_ exist until command executed - - // prepare static data - uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; - uint64 targetGUID = target ? target->GetGUID() : (uint64)0; - uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0; - - ScriptAction sa; - sa.sourceGUID = sourceGUID; - sa.targetGUID = targetGUID; - sa.ownerGUID = ownerGUID; - - sa.script = &script; - m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + delay, sa)); - - ///- If effects should be immediate, launch the script execution - if(delay == 0) - ScriptsProcess(); -} - -/// Process queued scripts -void World::ScriptsProcess() -{ - if (m_scriptSchedule.empty()) - return; - - ///- Process overdue queued scripts - std::multimap<time_t, ScriptAction>::iterator iter = m_scriptSchedule.begin(); - // ok as multimap is a *sorted* associative container - while (!m_scriptSchedule.empty() && (iter->first <= m_gameTime)) - { - ScriptAction const& step = iter->second; - - Object* source = NULL; - - if(step.sourceGUID) - { - switch(GUID_HIPART(step.sourceGUID)) - { - case HIGHGUID_ITEM: - // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM - { - Player* player = HashMapHolder<Player>::Find(step.ownerGUID); - if(player) - source = player->GetItemByGuid(step.sourceGUID); - break; - } - case HIGHGUID_UNIT: - source = HashMapHolder<Creature>::Find(step.sourceGUID); - break; - case HIGHGUID_PET: - source = HashMapHolder<Pet>::Find(step.sourceGUID); - break; - case HIGHGUID_VEHICLE: - source = HashMapHolder<Vehicle>::Find(step.sourceGUID); - break; - case HIGHGUID_PLAYER: - source = HashMapHolder<Player>::Find(step.sourceGUID); - break; - case HIGHGUID_GAMEOBJECT: - source = HashMapHolder<GameObject>::Find(step.sourceGUID); - break; - case HIGHGUID_CORPSE: - source = HashMapHolder<Corpse>::Find(step.sourceGUID); - break; - case HIGHGUID_MO_TRANSPORT: - for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter) - { - if((*iter)->GetGUID() == step.sourceGUID) - { - source = reinterpret_cast<Object*>(*iter); - break; - } - } - break; - default: - sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID)); - break; - } - } - - //if(source && !source->IsInWorld()) source = NULL; - - Object* target = NULL; - - if(step.targetGUID) - { - switch(GUID_HIPART(step.targetGUID)) - { - case HIGHGUID_UNIT: - target = HashMapHolder<Creature>::Find(step.targetGUID); - break; - case HIGHGUID_PET: - target = HashMapHolder<Pet>::Find(step.targetGUID); - break; - case HIGHGUID_VEHICLE: - target = HashMapHolder<Vehicle>::Find(step.targetGUID); - break; - case HIGHGUID_PLAYER: // empty GUID case also - target = HashMapHolder<Player>::Find(step.targetGUID); - break; - case HIGHGUID_GAMEOBJECT: - target = HashMapHolder<GameObject>::Find(step.targetGUID); - break; - case HIGHGUID_CORPSE: - target = HashMapHolder<Corpse>::Find(step.targetGUID); - break; - default: - sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID)); - break; - } - } - - //if(target && !target->IsInWorld()) target = NULL; - - switch (step.script->command) - { - case SCRIPT_COMMAND_TALK: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature."); - break; - } - - if(source->GetTypeId()!=TYPEID_UNIT) - { - sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - if(step.script->datalong > 3) - { - sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong); - break; - } - - uint64 unit_target = target ? target->GetGUID() : 0; - - //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text - switch(step.script->datalong) - { - case 0: // Say - ((Creature *)source)->Say(step.script->dataint, LANG_UNIVERSAL, unit_target); - break; - case 1: // Whisper - if(!unit_target) - { - sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong); - break; - } - ((Creature *)source)->Whisper(step.script->dataint,unit_target); - break; - case 2: // Yell - ((Creature *)source)->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target); - break; - case 3: // Emote text - ((Creature *)source)->TextEmote(step.script->dataint, unit_target); - break; - default: - break; // must be already checked at load - } - break; - } - - case SCRIPT_COMMAND_EMOTE: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature."); - break; - } - - if(source->GetTypeId()!=TYPEID_UNIT) - { - sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - ((Creature *)source)->HandleEmoteCommand(step.script->datalong); - break; - case SCRIPT_COMMAND_FIELD_SET: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object."); - break; - } - if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", - step.script->datalong,source->GetValuesCount(),source->GetTypeId()); - break; - } - - source->SetUInt32Value(step.script->datalong, step.script->datalong2); - break; - case SCRIPT_COMMAND_MOVE_TO: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature."); - break; - } - - if(source->GetTypeId()!=TYPEID_UNIT) - { - sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 ); - ((Unit *)source)->GetMap()->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0); - break; - case SCRIPT_COMMAND_FLAG_SET: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object."); - break; - } - if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).", - step.script->datalong,source->GetValuesCount(),source->GetTypeId()); - break; - } - - source->SetFlag(step.script->datalong, step.script->datalong2); - break; - case SCRIPT_COMMAND_FLAG_REMOVE: - if(!source) - { - sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object."); - break; - } - if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount()) - { - sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).", - step.script->datalong,source->GetValuesCount(),source->GetTypeId()); - break; - } - - source->RemoveFlag(step.script->datalong, step.script->datalong2); - break; - - case SCRIPT_COMMAND_TELEPORT_TO: - { - // accept player in any one from target/source arg - if (!target && !source) - { - sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object."); - break; - } - - // must be only Player - if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER)) - { - sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0); - break; - } - - Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source; - - pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o); - break; - } - - case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: - { - if(!step.script->datalong) // creature not specified - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object."); - break; - } - - WorldObject* summoner = dynamic_cast<WorldObject*>(source); - - if(!summoner) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - float x = step.script->x; - float y = step.script->y; - float z = step.script->z; - float o = step.script->o; - - Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2); - if (!pCreature) - { - sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong); - break; - } - - break; - } - - case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: - { - if(!step.script->datalong) // gameobject not specified - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object."); - break; - } - - WorldObject* summoner = dynamic_cast<WorldObject*>(source); - - if(!summoner) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - GameObject *go = NULL; - int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2; - - CellPair p(Trinity::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong); - MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(summoner, go,go_check); - - TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker); - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(summoner->GetMapId(), summoner)); - - if ( !go ) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong); - break; - } - - if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE || - go->GetGoType()==GAMEOBJECT_TYPE_DOOR || - go->GetGoType()==GAMEOBJECT_TYPE_BUTTON || - go->GetGoType()==GAMEOBJECT_TYPE_TRAP ) - { - sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong); - break; - } - - if( go->isSpawned() ) - break; //gameobject already spawned - - go->SetLootState(GO_READY); - go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds - - go->GetMap()->Add(go); - break; - } - case SCRIPT_COMMAND_OPEN_DOOR: - { - if(!step.script->datalong) // door not specified - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - Unit* caster = (Unit*)source; - - GameObject *door = NULL; - int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; - - CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); - MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check); - - TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker); - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source)); - - if (!door) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong); - break; - } - if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR) - { - sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType()); - break; - } - - if (door->GetGoState() != GO_STATE_READY) - break; //door already open - - door->UseDoorOrButton(time_to_close); - - if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) - ((GameObject*)target)->UseDoorOrButton(time_to_close); - break; - } - case SCRIPT_COMMAND_CLOSE_DOOR: - { - if(!step.script->datalong) // guid for door not specified - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door."); - break; - } - - if(!source) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - Unit* caster = (Unit*)source; - - GameObject *door = NULL; - int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2; - - CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong); - MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check); - - TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker); - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source)); - - if ( !door ) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong); - break; - } - if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR ) - { - sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType()); - break; - } - - if( door->GetGoState() == GO_STATE_READY ) - break; //door already closed - - door->UseDoorOrButton(time_to_open); - - if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON) - ((GameObject*)target)->UseDoorOrButton(time_to_open); - - break; - } - case SCRIPT_COMMAND_QUEST_EXPLORED: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source."); - break; - } - - if(!target) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target."); - break; - } - - // when script called for item spell casting then target == (unit or GO) and source is player - WorldObject* worldObject; - Player* player; - - if(target->GetTypeId()==TYPEID_PLAYER) - { - if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - worldObject = (WorldObject*)source; - player = (Player*)target; - } - else - { - if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); - break; - } - - if(source->GetTypeId()!=TYPEID_PLAYER) - { - sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - worldObject = (WorldObject*)target; - player = (Player*)source; - } - - // quest id and flags checked at script loading - if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && - (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) ) - player->AreaExploredOrEventHappens(step.script->datalong); - else - player->FailQuest(step.script->datalong); - - break; - } - - case SCRIPT_COMMAND_ACTIVATE_OBJECT: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - if(!target) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject."); - break; - } - - if(target->GetTypeId()!=TYPEID_GAMEOBJECT) - { - sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId()); - break; - } - - Unit* caster = (Unit*)source; - - GameObject *go = (GameObject*)target; - - go->Use(caster); - break; - } - - case SCRIPT_COMMAND_REMOVE_AURA: - { - Object* cmdTarget = step.script->datalong2 ? source : target; - - if(!cmdTarget) - { - sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target"); - break; - } - - if(!cmdTarget->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId()); - break; - } - - ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong); - break; - } - - case SCRIPT_COMMAND_CAST_SPELL: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster."); - break; - } - - Object* cmdTarget = step.script->datalong2 & 0x01 ? source : target; - - if(!cmdTarget) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x01 ? "source" : "target"); - break; - } - - if(!cmdTarget->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x01 ? "source" : "target",cmdTarget->GetTypeId()); - break; - } - - Unit* spellTarget = (Unit*)cmdTarget; - - Object* cmdSource = step.script->datalong2 & 0x02 ? target : source; - - if(!cmdSource) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x02 ? "target" : "source"); - break; - } - - if(!cmdSource->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x02 ? "target" : "source", cmdSource->GetTypeId()); - break; - } - - Unit* spellSource = (Unit*)cmdSource; - - //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast - spellSource->CastSpell(spellTarget,step.script->datalong,false); - - break; - } - - case SCRIPT_COMMAND_LOAD_PATH: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_START_MOVE is tried to apply to NON-existing unit."); - break; - } - - if(!source->isType(TYPEMASK_UNIT)) - { - sLog.outError("SCRIPT_COMMAND_START_MOVE source mover isn't unit (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - if(!WaypointMgr.GetPath(step.script->datalong)) - { - sLog.outError("SCRIPT_COMMAND_START_MOVE source mover has an invallid path, skipping.", step.script->datalong2); - break; - } - - dynamic_cast<Unit*>(source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2); - break; - } - - case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: - { - if(!step.script->datalong || !step.script->datalong2) - { - sLog.outError("SCRIPT_COMMAND_CALLSCRIPT calls invallid db_script_id or lowguid not present: skipping."); - break; - } - //our target - Creature* target = NULL; - - if(source) //using grid searcher - { - CellPair p(Trinity::ComputeCellPair(((Unit*)source)->GetPositionX(), ((Unit*)source)->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - //sLog.outDebug("Attempting to find Creature: Db GUID: %i", step.script->datalong); - Trinity::CreatureWithDbGUIDCheck target_check(((Unit*)source), step.script->datalong); - Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(((Unit*)source), target, target_check); - - TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker); - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, unit_checker, *(((Unit*)source)->GetMap())); - } - else //check hashmap holders - { - if(CreatureData const* data = objmgr.GetCreatureData(step.script->datalong)) - target = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), target); - } - //sLog.outDebug("attempting to pass target..."); - if(!target) - break; - //sLog.outDebug("target passed"); - //Lets choose our ScriptMap map - ScriptMapMap *datamap = NULL; - switch(step.script->dataint) - { - case 1://QUEST END SCRIPTMAP - datamap = &sQuestEndScripts; - break; - case 2://QUEST START SCRIPTMAP - datamap = &sQuestStartScripts; - break; - case 3://SPELLS SCRIPTMAP - datamap = &sSpellScripts; - break; - case 4://GAMEOBJECTS SCRIPTMAP - datamap = &sGameObjectScripts; - break; - case 5://EVENTS SCRIPTMAP - datamap = &sEventScripts; - break; - case 6://WAYPOINTS SCRIPTMAP - datamap = &sWaypointScripts; - break; - default: - sLog.outError("SCRIPT_COMMAND_CALLSCRIPT ERROR: no scriptmap present... ignoring"); - break; - } - //if no scriptmap present... - if(!datamap) - break; - - uint32 script_id = step.script->datalong2; - //insert script into schedule but do not start it - ScriptsStart(*datamap, script_id, target, NULL, false); - break; - } - - case SCRIPT_COMMAND_KILL: - { - if(!source || ((Creature*)source)->isDead()) - break; - - ((Creature*)source)->DealDamage(((Creature*)source), ((Creature*)source)->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - switch(step.script->dataint) - { - case 0: break; //return false not remove corpse - case 1: ((Creature*)source)->RemoveCorpse(); break; - } - break; - } - - case SCRIPT_COMMAND_PLAY_SOUND: - { - if(!source) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for NULL creature."); - break; - } - - WorldObject* pSource = dynamic_cast<WorldObject*>(source); - if(!pSource) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for non-world object (TypeId: %u), skipping.",source->GetTypeId()); - break; - } - - // bitmask: 0/1=anyone/target, 0/2=with distance dependent - Player* pTarget = NULL; - if(step.script->datalong2 & 1) - { - if(!target) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for NULL target."); - break; - } - - if(target->GetTypeId()!=TYPEID_PLAYER) - { - sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for non-player (TypeId: %u), skipping.",target->GetTypeId()); - break; - } - - pTarget = (Player*)target; - } - - // bitmask: 0/1=anyone/target, 0/2=with distance dependent - if(step.script->datalong2 & 2) - pSource->PlayDistanceSound(step.script->datalong,pTarget); - else - pSource->PlayDirectSound(step.script->datalong,pTarget); - break; - } - default: - sLog.outError("Unknown script command %u called.",step.script->command); - break; - } - - m_scriptSchedule.erase(iter); - - iter = m_scriptSchedule.begin(); - } - return; -} - /// Send a packet to all players (except self if mentioned) void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team) { @@ -2851,10 +2066,10 @@ void World::KickAllLess(AccountTypes sec) /// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author) { - LoginDatabase.escape_string(nameOrIP); - LoginDatabase.escape_string(reason); + loginDatabase.escape_string(nameOrIP); + loginDatabase.escape_string(reason); std::string safe_author=author; - LoginDatabase.escape_string(safe_author); + loginDatabase.escape_string(safe_author); uint32 duration_secs = TimeStringToSecs(duration); QueryResult *resultAccounts = NULL; //used for kicking @@ -2864,12 +2079,12 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string dura { case BAN_IP: //No SQL injection as strings are escaped - resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str()); - LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str()); + resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str()); + loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str()); break; case BAN_ACCOUNT: //No SQL injection as string is escaped - resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str()); + resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str()); break; case BAN_CHARACTER: //No SQL injection as string is escaped @@ -2896,7 +2111,7 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string dura if(mode!=BAN_IP) { //No SQL injection as strings are escaped - LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')", + loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')", account,duration_secs,safe_author.c_str(),reason.c_str()); } @@ -2915,8 +2130,8 @@ bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP) { if (mode == BAN_IP) { - LoginDatabase.escape_string(nameOrIP); - LoginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str()); + loginDatabase.escape_string(nameOrIP); + loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str()); } else { @@ -2930,7 +2145,7 @@ bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP) return false; //NO SQL injection as account is uint32 - LoginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account); + loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account); } return true; } @@ -3104,6 +2319,45 @@ void World::ProcessCliCommands() zprint("TC> "); } +void World::SendRNDBroadcast() +{ + std::string msg; + QueryResult *result = WorldDatabase.PQuery("SELECT `text` FROM autobroadcast AS r1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM autobroadcast)) AS id) AS r2 WHERE r1.id >= r2.id ORDER BY r1.id ASC LIMIT 1"); // ORDER BY RAND() is bad.. look it up to see why. + + if(!result) + return; + + msg = result->Fetch()[0].GetString(); + delete result; + + static uint32 abcenter = 0; + abcenter = sConfig.GetIntDefault("AutoBroadcast.Center", 0); + if(abcenter == 0) + { + sWorld.SendWorldText(LANG_AUTO_BROADCAST, msg.c_str()); + + sLog.outString("AutoBroadcast: '%s'",msg.c_str()); + } + if(abcenter == 1) + { + WorldPacket data(SMSG_NOTIFICATION, (msg.size()+1)); + data << msg; + sWorld.SendGlobalMessage(&data); + + sLog.outString("AutoBroadcast: '%s'",msg.c_str()); + } + if(abcenter == 2) + { + sWorld.SendWorldText(LANG_AUTO_BROADCAST, msg.c_str()); + + WorldPacket data(SMSG_NOTIFICATION, (msg.size()+1)); + data << msg; + sWorld.SendGlobalMessage(&data); + + sLog.outString("AutoBroadcast: '%s'",msg.c_str()); + } +} + void World::InitResultQueue() { m_resultQueue = new SqlResultQueue; @@ -3128,8 +2382,8 @@ void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId Field *fields = resultCharCount->Fetch(); uint32 charCount = fields[0].GetUInt32(); delete resultCharCount; - LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID); - LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID); + loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID); + loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID); } } @@ -3192,7 +2446,7 @@ void World::SetPlayerLimit( int32 limit, bool needUpdate ) m_playerLimit = limit; if(db_update_need) - LoginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID); + loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID); } void World::UpdateMaxSessionCounters() @@ -3203,14 +2457,14 @@ void World::UpdateMaxSessionCounters() void World::LoadDBVersion() { - QueryResult* result = WorldDatabase.Query("SELECT db_version FROM version LIMIT 1"); + QueryResult* result = WorldDatabase.Query("SELECT db_version, script_version FROM version LIMIT 1"); //QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version FROM db_version LIMIT 1"); if(result) { Field* fields = result->Fetch(); m_DBVersion = fields[0].GetCppString(); - //m_CreatureEventAIVersion = fields[1].GetCppString(); + m_CreatureEventAIVersion = fields[1].GetCppString(); delete result; } diff --git a/src/game/World.h b/src/game/World.h index 4fbde8ccb71..0bd2abb4c9b 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -29,6 +29,7 @@ #include "Timer.h" #include "Policies/Singleton.h" #include "SharedDefines.h" +#include "ace/Atomic_Op.h" #include <map> #include <set> @@ -79,7 +80,8 @@ enum WorldTimers WUPDATE_CORPSES = 5, WUPDATE_EVENTS = 6, WUPDATE_CLEANDB = 7, - WUPDATE_COUNT = 8 + WUPDATE_AUTOBROADCAST = 8, + WUPDATE_COUNT = 9 }; /// Configuration elements @@ -112,6 +114,9 @@ enum WorldConfigs CONFIG_STRICT_PLAYER_NAMES, CONFIG_STRICT_CHARTER_NAMES, CONFIG_STRICT_PET_NAMES, + CONFIG_MIN_PLAYER_NAME, + CONFIG_MIN_CHARTER_NAME, + CONFIG_MIN_PET_NAME, CONFIG_CHARACTERS_CREATING_DISABLED, CONFIG_CHARACTERS_PER_ACCOUNT, CONFIG_CHARACTERS_PER_REALM, @@ -138,8 +143,8 @@ enum WorldConfigs CONFIG_GM_ACCEPT_TICKETS, CONFIG_GM_CHAT, CONFIG_GM_WISPERING_TO, - CONFIG_GM_IN_GM_LIST, - CONFIG_GM_IN_WHO_LIST, + CONFIG_GM_LEVEL_IN_GM_LIST, + CONFIG_GM_LEVEL_IN_WHO_LIST, CONFIG_GM_LOG_TRADE, CONFIG_START_GM_LEVEL, CONFIG_ALLOW_GM_GROUP, @@ -160,6 +165,7 @@ enum WorldConfigs CONFIG_SKILL_GAIN_DEFENSE, CONFIG_SKILL_GAIN_GATHERING, CONFIG_SKILL_GAIN_WEAPON, + CONFIG_DURABILITY_LOSS_IN_PVP, CONFIG_MAX_OVERSPEED_PINGS, CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY, CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL, @@ -275,6 +281,7 @@ enum Rates RATE_XP_KILL, RATE_XP_QUEST, RATE_XP_EXPLORE, + RATE_REPAIRCOST, RATE_REPUTATION_GAIN, RATE_REPUTATION_LOWLEVEL_KILL, RATE_REPUTATION_LOWLEVEL_QUEST, @@ -308,6 +315,7 @@ enum Rates RATE_CORPSE_DECAY_LOOTED, RATE_INSTANCE_RESET_TIME, RATE_TARGET_POS_RECALCULATION_RANGE, + RATE_DURABILITY_LOSS_ON_DEATH, RATE_DURABILITY_LOSS_DAMAGE, RATE_DURABILITY_LOSS_PARRY, RATE_DURABILITY_LOSS_ABSORB, @@ -412,6 +420,7 @@ class World WorldSession* FindSession(uint32 id) const; void AddSession(WorldSession *s); + void SendRNDBroadcast(); bool RemoveSession(uint32 id); /// Get the number of current active sessions void UpdateMaxSessionCounters(); @@ -421,8 +430,18 @@ class World /// Get the maximum number of parallel sessions on the server since last reboot uint32 GetMaxQueuedSessionCount() const { return m_maxQueuedSessionCount; } uint32 GetMaxActiveSessionCount() const { return m_maxActiveSessionCount; } - Player* FindPlayerInZone(uint32 zone); + /// Get number of players + inline uint32 GetPlayerCount() const { return m_PlayerCount; } + inline uint32 GetMaxPlayerCount() const { return m_MaxPlayerCount; } + /// Increase/Decrease number of players + inline void IncreasePlayerCount() + { + m_PlayerCount++; + m_MaxPlayerCount = std::max(m_MaxPlayerCount, m_PlayerCount); + } + inline void DecreasePlayerCount() { m_PlayerCount--; } + Player* FindPlayerInZone(uint32 zone); Weather* FindWeather(uint32 id) const; Weather* AddWeather(uint32 zone_id); void RemoveWeather(uint32 zone_id); @@ -540,9 +559,10 @@ class World BanReturn BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author); bool RemoveBanAccount(BanMode mode, std::string nameOrIP); - void ScriptsStart(std::map<uint32, std::multimap<uint32, ScriptInfo> > const& scripts, uint32 id, Object* source, Object* target, bool start = true); - void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); - bool IsScriptScheduled() const { return !m_scriptSchedule.empty(); } + uint32 IncreaseScheduledScriptsCount() { return (uint32)++m_scheduledScripts; } + uint32 DecreaseScheduledScriptCount() { return (uint32)--m_scheduledScripts; } + uint32 DecreaseScheduledScriptCount(size_t count) { return (uint32)(m_scheduledScripts -= count); } + bool IsScriptScheduled() const { return m_scheduledScripts > 0; } bool IsAllowedMap(uint32 mapid) { return m_forbiddenMapIds.count(mapid) == 0 ;} @@ -579,7 +599,6 @@ class World void RecordTimeDiff(const char * text, ...); protected: void _UpdateGameTime(); - void ScriptsProcess(); // callback for UpdateRealmCharacters void _UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId); @@ -593,6 +612,9 @@ class World bool m_isClosed; + //atomic op counter for active scripts amount + ACE_Atomic_Op<ACE_Thread_Mutex, long> m_scheduledScripts; + time_t m_startTime; time_t m_gameTime; IntervalTimer m_timers[WUPDATE_COUNT]; @@ -610,8 +632,8 @@ class World DisconnectMap m_disconnects; uint32 m_maxActiveSessionCount; uint32 m_maxQueuedSessionCount; - - std::multimap<time_t, ScriptAction> m_scriptSchedule; + uint32 m_PlayerCount; + uint32 m_MaxPlayerCount; std::string m_newCharString; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 44bab655886..3b32eefcda7 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -53,6 +53,7 @@ m_latency(0), m_TutorialsChanged(false) { m_Address = sock->GetRemoteAddress (); sock->AddReference (); + loginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); } } @@ -77,11 +78,13 @@ WorldSession::~WorldSession() WorldPacket *packet = _recvQueue.next (); delete packet; } + loginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); + CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = %u;", GetAccountId()); } void WorldSession::SizeError(WorldPacket const& packet, uint32 size) const { - sLog.outError("Client (account %u) send packet %s (%u) with size %u but expected %u (attempt crash server?), skipped", + sLog.outError("Client (account %u) send packet %s (%u) with size " SIZEFMTD " but expected %u (attempt crash server?), skipped", GetAccountId(),LookupOpcodeName(packet.GetOpcode()),packet.GetOpcode(),packet.size(),size); } @@ -323,10 +326,10 @@ void WorldSession::LogoutPlayer(bool Save) } } - ///- Reset the online field in the account table - // no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage - //No SQL injection as AccountID is uint32 - LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = '%u'", GetAccountId()); + // Repop at GraveYard or other player far teleport will prevent saving player because of not present map + // Teleport player immediately for correct player save + while(_player->IsBeingTeleportedFar()) + HandleMoveWorldportAckOpcode(); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); @@ -380,19 +383,13 @@ void WorldSession::LogoutPlayer(bool Save) sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr.RemovePlayerSocial (_player->GetGUIDLow ()); - ///- Delete the player object - _player->CleanupsBeforeDelete(); // do some cleanup before deleting to prevent crash at crossreferences to already deleted data - ///- Remove the player from the world // the player may not be in the world when logging out // e.g if he got disconnected during a transfer to another map // calls to GetMap in this case may cause crashes - if(_player->IsInWorld()) _player->GetMap()->Remove(_player, false); - // RemoveFromWorld does cleanup that requires the player to be in the accessor - ObjectAccessor::Instance().RemoveObject(_player); - - delete _player; - _player = NULL; + Map* _map = _player->GetMap(); + _map->Remove(_player, true); + _player = NULL; // deleted in Remove call ///- Send the 'logout complete' packet to the client WorldPacket data( SMSG_LOGOUT_COMPLETE, 0 ); diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index f4842c0f0bc..22ab100197c 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -711,6 +711,7 @@ class TRINITY_DLL_SPEC WorldSession void HandleCalendarGetNumPending(WorldPacket& recv_data); void HandleSpellClick(WorldPacket& recv_data); + void HandleMirrrorImageDataRequest( WorldPacket & recv_data ); void HandleAlterAppearance(WorldPacket& recv_data); void HandleRemoveGlyph(WorldPacket& recv_data); void HandleCharCustomize(WorldPacket& recv_data); diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp index 440eeb31790..0efb0cd3d4e 100644 --- a/src/game/WorldSocket.cpp +++ b/src/game/WorldSocket.cpp @@ -678,7 +678,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) BigNumber K; - if (recvPacket.size () < (4 + 4 + 1 + 4 + 20)) + if (recvPacket.size () < (4 + 4 + 1 + 4 + 4 + 20)) { sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size"); return -1; @@ -700,7 +700,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) recvPacket >> account; recvPacket >> unk3; - if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20)) + if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 4 + 20)) { sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check"); return -1; @@ -709,19 +709,20 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) recvPacket >> clientSeed; recvPacket.read (digest, 20); - DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u", + DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", BuiltNumberClient, unk2, account.c_str (), + unk3, clientSeed); // Get the account information from the realmd database std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below - LoginDatabase.escape_string (safe_account); + loginDatabase.escape_string (safe_account); // No SQL injection, username escaped. QueryResult *result = - LoginDatabase.PQuery ("SELECT " + loginDatabase.PQuery ("SELECT " "id, " //0 "gmlevel, " //1 "sessionkey, " //2 @@ -786,7 +787,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) vold, vStr); - LoginDatabase.PExecute ("UPDATE account " + loginDatabase.PExecute ("UPDATE account " "SET " "v = '0', " "s = '0' " @@ -843,7 +844,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) // Re-check account ban (same check as in realmd) QueryResult *banresult = - LoginDatabase.PQuery ("SELECT " + loginDatabase.PQuery ("SELECT " "bandate, " "unbandate " "FROM account_banned " @@ -909,9 +910,9 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) // Update the last_ip in the database // No SQL injection, username escaped. - LoginDatabase.escape_string (address); + loginDatabase.escape_string (address); - LoginDatabase.PExecute ("UPDATE account " + loginDatabase.PExecute ("UPDATE account " "SET last_ip = '%s' " "WHERE username = '%s'", address.c_str (), diff --git a/src/game/pchdef.h b/src/game/pchdef.h index 4b5b9dfbe3e..7252e980e7d 100644 --- a/src/game/pchdef.h +++ b/src/game/pchdef.h @@ -9,8 +9,4 @@ #include "Database/SQLStorage.h" #include "Opcodes.h" #include "SharedDefines.h" - -#ifdef FASTBUILD -//add additional headers here to speed up compilation in release builds even more #include "ObjectMgr.h" -#endif
\ No newline at end of file diff --git a/src/shared/Common.h b/src/shared/Common.h index 735c57eedbe..a274c5d5a0b 100644 --- a/src/shared/Common.h +++ b/src/shared/Common.h @@ -130,6 +130,7 @@ #include <float.h> +#define I32FMT "%08I32X" #define I64FMT "%016I64X" #define snprintf _snprintf #define atoll __atoi64 @@ -141,6 +142,7 @@ #define stricmp strcasecmp #define strnicmp strncasecmp +#define I32FMT "%08X" #define I64FMT "%016llX" #endif @@ -151,6 +153,8 @@ #define SI64FMTD ACE_INT64_FORMAT_SPECIFIER #define SI64LIT(N) ACE_INT64_LITERAL(N) +#define SIZEFMTD ACE_SIZE_T_FORMAT_SPECIFIER + inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; } #define atol(a) strtoul( a, NULL, 10) diff --git a/src/shared/Database/Database.h b/src/shared/Database/Database.h index 7f2bdaefdb7..c7390d08a1b 100644 --- a/src/shared/Database/Database.h +++ b/src/shared/Database/Database.h @@ -41,7 +41,7 @@ class TRINITY_DLL_SPEC Database TransactionQueues m_tranQueues; ///< Transaction queues from diff. threads QueryQueues m_queryQueues; ///< Query queues from diff threads - SqlDelayThread* m_threadBody; ///< Pointer to delay sql executer + SqlDelayThread* m_threadBody; ///< Pointer to delay sql executer (owned by m_delayThread) ACE_Based::Thread* m_delayThread; ///< Pointer to executer thread public: diff --git a/src/shared/Database/DatabaseEnv.h b/src/shared/Database/DatabaseEnv.h index 1d3d735881c..d5d6867e82f 100644 --- a/src/shared/Database/DatabaseEnv.h +++ b/src/shared/Database/DatabaseEnv.h @@ -50,7 +50,7 @@ typedef DatabaseMysql DatabaseType; extern DatabaseType WorldDatabase; extern DatabaseType CharacterDatabase; -extern DatabaseType LoginDatabase; +extern DatabaseType loginDatabase; #endif diff --git a/src/shared/Database/DatabaseMysql.cpp b/src/shared/Database/DatabaseMysql.cpp index 0189b5883f7..f08ea67cbbe 100644 --- a/src/shared/Database/DatabaseMysql.cpp +++ b/src/shared/Database/DatabaseMysql.cpp @@ -440,8 +440,8 @@ void DatabaseMysql::InitDelayThread() assert(!m_delayThread); //New delay thread for delay execute - m_threadBody = new MySQLDelayThread(this); - m_delayThread = new ACE_Based::Thread(*m_threadBody); + m_threadBody = new MySQLDelayThread(this); // will deleted at m_delayThread delete + m_delayThread = new ACE_Based::Thread(m_threadBody); } void DatabaseMysql::HaltDelayThread() diff --git a/src/shared/Database/DatabasePostgre.cpp b/src/shared/Database/DatabasePostgre.cpp index c70067dfdba..8d00285255b 100644 --- a/src/shared/Database/DatabasePostgre.cpp +++ b/src/shared/Database/DatabasePostgre.cpp @@ -366,8 +366,8 @@ void DatabasePostgre::InitDelayThread() assert(!m_delayThread); //New delay thread for delay execute - m_threadBody = new PGSQLDelayThread(this); - m_delayThread = new ACE_Based::Thread(*m_threadBody); + m_threadBody = new PGSQLDelayThread(this); // Will be deleted on m_delayThread delete + m_delayThread = new ACE_Based::Thread(m_threadBody); } void DatabasePostgre::HaltDelayThread() diff --git a/src/shared/Database/QueryResultPostgre.h b/src/shared/Database/QueryResultPostgre.h index 30d69114dc6..a48c6d21fee 100644 --- a/src/shared/Database/QueryResultPostgre.h +++ b/src/shared/Database/QueryResultPostgre.h @@ -25,10 +25,12 @@ #define FD_SETSIZE 1024 #include <winsock2.h> #include <postgre/libpq-fe.h> +#include <postgre/postgres.h> #include <postgre/pg_type.h> #else #include <libpq-fe.h> -//#include <pg_type.h> +#include <postgres.h> +#include <catalog/pg_type.h> #endif class QueryResultPostgre : public QueryResult diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp index 50fd484bff5..4113d35236d 100644 --- a/src/shared/Database/SQLStorage.cpp +++ b/src/shared/Database/SQLStorage.cpp @@ -38,7 +38,6 @@ const char GameObjectInfodstfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiii"; const char ItemPrototypesrcfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiisiiii"; const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiii"; const char PageTextfmt[]="isi"; -const char SpellThreatfmt[]="ii"; const char InstanceTemplatesrcfmt[]="iiiiiiffffs"; const char InstanceTemplatedstfmt[]="iiiiiiffffi"; @@ -50,7 +49,6 @@ SQLStorage sEquipmentStorage(EquipmentInfofmt,"entry","creature_equip_template") SQLStorage sGOStorage(GameObjectInfosrcfmt, GameObjectInfodstfmt, "entry","gameobject_template"); SQLStorage sItemStorage(ItemPrototypesrcfmt, ItemPrototypedstfmt, "entry","item_template"); SQLStorage sPageTextStore(PageTextfmt,"entry","page_text"); -SQLStorage sSpellThreatStore(SpellThreatfmt,"entry","spell_threat"); SQLStorage sInstanceTemplate(InstanceTemplatesrcfmt, InstanceTemplatedstfmt, "map","instance_template"); void SQLStorage::Free () diff --git a/src/shared/Database/SQLStorage.h b/src/shared/Database/SQLStorage.h index 1b5b9d5dcf1..cc165af532e 100644 --- a/src/shared/Database/SQLStorage.h +++ b/src/shared/Database/SQLStorage.h @@ -65,6 +65,8 @@ class SQLStorage uint32 MaxEntry; uint32 iNumFields; + char const* GetTableName() const { return table; } + void Load(); void Free(); diff --git a/src/shared/Errors.h b/src/shared/Errors.h index 218ab561c12..bb17b94cbd0 100644 --- a/src/shared/Errors.h +++ b/src/shared/Errors.h @@ -21,10 +21,23 @@ #ifndef TRINITYCORE_ERRORS_H #define TRINITYCORE_ERRORS_H -//#include <ace/Stack_Trace.h> +#include "Common.h" -//#define WPAssert( assertion ) { if (!(assertion)) { ACE_Stack_Trace st; fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__,__FUNCTION__, #assertion, st.c_str()); assert( #assertion &&0 ); } } -#define WPAssert( assertion ) { if( !(assertion) ) { fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n", __FILE__, __LINE__,__FUNCTION__, #assertion ); assert( #assertion &&0 ); } } +#if PLATFORM != PLATFORM_WINDOWS +#ifndef HAVE_CONFIG_H +#include <config.h> +#endif +#endif + +#ifdef HAVE_ACE_STACK_TRACE_H +#include "ace/Stack_Trace.h" +#endif + +#ifdef HAVE_ACE_STACK_TRACE_H // old versions ACE not have Stack_Trace.h but used at some oS for better compatibility +#define WPAssert( assertion ) { if (!(assertion)) { ACE_Stack_Trace st; fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__,__FUNCTION__, #assertion, st.c_str()); assert( #assertion &&0 ); } } +#else +#define WPAssert( assertion ) { if (!(assertion)) { fprintf( stderr, "\n%s:%i in %s ASSERTION FAILED2:\n %s\n", __FILE__, __LINE__,__FUNCTION__, #assertion); assert( #assertion &&0 ); } } +#endif #define WPError( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); assert( false ); } #define WPWarning( assertion, errmsg ) if( ! (assertion) ) { sLog.outError( "\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); } diff --git a/src/shared/LockedQueue.h b/src/shared/LockedQueue.h index b085dd09b83..4087ebff0cf 100644 --- a/src/shared/LockedQueue.h +++ b/src/shared/LockedQueue.h @@ -27,11 +27,9 @@ namespace ACE_Based { - template <class T, class LockType, typename StorageType=std::deque<T> > class LockedQueue { - //! Serialize access to the Queue LockType _lock; @@ -54,14 +52,12 @@ namespace ACE_Based */ void add(const T& item) { + ACE_Guard<LockType> g(this->_lock); - ACE_Guard<LockType> g(_lock); - - ASSERT(!_canceled); - // throw Cancellation_Exception(); - - _queue.push_back(item); + ASSERT(!this->_canceled); + // throw Cancellation_Exception(); + this->_queue.push_back(item); } /** @@ -69,27 +65,25 @@ namespace ACE_Based */ T next() { + ACE_Guard<LockType> g(this->_lock); - ACE_Guard<LockType> g(_lock); + ASSERT (!_queue.empty() || !this->_canceled); + // throw Cancellation_Exception(); - ASSERT (!_queue.empty() || !_canceled); - // throw Cancellation_Exception(); - - T item = _queue.front(); - _queue.pop_front(); + T item = this->_queue.front(); + this->_queue.pop_front(); return item; - } T front() { - ACE_Guard<LockType> g(_lock); + ACE_Guard<LockType> g(this->_lock); - ASSERT (!_queue.empty()); - // throw NoSuchElement_Exception(); + ASSERT (!this->_queue.empty()); + // throw NoSuchElement_Exception(); - return _queue.front(); + return this->_queue.front(); } /** @@ -97,11 +91,9 @@ namespace ACE_Based */ void cancel() { + ACE_Guard<LockType> g(this->_lock); - ACE_Guard<LockType> g(_lock); - - _canceled = true; - + this->_canceled = true; } /** @@ -109,15 +101,13 @@ namespace ACE_Based */ bool isCanceled() { - // Faster check since the queue will not become un-canceled - if(_canceled) + if(this->_canceled) return true; - ACE_Guard<LockType> g(_lock); - - return _canceled; + ACE_Guard<LockType> g(this->_lock); + return this->_canceled; } /** @@ -125,20 +115,15 @@ namespace ACE_Based */ size_t size() { - - ACE_Guard<LockType> g(_lock); - return _queue.size(); - + ACE_Guard<LockType> g(this->_lock); + return this->_queue.size(); } bool empty() { - - ACE_Guard<LockType> g(_lock); - return _queue.empty(); + ACE_Guard<LockType> g(this->_lock); + return this->_queue.empty(); } - }; - } #endif diff --git a/src/shared/Log.cpp b/src/shared/Log.cpp index 0f1138279ff..8dc23066245 100644 --- a/src/shared/Log.cpp +++ b/src/shared/Log.cpp @@ -353,14 +353,16 @@ std::string Log::GetTimestampStr() void Log::outDB( LogTypes type, const char * str ) { - if(!str || std::string(str).empty() || type >= MAX_LOG_TYPES) - return; + if (!str || type >= MAX_LOG_TYPES) + return; std::string new_str(str); - LoginDatabase.escape_string(new_str); + if (new_str.empty()) + return; + loginDatabase.escape_string(new_str); - LoginDatabase.PExecute("INSERT INTO logs (time, realm, type, string) " - "VALUES (" UI64FMTD ", %u, %u, '%s');", uint64(time(0)), realm, (uint32)type, new_str.c_str()); + loginDatabase.PExecute("INSERT INTO logs (time, realm, type, string) " + "VALUES (" UI64FMTD ", %u, %u, '%s');", uint64(time(0)), realm, type, new_str.c_str()); } void Log::outString( const char * str, ... ) diff --git a/src/shared/ProgressBar.cpp b/src/shared/ProgressBar.cpp index b72118ad804..2eba31c2c40 100644 --- a/src/shared/ProgressBar.cpp +++ b/src/shared/ProgressBar.cpp @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <stdio.h> + #include "ProgressBar.h" char const* const barGoLink::empty = " "; diff --git a/src/shared/ProgressBar.h b/src/shared/ProgressBar.h index 50c5c7d11e5..af7b5e03093 100644 --- a/src/shared/ProgressBar.h +++ b/src/shared/ProgressBar.h @@ -20,7 +20,6 @@ #ifndef TRINITYCORE_PROGRESSBAR_H #define TRINITYCORE_PROGRESSBAR_H -#include <stdio.h> #include "Platform/Define.h" class TRINITY_DLL_SPEC barGoLink diff --git a/src/shared/Threading.cpp b/src/shared/Threading.cpp index 496e86353ca..652f468772f 100644 --- a/src/shared/Threading.cpp +++ b/src/shared/Threading.cpp @@ -101,8 +101,12 @@ Thread::Thread() : m_task(0), m_iThreadId(0), m_hThreadHandle(0) } -Thread::Thread(Runnable& instance) : m_task(&instance), m_iThreadId(0), m_hThreadHandle(0) +Thread::Thread(Runnable* instance) : m_task(instance), m_iThreadId(0), m_hThreadHandle(0) { + // register reference to m_task to prevent it deeltion until destructor + if (m_task) + m_task->incReference(); + bool _start = start(); ASSERT (_start); } @@ -110,6 +114,10 @@ Thread::Thread(Runnable& instance) : m_task(&instance), m_iThreadId(0), m_hThrea Thread::~Thread() { //Wait(); + + // deleted runnable object (if no other references) + if (m_task) + m_task->decReference(); } //initialize Thread's class static member @@ -118,15 +126,20 @@ ThreadPriority Thread::m_TpEnum; bool Thread::start() { - if(m_task == 0 || m_iThreadId != 0) + if (m_task == 0 || m_iThreadId != 0) return false; - return (ACE_Thread::spawn(&Thread::ThreadTask, (void*)m_task, THREADFLAG, &m_iThreadId, &m_hThreadHandle) == 0); + bool res = (ACE_Thread::spawn(&Thread::ThreadTask, (void*)m_task, THREADFLAG, &m_iThreadId, &m_hThreadHandle) == 0); + + if (res) + m_task->incReference(); + + return res; } bool Thread::wait() { - if(!m_hThreadHandle || !m_task) + if (!m_hThreadHandle || !m_task) return false; ACE_THR_FUNC_RETURN _value = ACE_THR_FUNC_RETURN(-1); @@ -140,7 +153,17 @@ bool Thread::wait() void Thread::destroy() { - ACE_Thread::kill(m_iThreadId, -1); + if (!m_iThreadId || !m_task) + return; + + if (ACE_Thread::kill(m_iThreadId, -1) != 0) + return; + + m_iThreadId = 0; + m_hThreadHandle = 0; + + // reference set at ACE_Thread::spawn + m_task->decReference(); } void Thread::suspend() @@ -158,6 +181,9 @@ ACE_THR_FUNC_RETURN Thread::ThreadTask(void * param) Runnable * _task = (Runnable*)param; _task->run(); + // task execution complete, free referecne added at + _task->decReference(); + return (ACE_THR_FUNC_RETURN)0; } diff --git a/src/shared/Threading.h b/src/shared/Threading.h index eac3c0e8efb..6c3f3724bc1 100644 --- a/src/shared/Threading.h +++ b/src/shared/Threading.h @@ -21,6 +21,7 @@ #include <ace/Thread.h> #include <ace/TSS_T.h> +#include "ace/Atomic_Op.h" #include <assert.h> #include "Errors.h" @@ -32,6 +33,15 @@ namespace ACE_Based public: virtual ~Runnable() {} virtual void run() = 0; + + void incReference() { ++m_refs; } + void decReference() + { + if(!--m_refs) + delete this; + } + private: + ACE_Atomic_Op<ACE_Thread_Mutex, int> m_refs; }; enum Priority @@ -61,7 +71,7 @@ namespace ACE_Based { public: Thread(); - Thread(Runnable& instance); + explicit Thread(Runnable* instance); ~Thread(); bool start(); diff --git a/src/shared/Util.cpp b/src/shared/Util.cpp index 354568c778f..644769f2069 100644 --- a/src/shared/Util.cpp +++ b/src/shared/Util.cpp @@ -131,7 +131,7 @@ Tokens StrSplit(const std::string &src, const std::string &sep) void stripLineInvisibleChars(std::string &str) { - static std::string invChars = " \t\7"; + static std::string invChars = " \t\7\n"; size_t wpos = 0; diff --git a/src/shared/Util.h b/src/shared/Util.h index ddbf968b2c2..496411d8be3 100644 --- a/src/shared/Util.h +++ b/src/shared/Util.h @@ -321,6 +321,11 @@ uint32 CreatePIDFile(const std::string& filename); #ifndef _FLAG96 #define _FLAG96 +#ifndef PAIR64_HIPART +#define PAIR64_HIPART(x) (uint32)((uint64(x) >> 32) & UI64LIT(0x00000000FFFFFFFF)) +#define PAIR64_LOPART(x) (uint32)(uint64(x) & UI64LIT(0x00000000FFFFFFFF)) +#endif + class flag96 { private: @@ -333,6 +338,13 @@ public: part[2]=p3; } + flag96(uint64 p1, uint32 p2) + { + part[0]=PAIR64_LOPART(p1); + part[1]=PAIR64_HIPART(p1); + part[2]=p2; + } + inline bool IsEqual(uint32 p1=0, uint32 p2=0, uint32 p3=0) const { return ( diff --git a/src/shared/vmap/CoordModelMapping.cpp b/src/shared/vmap/CoordModelMapping.cpp index 86e3347a614..39d1165f115 100644 --- a/src/shared/vmap/CoordModelMapping.cpp +++ b/src/shared/vmap/CoordModelMapping.cpp @@ -21,7 +21,7 @@ #include "CoordModelMapping.h" #include <string.h> -#include <cstdio> +#include <stdio.h> using namespace G3D; @@ -45,6 +45,13 @@ namespace VMAP return(CMappingEntry::getKeyString(iMapId,xPos, yPos)); } + const std::string CMappingEntry::getKeyString( unsigned int pMapId, int pXPos, int pYPos ) + { + char b[100]; + sprintf(b,"%03u_%d_%d", pMapId, pXPos, pYPos); + return(std::string(b)); + } + //============================================================ //============================================================ //============================================================ diff --git a/src/shared/vmap/CoordModelMapping.h b/src/shared/vmap/CoordModelMapping.h index c1f49462962..7684bf1b373 100644 --- a/src/shared/vmap/CoordModelMapping.h +++ b/src/shared/vmap/CoordModelMapping.h @@ -75,12 +75,7 @@ namespace VMAP const std::string getKeyString() const; inline const G3D::Array<std::string>& getFilenames() const { return(iFilenames); } - static const std::string getKeyString(unsigned int pMapId, int pXPos, int pYPos) - { - char b[100]; - sprintf(b,"%03u_%d_%d", pMapId, pXPos, pYPos); - return(std::string(b)); - } + static const std::string getKeyString(unsigned int pMapId, int pXPos, int pYPos); }; diff --git a/src/shared/vmap/DebugCmdLogger.cpp b/src/shared/vmap/DebugCmdLogger.cpp index e6b36572c45..c899606045b 100644 --- a/src/shared/vmap/DebugCmdLogger.cpp +++ b/src/shared/vmap/DebugCmdLogger.cpp @@ -21,6 +21,7 @@ #include <cstdio> #include "DebugCmdLogger.h" +#include <stdio.h> using namespace G3D; diff --git a/src/shared/vmap/TileAssembler.cpp b/src/shared/vmap/TileAssembler.cpp index cbaa4e58108..75997a847a2 100644 --- a/src/shared/vmap/TileAssembler.cpp +++ b/src/shared/vmap/TileAssembler.cpp @@ -243,7 +243,7 @@ namespace VMAP char destnamebuffer[500]; char fullnamedestnamebuffer[500]; - + if(nameCollection.iMainFiles.size() >0) { sprintf(destnamebuffer,"%03u_%i_%i.vmap",pMapId, pYPos, pXPos); // flip it here too diff --git a/src/shared/vmap/VMapManager.cpp b/src/shared/vmap/VMapManager.cpp index f5c2640be70..342da0eb9e2 100644 --- a/src/shared/vmap/VMapManager.cpp +++ b/src/shared/vmap/VMapManager.cpp @@ -446,7 +446,7 @@ namespace VMAP //========================================================= /** - get height or INVALID_HEIGHT if to hight was calculated + get height or INVALID_HEIGHT if to height was calculated */ //int gGetHeightCounter = 0; diff --git a/src/tools/genrevision/Makefile.am b/src/tools/genrevision/Makefile.am index 3f60ac14ab2..fc66e8181b3 100644 --- a/src/tools/genrevision/Makefile.am +++ b/src/tools/genrevision/Makefile.am @@ -19,12 +19,12 @@ ## CPP flags for includes, defines, etc. AM_CPPFLAGS = -I$(srcdir) -## Build world list daemon as standalone program +## Build as standalone program bin_PROGRAMS = genrevision genrevision_SOURCES = \ genrevision.cpp -## Link world daemon against the shared library +## Link against the shared library genrevision_LDADD = genrevision_LDFLAGS = -L$(libdir) diff --git a/src/trinitycore/CMakeLists.txt b/src/trinitycore/CMakeLists.txt index 7eb13185d91..ffd8e6431c4 100644 --- a/src/trinitycore/CMakeLists.txt +++ b/src/trinitycore/CMakeLists.txt @@ -22,6 +22,9 @@ add_definitions( IF (DO_MYSQL) SET(trinity-core_LINK_FLAGS "-pthread ${trinity-core_LINK_FLAGS}") ENDIF(DO_MYSQL) +IF (DO_POSTGRESQL) + SET(trinity-core_LINK_FLAGS "-pthread ${trinity-core_LINK_FLAGS}") +ENDIF(DO_POSTGRESQL) IF (CMAKE_SYSTEM_NAME MATCHES "Darwin") @@ -48,7 +51,7 @@ readline gomp ${SCRIPT_LIB} ${MYSQL_LIBRARIES} -${POSTGRE_LIBS} +${POSTGRESQL_LIBRARIES} ${SSLLIB} ${ACE_LIBRARY} ${ZLIB} diff --git a/src/trinitycore/CliRunnable.cpp b/src/trinitycore/CliRunnable.cpp index 15dd45edfff..d950adc22f8 100644 --- a/src/trinitycore/CliRunnable.cpp +++ b/src/trinitycore/CliRunnable.cpp @@ -239,7 +239,7 @@ bool ChatHandler::HandleAccountOnlineListCommand(const char* /*args*/) ///- Get the username, last IP and GM level of each account // No SQL injection. account is uint32. // 0 1 2 3 - QueryResult *resultLogin = LoginDatabase.PQuery("SELECT username, last_ip, gmlevel, expansion FROM account WHERE id = '%u'",account); + QueryResult *resultLogin = loginDatabase.PQuery("SELECT username, last_ip, gmlevel, expansion FROM account WHERE id = '%u'",account); if(resultLogin) { diff --git a/src/trinitycore/Main.cpp b/src/trinitycore/Main.cpp index eb51c770896..faa88c994d5 100644 --- a/src/trinitycore/Main.cpp +++ b/src/trinitycore/Main.cpp @@ -59,7 +59,7 @@ int m_ServiceStatus = -1; DatabaseType WorldDatabase; ///< Accessor to the world database DatabaseType CharacterDatabase; ///< Accessor to the character database -DatabaseType LoginDatabase; ///< Accessor to the realm/login database +DatabaseType loginDatabase; ///< Accessor to the realm/login database uint32 realmID; ///< Id of the realm diff --git a/src/trinitycore/Master.cpp b/src/trinitycore/Master.cpp index 4d7eca8f04e..76fdbd661de 100644 --- a/src/trinitycore/Master.cpp +++ b/src/trinitycore/Master.cpp @@ -136,7 +136,7 @@ public: loopCounter = 0; sLog.outDetail ("Ping MySQL to keep connection alive"); delete WorldDatabase.Query ("SELECT 1 FROM command LIMIT 1"); - delete LoginDatabase.Query ("SELECT 1 FROM realmlist LIMIT 1"); + delete loginDatabase.Query ("SELECT 1 FROM realmlist LIMIT 1"); delete CharacterDatabase.Query ("SELECT 1 FROM bugreport LIMIT 1"); } } @@ -182,7 +182,7 @@ public: { while (!World::IsStopped()) { - ACE_Based::Thread::Sleep (static_cast<unsigned long> (socketSelecttime / 1000)); + ACE_Based::Thread::Sleep(static_cast<unsigned long> (socketSelecttime / 1000)); checkping (); } } @@ -238,11 +238,13 @@ int Master::Run() _HookSignals(); ///- Launch WorldRunnable thread - ACE_Based::Thread t(*new WorldRunnable); - t.setPriority ((ACE_Based::Priority )2); + ACE_Based::Thread world_thread(new WorldRunnable); + world_thread.setPriority(ACE_Based::Highest); // set server online - LoginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID); + loginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID); + + ACE_Based::Thread* cliThread = NULL; #ifdef WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) @@ -251,10 +253,10 @@ int Master::Run() #endif { ///- Launch CliRunnable thread - ACE_Based::Thread td1(*new CliRunnable); + cliThread = new ACE_Based::Thread(new CliRunnable); } - ACE_Based::Thread td2(*new RARunnable); + ACE_Based::Thread rar_thread(new RARunnable); ///- Handle affinity for multiple processors and process priority on Windows #ifdef WIN32 @@ -310,13 +312,12 @@ int Master::Run() uint32 loopCounter = 0; ///- Start up freeze catcher thread - uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0); - if(freeze_delay) + if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); - ACE_Based::Thread t(*fdr); - t.setPriority(ACE_Based::High); + ACE_Based::Thread freeze_thread(fdr); + freeze_thread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket @@ -333,15 +334,15 @@ int Master::Run() sWorldSocketMgr->Wait (); // set server offline - LoginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID); + loginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master - t.wait(); - td2.wait (); + world_thread.wait(); + rar_thread.wait (); ///- Clean database before leaving clearOnlineAccounts(); @@ -349,13 +350,14 @@ int Master::Run() ///- Wait for delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); - LoginDatabase.HaltDelayThread(); + loginDatabase.HaltDelayThread(); sLog.outString( "Halting process..." ); - #ifdef WIN32 - if (sConfig.GetBoolDefault("Console.Enable", true)) + if (cliThread) { + #ifdef WIN32 + // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread @@ -390,8 +392,17 @@ int Master::Run() b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); + + cliThread->wait(); + + #else + + cliThread->destroy(); + + #endif + + delete cliThread; } - #endif // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module @@ -438,7 +449,7 @@ bool Master::_StartDB() } ///- Get login database info from configuration file - dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); + dbstring = sConfig.GetStringDefault("loginDatabaseInfo", ""); if(dbstring.empty()) { sLog.outError("Login database not specified in configuration file"); @@ -446,7 +457,7 @@ bool Master::_StartDB() } ///- Initialise the login database - if(!LoginDatabase.Initialize(dbstring.c_str())) + if(!loginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); return false; @@ -494,7 +505,7 @@ void Master::clearOnlineAccounts() { // Cleanup online status for characters hosted at current realm /// \todo Only accounts with characters logged on *this* realm should have online status reset. Move the online column from 'account' to 'realmcharacters'? - LoginDatabase.PExecute( + loginDatabase.PExecute( "UPDATE account SET online = 0 WHERE online > 0 " "AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = '%d')",realmID); diff --git a/src/trinitycore/RASocket.cpp b/src/trinitycore/RASocket.cpp index 50a1af87256..d0ee5cc8053 100644 --- a/src/trinitycore/RASocket.cpp +++ b/src/trinitycore/RASocket.cpp @@ -25,7 +25,6 @@ #include "Common.h" #include "Config/ConfigEnv.h" #include "Database/DatabaseEnv.h" - #include "AccountMgr.h" #include "Log.h" #include "RASocket.h" @@ -153,9 +152,9 @@ void RASocket::OnRead() AccountMgr::normalizeString(login); ///- Escape the Login to allow quotes in names - LoginDatabase.escape_string(login); + loginDatabase.escape_string(login); - QueryResult* result = LoginDatabase.PQuery("SELECT gmlevel FROM account WHERE username = '%s'",login.c_str()); + QueryResult* result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE username = '%s'",login.c_str()); ///- If the user is not found, deny access if(!result) @@ -194,12 +193,12 @@ void RASocket::OnRead() AccountMgr::normalizeString(login); AccountMgr::normalizeString(pw); - LoginDatabase.escape_string(login); - LoginDatabase.escape_string(pw); + loginDatabase.escape_string(login); + loginDatabase.escape_string(pw); - QueryResult *check = LoginDatabase.PQuery( - "SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", - login.c_str(), pw.c_str()); + QueryResult *check = loginDatabase.PQuery( + "SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT('%s',':','%s'))", + login.c_str(), login.c_str(), pw.c_str()); if(check) { diff --git a/src/trinitycore/WorldRunnable.cpp b/src/trinitycore/WorldRunnable.cpp index ad0243a36ae..06c0e69fa16 100644 --- a/src/trinitycore/WorldRunnable.cpp +++ b/src/trinitycore/WorldRunnable.cpp @@ -50,7 +50,7 @@ void WorldRunnable::run() ///- Init new SQL thread for the world database WorldDatabase.ThreadStart(); // let thread do safe mySQL requests (one connection call enough) CharacterDatabase.ThreadStart(); - LoginDatabase.ThreadStart(); + loginDatabase.ThreadStart(); sWorld.InitResultQueue(); uint32 realCurrTime = 0; @@ -100,5 +100,5 @@ void WorldRunnable::run() ///- End the database thread WorldDatabase.ThreadEnd(); // free mySQL thread resources CharacterDatabase.ThreadStart(); - LoginDatabase.ThreadEnd(); + loginDatabase.ThreadEnd(); } diff --git a/src/trinitycore/trinitycore.conf.dist b/src/trinitycore/trinitycore.conf.dist index c35a6efa952..1db57b9e08a 100644 --- a/src/trinitycore/trinitycore.conf.dist +++ b/src/trinitycore/trinitycore.conf.dist @@ -536,6 +536,18 @@ ChatLogTimestamp = 0 # (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts). # 3 basic latin characters + server timezone specific # +# MinPlayerName +# Minimal name length (1..12) +# Default: 2 +# +# MinCharterName +# Minimal name length (1..24) +# Default: 2 +# +# MinPetName +# Minimal name length (1..12) +# Default: 2 +# # CharactersCreatingDisabled # Disable characters creating for specific team or any (non-player accounts not affected) # Default: 0 - enabled @@ -620,8 +632,8 @@ ChatLogTimestamp = 0 # # AllFlightPaths # Players will start with all flight paths (Note: ALL flight paths, not only player's team) -# Default: 0 (true) -# 1 (false) +# Default: 0 (false) +# 1 (true) # # AlwaysMaxSkillForLevel # Players will automatically gain max level dependent (weapon/defense) skill when logging in, leveling up etc. @@ -729,6 +741,9 @@ StrictPlayerNames = 0 StrictCharterNames = 0 StrictPetNames = 0 MaxWhoListReturns = 49 +MinPlayerName = 2 +MinCharterName = 2 +MinPetName = 2 CharactersCreatingDisabled = 0 CharactersPerAccount = 50 CharactersPerRealm = 10 @@ -1014,15 +1029,19 @@ Channel.SilentlyGMJoin = 0 # 0 (disable) # 1 (enable) # -# GM.InGMList -# Is GM showed in GM list (if visible) in non-GM state (.gm off) -# Default: 0 (false) -# 1 (true) +# GM.InGMList.Level +# Max GM level showed in GM list (if visible) in non-GM state (.gm off) +# 0 (only players) +# 1 (only moderators) +# 2 (only gamemasters) +# Default: 3 (anyone) # -# GM.InWhoList -# Is GM showed in who list (if visible). -# Default: 0 (false) -# 1 (true) +# GM.InWhoList.Level +# Max GM level showed in who list (if visible). +# 0 (only players) +# 1 (only moderators) +# 2 (only gamemasters) +# Default: 3 (anyone) # # GM.LogTrade # Include GM trade and trade slot enchanting operations in GM log if it enable @@ -1060,8 +1079,8 @@ GM.Visible = 2 GM.AcceptTickets = 2 GM.Chat = 2 GM.WhisperingTo = 2 -GM.InGMList = 0 -GM.InWhoList = 0 +GM.InGMList.Level = 3 +GM.InWhoList.Level = 3 GM.LogTrade = 1 GM.StartLevel = 80 GM.AllowInvite = 0 @@ -1160,6 +1179,9 @@ Visibility.Distance.Grey.Object = 10 # XP needed per level past 70 (Rates below 1 not recommended) # Default: 1 # +# Rate.RepairCost +# Repair cost rate (1 - standard, 2 - double cost, 0.5 - half cost, etc) +# # Rate.Rest.InGame # Rate.Rest.Offline.InTavernOrCity # Rate.Rest.Offline.InWilderness @@ -1221,6 +1243,14 @@ Visibility.Distance.Grey.Object = 10 # Default: 0 - no decrease # 75 - in 2 times each 75 skill points # +# DurabilityLoss.InPvP +# If true, players take durability loss on death in PvP. +# Default: 0 (false) +# 1 (true) +# +# DurabilityLoss.OnDeath +# Durability loss percentage on death (10 - standard, 20 - double, 5 - half) +# # DurabilityLossChance.Damage # Chance lost one from equiped items durability point at damage apply or receive. # Default: 0.5 (100/0.5 = 200) Each 200 damage apply one from 19 possible equipped items @@ -1279,6 +1309,7 @@ Rate.XP.Kill = 1 Rate.XP.Quest = 1 Rate.XP.Explore = 1 Rate.XP.PastLevel70 = 1 +Rate.RepairCost = 1 Rate.Rest.InGame = 1 Rate.Rest.Offline.InTavernOrCity = 1 Rate.Rest.Offline.InWilderness = 1 @@ -1304,6 +1335,8 @@ SkillChance.Green = 25 SkillChance.Grey = 0 SkillChance.MiningSteps = 0 SkillChance.SkinningSteps = 0 +DurabilityLoss.InPvP = 0 +DurabilityLoss.OnDeath = 10 DurabilityLossChance.Damage = 0.5 DurabilityLossChance.Absorb = 0.5 DurabilityLossChance.Parry = 0.05 @@ -1314,6 +1347,28 @@ Death.CorpseReclaimDelay.PvE = 0 Death.Bones.World = 1 Death.Bones.BattlegroundOrArena = 1 +################################################################################################################### +# AUTO BROADCAST +# +# AutoBroadcast.On +# Enable auto broadcast +# Default: 0 - off +# 1 - on +# +# AutoBroadcast.Center +# Display method +# Default: 0 - announce +# 1 - notify +# 2 - both +# +# AutoBroadcast.Timer +# Timer for auto broadcast +# +################################################################################################################### + +AutoBroadcast.On = 0 +AutoBroadcast.Center = 0 +AutoBroadcast.Timer = 60000 ################################################################################################################### # BATTLEGROUND CONFIG @@ -1439,6 +1494,10 @@ Network.TcpNodelay = 1 ################################################################################################################### # AUCTION HOUSE BOT SETTINGS # +# AuctionHouseBot.DEBUG +# Enable/Disable Debugging output +# Default 0 (disabled) +# # AuctionHouseBot.EnableSeller # Enable/Disable the part of AHBot that puts items up for auction # Default 0 (disabled) @@ -1447,56 +1506,107 @@ Network.TcpNodelay = 1 # Enable/Disable the part of AHBot that buys items from players # Default 0 (disabled) # +# AuctionHouseBot.UseBuyPriceForSeller +# Should the Seller use BuyPrice or SellPrice to determine Bid Prices +# Default 0 (use SellPrice) +# +# AuctionHouseBot.UseBuyPriceForBuyer +# Should the Buyer use BuyPrice or SellPrice to determine Bid Prices +# Default 0 (use SellPrice) +# # Auction House Bot character data # AuctionHouseBot.Account is the account number (in realmd->account table) of the player you want to run as the auction bot. -# AuctionHouseBot.GUID is the GUID (in characters->characters table) of the player you want to run as the auction bot. +# AuctionHouseBot.GUID is the GUID (in characters->characters table) of the player you want to run as the auction bot. # Default: 0 (Auction House Bot disabled) # +# AuctionHouseBot.ItemsPerCycle +# Number of Items to Add/Remove from the AH during mass operations +# Default 200 +# +################################################################################################################### + +AuctionHouseBot.DEBUG = 0 +AuctionHouseBot.EnableSeller = 0 +AuctionHouseBot.EnableBuyer = 0 +AuctionHouseBot.UseBuyPriceForSeller = 0 +AuctionHouseBot.UseBuyPriceForBuyer = 0 +AuctionHouseBot.Account = 0 +AuctionHouseBot.GUID = 0 +AuctionHouseBot.ItemsPerCycle = 200 + +################################################################################################################### +# AUCTION HOUSE BOT FILTERS PART 1 +# # AuctionHouseBot.VendorItems # Include items that can be bought from vendors. -# Default 0 +# Default 0 (False) # # AuctionHouseBot.LootItems # Include items that can be looted or fished for. -# Default 1 +# Default 1 (True) # # AuctionHouseBot.OtherItems # Include misc. items. -# Default 0 +# Default 0 (False) # # AuctionHouseBot.Bonding_types # Indicates which bonding types to allow seller to put up for auction # No_Bind -# Default 1 +# Default 1 (True) # Bind_When_Picked_Up -# Default 0 +# Default 0 (False) # Bind_When_Equipped -# Default 1 +# Default 1 (True) # Bind_When_Use -# Default 1 +# Default 1 (True) # Bind_Quest_Item -# Default 0 +# Default 0 (False) # -# AuctionHouseBot.ItemsPerCycle -# Number of Items to Add/Remove from the AH during mass operations -# Default 200 +# AuctionHouseBot.DisableBeta_PTR_Unused +# Disable certain items that are usually unavailable to Players +# Default 0 (False) # -# AuctionHouseBot.UseBuyPriceForSeller -# Should the Seller use BuyPrice or SellPrice to determine Bid Prices -# Default 0 (use SellPrice) +# AuctionHouseBot.DisablePermEnchant +# Disable Items with a Permanent Enchantment +# Default 0 (False) # -# AuctionHouseBot.UseBuyPriceForBuyer -# Should the Buyer use BuyPrice or SellPrice to determine Bid Prices -# Default 0 (use SellPrice) +# AuctionHouseBot.DisableConjured +# Disable Conjured Items +# Default 0 (False) +# +# AuctionHouseBot.DisableGems +# Disable Gems +# Default 0 (False) +# +# AuctionHouseBot.DisableMoney +# Disable Items that are used as money +# Default 0 (False) # -# All other settings have been moved to sql +# AuctionHouseBot.DisableMoneyLoot +# Disable Items that have Money as a loot +# Default 0 (False) +# +# AuctionHouseBot.DisableLootable +# Disable Items that have other items as loot +# Default 0 (False) +# +# AuctionHouseBot.DisableKeys +# Disable Items that are keys +# Default 0 (False) +# +# AuctionHouseBot.DisableDuration +# Disable Items with a duration +# Default 0 (False) +# +# AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel +# Disable items that are BOP or Quest Item +# with a Required level that is less than the Item Level +# (This prevents a level 10 with a level 60 weapon or armor) +# (May need further refinement) +# Default 0 (False) # ################################################################################################################### -AuctionHouseBot.EnableSeller = 0 -AuctionHouseBot.EnableBuyer = 0 -AuctionHouseBot.Account = 0 -AuctionHouseBot.GUID = 0 AuctionHouseBot.VendorItems = 0 AuctionHouseBot.LootItems = 1 AuctionHouseBot.OtherItems = 0 @@ -1505,9 +1615,123 @@ AuctionHouseBot.Bind_When_Picked_Up = 0 AuctionHouseBot.Bind_When_Equipped = 1 AuctionHouseBot.Bind_When_Use = 1 AuctionHouseBot.Bind_Quest_Item = 0 -AuctionHouseBot.ItemsPerCycle = 200 -AuctionHouseBot.UseBuyPriceForSeller = 0 -AuctionHouseBot.UseBuyPriceForBuyer = 0 +AuctionHouseBot.DisableBeta_PTR_Unused = 0 +AuctionHouseBot.DisablePermEnchant = 0 +AuctionHouseBot.DisableConjured = 0 +AuctionHouseBot.DisableGems = 0 +AuctionHouseBot.DisableMoney = 0 +AuctionHouseBot.DisableMoneyLoot = 0 +AuctionHouseBot.DisableLootable = 0 +AuctionHouseBot.DisableKeys = 0 +AuctionHouseBot.DisableDuration = 0 +AuctionHouseBot.DisableBOP_Or_Quest_NoReqLevel = 0 + +################################################################################################################### +# AUCTION HOUSE BOT FILTERS PART 2 +# +# These Filters are boolean (0 or 1) and will disable items that are +# specifically meant for the Class named. +# (UnusedClass is Class 10, which was skipped for some reason) +# Default 0 (allowed) +################################################################################################################### + +AuctionHouseBot.DisableWarriorItems = 0 +AuctionHouseBot.DisablePaladinItems = 0 +AuctionHouseBot.DisableHunterItems = 0 +AuctionHouseBot.DisableRogueItems = 0 +AuctionHouseBot.DisablePriestItems = 0 +AuctionHouseBot.DisableDKItems = 0 +AuctionHouseBot.DisableShamanItems = 0 +AuctionHouseBot.DisableMageItems = 0 +AuctionHouseBot.DisableWarlockItems = 0 +AuctionHouseBot.DisableUnusedClassItems = 0 +AuctionHouseBot.DisableDruidItems = 0 + +################################################################################################################### +# AUCTION HOUSE BOT FILTERS PART 3 +# +# AuctionHouseBot.DisableItemsBelowLevel +# Prevent Seller from listing Items below this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveLevel +# Prevent Seller from listing Items above this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowLevel +# Prevent Seller from listing Trade Goods below this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveLevel +# Prevent Seller from listing Trade Goods above this Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsBelowGUID +# Prevent Seller from listing Items below this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveGUID +# Prevent Seller from listing Items above this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowGUID +# Prevent Seller from listing Trade Goods below this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveGUID +# Prevent Seller from listing Trade Goods above this GUID +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsBelowReqLevel +# Prevent Seller from listing Items below this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveReqLevel +# Prevent Seller from listing Items above this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowReqLevel +# Prevent Seller from listing Trade Goods below this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveReqLevel +# Prevent Seller from listing Trade Goods above this Required Level +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsBelowReqSkillRank +# Prevent Seller from listing Items below this Required Skill Rank +# Default 0 (Off) +# +# AuctionHouseBot.DisableItemsAboveReqSkillRank +# Prevent Seller from listing Items above this Required Skill Rank +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsBelowReqSkillRank +# Prevent Seller from listing Trade Goods below this Required Skill Rank +# Default 0 (Off) +# +# AuctionHouseBot.DisableTGsAboveReqSkillRank +# Prevent Seller from listing Trade Goods above this Required Skill Rank +# Default 0 (Off) +# +################################################################################################################### + +AuctionHouseBot.DisableItemsBelowLevel = 0 +AuctionHouseBot.DisableItemsAboveLevel = 0 +AuctionHouseBot.DisableTGsBelowLevel = 0 +AuctionHouseBot.DisableTGsAboveLevel = 0 +AuctionHouseBot.DisableItemsBelowGUID = 0 +AuctionHouseBot.DisableItemsAboveGUID = 0 +AuctionHouseBot.DisableTGsBelowGUID = 0 +AuctionHouseBot.DisableTGsAboveGUID = 0 +AuctionHouseBot.DisableItemsBelowReqLevel = 0 +AuctionHouseBot.DisableItemsAboveReqLevel = 0 +AuctionHouseBot.DisableTGsBelowReqLevel = 0 +AuctionHouseBot.DisableTGsAboveReqLevel = 0 +AuctionHouseBot.DisableItemsBelowReqSkillRank = 0 +AuctionHouseBot.DisableItemsAboveReqSkillRank = 0 +AuctionHouseBot.DisableTGsBelowReqSkillRank = 0 +AuctionHouseBot.DisableTGsAboveReqSkillRank = 0 ################################################################################################################### # CONSOLE AND REMOTE ACCESS diff --git a/src/trinityrealm/AuthCodes.h b/src/trinityrealm/AuthCodes.h index 4ef5e4e8699..2a215968c3b 100644 --- a/src/trinityrealm/AuthCodes.h +++ b/src/trinityrealm/AuthCodes.h @@ -70,6 +70,6 @@ enum LoginResult // others will not and opposite // will only support WoW, WoW:TBC and WoW:WotLK 3.1.3 client build 9947... -#define EXPECTED_TRINITY_CLIENT_BUILD {9947, 0} +#define EXPECTED_MANGOS_CLIENT_BUILD {9947, 0} #endif diff --git a/src/trinityrealm/AuthSocket.cpp b/src/trinityrealm/AuthSocket.cpp index 8c9eab653ec..06c55f4955e 100644 --- a/src/trinityrealm/AuthSocket.cpp +++ b/src/trinityrealm/AuthSocket.cpp @@ -36,7 +36,7 @@ extern RealmList m_realmList; -extern DatabaseType LoginDatabase; +extern DatabaseType loginDatabase; #define ChunkSize 2048 @@ -112,7 +112,7 @@ typedef struct AUTH_LOGON_PROOF_C uint8 M1[20]; uint8 crc_hash[20]; uint8 number_of_keys; - uint8 unk; // Added in 1.12.x client branch + uint8 securityFlags; // 0x00-0x04 } sAuthLogonProof_C; /* typedef struct @@ -264,17 +264,11 @@ void AuthSocket::OnRead() ///- Get the command out of it ibuf.SoftRead((char *)&_cmd, 1); // UQ1: No longer exists in new net code ??? - //ibuf.Read((char *)&_cmd, 1); - /*char *command = (char *)malloc(1); - ibuf.Read(command, 1); - - _cmd = (uint8)command;*/ - // assert(0); size_t i; ///- Circle through known commands and call the correct command handler - for (i=0;i<AUTH_TOTAL_COMMANDS; i++) + for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i) { if ((uint8)table[i].cmd == _cmd && (table[i].status == STATUS_CONNECTED || @@ -292,7 +286,7 @@ void AuthSocket::OnRead() } ///- Report unknown commands in the debug log - if (i==AUTH_TOTAL_COMMANDS) + if (i == AUTH_TOTAL_COMMANDS) { DEBUG_LOG("[Auth] got unknown packet %u", (uint32)_cmd); return; @@ -306,13 +300,13 @@ void AuthSocket::_SetVSFields(const std::string& rI) BigNumber I; I.SetHexStr(rI.c_str()); - //In case of leading zeroes in the rI hash, restore them + // In case of leading zeros in the rI hash, restore them uint8 mDigest[SHA_DIGEST_LENGTH]; - memset(mDigest,0,SHA_DIGEST_LENGTH); + memset(mDigest, 0, SHA_DIGEST_LENGTH); if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) - memcpy(mDigest,I.AsByteArray(),I.GetNumBytes()); + memcpy(mDigest, I.AsByteArray(), I.GetNumBytes()); - std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH); + std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); Sha1Hash sha; sha.UpdateData(s.AsByteArray(), s.GetNumBytes()); @@ -325,7 +319,7 @@ void AuthSocket::_SetVSFields(const std::string& rI) const char *v_hex, *s_hex; v_hex = v.AsHexStr(); s_hex = s.AsHexStr(); - LoginDatabase.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '%s'",v_hex,s_hex, _safelogin.c_str() ); + loginDatabase.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '%s'", v_hex, s_hex, _safelogin.c_str() ); OPENSSL_free((void*)v_hex); OPENSSL_free((void*)s_hex); } @@ -380,19 +374,19 @@ bool AuthSocket::_HandleLogonChallenge() //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction - _safelogin=_login; - LoginDatabase.escape_string(_safelogin); + _safelogin = _login; + loginDatabase.escape_string(_safelogin); pkt << (uint8) AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); std::string address = GetRemoteAddress(); - LoginDatabase.escape_string(address); - QueryResult *result = LoginDatabase.PQuery( "SELECT * FROM ip_banned WHERE ip = '%s'",address.c_str()); + loginDatabase.escape_string(address); + QueryResult *result = loginDatabase.PQuery( "SELECT * FROM ip_banned WHERE ip = '%s'",address.c_str()); if(result) { pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED; @@ -404,7 +398,7 @@ bool AuthSocket::_HandleLogonChallenge() ///- Get the account details from the account table // No SQL injection (escaped user name) - result = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel FROM account WHERE username = '%s'",_safelogin.c_str ()); + result = loginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel FROM account WHERE username = '%s'",_safelogin.c_str ()); if( result ) { ///- If the IP is 'locked', check that the player comes indeed from the correct IP address @@ -432,9 +426,9 @@ bool AuthSocket::_HandleLogonChallenge() if (!locked) { //set expired bans to inactive - LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); + loginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); ///- If the account is banned, reject the logon attempt - QueryResult *banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = %u AND active = 1", (*result)[1].GetUInt32()); + QueryResult *banresult = loginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = %u AND active = 1", (*result)[1].GetUInt32()); if(banresult) { if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) @@ -457,35 +451,56 @@ bool AuthSocket::_HandleLogonChallenge() _SetVSFields(rI); b.SetRand(19 * 8); - BigNumber gmod=g.ModExp(b, N); + BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; - unk3.SetRand(16*8); + unk3.SetRand(16 * 8); ///- Fill the response packet with the result - pkt << (uint8)REALM_AUTH_SUCCESS; + pkt << uint8(REALM_AUTH_SUCCESS); - // B may be calculated < 32B so we force minnimal length to 32B - pkt.append(B.AsByteArray(32), 32); // 32 bytes - pkt << (uint8)1; + // B may be calculated < 32B so we force minimal length to 32B + pkt.append(B.AsByteArray(32), 32); // 32 bytes + pkt << uint8(1); pkt.append(g.AsByteArray(), 1); - pkt << (uint8)32; + pkt << uint8(32); pkt.append(N.AsByteArray(), 32); pkt.append(s.AsByteArray(), s.GetNumBytes()); // 32 bytes pkt.append(unk3.AsByteArray(), 16); - pkt << (uint8)0; // Added in 1.12.x client branch + uint8 securityFlags = 0; + pkt << uint8(securityFlags); // security flags (0x0...0x04) + + if(securityFlags & 0x01) // PIN input + { + pkt << uint32(0); + pkt << uint64(0) << uint64(0); // 16 bytes hash? + } + + if(securityFlags & 0x02) // Matrix input + { + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint64(0); + } + + if(securityFlags & 0x04) // Security token input + { + pkt << uint8(1); + } uint8 secLevel = (*result)[4].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); - for(int i = 0; i <4; ++i) + for(int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; - sLog.outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3],ch->country[2],ch->country[1],ch->country[0], GetLocaleByName(_localizationName)); + sLog.outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); } } delete result; @@ -510,13 +525,13 @@ bool AuthSocket::_HandleLogonProof() ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C)); ///- Check if the client has one of the expected version numbers - bool valid_version=false; - int accepted_versions[]=EXPECTED_TRINITY_CLIENT_BUILD; - for(int i=0;accepted_versions[i];i++) + bool valid_version = false; + int accepted_versions[] = EXPECTED_MANGOS_CLIENT_BUILD; + for(int i = 0; accepted_versions[i]; ++i) { - if(_build==accepted_versions[i]) + if(_build == accepted_versions[i]) { - valid_version=true; + valid_version = true; break; } } @@ -529,9 +544,9 @@ bool AuthSocket::_HandleLogonProof() // 24 = len("./patches/65535enGB.mpq")+1 char tmp[24]; // No buffer overflow (fixed length of arguments) - sprintf(tmp,"./patches/%d%s.mpq",_build, _localizationName.c_str()); - // This will be closed at the destruction of the AuthSocket (client deconnection) - FILE *pFile=fopen(tmp,"rb"); + sprintf(tmp, "./patches/%d%s.mpq", _build, _localizationName.c_str()); + // This will be closed at the destruction of the AuthSocket (client disconnection) + FILE *pFile = fopen(tmp, "rb"); if(!pFile) { @@ -540,37 +555,37 @@ bool AuthSocket::_HandleLogonProof() pkt << (uint8) 0x00; pkt << (uint8) REALM_AUTH_WRONG_BUILD_NUMBER; DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); - DEBUG_LOG("[AuthChallenge] Patch %s not found",tmp); + DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); SendBuf((char const*)pkt.contents(), pkt.size()); return true; } else // have patch { - pPatch=pFile; + pPatch = pFile; XFER_INIT xferh; ///- Get the MD5 hash of the patch file (get it from preloaded Patcher cache or calculate it) - if(PatchesCache.GetHash(tmp,(uint8*)&xferh.md5)) + if(PatchesCache.GetHash(tmp, (uint8*)&xferh.md5)) { - DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s",tmp); + DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s", tmp); } else - { //calculate patch md5 - printf("\n[AuthChallenge] Patch info for %s was not cached.",tmp); + { // calculate patch md5 + printf("\n[AuthChallenge] Patch info for %s was not cached.", tmp); PatchesCache.LoadPatchMD5(tmp); - PatchesCache.GetHash(tmp,(uint8*)&xferh.md5); + PatchesCache.GetHash(tmp, (uint8*)&xferh.md5); } ///- Send a packet to the client with the file length and MD5 hash - uint8 data[2]={AUTH_LOGON_PROOF,REALM_AUTH_UPDATE_CLIENT}; - SendBuf((const char*)data,sizeof(data)); + uint8 data[2] = { AUTH_LOGON_PROOF, REALM_AUTH_UPDATE_CLIENT }; + SendBuf((const char*)data, sizeof(data)); - memcpy(&xferh,"0\x05Patch",7); - xferh.cmd=XFER_INITIATE; - fseek(pPatch,0,SEEK_END); - xferh.file_size=ftell(pPatch); + memcpy(&xferh, "0\x05Patch", 7); + xferh.cmd = XFER_INITIATE; + fseek(pPatch, 0, SEEK_END); + xferh.file_size = ftell(pPatch); - SendBuf((const char*)&xferh,sizeof(xferh)); + SendBuf((const char*)&xferh, sizeof(xferh)); return true; } } @@ -591,27 +606,27 @@ bool AuthSocket::_HandleLogonProof() uint8 t1[16]; uint8 vK[40]; memcpy(t, S.AsByteArray(), 32); - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; ++i) { - t1[i] = t[i*2]; + t1[i] = t[i * 2]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); - for (int i = 0; i < 20; i++) + for (int i = 0; i < 20; ++i) { - vK[i*2] = sha.GetDigest()[i]; + vK[i * 2] = sha.GetDigest()[i]; } - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; ++i) { - t1[i] = t[i*2+1]; + t1[i] = t[i * 2 + 1]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); - for (int i = 0; i < 20; i++) + for (int i = 0; i < 20; ++i) { - vK[i*2+1] = sha.GetDigest()[i]; + vK[i * 2 + 1] = sha.GetDigest()[i]; } K.SetBinary(vK, 40); @@ -624,7 +639,7 @@ bool AuthSocket::_HandleLogonProof() sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); - for (int i = 0; i < 20; i++) + for (int i = 0; i < 20; ++i) { hash[i] ^= sha.GetDigest()[i]; } @@ -653,7 +668,7 @@ bool AuthSocket::_HandleLogonProof() ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket const char* K_hex = K.AsHexStr(); - LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '%s'", K_hex, GetRemoteAddress().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str() ); + loginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '%s'", K_hex, GetRemoteAddress().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str() ); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client @@ -676,17 +691,17 @@ bool AuthSocket::_HandleLogonProof() } else { - char data[4]={AUTH_LOGON_PROOF,REALM_AUTH_NO_MATCH,3,0}; - SendBuf(data,sizeof(data)); + char data[4]= { AUTH_LOGON_PROOF, REALM_AUTH_NO_MATCH, 3, 0}; + SendBuf(data, sizeof(data)); sLog.outBasic("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); if(MaxWrongPassCount > 0) { //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP - LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '%s'",_safelogin.c_str()); + loginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '%s'",_safelogin.c_str()); - if(QueryResult *loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '%s'", _safelogin.c_str())) + if(QueryResult *loginfail = loginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '%s'", _safelogin.c_str())) { Field* fields = loginfail->Fetch(); uint32 failed_logins = fields[1].GetUInt32(); @@ -699,7 +714,7 @@ bool AuthSocket::_HandleLogonProof() if(WrongPassBanType) { uint32 acc_id = fields[0].GetUInt32(); - LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban',1)", + loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); sLog.outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); @@ -707,8 +722,8 @@ bool AuthSocket::_HandleLogonProof() else { std::string current_ip = GetRemoteAddress(); - LoginDatabase.escape_string(current_ip); - LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban')", + loginDatabase.escape_string(current_ip); + loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); sLog.outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); @@ -754,7 +769,7 @@ bool AuthSocket::_HandleReconnectChallenge() _login = (const char*)ch->I; _safelogin = _login; - QueryResult *result = LoginDatabase.PQuery ("SELECT sessionkey FROM account WHERE username = '%s'", _safelogin.c_str ()); + QueryResult *result = loginDatabase.PQuery ("SELECT sessionkey FROM account WHERE username = '%s'", _safelogin.c_str ()); // Stop if the account is not found if (!result) @@ -772,7 +787,7 @@ bool AuthSocket::_HandleReconnectChallenge() ByteBuffer pkt; pkt << (uint8) AUTH_RECONNECT_CHALLENGE; pkt << (uint8) 0x00; - _reconnectProof.SetRand(16*8); + _reconnectProof.SetRand(16 * 8); pkt.append(_reconnectProof.AsByteBuffer()); // 16 bytes random pkt << (uint64) 0x00 << (uint64) 0x00; // 16 bytes zeros SendBuf((char const*)pkt.contents(), pkt.size()); @@ -834,7 +849,7 @@ bool AuthSocket::_HandleRealmList() ///- Get the user id (else close the connection) // No SQL injection (escaped user name) - QueryResult *result = LoginDatabase.PQuery("SELECT id,sha_pass_hash FROM account WHERE username = '%s'",_safelogin.c_str()); + QueryResult *result = loginDatabase.PQuery("SELECT id,sha_pass_hash FROM account WHERE username = '%s'",_safelogin.c_str()); if(!result) { sLog.outError("[ERROR] user %s tried to login and we cannot find him in the database.",_login.c_str()); @@ -854,12 +869,12 @@ bool AuthSocket::_HandleRealmList() pkt << (uint32) 0; pkt << (uint16) m_realmList.size(); RealmList::RealmMap::const_iterator i; - for( i = m_realmList.begin(); i != m_realmList.end(); i++ ) + for( i = m_realmList.begin(); i != m_realmList.end(); ++i ) { uint8 AmountOfCharacters; // No SQL injection. id of realm is controlled by the database. - result = LoginDatabase.PQuery( "SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'",i->second.m_ID,id); + result = loginDatabase.PQuery( "SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'",i->second.m_ID,id); if( result ) { Field *fields = result->Fetch(); @@ -901,7 +916,7 @@ bool AuthSocket::_HandleXferResume() { DEBUG_LOG("Entering _HandleXferResume"); ///- Check packet length and patch existence - if (ibuf.GetLength()<9 || !pPatch) + if (ibuf.GetLength() < 9 || !pPatch) { sLog.outError("Error while resuming patch transfer (wrong packet)"); return false; @@ -911,9 +926,9 @@ bool AuthSocket::_HandleXferResume() uint64 start; ibuf.Remove(1); ibuf.Read((char*)&start,sizeof(start)); - fseek(pPatch,start,0); + fseek(pPatch, start, 0); - ACE_Based::Thread u(*new PatcherRunnable(this)); + ACE_Based::Thread u(new PatcherRunnable(this)); return true; } @@ -942,23 +957,23 @@ bool AuthSocket::_HandleXferAccept() return false; } - ///- Launch a PatcherRunnable thread, starting at the begining of the patch file - ibuf.Remove(1); //clear input buffer - fseek(pPatch,0,0); + ///- Launch a PatcherRunnable thread, starting at the beginning of the patch file + ibuf.Remove(1); // clear input buffer + fseek(pPatch, 0, 0); - ACE_Based::Thread u(*new PatcherRunnable(this)); + ACE_Based::Thread u(new PatcherRunnable(this)); return true; } /// Check if there is lag on the connection to the client bool AuthSocket::IsLag() { - return (TCP_BUFSIZE_READ-GetOutputLength()< 2*ChunkSize); + return (TCP_BUFSIZE_READ-GetOutputLength() < 2 * ChunkSize); } PatcherRunnable::PatcherRunnable(class AuthSocket * as) { - mySocket=as; + mySocket = as; } /// Send content of patch file to the client @@ -977,8 +992,8 @@ void PatcherRunnable::run() ACE_Based::Thread::Sleep(1); } ///- And send content of the patch file to the client - xfdata.data_size=fread(&xfdata.data,1,ChunkSize,mySocket->pPatch); - mySocket->SendBuf((const char*)&xfdata,xfdata.data_size +(sizeof(XFER_DATA_STRUCT)-ChunkSize)); + xfdata.data_size = fread(&xfdata.data, 1, ChunkSize, mySocket->pPatch); + mySocket->SendBuf((const char*)&xfdata, xfdata.data_size + (sizeof(XFER_DATA_STRUCT) - ChunkSize)); } } @@ -999,8 +1014,9 @@ void Patcher::LoadPatchesInfo() errno = 0; if ((dp = readdir(dirp)) != NULL) { - int l=strlen(dp->d_name); - if(l<8)continue; + int l = strlen(dp->d_name); + if(l < 8) + continue; if(!memcmp(&dp->d_name[l-4],".mpq",4)) LoadPatchMD5(dp->d_name); } @@ -1023,15 +1039,15 @@ void Patcher::LoadPatchesInfo() void Patcher::LoadPatchesInfo() { WIN32_FIND_DATA fil; - HANDLE hFil=FindFirstFile("./patches/*.mpq",&fil); - if(hFil==INVALID_HANDLE_VALUE) - return; //no patches were found + HANDLE hFil=FindFirstFile("./patches/*.mpq", &fil); + if(hFil == INVALID_HANDLE_VALUE) + return; // no patches were found do { LoadPatchMD5(fil.cFileName); } - while(FindNextFile(hFil,&fil)); + while(FindNextFile(hFil, &fil)); } #endif @@ -1041,11 +1057,11 @@ void Patcher::LoadPatchMD5(char * szFileName) ///- Try to open the patch file std::string path = "./patches/"; path += szFileName; - FILE * pPatch=fopen(path.c_str(),"rb"); - sLog.outDebug("Loading patch info from %s\n",path.c_str()); + FILE *pPatch = fopen(path.c_str(), "rb"); + sLog.outDebug("Loading patch info from %s\n", path.c_str()); if(!pPatch) { - sLog.outError("Error loading patch %s\n",path.c_str()); + sLog.outError("Error loading patch %s\n", path.c_str()); return; } @@ -1064,16 +1080,16 @@ void Patcher::LoadPatchMD5(char * szFileName) ///- Store the result in the internal patch hash map _patches[path] = new PATCH_INFO; - MD5_Final((uint8 *)&_patches[path]->md5 , &ctx); + MD5_Final((uint8 *)&_patches[path]->md5, &ctx); } /// Get cached MD5 hash for a given patch file -bool Patcher::GetHash(char * pat,uint8 mymd5[16]) +bool Patcher::GetHash(char * pat, uint8 mymd5[16]) { - for( Patches::iterator i = _patches.begin(); i != _patches.end(); i++ ) - if(!stricmp(pat,i->first.c_str () )) + for( Patches::iterator i = _patches.begin(); i != _patches.end(); ++i ) + if(!stricmp(pat, i->first.c_str())) { - memcpy(mymd5,i->second->md5,16); + memcpy(mymd5, i->second->md5, 16); return true; } @@ -1089,6 +1105,6 @@ Patcher::Patcher() /// Empty and delete the patch map on termination Patcher::~Patcher() { - for(Patches::iterator i = _patches.begin(); i != _patches.end(); i++ ) + for(Patches::iterator i = _patches.begin(); i != _patches.end(); ++i ) delete i->second; } diff --git a/src/trinityrealm/AuthSocket.h b/src/trinityrealm/AuthSocket.h index 43b880a1e74..ecfdd159000 100644 --- a/src/trinityrealm/AuthSocket.h +++ b/src/trinityrealm/AuthSocket.h @@ -60,7 +60,7 @@ class AuthSocket: public TcpSocket void _SetVSFields(const std::string& rI); FILE *pPatch; - ACE_Thread_Mutex patcherLock; + ACE_Thread_Mutex patcherLock; bool IsLag(); private: diff --git a/src/trinityrealm/CMakeLists.txt b/src/trinityrealm/CMakeLists.txt index 62f943a1c96..dc5b67c7798 100644 --- a/src/trinityrealm/CMakeLists.txt +++ b/src/trinityrealm/CMakeLists.txt @@ -18,9 +18,9 @@ add_definitions( IF (DO_MYSQL) SET(trinity-realm_LINK_FLAGS "-pthread ${trinity-realm_LINK_FLAGS}") ENDIF(DO_MYSQL) -IF (DO_POSTGRE) - SET(trinity-realm_LINK_FLAGS "${POSTGRE_LIBS} ${trinity-realm_LINK_FLAGS}") -ENDIF(DO_POSTGRE) +IF (DO_POSTGRESQL) + SET(trinity-realm_LINK_FLAGS "-pthread ${trinity-realm_LINK_FLAGS}") +ENDIF(DO_POSTGRESQL) IF (CMAKE_SYSTEM_NAME MATCHES "Darwin") SET(trinity-realm_LINK_FLAGS "-framework Carbon ${trinity-realm_LINK_FLAGS}") @@ -41,6 +41,7 @@ zlib gomp ${SSLLIB} ${MYSQL_LIBRARIES} +${POSTGRESQL_LIBRARIES} ${OSX_LIBS} ) diff --git a/src/trinityrealm/Main.cpp b/src/trinityrealm/Main.cpp index 3d934f4ba85..1985009ea93 100644 --- a/src/trinityrealm/Main.cpp +++ b/src/trinityrealm/Main.cpp @@ -66,7 +66,7 @@ void HookSignals(); bool stopEvent = false; ///< Setting it to true stops the server RealmList m_realmList; ///< Holds the list of realms for this server -DatabaseType LoginDatabase; ///< Accessor to the realm server database +DatabaseType loginDatabase; ///< Accessor to the realm server database /// Print out the usage string for this program on the console. void usage(const char *prog) @@ -304,7 +304,7 @@ extern int main(int argc, char **argv) { loopCounter = 0; sLog.outDetail("Ping MySQL to keep connection alive"); - delete LoginDatabase.Query("SELECT 1 FROM realmlist LIMIT 1"); + delete loginDatabase.Query("SELECT 1 FROM realmlist LIMIT 1"); } #ifdef WIN32 if (m_ServiceStatus == 0) stopEvent = true; @@ -313,8 +313,8 @@ extern int main(int argc, char **argv) } ///- Wait for the delay thread to exit - LoginDatabase.ThreadEnd(); - LoginDatabase.HaltDelayThread(); + loginDatabase.ThreadEnd(); + loginDatabase.HaltDelayThread(); ///- Remove signal handling before leaving UnhookSignals(); @@ -346,19 +346,19 @@ void OnSignal(int s) /// Initialize connection to the database bool StartDB() { - std::string dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); + std::string dbstring = sConfig.GetStringDefault("loginDatabaseInfo", ""); if(dbstring.empty()) { sLog.outError("Database not specified"); return false; } - if(!LoginDatabase.Initialize(dbstring.c_str())) + if(!loginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to database"); return false; } - LoginDatabase.ThreadStart(); + loginDatabase.ThreadStart(); return true; } diff --git a/src/trinityrealm/RealmList.cpp b/src/trinityrealm/RealmList.cpp index 6a3d6b47e0f..4de3a796179 100644 --- a/src/trinityrealm/RealmList.cpp +++ b/src/trinityrealm/RealmList.cpp @@ -29,7 +29,7 @@ INSTANTIATE_SINGLETON_1( RealmList ); -extern DatabaseType LoginDatabase; +extern DatabaseType loginDatabase; RealmList::RealmList( ) : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { @@ -82,7 +82,7 @@ void RealmList::UpdateRealms(bool init) { sLog.outDetail("Updating Realm List..."); - QueryResult *result = LoginDatabase.Query( "SELECT id, name, address, port, icon, color, timezone, allowedSecurityLevel, population FROM realmlist WHERE color <> 3 ORDER BY name" ); + QueryResult *result = loginDatabase.Query( "SELECT id, name, address, port, icon, color, timezone, allowedSecurityLevel, population FROM realmlist WHERE color <> 3 ORDER BY name" ); ///- Circle through results and add them to the realm map if(result) |