diff options
Diffstat (limited to 'src')
174 files changed, 4307 insertions, 2264 deletions
diff --git a/src/bindings/scripts/ScriptMgr.cpp b/src/bindings/scripts/ScriptMgr.cpp index 18465bfacf7..849c4d64be5 100644 --- a/src/bindings/scripts/ScriptMgr.cpp +++ b/src/bindings/scripts/ScriptMgr.cpp @@ -389,6 +389,7 @@ extern void AddSC_boss_sapphiron(); extern void AddSC_boss_four_horsemen(); extern void AddSC_boss_faerlina(); extern void AddSC_boss_heigan(); +extern void AddSC_boss_gothik(); extern void AddSC_instance_naxxramas(); //Netherstorm @@ -1327,6 +1328,7 @@ void ScriptsInit(char const* cfg_file = "trinitycore.conf") AddSC_boss_sapphiron(); AddSC_boss_four_horsemen(); AddSC_boss_heigan(); + AddSC_boss_gothik(); AddSC_instance_naxxramas(); //Netherstorm @@ -1657,7 +1659,7 @@ void Script::RegisterSelf() m_scripts[id] = this; ++num_sc_scripts; } - else + else if(Name.find("example") == std::string::npos) { error_db_log("CRASH ALERT! TrinityScript: RegisterSelf, but script named %s does not have ScriptName assigned in database.",(this)->Name.c_str()); delete this; diff --git a/src/bindings/scripts/VC80/80ScriptDev2.vcproj b/src/bindings/scripts/VC80/80ScriptDev2.vcproj index c442ae52a2d..28875c526ab 100644 --- a/src/bindings/scripts/VC80/80ScriptDev2.vcproj +++ b/src/bindings/scripts/VC80/80ScriptDev2.vcproj @@ -68,10 +68,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="TrinityCore.lib zthread.lib" + AdditionalDependencies="TrinityCore.lib aced.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="2" - AdditionalLibraryDirectories="..\..\..\..\win\VC80\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/TrinityScript.pdb" SubSystem="2" @@ -151,10 +151,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="TrinityCore.lib zthread.lib" + AdditionalDependencies="TrinityCore.lib ace.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="1" - AdditionalLibraryDirectories="..\..\..\..\win\VC80\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" @@ -236,10 +236,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="TrinityCore.lib zthread.lib" + AdditionalDependencies="TrinityCore.lib aced.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="2" - AdditionalLibraryDirectories="..\..\..\..\win\VC80\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/TrinityScript.pdb" SubSystem="2" @@ -320,10 +320,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="TrinityCore.lib zthread.lib" + AdditionalDependencies="TrinityCore.lib ace.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="1" - AdditionalLibraryDirectories="..\..\..\..\win\VC80\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC80\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" diff --git a/src/bindings/scripts/VC90/90ScriptDev2.vcproj b/src/bindings/scripts/VC90/90ScriptDev2.vcproj index 398e54d6ec4..8f8330db453 100644 --- a/src/bindings/scripts/VC90/90ScriptDev2.vcproj +++ b/src/bindings/scripts/VC90/90ScriptDev2.vcproj @@ -68,10 +68,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="trinitycore.lib zthread.lib" + AdditionalDependencies="trinitycore.lib aced.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="2" - AdditionalLibraryDirectories="..\..\..\..\win\VC90\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/TrinityScript.pdb" SubSystem="2" @@ -152,10 +152,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="trinitycore.lib zthread.lib" + AdditionalDependencies="trinitycore.lib ace.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="1" - AdditionalLibraryDirectories="..\..\..\..\win\VC90\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" @@ -237,10 +237,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="trinitycore.lib zthread.lib" + AdditionalDependencies="trinitycore.lib aced.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="2" - AdditionalLibraryDirectories="..\..\..\..\win\VC90\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="true" ProgramDatabaseFile="$(OutDir)/TrinityScript.pdb" SubSystem="2" @@ -320,10 +320,10 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="trinitycore.lib zthread.lib" + AdditionalDependencies="trinitycore.lib ace.lib" OutputFile="$(OutDir)/TrinityScript.dll" LinkIncremental="1" - AdditionalLibraryDirectories="..\..\..\..\win\VC90\zthread__$(PlatformName)_$(ConfigurationName);..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName)" + AdditionalLibraryDirectories="..\..\..\..\win\VC90\trinitycore__$(PlatformName)_$(ConfigurationName);..\..\..\..\dep\lib\$(PlatformName)_$(ConfigurationName)" GenerateDebugInformation="false" SubSystem="2" OptimizeReferences="2" diff --git a/src/bindings/scripts/include/precompiled.h b/src/bindings/scripts/include/precompiled.h index 2c36cc924e0..fa676f460ef 100644 --- a/src/bindings/scripts/include/precompiled.h +++ b/src/bindings/scripts/include/precompiled.h @@ -12,10 +12,11 @@ #include "GridNotifiersImpl.h" #include "Unit.h" #include "GameObject.h" -#include "TemporarySummon.h" #include "sc_creature.h" #include "sc_gossip.h" #include "sc_instance.h" +#include "AggressorAI.h" +#include "NullCreatureAI.h" #ifdef WIN32 #include <windows.h> diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp index 258c7627dce..e575e40fac1 100644 --- a/src/bindings/scripts/include/sc_creature.cpp +++ b/src/bindings/scripts/include/sc_creature.cpp @@ -9,6 +9,7 @@ #include "Item.h" #include "Spell.h" #include "ObjectMgr.h" +#include "TemporarySummon.h" // Spell summary for ScriptedAI::SelectSpell struct TSpellSummary { @@ -16,13 +17,26 @@ struct TSpellSummary { uint8 Effects; // set of enum SelectEffect } *SpellSummary; +void SummonList::DoZoneInCombat(uint32 entry) +{ + for(iterator i = begin(); i != end();) + { + Creature *summon = Unit::GetCreature(*m_creature, *i); + ++i; + if(summon && summon->IsAIEnabled + && (!entry || summon->GetEntry() == entry)) + summon->AI()->DoZoneInCombat(); + } +} + void SummonList::DoAction(uint32 entry, uint32 info) { for(iterator i = begin(); i != end();) { Creature *summon = Unit::GetCreature(*m_creature, *i); ++i; - if(summon && summon->IsAIEnabled) + if(summon && summon->IsAIEnabled + && (!entry || summon->GetEntry() == entry)) summon->AI()->DoAction(info); } } @@ -55,7 +69,11 @@ void SummonList::DespawnAll() else { erase(begin()); - summon->setDeathState(JUST_DIED); + summon->SetVisibility(VISIBILITY_OFF); + if(summon->HasSummonMask(SUMMON_MASK_SUMMON) && !summon->isPet()) + ((TempSummon*)summon)->UnSummon(); + else + summon->setDeathState(JUST_DIED); summon->RemoveCorpse(); } } @@ -108,26 +126,6 @@ void ScriptedAI::UpdateAI(const uint32 diff) } } -void ScriptedAI::EnterEvadeMode() -{ - //m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(); - m_creature->LoadCreaturesAddon(); - m_creature->SetLootRecipient(NULL); - - if(m_creature->isAlive()) - m_creature->GetMotionMaster()->MoveTargetedHome(); - - Reset(); -} - -void ScriptedAI::JustRespawned() -{ - Reset(); -} - void ScriptedAI::DoStartMovement(Unit* victim, float distance, float angle) { if (!victim) @@ -228,6 +226,19 @@ Creature* ScriptedAI::DoSpawnCreature(uint32 id, float x, float y, float z, floa return m_creature->SummonCreature(id,m_creature->GetPositionX() + x,m_creature->GetPositionY() + y,m_creature->GetPositionZ() + z, angle, (TempSummonType)type, despawntime); } +Creature *ScriptedAI::DoSummon(uint32 entry, const float pos[4], uint32 despawntime, TempSummonType type) +{ + return me->SummonCreature(entry, pos[0], pos[1], pos[2], pos[3], type, despawntime); +} + +Creature *ScriptedAI::DoSummon(uint32 entry, WorldObject *obj, float radius, uint32 despawntime, TempSummonType type) +{ + float x, y, z; + obj->GetGroundPointAroundUnit(x, y, z, radius * rand_norm(), rand_norm()*2*M_PI); + return me->SummonCreature(entry, x, y, z, me->GetOrientation(), type, despawntime); +} + + Unit* ScriptedAI::SelectUnit(SelectAggroTarget target, uint32 position) { //ThreatList m_threatlist; @@ -259,147 +270,7 @@ Unit* ScriptedAI::SelectUnit(SelectAggroTarget target, uint32 position) return NULL; } -struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, bool> -{ - const Unit* me; - TargetDistanceOrder(const Unit* Target) : me(Target) {}; - // functor for operator ">" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (me->GetDistance(_Left) < me->GetDistance(_Right)); - } -}; - -Unit* ScriptedAI::SelectUnit(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly) -{ - if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) - { - std::list<HostilReference*> &m_threatlist = m_creature->getThreatManager().getThreatList(); - if(m_threatlist.empty()) return NULL; - std::list<Unit*> targetList; - std::list<HostilReference*>::iterator itr = m_threatlist.begin(); - for(; itr!= m_threatlist.end(); ++itr) - { - Unit *target = (*itr)->getTarget(); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - continue; - } - targetList.push_back(target); - } - if(position >= targetList.size()) - return NULL; - targetList.sort(TargetDistanceOrder(m_creature)); - if(targetType == SELECT_TARGET_NEAREST) - { - std::list<Unit*>::iterator i = targetList.begin(); - advance(i, position); - return *i; - } - else - { - std::list<Unit*>::reverse_iterator i = targetList.rbegin(); - advance(i, position); - return *i; - } - } - else - { - std::list<HostilReference*> m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list<HostilReference*>::iterator i; - Unit *target; - while(position < m_threatlist.size()) - { - if(targetType == SELECT_TARGET_BOTTOMAGGRO) - { - i = m_threatlist.end(); - advance(i, - (int32)position - 1); - } - else - { - i = m_threatlist.begin(); - if(targetType == SELECT_TARGET_TOPAGGRO) - advance(i, position); - else // random - advance(i, position + rand()%(m_threatlist.size() - position)); - } - - target = (*i)->getTarget(); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - m_threatlist.erase(i); - } - else - { - return target; - } - } - } - - return NULL; -} - -void ScriptedAI::SelectUnitList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly) -{ - if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) - { - std::list<HostilReference*> &m_threatlist = m_creature->getThreatManager().getThreatList(); - if(m_threatlist.empty()) return; - std::list<HostilReference*>::iterator itr = m_threatlist.begin(); - for(; itr!= m_threatlist.end(); ++itr) - { - Unit *target = (*itr)->getTarget(); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - continue; - } - targetList.push_back(target); - } - targetList.sort(TargetDistanceOrder(m_creature)); - targetList.resize(num); - if(targetType == SELECT_TARGET_FARTHEST) - targetList.reverse(); - } - else - { - std::list<HostilReference*> m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list<HostilReference*>::iterator i; - Unit *target; - while(m_threatlist.size() && num) - { - if(targetType == SELECT_TARGET_BOTTOMAGGRO) - { - i = m_threatlist.end(); - --i; - } - else - { - i = m_threatlist.begin(); - if(targetType == SELECT_TARGET_RANDOM) - advance(i, rand()%m_threatlist.size()); - } - - target = (*i)->getTarget(); - m_threatlist.erase(i); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - continue; - } - targetList.push_back(target); - --num; - } - } -} - -SpellEntry const* ScriptedAI::SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects) +SpellEntry const* ScriptedAI::SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTargetType Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects) { //No target so we can't cast if (!Target) @@ -515,7 +386,6 @@ bool ScriptedAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered) return true; } - float GetSpellMaxRangeForHostile(uint32 id) { SpellEntry const *spellInfo = GetSpellStore()->LookupEntry(id); @@ -531,7 +401,7 @@ void FillSpellSummary() SpellEntry const* TempSpell; - for (int i=0; i < GetSpellStore()->GetNumRows(); i++ ) + for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i) { SpellSummary[i].Effects = 0; SpellSummary[i].Targets = 0; @@ -541,7 +411,7 @@ void FillSpellSummary() if (!TempSpell) continue; - for (int j=0; j<3; j++) + for(uint32 j = 0; j < 3; ++j) { //Spell targets self if ( TempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER ) @@ -649,6 +519,11 @@ void ScriptedAI::DoTeleportTo(float x, float y, float z, uint32 time) m_creature->SendMonsterMove(x, y, z, time); } +void ScriptedAI::DoTeleportTo(const float pos[4]) +{ + me->NearTeleportTo(pos[0], pos[1], pos[2], pos[3]); +} + void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float x, float y, float z, float o) { if(!pUnit || pUnit->GetTypeId() != TYPEID_PLAYER) @@ -775,23 +650,85 @@ void Scripted_NoMovementAI::AttackStart(Unit* who) } } +void BossAI::_Reset() +{ + events.Reset(); + summons.DespawnAll(); + instance->SetBossState(bossId, NOT_STARTED); +} + +void BossAI::_JustDied() +{ + events.Reset(); + summons.DespawnAll(); + instance->SetBossState(bossId, DONE); +} + +void BossAI::_EnterCombat() +{ + DoZoneInCombat(); + instance->SetBossState(bossId, IN_PROGRESS); +} + +void BossAI::JustSummoned(Creature *summon) +{ + summons.Summon(summon); + if(me->isInCombat()) + DoZoneInCombat(summon); +} + +void BossAI::SummonedCreatureDespawn(Creature *summon) +{ + summons.Despawn(summon); +} + +#define GOBJECT(x) (const_cast<GameObjectInfo*>(GetGameObjectInfo(x))) + void LoadOverridenSQLData() { GameObjectInfo *goInfo; // Sunwell Plateau : Kalecgos : Spectral Rift - goInfo = const_cast<GameObjectInfo*>(GetGameObjectInfo(187055)); - if(goInfo && goInfo->type == GAMEOBJECT_TYPE_GOOBER) - goInfo->goober.lockId = 57; // need LOCKTYPE_QUICK_OPEN + if(goInfo = GOBJECT(187055)) + if(goInfo->type == GAMEOBJECT_TYPE_GOOBER) + goInfo->goober.lockId = 57; // need LOCKTYPE_QUICK_OPEN + + // Naxxramas : Sapphiron Birth + if(goInfo = GOBJECT(181356)) + if(goInfo->type == GAMEOBJECT_TYPE_TRAP) + goInfo->trap.radius = 50; } void LoadOverridenDBCData() { SpellEntry *spellInfo; + for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i) + { + spellInfo = (SpellEntry*)GetSpellStore()->LookupEntry(i); + if(!spellInfo) + continue; - // Black Temple : Illidan : Parasitic Shadowfiend Passive - spellInfo = const_cast<SpellEntry*>(GetSpellStore()->LookupEntry(41913)); - if(spellInfo) - spellInfo->EffectApplyAuraName[0] = 4; // proc debuff, and summon infinite fiends + switch(i) + { + // Black Temple : Illidan : Parasitic Shadowfiend Passive + case 41013: + spellInfo->EffectApplyAuraName[0] = 4; // proc debuff, and summon infinite fiends + break; + //temp, not needed in 310 + case 28531: + case 55799: + spellInfo->DurationIndex = 21; + spellInfo->Effect[0] = SPELL_EFFECT_APPLY_AREA_AURA_ENEMY; + break; + // Naxxramas: Gothik : Inform Inf range + case 27892: + case 27928: + case 27935: + case 27915: + case 27931: + case 27937: + spellInfo->rangeIndex = 13; + break; + } + } } - diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h index 638b6926a27..80016619e8b 100644 --- a/src/bindings/scripts/include/sc_creature.h +++ b/src/bindings/scripts/include/sc_creature.h @@ -8,75 +8,28 @@ #ifndef SC_CREATURE_H #define SC_CREATURE_H -#include "CreatureAI.h" #include "Creature.h" +#include "CreatureAI.h" +#include "CreatureAIImpl.h" -#define HEROIC(n,h) (HeroicMode ? h : n) - -template<class T> -inline -const T& RAND(const T& v1, const T& v2) -{ - return rand()%2 ? v1 : v2; -} - -template<class T> -inline -const T& RAND(const T& v1, const T& v2, const T& v3) -{ - switch(rand()%3) - { - default: - case 0: return v1; - case 1: return v2; - case 2: return v3; - } -} - -template<class T> -inline -const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4) -{ - switch(rand()%4) - { - default: - case 0: return v1; - case 1: return v2; - case 2: return v3; - case 3: return v4; - } -} - -template<class T> -inline -const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) -{ - switch(rand()%4) - { - default: - case 0: return v1; - case 1: return v2; - case 2: return v3; - case 3: return v4; - case 4: return v5; - } -} - -float GetSpellMaxRangeForHostile(uint32 id); +class ScriptedInstance; class SummonList : private std::list<uint64> { -public: - explicit SummonList(Creature* creature) : m_creature(creature) {} - void Summon(Creature *summon) { push_back(summon->GetGUID()); } - void Despawn(Creature *summon) { remove(summon->GetGUID()); } - void DespawnEntry(uint32 entry); - void DespawnAll(); - void DoAction(uint32 entry, uint32 info); -private: - Creature *m_creature; + public: + explicit SummonList(Creature* creature) : m_creature(creature) {} + void Summon(Creature *summon) { push_back(summon->GetGUID()); } + void Despawn(Creature *summon) { remove(summon->GetGUID()); } + void DespawnEntry(uint32 entry); + void DespawnAll(); + void DoAction(uint32 entry, uint32 info); + void DoZoneInCombat(uint32 entry = 0); + private: + Creature *m_creature; }; +float GetSpellMaxRangeForHostile(uint32 id); + //Get a single creature of given entry Unit* FindCreature(uint32 entry, float range, Unit* Finder); @@ -106,9 +59,6 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI void AttackStart(Unit *); void AttackStart(Unit *, bool melee); - //Called at stoping attack by any attacker - void EnterEvadeMode(); - // Called at any Damage from any attacker (before damage apply) void DamageTaken(Unit *done_by, uint32 &damage) {} @@ -133,11 +83,8 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI // Called when spell hits a target void SpellHitTarget(Unit* target, const SpellEntry*) {} - // Called when creature is spawned or respawned (for reseting variables) - void JustRespawned(); - //Called at waypoint reached or PointMovement end - void MovementInform(uint32, uint32){} + void MovementInform(uint32 type, uint32 id){} // Called when AI is temporarily replaced or put back when possess is applied or removed void OnPossess(bool apply) {} @@ -206,6 +153,7 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI void DoModifyThreatPercent(Unit *pUnit, int32 pct); void DoTeleportTo(float x, float y, float z, uint32 time = 0); + void DoTeleportTo(const float pos[4]); void DoAction(const int32 param) {} @@ -224,16 +172,16 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI //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); + Creature *DoSummon(uint32 entry, WorldObject *obj, float radius = 5.0f, uint32 despawntime = 30000, TempSummonType type = TEMPSUMMON_CORPSE_TIMED_DESPAWN); //Selects a unit from the creature's current aggro list Unit* SelectUnit(SelectAggroTarget target, uint32 position); - Unit* SelectUnit(SelectAggroTarget target, uint32 position, float dist, bool playerOnly); - void SelectUnitList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget target, float dist, bool playerOnly); bool HealthBelowPct(uint32 pct) const { return me->GetHealth() * 100 < m_creature->GetMaxHealth() * pct; } //Returns spells that meet the specified criteria from the creatures spell list - SpellEntry const* SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effect); + SpellEntry const* SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTargetType Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effect); //Checks if you can cast the specified spell bool CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered = false); @@ -254,19 +202,29 @@ struct TRINITY_DLL_DECL Scripted_NoMovementAI : public ScriptedAI void AttackStart(Unit *); }; -struct TRINITY_DLL_DECL NullCreatureAI : public ScriptedAI +struct TRINITY_DLL_DECL BossAI : public ScriptedAI { - NullCreatureAI(Creature* c) : ScriptedAI(c) {} - ~NullCreatureAI() {} + BossAI(Creature *c, uint32 id) : ScriptedAI(c), bossId(id) + , summons(me), instance(c->GetInstanceData()) + {} - void Reset() {} - void EnterCombat(Unit*) {} - void MoveInLineOfSight(Unit *) {} - void AttackStart(Unit *) {} - void EnterEvadeMode() {} - bool IsVisible(Unit *) const { return false; } + uint32 bossId; + EventMap events; + SummonList summons; + InstanceData *instance; + + void JustSummoned(Creature *summon); + void SummonedCreatureDespawn(Creature *summon); + + void UpdateAI(const uint32 diff) = 0; + + void _Reset(); + void _EnterCombat(); + void _JustDied(); - void UpdateAI(const uint32) {} + void Reset() { _Reset(); } + void EnterCombat(Unit *who) { _EnterCombat(); } + void JustDied(Unit *killer) { _JustDied(); } }; #endif diff --git a/src/bindings/scripts/include/sc_instance.h b/src/bindings/scripts/include/sc_instance.h index cdf0e03aa37..0620e89af07 100644 --- a/src/bindings/scripts/include/sc_instance.h +++ b/src/bindings/scripts/include/sc_instance.h @@ -17,20 +17,7 @@ class TRINITY_DLL_DECL ScriptedInstance : public InstanceData { public: - ScriptedInstance(Map *map) : InstanceData(map) {} - ~ScriptedInstance() {} - - //All-purpose data storage 64 bit - virtual uint64 GetData64(uint32 Data) { return 0; } - virtual void SetData64(uint32 Data, uint64 Value) { } - - // Called every instance update - virtual void Update(uint32) {} - - // Save and Load instance data to the database - const char* Save() { return NULL; } - void Load(const char* in) { } }; #endif diff --git a/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp b/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp index 2f2d5349f2a..ec987e31c0e 100644 --- a/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp +++ b/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp @@ -156,11 +156,41 @@ struct TRINITY_DLL_DECL generic_creatureAI : public ScriptedAI } } }; + CreatureAI* GetAI_generic_creature(Creature *_Creature) { return new generic_creatureAI (_Creature); } +struct TRINITY_DLL_DECL trigger_periodicAI : public NullCreatureAI +{ + trigger_periodicAI(Creature* c) : NullCreatureAI(c) + { + spell = me->m_spells[0] ? GetSpellStore()->LookupEntry(me->m_spells[0]) : NULL; + interval = me->m_spells[1] ? me->m_spells[1] : 1000; + timer = interval; + } + + uint32 timer, interval; + const SpellEntry * spell; + + void UpdateAI(const uint32 diff) + { + if(timer < diff) + { + if(spell) + me->CastSpell(me, spell, true); + timer = interval; + } + else + timer -= diff; + } +}; + +CreatureAI* GetAI_trigger_periodic(Creature *_Creature) +{ + return new trigger_periodicAI (_Creature); +} void AddSC_generic_creature() { @@ -169,5 +199,10 @@ void AddSC_generic_creature() newscript->Name="generic_creature"; newscript->GetAI = &GetAI_generic_creature; newscript->RegisterSelf(); + + newscript = new Script; + newscript->Name="trigger_periodic"; + newscript->GetAI = &GetAI_trigger_periodic; + newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp index 89fd75b9bc8..52e5a3e8915 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp @@ -262,7 +262,7 @@ struct TRINITY_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI if (HeroicMode && banish_Timer < diff) { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0,30,false); + Unit *target = SelectTarget(SELECT_TARGET_RANDOM,0,30,false); if (target) { DoCast(target,SPELL_BANISH); diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp index 99bce54be62..599767b591f 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp @@ -118,7 +118,7 @@ struct TRINITY_DLL_DECL boss_murmurAI : public Scripted_NoMovementAI // Murmur's Touch if (MurmursTouch_Timer < diff) { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,80,true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,80,true)) DoCast(target, SPELL_MURMURS_TOUCH); MurmursTouch_Timer = 25000 + rand()%10000; }else MurmursTouch_Timer -= diff; @@ -162,7 +162,7 @@ struct TRINITY_DLL_DECL boss_murmurAI : public Scripted_NoMovementAI // Sonic Shock if(SonicShock_Timer < diff) { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,20,false)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,20,false)) if(target->isAlive()) DoCast(target, SPELL_SONIC_SHOCK); SonicShock_Timer = 10000+rand()%10000; diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp index 3cfb0af2fa1..37194a89b21 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp @@ -191,7 +191,7 @@ struct TRINITY_DLL_DECL instance_shadow_labyrinth : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { return str_data.c_str(); } diff --git a/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/instance_ahnkahet.cpp b/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/instance_ahnkahet.cpp index 41cb91f86b7..595a05a727f 100644 --- a/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/instance_ahnkahet.cpp +++ b/src/bindings/scripts/scripts/zone/azjol_nerub/ahnkahet/instance_ahnkahet.cpp @@ -129,7 +129,7 @@ struct TRINITY_DLL_DECL instance_ahnkahet : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; diff --git a/src/bindings/scripts/scripts/zone/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp b/src/bindings/scripts/scripts/zone/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp index bd3fccd98d9..7e0252f2009 100644 --- a/src/bindings/scripts/scripts/zone/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp +++ b/src/bindings/scripts/scripts/zone/azjol_nerub/azjol_nerub/instance_azjol_nerub.cpp @@ -117,7 +117,7 @@ struct TRINITY_DLL_DECL instance_azjol_nerub : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; 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 1a3c40273af..104ef575de5 100644 --- a/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp +++ b/src/bindings/scripts/scripts/zone/azuremyst_isle/azuremyst_isle.cpp @@ -416,7 +416,8 @@ bool GossipSelect_npc_susurrus(Player *player, Creature *_Creature, uint32 sende nodes.resize(2); nodes[0] = 92; //from susurrus nodes[1] = 91; //end at exodar - player->ActivateTaxiPathTo(nodes,11686); //TaxiPath 506. Using invisible model, possible Trinity must allow 0(from dbc) for cases like this. +// player->ActivateTaxiPathTo(nodes,11686); //TaxiPath 506. Using invisible model, possible Trinity must allow 0(from dbc) for cases like this. + player->ActivateTaxiPathTo(nodes); } return true; } 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 60c51f0be33..68431cb81ee 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp @@ -785,7 +785,7 @@ struct TRINITY_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI case EVENT_PARASITIC_SHADOWFIEND: { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1, 200, true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 200, true)) m_creature->CastSpell(target, SPELL_PARASITIC_SHADOWFIEND, true); Timer[EVENT_PARASITIC_SHADOWFIEND] = 35000 + rand()%10000; }break; @@ -907,7 +907,7 @@ struct TRINITY_DLL_DECL flame_of_azzinothAI : public ScriptedAI void ChargeCheck() { - Unit* target = SelectUnit(SELECT_TARGET_FARTHEST, 0, 200, false); + Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0, 200, false); if(target && (!m_creature->IsWithinCombatRange(target, FLAME_CHARGE_DISTANCE))) { m_creature->AddThreat(target, 5000000.0f); @@ -1765,7 +1765,7 @@ struct TRINITY_DLL_DECL mob_parasitic_shadowfiendAI : public ScriptedAI { if(!m_creature->getVictim()) { - if(Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true)) + if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true)) AttackStart(target); else { @@ -1862,15 +1862,15 @@ void boss_illidan_stormrageAI::JustSummoned(Creature* summon) summon->setDeathState(JUST_DIED); return; } - Unit *target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0, 999, true); + Unit *target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 999, true); if(!target || target->HasAura(SPELL_PARASITIC_SHADOWFIEND) || target->HasAura(SPELL_PARASITIC_SHADOWFIEND2)) - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true); if(target) summon->AI()->AttackStart(target); }break; case SHADOW_DEMON: - if(Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true)) // only on players. + if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true)) // only on players. { summon->AddThreat(target, 5000000.0f); summon->AI()->AttackStart(target); 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 c01db75bd58..ff90f7e6a81 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp @@ -53,7 +53,9 @@ EndScriptData */ struct TRINITY_DLL_DECL molten_flameAI : public NullCreatureAI { - molten_flameAI(Creature *c) : NullCreatureAI(c) + molten_flameAI(Creature *c) : NullCreatureAI(c) {} + + void InitializeAI() { float x, y, z; me->GetNearPoint(me, x, y, z, 1, 50, M_PI*2*rand_norm()); @@ -198,7 +200,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 5000, GCD_CAST, PHASE_STRIKE); break; case EVENT_SWITCH_TARGET: - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1, 100, true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true)) { DoResetThreat(); m_creature->AddThreat(target, 5000000.0f); @@ -208,7 +210,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI break; case EVENT_VOLCANO: { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true); if(!target) target = m_creature->getVictim(); if(target) { 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 7d6b7140a9d..032bccc57ed 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 @@ -171,7 +171,7 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI { //m_creature->CastSpell(m_creature, SPELL_NEEDLE_SPINE, true); std::list<Unit*> target; - SelectUnitList(target, 3, SELECT_TARGET_RANDOM, 80, true); + SelectTargetList(target, 3, SELECT_TARGET_RANDOM, 80, true); for(std::list<Unit*>::iterator i = target.begin(); i != target.end(); ++i) m_creature->CastSpell(*i, 39835, true); events.ScheduleEvent(EVENT_NEEDLE, 15000+rand()%10000, GCD_CAST); diff --git a/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp b/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp index 43646746505..bf5d62a7b86 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/instance_black_temple.cpp @@ -303,7 +303,7 @@ struct TRINITY_DLL_DECL instance_black_temple : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { return str_data.c_str(); } 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 6e26f3a0c03..d9f3ecd808a 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 @@ -265,7 +265,7 @@ struct TRINITY_DLL_DECL instance_blackrock_depths : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { return str_data.c_str(); } diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp index 21b39fa378b..13b0c78ebc1 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp @@ -148,7 +148,7 @@ struct TRINITY_DLL_DECL boss_anetheronAI : public hyjal_trashAI if(SwarmTimer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,100,true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,100,true); if(target) DoCast(target,SPELL_CARRION_SWARM); @@ -170,7 +170,7 @@ struct TRINITY_DLL_DECL boss_anetheronAI : public hyjal_trashAI { for(uint8 i=0;i<3;++i) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,100,true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,100,true); if(target) target->CastSpell(target,SPELL_SLEEP,true); } @@ -194,7 +194,7 @@ struct TRINITY_DLL_DECL boss_anetheronAI : public hyjal_trashAI }else AuraTimer -= diff; if(InfernoTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,100,true), SPELL_INFERNO); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,100,true), SPELL_INFERNO); InfernoTimer = 45000; switch(rand()%2) { diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp index 15085963b20..33e3d344da2 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp @@ -140,13 +140,13 @@ struct TRINITY_DLL_DECL boss_azgalorAI : public hyjal_trashAI if(RainTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,30,true), SPELL_RAIN_OF_FIRE); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,30,true), SPELL_RAIN_OF_FIRE); RainTimer = 20000+rand()%15000; }else RainTimer -= diff; if(DoomTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,1,100,true), SPELL_DOOM);//never on tank + DoCast(SelectTarget(SELECT_TARGET_RANDOM,1,100,true), SPELL_DOOM);//never on tank DoomTimer = 45000+rand()%5000; }else DoomTimer -= diff; @@ -260,7 +260,7 @@ struct TRINITY_DLL_DECL mob_lesser_doomguardAI : public hyjal_trashAI if(CrippleTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,100,true), SPELL_CRIPPLE); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,100,true), SPELL_CRIPPLE); CrippleTimer = 25000+rand()%5000; }else CrippleTimer -= diff; diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp index addbddab5b8..3e6b2bc8e98 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp @@ -169,7 +169,7 @@ struct TRINITY_DLL_DECL boss_rage_winterchillAI : public hyjal_trashAI }else NovaTimer -= diff; if(IceboltTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,40,true), SPELL_ICEBOLT); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,40,true), SPELL_ICEBOLT); IceboltTimer = 11000+rand()%20000; }else IceboltTimer -= diff; diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp index 583c7831af5..30f0c14caaf 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp @@ -724,7 +724,7 @@ struct mob_necromancerAI : public hyjal_trashAI void JustSummoned(Creature* summon) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,30,true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,30,true); if(target && summon) summon->Attack(target,false); summons.Summon(summon); diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp index 0dfa99198ac..cdcd6cb6b66 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp @@ -279,7 +279,7 @@ struct TRINITY_DLL_DECL instance_mount_hyjal : public ScriptedInstance }else debug_log("TSCR: Instance Hyjal: UpdateWorldState, but PlayerList is empty!"); } - const char* Save() + std::string GetSaveData() { return str_data.c_str(); } diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp index eb35a3c74b4..254a4d1d899 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp @@ -322,7 +322,7 @@ struct TRINITY_DLL_DECL boss_the_lurker_belowAI : public Scripted_NoMovementAI if(WaterboltTimer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_NEAREST,0,14,true); + Unit* target = SelectTarget(SELECT_TARGET_NEAREST,0,14,true); if(!target) { target = SelectUnit(SELECT_TARGET_RANDOM,0); diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp index cea591182d5..f8d27df5bb0 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp @@ -235,7 +235,7 @@ struct TRINITY_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI for(uint8 i = 0; i < 4; i++) { counter = 0; - do{target = SelectUnit(SELECT_TARGET_RANDOM, 1, 50, true); //target players only + do{target = SelectTarget(SELECT_TARGET_RANDOM, 1, 50, true); //target players only if(counter < Playercount) break; if(target) itr = list.find(target->GetGUID()); @@ -272,7 +272,7 @@ struct TRINITY_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI for (int8 g = 0; g < 4; g++) //one unit cant cast more than one spell per update, so some players have to cast for us XD { counter = 0; - do {globuletarget = SelectUnit(SELECT_TARGET_RANDOM, 0,50,true); + do {globuletarget = SelectTarget(SELECT_TARGET_RANDOM, 0,50,true); if(globuletarget) itr = globulelist.find(globuletarget->GetGUID()); if (counter > Playercount) break; diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp index 6c4ae72aec1..8aa759a87c8 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/instance_serpent_shrine.cpp @@ -236,7 +236,7 @@ struct TRINITY_DLL_DECL instance_serpentshrine_cavern : public ScriptedInstance } return 0; } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; std::ostringstream stream; diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp index 6d01da7f625..d375d073c35 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp @@ -209,7 +209,7 @@ struct TRINITY_DLL_DECL instance_steam_vault : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; std::ostringstream stream; diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp index 370b07c8adc..72c7992e109 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp @@ -165,7 +165,7 @@ struct TRINITY_DLL_DECL boss_the_black_stalkerAI : public ScriptedAI // Static Charge if(StaticCharge_Timer < diff) { - if(Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0,30,true)) + if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM,0,30,true)) DoCast(target, SPELL_STATIC_CHARGE); StaticCharge_Timer = 10000; }else StaticCharge_Timer -= diff; diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp b/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp index 34943449b1e..4c90fdf49a8 100644 --- a/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp +++ b/src/bindings/scripts/scripts/zone/gruuls_lair/instance_gruuls_lair.cpp @@ -144,7 +144,7 @@ struct TRINITY_DLL_DECL instance_gruuls_lair : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; std::ostringstream stream; diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp index 115dfeab269..52e6f2e363c 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/boss_moroes.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2006 - 2008 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 @@ -62,7 +62,10 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI { boss_moroesAI(Creature *c) : ScriptedAI(c) { - FirstTime = true; + for(int i = 0; i < 4; i++) + { + AddId[i] = 0; + } pInstance = ((ScriptedInstance*)c->GetInstanceData()); } @@ -77,7 +80,6 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI uint32 CheckAdds_Timer; uint32 AddId[4]; - bool FirstTime; bool InVanish; bool Enrage; @@ -91,12 +93,10 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI Enrage = false; InVanish = false; - - SpawnAdds(); - - m_creature->setFaction(16); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if(m_creature->GetHealth() > 0) + { + SpawnAdds(); + } if(pInstance) pInstance->SetData(DATA_MOROES_EVENT, NOT_STARTED); @@ -106,9 +106,11 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI { if(pInstance) pInstance->SetData(DATA_MOROES_EVENT, IN_PROGRESS); + + DoZoneInCombat(); } - void EnterCombat(Unit* who) + void Aggro(Unit* who) { StartEvent(); @@ -129,7 +131,7 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI void JustDied(Unit* victim) { - DoScriptText(SAY_DEATH, m_creature); + DoScriptText(SAY_DEATH, m_creature); if (pInstance) pInstance->SetData(DATA_MOROES_EVENT, DONE); @@ -147,33 +149,21 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { - if (i->getSource()->isAlive() && i->getSource()->HasAura(SPELL_GARROTE)) + if (i->getSource()->isAlive() && i->getSource()->HasAura(SPELL_GARROTE,0)) i->getSource()->RemoveAurasDueToSpell(SPELL_GARROTE); } } } - uint8 CheckAdd(uint64 guid) - { - Unit* pUnit = Unit::GetUnit((*m_creature), guid); - if (pUnit) - { - if (!pUnit->isAlive()) - return 1; // Exists but is dead - else - return 2; // Exists and is alive - } - return 0; // Does not exist - } - void SpawnAdds() { - Creature *pCreature = NULL; - - if (FirstTime) + DeSpawnAdds(); + if(isAddlistEmpty()) { + Creature *pCreature = NULL; std::vector<uint32> AddList; + for(uint8 i = 0; i < 6; ++i) AddList.push_back(Adds[i]); @@ -193,48 +183,44 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI } ++i; } - - FirstTime = false; - } - else + }else { - for(uint8 i = 0; i < 4; ++i) + for(int i = 0; i < 4; i++) { - switch(CheckAdd(AddGUID[i])) + Creature *pCreature = m_creature->SummonCreature(AddId[i], Locations[i][0], Locations[i][1], POS_Z, Locations[i][2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + if (pCreature) { - case 0: - pCreature = m_creature->SummonCreature(AddId[i], Locations[i][0], Locations[i][1], POS_Z, Locations[i][2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); - if (pCreature) - AddGUID[i] = pCreature->GetGUID(); - break; - case 1: - pCreature = (Unit::GetCreature((*m_creature), AddGUID[i])); - if (pCreature) - { - pCreature->Respawn(); - pCreature->AI()->EnterEvadeMode(); - } - break; - case 2: - pCreature = (Unit::GetCreature((*m_creature), AddGUID[i])); - if (!pCreature->IsInEvadeMode()) - pCreature->AI()->EnterEvadeMode(); - break; + AddGUID[i] = pCreature->GetGUID(); } } } } + bool isAddlistEmpty() + { + for(int i = 0; i < 4; i++) + { + if(AddId[i] == 0) + return true; + } + return false; + } + void DeSpawnAdds() { for(uint8 i = 0; i < 4 ; ++i) { - Unit* Temp = NULL; + Creature* Temp = NULL; if (AddGUID[i]) { - Temp = Unit::GetUnit((*m_creature),AddGUID[i]); + Temp = Creature::GetCreature((*m_creature),AddGUID[i]); if (Temp && Temp->isAlive()) + { + (*Temp).GetMotionMaster()->Clear(true); Temp->DealDamage(Temp, Temp->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + Temp->RemoveCorpse(); + } + } } } @@ -246,7 +232,7 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI Creature* Temp = NULL; if (AddGUID[i]) { - Temp = Unit::GetCreature(*m_creature, AddGUID[i]); + Temp = Creature::GetCreature((*m_creature),AddGUID[i]); if (Temp && Temp->isAlive()) { Temp->AI()->AttackStart(m_creature->getVictim()); @@ -295,39 +281,12 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI //Cast Vanish, then Garrote random victim if (Vanish_Timer < diff) { - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); DoCast(m_creature, SPELL_VANISH); InVanish = true; Vanish_Timer = 30000; Wait_Timer = 5000; }else Vanish_Timer -= diff; - if (InVanish) - { - if (Wait_Timer < diff) - { - switch(rand()%2) - { - case 0: DoScriptText(SAY_SPECIAL_1, m_creature); break; - case 1: DoScriptText(SAY_SPECIAL_2, m_creature); break; - } - - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - target->CastSpell(target, SPELL_GARROTE,true); - - m_creature->setFaction(16); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); - m_creature->AI()->AttackStart(m_creature->getVictim()); - InVanish = false; - }else Wait_Timer -= diff; - } - - //Gouge highest aggro, and attack second highest if (Gouge_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_GOUGE); @@ -336,27 +295,32 @@ struct TRINITY_DLL_DECL boss_moroesAI : public ScriptedAI if (Blind_Timer < diff) { - Unit* target = NULL; - std::list<HostilReference*> t_list = m_creature->getThreatManager().getThreatList(); - - if (t_list.empty()) - return; + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if (target && target->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinMeleeRange(target)) + { + DoCast(target, SPELL_BLIND); + Blind_Timer = 40000; + } + else + Blind_Timer = 1000; + }else Blind_Timer -= diff; + } - std::vector<Unit*> target_list; - for (std::list<HostilReference*>::iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) + if (InVanish) + { + if (Wait_Timer < diff) + { + switch(rand()%2) { - target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid()); - if (target && target->GetDistance2d(m_creature) < 5) - target_list.push_back(target); + case 0: DoScriptText(SAY_SPECIAL_1, m_creature); break; + case 1: DoScriptText(SAY_SPECIAL_2, m_creature); break; } - if (target_list.size()) - target = *(target_list.begin()+rand()%target_list.size()); - if (target) - DoCast(target, SPELL_BLIND); + if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + target->CastSpell(target, SPELL_GARROTE,true); - Blind_Timer = 40000; - }else Blind_Timer -= diff; + InVanish = false; + }else Wait_Timer -= diff; } if (!InVanish) @@ -384,7 +348,7 @@ struct TRINITY_DLL_DECL boss_moroes_guestAI : public ScriptedAI pInstance->SetData(DATA_MOROES_EVENT, NOT_STARTED); } - void EnterCombat(Unit* who) {} + void Aggro(Unit* who) {} void AcquireGUID() { @@ -542,7 +506,7 @@ struct TRINITY_DLL_DECL boss_baron_rafe_dreugerAI : public boss_moroes_guestAI struct TRINITY_DLL_DECL boss_lady_catriona_von_indiAI : public boss_moroes_guestAI { //Holy Priest - boss_lady_catriona_von_indiAI(Creature *c) : boss_moroes_guestAI(c) {Reset();} + boss_lady_catriona_von_indiAI(Creature *c) : boss_moroes_guestAI(c) {} uint32 DispelMagic_Timer; uint32 GreaterHeal_Timer; @@ -612,7 +576,7 @@ struct TRINITY_DLL_DECL boss_lady_catriona_von_indiAI : public boss_moroes_guest struct TRINITY_DLL_DECL boss_lady_keira_berrybuckAI : public boss_moroes_guestAI { //Holy Pally - boss_lady_keira_berrybuckAI(Creature *c) : boss_moroes_guestAI(c) {Reset();} + boss_lady_keira_berrybuckAI(Creature *c) : boss_moroes_guestAI(c) {} uint32 Cleanse_Timer; uint32 GreaterBless_Timer; @@ -729,7 +693,7 @@ struct TRINITY_DLL_DECL boss_lord_robin_darisAI : public boss_moroes_guestAI struct TRINITY_DLL_DECL boss_lord_crispin_ferenceAI : public boss_moroes_guestAI { //Arms Warr - boss_lord_crispin_ferenceAI(Creature *c) : boss_moroes_guestAI(c) {Reset();} + boss_lord_crispin_ferenceAI(Creature *c) : boss_moroes_guestAI(c) {} uint32 Disarm_Timer; uint32 HeroicStrike_Timer; diff --git a/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp b/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp index e8dccdd62a4..62ad6fcf42c 100644 --- a/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp +++ b/src/bindings/scripts/scripts/zone/karazhan/instance_karazhan.cpp @@ -247,7 +247,7 @@ struct TRINITY_DLL_DECL instance_karazhan : public ScriptedInstance } } - const char* Save() + std::string GetSaveData() { return str_data.c_str(); } diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp index 0a0fb17cce4..c675c8d7c27 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2008 - 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 @@ -14,14 +14,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Anubrekhan -SD%Complete: 100 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" +#include "def_naxxramas.h" #define SAY_GREET RAND(-1533000,-1533004,-1533005,-1533006,-1533007) #define SAY_AGGRO RAND(-1533001,-1533002,-1533003) @@ -31,46 +25,29 @@ EndScriptData */ #define SPELL_LOCUSTSWARM HEROIC(28785,54021) #define SPELL_SELF_SPAWN_5 29105 //This spawns 5 corpse scarabs ontop of us (most likely the player casts this on death) -#define SPELL_SELF_SPAWN_10 28864 //This is used by the crypt guards when they die #define EVENT_IMPALE 1 #define EVENT_LOCUST 2 #define MOB_CRYPT_GUARD 16573 -struct TRINITY_DLL_DECL boss_anubrekhanAI : public ScriptedAI +struct TRINITY_DLL_DECL boss_anubrekhanAI : public BossAI { - boss_anubrekhanAI(Creature *c) : ScriptedAI(c), summons(me) {} + boss_anubrekhanAI(Creature *c) : BossAI(c, BOSS_ANUBREKHAN) {} bool HasTaunted; - EventMap events; - SummonList summons; void Prepare() { HasTaunted = false; - DoSpawnCreature(MOB_CRYPT_GUARD, 0, 10, 0, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); + DoSpawnCreature(MOB_CRYPT_GUARD, 0, 10, 0, me->GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); if(HeroicMode) - DoSpawnCreature(MOB_CRYPT_GUARD, 0, -10, 0, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); + DoSpawnCreature(MOB_CRYPT_GUARD, 0, -10, 0, me->GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); } void InitializeAI() { Prepare(); } void JustReachedHome() { Prepare(); } - void Reset() - { - events.Reset(); - summons.DespawnAll(); - } - - void JustSummoned(Creature *summon) - { - summons.Summon(summon); - DoZoneInCombat(summon); - } - - void SummonedCreatureDespawn(Creature *summon) {summons.Despawn(summon);} - void KilledUnit(Unit* victim) { //Force the player to spawn corpse scarabs via spell @@ -82,9 +59,8 @@ struct TRINITY_DLL_DECL boss_anubrekhanAI : public ScriptedAI void EnterCombat(Unit *who) { + _EnterCombat(); DoScriptText(SAY_AGGRO, me); - DoZoneInCombat(); - events.ScheduleEvent(EVENT_IMPALE, 15000, 1); events.ScheduleEvent(EVENT_LOCUST, 80000 + rand()%40000, 1); } diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp index 5ec67a8920b..9ee594b02b5 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp @@ -1,4 +1,6 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* + * Copyright (C) 2008 - 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 @@ -14,83 +16,63 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Faerlina -SD%Complete: 50 -SDComment: -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" +#include "def_naxxramas.h" -#define SAY_GREET -1533009 -#define SAY_AGGRO1 -1533010 -#define SAY_AGGRO2 -1533011 -#define SAY_AGGRO3 -1533012 -#define SAY_AGGRO4 -1533013 -#define SAY_SLAY1 -1533014 -#define SAY_SLAY2 -1533015 -#define SAY_DEATH -1533016 +#define SAY_GREET -1533009 +#define SAY_AGGRO RAND(-1533010,-1533011,-1533012,-1533013) +#define SAY_SLAY RAND(-1533014,-1533015) +#define SAY_DEATH -1533016 //#define SOUND_RANDOM_AGGRO 8955 //soundId containing the 4 aggro sounds, we not using this -#define SPELL_POSIONBOLT_VOLLEY 28796 -#define H_SPELL_POSIONBOLT_VOLLEY 54098 -#define SPELL_ENRAGE 28798 -#define H_SPELL_ENRAGE 54100 -#define SPELL_RAINOFFIRE 28794 //Not sure if targeted AoEs work if casted directly upon a player +#define SPELL_POSION_BOLT_VOLLEY HEROIC(28796,54098) +#define SPELL_RAIN_OF_FIRE HEROIC(28794,54099) +#define SPELL_FRENZY HEROIC(28798,54100) +#define SPELL_WIDOWS_EMBRACE HEROIC(28732,54097) -struct TRINITY_DLL_DECL boss_faerlinaAI : public ScriptedAI +enum Events { - boss_faerlinaAI(Creature *c) : ScriptedAI(c) {} + EVENT_POSION = 1, + EVENT_FIRE, + EVENT_FRENZY, +}; - uint32 PoisonBoltVolley_Timer; - uint32 RainOfFire_Timer; - uint32 Enrage_Timer; - bool HasTaunted; +struct TRINITY_DLL_DECL boss_faerlinaAI : public BossAI +{ + boss_faerlinaAI(Creature *c) : BossAI(c, BOSS_FAERLINA), greet(false) {} - void Reset() - { - PoisonBoltVolley_Timer = 8000; - RainOfFire_Timer = 16000; - Enrage_Timer = 60000; - HasTaunted = false; - } + bool greet; void EnterCombat(Unit *who) { - switch (rand()%4) - { - case 0: DoScriptText(SAY_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_AGGRO2, m_creature); break; - case 2: DoScriptText(SAY_AGGRO3, m_creature); break; - case 3: DoScriptText(SAY_AGGRO4, m_creature); break; - } + _EnterCombat(); + DoScriptText(SAY_AGGRO, me); + events.ScheduleEvent(EVENT_POSION, 10000 + rand()%15000); + events.ScheduleEvent(EVENT_FIRE, 5000 + rand()%15000); + events.ScheduleEvent(EVENT_FRENZY, 60000 + rand()%20000); } void MoveInLineOfSight(Unit *who) { - if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f)) - { - DoScriptText(SAY_GREET, m_creature); - HasTaunted = true; - + if(!greet) + { + DoScriptText(SAY_GREET, me); + greet = true; } - ScriptedAI::MoveInLineOfSight(who); + BossAI::MoveInLineOfSight(who); } void KilledUnit(Unit* victim) { - switch (rand()%2) - { - case 0: DoScriptText(SAY_SLAY1, m_creature); break; - case 1: DoScriptText(SAY_SLAY2, m_creature); break; - } + if(!(rand()%3)) + DoScriptText(SAY_SLAY, me); } void JustDied(Unit* Killer) { - DoScriptText(SAY_DEATH, m_creature); + _JustDied(); + DoScriptText(SAY_DEATH, me); } void UpdateAI(const uint32 diff) @@ -98,31 +80,33 @@ struct TRINITY_DLL_DECL boss_faerlinaAI : public ScriptedAI if (!UpdateVictim()) return; - //PoisonBoltVolley_Timer - if (PoisonBoltVolley_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_POSIONBOLT_VOLLEY); - PoisonBoltVolley_Timer = 11000; - }else PoisonBoltVolley_Timer -= diff; + events.Update(diff); - //RainOfFire_Timer - if (RainOfFire_Timer < diff) + while(uint32 eventId = events.ExecuteEvent()) { - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0)) - DoCast(target,SPELL_RAINOFFIRE); - RainOfFire_Timer = 16000; - }else RainOfFire_Timer -= diff; - - //Enrage_Timer - if (Enrage_Timer < diff) - { - DoCast(m_creature,SPELL_ENRAGE); - Enrage_Timer = 61000; - }else Enrage_Timer -= diff; + switch(eventId) + { + case EVENT_POSION: + if(!me->HasAura(SPELL_WIDOWS_EMBRACE)) + DoCastAOE(SPELL_POSION_BOLT_VOLLEY); + events.ScheduleEvent(EVENT_POSION, 10000 + rand()%15000); + return; + case EVENT_FIRE: + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_RAIN_OF_FIRE); + events.ScheduleEvent(EVENT_FIRE, 5000 + rand()%15000); + return; + case EVENT_FRENZY: + DoCast(me,SPELL_FRENZY); + events.ScheduleEvent(EVENT_FRENZY, 60000 + rand()%20000); + return; + } + } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_faerlina(Creature *_Creature) { return new boss_faerlinaAI (_Creature); @@ -136,4 +120,3 @@ void AddSC_boss_faerlina() newscript->GetAI = &GetAI_boss_faerlina; newscript->RegisterSelf(); } - diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp index 0becff399da..7def6c370f4 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2008 - 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 @@ -14,14 +14,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Gothik -SD%Complete: 0 -SDComment: Placeholder -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" +#include "def_naxxramas.h" #define SAY_SPEECH -1533040 #define SAY_KILL -1533041 @@ -29,36 +23,336 @@ EndScriptData */ #define SAY_TELEPORT -1533043 //Gothik -#define SPELL_HARVESTSOUL 28679 -#define SPELL_SHADOWBOLT 29317 -#define H_SPELL_SHADOWBOLT 56405 -//Unrelenting Trainee -#define SPELL_EAGLECLAW 30285 -#define SPELL_KNOCKDOWN_PASSIVE 6961 - -//Unrelenting Deathknight -#define SPELL_CHARGE 22120 -#define SPELL_SHADOW_MARK 27825 - -//Unrelenting Rider -#define SPELL_UNHOLY_AURA 55606 -#define H_SPELL_UNHOLY_AURA 55608 -#define SPELL_SHADOWBOLT_VOLLEY 27831 //Search thru targets and find those who have the SHADOW_MARK to cast this on -#define H_SPELL_SHADOWBOLT_VOLLEY 55638 - -//Spectral Trainee -#define SPELL_ARCANE_EXPLOSION 27989 - -//Spectral Deathknight -#define SPELL_WHIRLWIND 28334 -#define SPELL_SUNDER_ARMOR 25051 //cannot find sunder that reduces armor by 2950 -#define SPELL_CLEAVE 20677 -#define SPELL_MANA_BURN 17631 - -//Spectral Rider -#define SPELL_LIFEDRAIN 24300 -//USES SAME UNHOLY AURA AS UNRELENTING RIDER - -//Spectral Horse -#define SPELL_STOMP 27993 +#define SPELL_HARVEST_SOUL 28679 +#define SPELL_SHADOW_BOLT HEROIC(29317,56405) + +#define SPELL_INFORM_LIVE_TRAINEE 27892 +#define SPELL_INFORM_LIVE_KNIGHT 27928 +#define SPELL_INFORM_LIVE_RIDER 27935 +#define SPELL_INFORM_DEAD_TRAINEE 27915 +#define SPELL_INFORM_DEAD_KNIGHT 27931 +#define SPELL_INFORM_DEAD_RIDER 27937 + +#define MOB_LIVE_TRAINEE 16124 +#define MOB_LIVE_KNIGHT 16125 +#define MOB_LIVE_RIDER 16126 +#define MOB_DEAD_TRAINEE 16127 +#define MOB_DEAD_KNIGHT 16148 +#define MOB_DEAD_RIDER 16150 +#define MOB_DEAD_HORSE 16149 + +const struct Waves { uint32 entry, number, time; } +waves[] = +{ + {MOB_LIVE_TRAINEE, 2, 20000}, + {MOB_LIVE_TRAINEE, 2, 20000}, + {MOB_LIVE_TRAINEE, 2, 10000}, + {MOB_LIVE_KNIGHT, 1, 10000}, + {MOB_LIVE_TRAINEE, 2, 15000}, + {MOB_LIVE_KNIGHT, 1, 10000}, + {MOB_LIVE_TRAINEE, 2, 15000}, + {MOB_LIVE_TRAINEE, 2, 0}, + {MOB_LIVE_KNIGHT, 1, 10000}, + {MOB_LIVE_RIDER, 1, 10000}, + {MOB_LIVE_TRAINEE, 2, 5000}, + {MOB_LIVE_KNIGHT, 1, 15000}, + {MOB_LIVE_TRAINEE, 2, 0}, + {MOB_LIVE_RIDER, 1, 10000}, + {MOB_LIVE_KNIGHT, 2, 10000}, + {MOB_LIVE_TRAINEE, 2, 10000}, + {MOB_LIVE_RIDER, 1, 5000}, + {MOB_LIVE_KNIGHT, 1, 5000}, + {MOB_LIVE_TRAINEE, 2, 20000}, + {MOB_LIVE_TRAINEE, 2, 0}, + {MOB_LIVE_KNIGHT, 1, 0}, + {MOB_LIVE_RIDER, 1, 15000}, + {MOB_LIVE_TRAINEE, 2, 29000}, + {0, 0, 0}, +}; + +#define POS_Y_GATE -3360.78f + +enum Events +{ + EVENT_SUMMON = 1, + EVENT_HARVEST, + EVENT_BOLT, +}; + +#define POS_LIVE 3 +#define POS_DEAD 5 + +const float PosSummonLive[POS_LIVE][4] = +{ + {2669.7, -3430.9, 268.56, 1.6}, + {2692.0, -3430.9, 268.56, 1.6}, + {2714.1, -3430.9, 268.56, 1.6}, +}; + +const float PosSummonDead[POS_DEAD][4] = +{ + {2725.1, -3310.0, 268.85, 3.4}, + {2699.3, -3322.8, 268.60, 3.3}, + {2733.1, -3348.5, 268.84, 3.1}, + {2682.8, -3304.2, 268.85, 3.9}, + {2664.8, -3340.7, 268.23, 3.7}, +}; + +const float PosGround[4] = {2691.2, -3362.7, 267.68, 1.7}; +const float PosPlatform[4] = {2640.5, -3360.6, 285.26, 0}; + +struct TRINITY_DLL_DECL boss_gothikAI : public BossAI +{ + boss_gothikAI(Creature *c) : BossAI(c, BOSS_GOTHIK) {} + + uint32 waveCount; + std::vector<Creature*> liveTrigger; + std::vector<Creature*> deadTrigger; + + void Reset() + { + liveTrigger.clear(); + deadTrigger.clear(); + me->setActive(false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + me->SetReactState(REACT_PASSIVE); + _Reset(); + } + + void EnterCombat(Unit *who) + { + for(uint32 i = 0; i < POS_LIVE; ++i) + if(Creature *trigger = DoSummon(WORLD_TRIGGER, PosSummonLive[i])) + liveTrigger.push_back(trigger); + for(uint32 i = 0; i < POS_DEAD; ++i) + if(Creature *trigger = DoSummon(WORLD_TRIGGER, PosSummonDead[i])) + deadTrigger.push_back(trigger); + + if(liveTrigger.size() < POS_LIVE || deadTrigger.size() < POS_DEAD) + { + error_log("Script Gothik: cannot summon triggers!"); + EnterEvadeMode(); + return; + } + + _EnterCombat(); + me->setActive(true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + waveCount = 0; + events.ScheduleEvent(EVENT_SUMMON, 30000); + DoTeleportTo(PosPlatform); + DoScriptText(SAY_SPEECH, me); + if(instance) + instance->SetData(DATA_GOTHIK_GATE, 1); + } + + void JustSummoned(Creature *summon) + { + if(summon->GetEntry() == WORLD_TRIGGER) + summon->setActive(true); + else + { + summon->AI()->DoAction(me->HasReactState(REACT_PASSIVE) ? 1 : 0); + summon->AI()->EnterEvadeMode(); + } + summons.Summon(summon); + } + + void KilledUnit(Unit* victim) + { + if(!(rand()%5)) + DoScriptText(SAY_KILL, me); + } + + void JustDied(Unit* Killer) + { + _JustDied(); + DoScriptText(SAY_DEATH, me); + } + + void SpellHit(Unit *caster, const SpellEntry *spell) + { + uint32 spellId = 0; + switch(spell->Id) + { + case SPELL_INFORM_LIVE_TRAINEE: spellId = SPELL_INFORM_DEAD_TRAINEE; break; + case SPELL_INFORM_LIVE_KNIGHT: spellId = SPELL_INFORM_DEAD_KNIGHT; break; + case SPELL_INFORM_LIVE_RIDER: spellId = SPELL_INFORM_DEAD_RIDER; break; + } + if(spellId && me->isInCombat()) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_SPELLCAST); + me->CastSpell(deadTrigger[rand()%POS_DEAD], spellId, true); + } + } + + void SpellHitTarget(Unit *target, const SpellEntry *spell) + { + if(!me->isInCombat()) + return; + + switch(spell->Id) + { + case SPELL_INFORM_DEAD_TRAINEE: DoSummon(MOB_DEAD_TRAINEE, target, 0); break; + case SPELL_INFORM_DEAD_KNIGHT: DoSummon(MOB_DEAD_KNIGHT, target, 0); break; + case SPELL_INFORM_DEAD_RIDER: DoSummon(MOB_DEAD_RIDER, target, 1.0f); + DoSummon(MOB_DEAD_HORSE, target, 1.0f); break; + } + } + + void UpdateAI(const uint32 diff) + { + if(!me->isInCombat()) + return; + + if(me->getThreatManager().isThreatListEmpty()) + { + EnterEvadeMode(); + return; + } + + if(me->HasReactState(REACT_AGGRESSIVE) && !UpdateVictim()) + return; + + events.Update(diff); + + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while(uint32 eventId = events.ExecuteEvent()) + { + switch(eventId) + { + case EVENT_SUMMON: + if(waves[waveCount].entry) + { + for(uint32 i = 0; i < waves[waveCount].number; ++i) + DoSummon(waves[waveCount].entry, liveTrigger[rand()%POS_LIVE], 1.0f); + events.ScheduleEvent(EVENT_SUMMON, waves[waveCount].time); + ++waveCount; + } + else + { + DoScriptText(SAY_TELEPORT, me); + DoTeleportTo(PosGround); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2); + if(instance) + instance->SetData(DATA_GOTHIK_GATE, 0); + summons.DoAction(0, 0); + summons.DoZoneInCombat(); + events.ScheduleEvent(EVENT_BOLT, 1000); + events.ScheduleEvent(EVENT_HARVEST, 15000); + } + break; + case EVENT_BOLT: + DoCast(me->getVictim(), SPELL_SHADOW_BOLT); + events.ScheduleEvent(EVENT_BOLT, 1000); + return; + case EVENT_HARVEST: + DoCast(me->getVictim(), SPELL_HARVEST_SOUL); + events.ScheduleEvent(EVENT_HARVEST, 15000); + return; + } + } + + DoMeleeAttackIfReady(); + } +}; + +struct TRINITY_DLL_DECL mob_gothik_minionAI : public SpellAI +{ + mob_gothik_minionAI(Creature *c) : SpellAI(c) + { + liveSide = me->GetPositionY() < POS_Y_GATE; + } + + bool liveSide; + bool gateClose; + +#define SIDE_CHECK(who) (liveSide == (who->GetPositionY() < POS_Y_GATE)) + + void DoAction(const int32 param) + { + gateClose = param; + } + + void DamageTaken(Unit *attacker, uint32 &damage) + { + if(gateClose && !SIDE_CHECK(attacker)) + damage = 0; + } + + void JustDied(Unit *killer) + { + if(me->isSummon()) + { + if(Unit *owner = ((TempSummon*)me)->GetSummoner()) + SpellAI::JustDied(owner); + } + } + + void EnterEvadeMode() + { + if(!gateClose) + { + SpellAI::EnterEvadeMode(); + return; + } + + if(!_EnterEvadeMode()) + return; + + Map *map = me->GetMap(); + if(map->IsDungeon()) + { + Map::PlayerList const &PlayerList = map->GetPlayers(); + for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if(i->getSource()->isAlive() && SIDE_CHECK(i->getSource())) + { + AttackStart(i->getSource()); + return; + } + } + } + + me->GetMotionMaster()->MoveIdle(); + Reset(); + } + + void UpdateAI(const uint32 diff) + { + if(gateClose && (!SIDE_CHECK(me) || me->getVictim() && !SIDE_CHECK(me->getVictim()))) + { + EnterEvadeMode(); + return; + } + + SpellAI::UpdateAI(diff); + } +}; + +CreatureAI* GetAI_boss_gothik(Creature *_Creature) +{ + return new boss_gothikAI (_Creature); +} + +CreatureAI* GetAI_mob_gothik_minion(Creature *_Creature) +{ + return new mob_gothik_minionAI (_Creature); +} + +void AddSC_boss_gothik() +{ + Script *newscript; + newscript = new Script; + newscript->Name="boss_gothik"; + newscript->GetAI = &GetAI_boss_gothik; + newscript->RegisterSelf(); + newscript = new Script; + newscript->Name="mob_gothik_minion"; + newscript->GetAI = &GetAI_mob_gothik_minion; + newscript->RegisterSelf(); +} diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp index f18cd81064a..45f54611ae3 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_grobbulus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2008 - 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 @@ -14,20 +14,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Grobbulus -SD%Complete: 0 -SDComment: Place holder -SDCategory: Naxxramas -EndScriptData */ - -/*Poison Cloud 26590 -Slime Spray 28157 -Fallout slime 28218 -Mutating Injection 28169 -Enrages 26527*/ - #include "precompiled.h" +#include "def_naxxramas.h" #define SPELL_BOMBARD_SLIME 28280 @@ -43,20 +31,13 @@ Enrages 26527*/ #define MOB_FALLOUT_SLIME 16290 -struct TRINITY_DLL_DECL boss_grobbulusAI : public ScriptedAI +struct TRINITY_DLL_DECL boss_grobbulusAI : public BossAI { - boss_grobbulusAI(Creature *c) : ScriptedAI(c) {} - - EventMap events; - - void Reset() - { - events.Reset(); - } + boss_grobbulusAI(Creature *c) : BossAI(c, BOSS_GROBBULUS) {} void EnterCombat(Unit *who) { - DoZoneInCombat(); + _EnterCombat(); events.ScheduleEvent(EVENT_CLOUD, 15000); events.ScheduleEvent(EVENT_INJECT, 20000); events.ScheduleEvent(EVENT_SPRAY, 15000+rand()%15000); //not sure diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp index 9207b2c09a2..0302a93c488 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_heigan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2008 - 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 @@ -14,13 +14,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Heigan -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" #include "def_naxxramas.h" @@ -50,25 +43,14 @@ enum Phases //Spell by eye stalks #define SPELL_MIND_FLAY 26143 -struct TRINITY_DLL_DECL boss_heiganAI : public ScriptedAI +struct TRINITY_DLL_DECL boss_heiganAI : public BossAI { - boss_heiganAI(Creature *c) : ScriptedAI(c) - { - instance = ((ScriptedInstance*)c->GetInstanceData()); - } + boss_heiganAI(Creature *c) : BossAI(c, BOSS_HEIGAN) {} - EventMap events; - ScriptedInstance *instance; uint32 eruptSection; bool eruptDirection; Phases phase; - void Reset() - { - events.Reset(); - instance->SetBossState(BOSS_HEIGAN, NOT_STARTED); - } - void KilledUnit(Unit* Victim) { if(!(rand()%5)) @@ -77,16 +59,15 @@ struct TRINITY_DLL_DECL boss_heiganAI : public ScriptedAI void JustDied(Unit* Killer) { + _JustDied(); DoScriptText(SAY_DEATH, me); - instance->SetBossState(BOSS_HEIGAN, DONE); } void EnterCombat(Unit *who) { + _EnterCombat(); DoScriptText(SAY_AGGRO, me); - DoZoneInCombat(); EnterPhase(PHASE_FIGHT); - instance->SetBossState(BOSS_HEIGAN, IN_PROGRESS); } void EnterPhase(Phases newPhase) diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp index 087bc8dc12c..1f7b1a55daa 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_noth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2008 - 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 @@ -14,13 +14,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Noth -SD%Complete: 40 -SDComment: Missing Balcony stage -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" #include "def_naxxramas.h" @@ -34,6 +27,7 @@ EndScriptData */ #define SPELL_CURSE_PLAGUEBRINGER HEROIC(29213,54835) #define SPELL_BLINK RAND(29208,29209,29210,29211) #define SPELL_CRIPPLE HEROIC(29212,54814) +#define SPELL_TELEPORT 29216 #define MOB_WARRIOR 16984 #define MOB_CHAMPION 16983 @@ -45,8 +39,16 @@ EndScriptData */ #define TELE_Z 274.040 #define TELE_O 6.277 -// IMPORTANT: BALCONY TELEPORT NOT ADDED YET! WILL BE ADDED SOON! -// Dev note 26.12.2008: When is soon? :) +#define MAX_SUMMON_POS 5 + +const float SummonPos[MAX_SUMMON_POS][4] = +{ + {2728.12, -3544.43, 261.91, 6.04}, + {2729.05, -3544.47, 261.91, 5.58}, + {2728.24, -3465.08, 264.20, 3.56}, + {2704.11, -3456.81, 265.53, 4.51}, + {2663.56, -3464.43, 262.66, 5.20}, +}; enum Events { @@ -54,62 +56,91 @@ enum Events EVENT_CURSE, EVENT_BLINK, EVENT_WARRIOR, + EVENT_BALCONY, + EVENT_WAVE, + EVENT_GROUND, }; -struct TRINITY_DLL_DECL boss_nothAI : public ScriptedAI +struct TRINITY_DLL_DECL boss_nothAI : public BossAI { - boss_nothAI(Creature *c) : ScriptedAI(c), summons(me) - { - instance = ((ScriptedInstance*)c->GetInstanceData()); - } + boss_nothAI(Creature *c) : BossAI(c, BOSS_NOTH) {} - EventMap events; - SummonList summons; - ScriptedInstance *instance; + uint32 waveCount, balconyCount; void Reset() { - events.Reset(); - summons.DespawnAll(); - instance->SetBossState(BOSS_NOTH, NOT_STARTED); + _Reset(); + me->setActive(false); } void EnterCombat(Unit *who) { + _EnterCombat(); DoScriptText(SAY_AGGRO, me); - DoZoneInCombat(); - - events.ScheduleEvent(EVENT_CURSE, 20000+rand()%10000); - events.ScheduleEvent(EVENT_WARRIOR, 30000); - if(HeroicMode) - events.ScheduleEvent(EVENT_BLINK, 20000+rand()%10000); + me->setActive(true); + balconyCount = 0; + EnterPhaseGround(); + } - instance->SetBossState(BOSS_NOTH, IN_PROGRESS); + void EnterPhaseGround() + { + DoZoneInCombat(); + if(me->getThreatManager().isThreatListEmpty()) + EnterEvadeMode(); + else + { + events.ScheduleEvent(EVENT_BALCONY, 110000); + events.ScheduleEvent(EVENT_CURSE, 20000+rand()%10000); + events.ScheduleEvent(EVENT_WARRIOR, 30000); + if(HeroicMode) + events.ScheduleEvent(EVENT_BLINK, 20000+rand()%10000); + } } void KilledUnit(Unit* victim) { - DoScriptText(SAY_SLAY, me); + if(!(rand()%5)) + DoScriptText(SAY_SLAY, me); } void JustSummoned(Creature *summon) { summons.Summon(summon); - DoZoneInCombat(summon); + summon->setActive(true); + summon->AI()->DoZoneInCombat(); } - void SummonedCreatureDespawn(Creature *summon) { summons.Despawn(summon); } - void JustDied(Unit* Killer) { + _JustDied(); DoScriptText(SAY_DEATH, me); - instance->SetBossState(BOSS_NOTH, DONE); + } + + void SummonUndead(uint32 entry, uint32 num) + { + for(uint32 i = 0; i < num; ++i) + { + uint32 pos = rand()%MAX_SUMMON_POS; + me->SummonCreature(entry, SummonPos[pos][0], SummonPos[pos][1], SummonPos[pos][2], + SummonPos[pos][3], TEMPSUMMON_CORPSE_DESPAWN, 60000); + } } void UpdateAI(const uint32 diff) { - if(!UpdateVictim()) - return; + if(me->HasReactState(REACT_AGGRESSIVE)) // ground + { + if(!UpdateVictim()) + return; + } + else // balcony + { + if(me->getThreatManager().isThreatListEmpty()) // if no enemy, go back at once + { + events.Reset(); + events.ScheduleEvent(EVENT_GROUND, 0); + } + } events.Update(diff); @@ -123,8 +154,7 @@ struct TRINITY_DLL_DECL boss_nothAI : public ScriptedAI return; case EVENT_WARRIOR: DoScriptText(SAY_SUMMON, me); - for(uint8 i = 0; i < 6; i++) - m_creature->SummonCreature(MOB_WARRIOR,2684.804,-3502.517,261.313,0,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,80000); + SummonUndead(MOB_WARRIOR, HEROIC(2,3)); events.ScheduleEvent(EVENT_WARRIOR, 30000); return; case EVENT_BLINK: @@ -133,10 +163,46 @@ struct TRINITY_DLL_DECL boss_nothAI : public ScriptedAI DoResetThreat(); events.ScheduleEvent(EVENT_BLINK, 20000+rand()%10000); return; + case EVENT_BALCONY: + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->AttackStop(); + me->RemoveAllAuras(); + me->NearTeleportTo(TELE_X, TELE_Y, TELE_Z, TELE_O); + events.Reset(); + events.ScheduleEvent(EVENT_WAVE, 2000); + waveCount = 0; + return; + case EVENT_WAVE: + DoScriptText(SAY_SUMMON, me); + switch(balconyCount) + { + case 0: SummonUndead(MOB_CHAMPION, HEROIC(2,4)); break; + case 1: SummonUndead(MOB_CHAMPION, HEROIC(1,2)); + SummonUndead(MOB_GUARDIAN, HEROIC(1,2)); break; + case 2: SummonUndead(MOB_GUARDIAN, HEROIC(2,4)); break; + default:SummonUndead(MOB_CHAMPION, HEROIC(5,10)); + SummonUndead(MOB_GUARDIAN, HEROIC(5,10));break; + } + ++waveCount; + events.ScheduleEvent(waveCount < 2 ? EVENT_WAVE : EVENT_GROUND, 34000); + return; + 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); + EnterPhaseGround(); + return; + } } } - DoMeleeAttackIfReady(); + if(me->HasReactState(REACT_AGGRESSIVE)) + DoMeleeAttackIfReady(); } }; diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp index 3f51fc08ee4..7886fad94cc 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_patchwerk.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2008 - 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 @@ -14,14 +14,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Patchwerk -SD%Complete: 80 -SDComment: Some issues with hateful strike inturrupting the melee swing timer. -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" +#include "def_naxxramas.h" #define SAY_AGGRO RAND(-1533017,-1533018) #define SAY_SLAY -1533019 @@ -39,18 +33,11 @@ EndScriptData */ #define EVENT_HATEFUL 2 #define EVENT_SLIME 3 -struct TRINITY_DLL_DECL boss_patchwerkAI : public ScriptedAI +struct TRINITY_DLL_DECL boss_patchwerkAI : public BossAI { - boss_patchwerkAI(Creature *c) : ScriptedAI(c) {} + boss_patchwerkAI(Creature *c) : BossAI(c, BOSS_PATCHWERK) {} bool Enraged; - EventMap events; - - void Reset() - { - events.Reset(); - Enraged = false; - } void KilledUnit(Unit* Victim) { @@ -60,13 +47,15 @@ struct TRINITY_DLL_DECL boss_patchwerkAI : public ScriptedAI void JustDied(Unit* Killer) { + _JustDied(); DoScriptText(SAY_DEATH, me); } void EnterCombat(Unit *who) { + _EnterCombat(); + Enraged = false; DoScriptText(SAY_AGGRO, me); - DoZoneInCombat(); events.ScheduleEvent(EVENT_HATEFUL, 1200); events.ScheduleEvent(EVENT_BERSERK, 360000); } @@ -88,15 +77,14 @@ struct TRINITY_DLL_DECL boss_patchwerkAI : public ScriptedAI //amount of HP within melee distance uint32 MostHP = 0; Unit* pMostHPTarget = NULL; - std::list<HostilReference*>::iterator i = m_creature->getThreatManager().getThreatList().begin(); - for(; i != m_creature->getThreatManager().getThreatList().end();) + std::list<HostilReference*>::iterator i = me->getThreatManager().getThreatList().begin(); + for(; i != me->getThreatManager().getThreatList().end(); ++i) { - Unit* pTemp = Unit::GetUnit(*m_creature, (*i)->getUnitGuid()); - ++i; - if (pTemp && pTemp->isAlive() && pTemp->GetHealth() > MostHP && m_creature->IsWithinMeleeRange(pTemp)) + Unit* target = (*i)->getTarget(); + if (target->isAlive() && target->GetHealth() > MostHP && me->IsWithinMeleeRange(target)) { - MostHP = pTemp->GetHealth(); - pMostHPTarget = pTemp; + MostHP = target->GetHealth(); + pMostHPTarget = target; } } diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp index 64147eaea8a..67fcaee7de3 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_razuvious.cpp @@ -1,4 +1,6 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* + * Copyright (C) 2008 - 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 @@ -14,14 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Razuvious -SD%Complete: 50 -SDComment: Missing adds and event is impossible without Mind Control -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" +#include "def_naxxramas.h" //Razuvious - NO TEXT sound only //8852 aggro01 - Hah hah, I'm just getting warmed up! @@ -37,121 +33,86 @@ EndScriptData */ //8860 death - An honorable... death... //8947 - Aggro Mixed? - ? -#define SOUND_AGGRO1 8852 -#define SOUND_AGGRO2 8853 -#define SOUND_AGGRO3 8854 -#define SOUND_SLAY1 8861 -#define SOUND_SLAY2 8863 -#define SOUND_COMMND1 8855 -#define SOUND_COMMND2 8856 -#define SOUND_COMMND3 8858 -#define SOUND_COMMND4 8859 -#define SOUND_COMMND5 8861 +#define SOUND_AGGRO RAND(8852,8853,8854) +#define SOUND_SLAY RAND(8861,8863) +#define SOUND_COMMND RAND(8855,8856,8858,8859,8861) #define SOUND_DEATH 8860 #define SOUND_AGGROMIX 8847 -#define SPELL_UNBALANCINGSTRIKE 26613 -#define SPELL_DISRUPTINGSHOUT 29107 +#define SPELL_UNBALANCING_STRIKE 26613 +#define SPELL_DISRUPTING_SHOUT HEROIC(29107,55543) +#define SPELL_JAGGED_KNIFE 55550 +#define SPELL_HOPELESS 29125 -struct TRINITY_DLL_DECL boss_razuviousAI : public ScriptedAI +enum Events { - boss_razuviousAI(Creature *c) : ScriptedAI(c) {} - - uint32 UnbalancingStrike_Timer; - uint32 DisruptingShout_Timer; - uint32 CommandSound_Timer; + EVENT_STRIKE, + EVENT_SHOUT, + EVENT_KNIFE, + EVENT_COMMAND, +}; - void Reset() - { - UnbalancingStrike_Timer = 30000; //30 seconds - DisruptingShout_Timer = 25000; //25 seconds - CommandSound_Timer = 40000; //40 seconds - } +struct TRINITY_DLL_DECL boss_razuviousAI : public BossAI +{ + boss_razuviousAI(Creature *c) : BossAI(c, BOSS_RAZUVIOUS) {} - void KilledUnit(Unit* Victim) + void KilledUnit(Unit* victim) { - if (rand()%3) - return; - - switch (rand()%2) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_SLAY1); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_SLAY2); - break; - } + if(!(rand()%3)) + DoPlaySoundToSet(me, SOUND_SLAY); } - void JustDied(Unit* Killer) + void JustDied(Unit* killer) { - DoPlaySoundToSet(m_creature, SOUND_DEATH); + _JustDied(); + DoPlaySoundToSet(me, SOUND_DEATH); + me->CastSpell(me, SPELL_HOPELESS, true); // TODO: this may affect other creatures } void EnterCombat(Unit *who) { - switch (rand()%3) - { - case 0: - DoPlaySoundToSet(m_creature, SOUND_AGGRO1); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_AGGRO2); - break; - case 2: - DoPlaySoundToSet(m_creature, SOUND_AGGRO3); - break; - } + _EnterCombat(); + DoPlaySoundToSet(m_creature, SOUND_AGGRO); + events.ScheduleEvent(EVENT_STRIKE, 30000); + events.ScheduleEvent(EVENT_SHOUT, 25000); + events.ScheduleEvent(EVENT_COMMAND, 40000); } void UpdateAI(const uint32 diff) { - if (!UpdateVictim()) + if(!UpdateVictim()) return; - //UnbalancingStrike_Timer - if (UnbalancingStrike_Timer < diff) - { - DoCast(m_creature->getVictim(),SPELL_UNBALANCINGSTRIKE); - UnbalancingStrike_Timer = 30000; - }else UnbalancingStrike_Timer -= diff; - - //DisruptingShout_Timer - if (DisruptingShout_Timer < diff) - { - DoCast(m_creature->getVictim(), SPELL_DISRUPTINGSHOUT); - DisruptingShout_Timer = 25000; - }else DisruptingShout_Timer -= diff; + events.Update(diff); - //CommandSound_Timer - if (CommandSound_Timer < diff) + while(uint32 eventId = events.ExecuteEvent()) { - switch (rand()%5) + switch(eventId) { - case 0: - DoPlaySoundToSet(m_creature, SOUND_COMMND1); - break; - case 1: - DoPlaySoundToSet(m_creature, SOUND_COMMND2); - break; - case 2: - DoPlaySoundToSet(m_creature, SOUND_COMMND3); - break; - case 3: - DoPlaySoundToSet(m_creature, SOUND_COMMND4); - break; - case 4: - DoPlaySoundToSet(m_creature, SOUND_COMMND5); - break; + case EVENT_STRIKE: + DoCast(me->getVictim(), SPELL_UNBALANCING_STRIKE); + events.ScheduleEvent(EVENT_STRIKE, 30000); + return; + case EVENT_SHOUT: + DoCastAOE(SPELL_DISRUPTING_SHOUT); + events.ScheduleEvent(EVENT_SHOUT, 25000); + return; + case EVENT_KNIFE: + if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45)) + DoCast(target, SPELL_JAGGED_KNIFE); + events.ScheduleEvent(EVENT_KNIFE, 25000); + return; + case EVENT_COMMAND: + DoPlaySoundToSet(me, SOUND_COMMND); + events.ScheduleEvent(EVENT_COMMAND, 40000); + return; } - - CommandSound_Timer = 40000; - }else CommandSound_Timer -= diff; + } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_razuvious(Creature *_Creature) { return new boss_razuviousAI (_Creature); @@ -165,4 +126,3 @@ void AddSC_boss_razuvious() newscript->GetAI = &GetAI_boss_razuvious; newscript->RegisterSelf(); } - diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp index a0cfb77c06c..71259df7824 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_sapphiron.cpp @@ -1,4 +1,6 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* + * Copyright (C) 2008 - 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 @@ -14,171 +16,324 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Boss_Sapphiron -SD%Complete: 0 -SDComment: Place Holder -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" +#include "def_naxxramas.h" #define EMOTE_BREATH -1533082 #define EMOTE_ENRAGE -1533083 -#define SPELL_ICEBOLT 28522 -#define SPELL_FROST_BREATH 29318 #define SPELL_FROST_AURA HEROIC(28531,55799) -#define SPELL_LIFE_DRAIN HEROIC(28542,55665) -//#define SPELL_CHILL 28560 -#define SPELL_BLIZZARD 28547 -#define SPELL_BESERK 26662 #define SPELL_CLEAVE 19983 -#define SPELL_TAIL_SWEEP 55697 +#define SPELL_TAIL_SWEEP HEROIC(55697,55696) +#define SPELL_SUMMON_BLIZZARD 28560 +#define SPELL_LIFE_DRAIN HEROIC(28542,55665) +#define SPELL_ICEBOLT 28522 +#define SPELL_FROST_BREATH 29318 +#define SPELL_FROST_EXPLOSION 28524 +#define SPELL_FROST_MISSILE 30101 +#define SPELL_BERSERK 26662 +#define SPELL_DIES 29357 +#define SPELL_CHILL HEROIC(28547,55699) -struct TRINITY_DLL_DECL boss_sapphironAI : public ScriptedAI +#define MOB_BLIZZARD 16474 +#define GO_ICEBLOCK 181247 + +enum Phases { - boss_sapphironAI(Creature* c) : ScriptedAI(c) {} - - uint32 Icebolt_Count; - uint32 Icebolt_Timer; - uint32 FrostBreath_Timer; - uint32 FrostAura_Timer; - uint32 LifeDrain_Timer; - uint32 Blizzard_Timer; - uint32 Tail_Sweep_Timer; - uint32 Cleave_Timer; - uint32 Fly_Timer; - uint32 Fly2_Timer; - uint32 Beserk_Timer; - uint32 phase; - bool IsInFly; - uint32 land_Timer; + PHASE_NULL = 0, + PHASE_BIRTH, + PHASE_GROUND, + PHASE_FLIGHT, +}; + +enum Events +{ + EVENT_BERSERK = 1, + EVENT_CLEAVE, + EVENT_TAIL, + EVENT_DRAIN, + EVENT_BLIZZARD, + EVENT_FLIGHT, + EVENT_LIFTOFF, + EVENT_ICEBOLT, + EVENT_BREATH, + EVENT_EXPLOSION, + EVENT_LAND, + EVENT_GROUND, + EVENT_BIRTH, +}; + +typedef std::map<uint64, uint64> IceBlockMap; + +struct TRINITY_DLL_DECL boss_sapphironAI : public BossAI +{ + boss_sapphironAI(Creature* c) : BossAI(c, BOSS_SAPPHIRON) + , phase(PHASE_NULL) + {} + + Phases phase; + uint32 iceboltCount; + IceBlockMap iceblocks; + + void InitializeAI() + { + float x, y, z; + me->GetPosition(x, y, z); + me->SummonGameObject(GO_BIRTH, x, y, z, 0, 0, 0, 0, 0, 0); + me->SetVisibility(VISIBILITY_OFF); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + + Reset(); + } void Reset() { - FrostAura_Timer = 2000; - LifeDrain_Timer = 24000; - Blizzard_Timer = 20000; - Tail_Sweep_Timer=(rand()%2+9)*1000; - Cleave_Timer=10000; - Fly_Timer = 45000; - Icebolt_Timer = 4000; - land_Timer = 0; - Beserk_Timer = 15*60000; - phase = 1; - Icebolt_Count = 0; - IsInFly = false; - - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + _Reset(); + + if(phase = PHASE_FLIGHT) + ClearIceBlock(); + + phase = PHASE_NULL; } void EnterCombat(Unit *who) { - DoZoneInCombat(); + _EnterCombat(); + me->CastSpell(me, SPELL_FROST_AURA, true); + + events.ScheduleEvent(EVENT_BERSERK, 15*60000); + EnterPhaseGround(); + } + + void SpellHitTarget(Unit *target, const SpellEntry *spell) + { + if(spell->Id == SPELL_ICEBOLT) + { + IceBlockMap::iterator itr = iceblocks.find(target->GetGUID()); + if(itr != iceblocks.end() && !itr->second) + { + if(GameObject *iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25000)) + itr->second = iceblock->GetGUID(); + } + } + } + + void JustDied(Unit*) + { + _JustDied(); + me->CastSpell(me, SPELL_DIES, true); + } + + void MovementInform(uint32, uint32 id) + { + if(id == 1) + events.ScheduleEvent(EVENT_LIFTOFF, 0); + } + + void DoAction(const int32 param) + { + if(param == DATA_SAPPHIRON_BIRTH) + { + phase = PHASE_BIRTH; + events.ScheduleEvent(EVENT_BIRTH, 23000); + } + } + + void EnterPhaseGround() + { + phase = PHASE_GROUND; + me->SetReactState(REACT_AGGRESSIVE); + events.SetPhase(PHASE_GROUND); + events.ScheduleEvent(EVENT_CLEAVE, 5000+rand()%10000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_TAIL, 5000+rand()%10000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_DRAIN, 24000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_BLIZZARD, 5000+rand()%5000, 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_FLIGHT, 45000); + } + + void ClearIceBlock() + { + for(IceBlockMap::iterator itr = iceblocks.begin(); itr != iceblocks.end(); ++itr) + { + if(Player *player = Unit::GetPlayer(itr->first)) + player->RemoveAura(SPELL_ICEBOLT); + if(GameObject *go = GameObject::GetGameObject(*me, itr->second)) + go->Delete(); + } + iceblocks.clear(); } void UpdateAI(const uint32 diff) { - if (!UpdateVictim()) + if(!phase) return; - if(phase == 1) + events.Update(diff); + + if(phase == PHASE_GROUND) { - if(LifeDrain_Timer < diff) - { - DoCastAOE(SPELL_LIFE_DRAIN); - LifeDrain_Timer = 24000; - }else LifeDrain_Timer -= diff; + if(!UpdateVictim()) + return; - if(Blizzard_Timer < diff) + while(uint32 eventId = events.ExecuteEvent()) { - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0)) + switch(eventId) { - DoCast(target,SPELL_BLIZZARD); - //It seems NO damage? + case EVENT_BERSERK: + DoScriptText(EMOTE_ENRAGE, m_creature); + DoCast(me, SPELL_BERSERK); + return; + case EVENT_CLEAVE: + DoCast(me->getVictim(), SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 5000+rand()%10000, 0, PHASE_GROUND); + return; + case EVENT_TAIL: + DoCastAOE(SPELL_TAIL_SWEEP); + events.ScheduleEvent(EVENT_TAIL, 5000+rand()%10000, 0, PHASE_GROUND); + return; + case EVENT_DRAIN: + DoCastAOE(SPELL_LIFE_DRAIN); + events.ScheduleEvent(EVENT_DRAIN, 24000, 0, PHASE_GROUND); + return; + case EVENT_BLIZZARD: + { + //DoCastAOE(SPELL_SUMMON_BLIZZARD); + float x, y, z; + me->GetGroundPointAroundUnit(x, y, z, rand_norm()*20, rand_norm()*2*M_PI); + if(Creature *summon = me->SummonCreature(MOB_BLIZZARD, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 25000+rand()%5000)) + summon->GetMotionMaster()->MoveRandom(40); + events.ScheduleEvent(EVENT_BLIZZARD, HEROIC(20000,7000), 0, PHASE_GROUND); + break; + } + case EVENT_FLIGHT: + phase = PHASE_FLIGHT; + events.SetPhase(PHASE_FLIGHT); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + float x, y, z, o; + me->GetHomePosition(x, y, z, o); + me->GetMotionMaster()->MovePoint(1, x, y, z); + return; } - Blizzard_Timer = 20000; - }else Blizzard_Timer -= diff; + } - //SPELL_CLEAVE - if(Cleave_Timer < diff) + DoMeleeAttackIfReady(); + } + else + { + /*if(me->getThreatManager().isThreatListEmpty()) { - DoCast(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 10000; - }else Cleave_Timer -= diff; + EnterEvadeMode(); + return; + }*/ - //Tail Sweep_Timer, - if(Tail_Sweep_Timer < diff) + if(uint32 eventId = events.ExecuteEvent()) { - DoCast(m_creature,SPELL_TAIL_SWEEP); - Tail_Sweep_Timer=(rand()%2+9)*1000; - }else Tail_Sweep_Timer -= diff; + switch(eventId) + { + case EVENT_LIFTOFF: + me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + events.ScheduleEvent(EVENT_ICEBOLT, 1500); + iceboltCount = HEROIC(2,3); + return; + case EVENT_ICEBOLT: + { + std::vector<Unit*> targets; + std::list<HostilReference*>::iterator i = me->getThreatManager().getThreatList().begin(); + for(; i != me->getThreatManager().getThreatList().end(); ++i) + if((*i)->getTarget()->GetTypeId() == TYPEID_PLAYER && !(*i)->getTarget()->HasAura(SPELL_ICEBOLT)) + targets.push_back((*i)->getTarget()); + + if(targets.empty()) + iceboltCount = 0; + else + { + std::vector<Unit*>::iterator itr = targets.begin(); + advance(itr, rand()%targets.size()); + iceblocks.insert(std::make_pair((*itr)->GetGUID(), 0)); + DoCast(*itr, SPELL_ICEBOLT); + --iceboltCount; + } + + if(iceboltCount) + events.ScheduleEvent(EVENT_ICEBOLT, 1000); + else + events.ScheduleEvent(EVENT_BREATH, 1000); + return; + } + case EVENT_BREATH: + { + DoScriptText(EMOTE_BREATH, me); + DoCastAOE(SPELL_FROST_MISSILE); + events.ScheduleEvent(EVENT_EXPLOSION, 8000); + return; + } + case EVENT_EXPLOSION: + CastExplosion(); + ClearIceBlock(); + events.ScheduleEvent(EVENT_LAND, 3000); + return; + case EVENT_LAND: + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + events.ScheduleEvent(EVENT_GROUND, 1500); + return; + case EVENT_GROUND: + EnterPhaseGround(); + return; + case EVENT_BIRTH: + me->SetVisibility(VISIBILITY_ON); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + return; + } + }//if(uint32 eventId = events.ExecuteEvent()) + }//if(phase == PHASE_GROUND) + } + + void CastExplosion() + { + DoZoneInCombat(); // make sure everyone is in threatlist + std::vector<Unit*> targets; + std::list<HostilReference*>::iterator i = me->getThreatManager().getThreatList().begin(); + for(; i != me->getThreatManager().getThreatList().end(); ++i) + { + Unit *target = (*i)->getTarget(); + if(target->GetTypeId() != TYPEID_PLAYER) + continue; - if (m_creature->GetHealth()*100 / m_creature->GetMaxHealth() > 10) + if(target->HasAura(SPELL_ICEBOLT)) { - if(Fly_Timer < diff) - { - phase = 2; - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetHover(true); - Icebolt_Timer = 4000; - Icebolt_Count = 0; - IsInFly = true; - }else Fly_Timer -= diff; + target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true); + targets.push_back(target); + continue; } - } - if (phase == 2) - { - if(Icebolt_Timer < diff && Icebolt_Count < 5) + for(IceBlockMap::iterator itr = iceblocks.begin(); itr != iceblocks.end(); ++itr) { - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0)) + if(GameObject *go = GameObject::GetGameObject(*me, itr->second)) { - DoCast(target,SPELL_ICEBOLT); - ++Icebolt_Count; - error_log("Count incremented"); + if(go->IsInBetween(me, target, 2.0f) + && me->GetExactDistance2d(target->GetPositionX(), target->GetPositionY()) - me->GetExactDistance2d(go->GetPositionX(), go->GetPositionY()) < 5.0f) + { + target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true); + targets.push_back(target); + break; + } } - FrostBreath_Timer = 6000; - Icebolt_Timer = 4000; - }else Icebolt_Timer -= diff; - - if(Icebolt_Count == 5 && IsInFly && FrostBreath_Timer < diff ) - { - DoScriptText(EMOTE_BREATH, m_creature); - DoCast(m_creature->getVictim(),SPELL_FROST_BREATH); - land_Timer = 2000; - IsInFly = false; - FrostBreath_Timer = 6000; - }else FrostBreath_Timer -= diff; - - if(!IsInFly && land_Timer < diff) - { - phase = 1; - m_creature->HandleEmoteCommand(EMOTE_ONESHOT_LAND); - m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - m_creature->SetHover(true); - land_Timer = 0; - Fly_Timer = 67000; - }else land_Timer -= diff; + } } - if (Beserk_Timer < diff) - { - DoScriptText(EMOTE_ENRAGE, m_creature); - DoCast(m_creature,SPELL_BESERK); - Beserk_Timer = 300000; - }else Beserk_Timer -= diff; + me->CastSpell(me, SPELL_FROST_EXPLOSION, true); - if (phase!=2) - DoMeleeAttackIfReady(); + for(std::vector<Unit*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + (*itr)->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, false); } }; diff --git a/src/bindings/scripts/scripts/zone/naxxramas/def_naxxramas.h b/src/bindings/scripts/scripts/zone/naxxramas/def_naxxramas.h index b0931c556fe..383200d4600 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/def_naxxramas.h +++ b/src/bindings/scripts/scripts/zone/naxxramas/def_naxxramas.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Trinity <http://www.trinitycore.org/> + * Copyright (C) 2008 - 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 @@ -21,15 +21,32 @@ enum Encounter { + BOSS_ANUBREKHAN, + BOSS_FAERLINA, + BOSS_MAEXXNA, BOSS_NOTH, BOSS_HEIGAN, BOSS_LOATHEB, + BOSS_PATCHWERK, + BOSS_GROBBULUS, + BOSS_GLUTH, + BOSS_THADDIUS, + BOSS_RAZUVIOUS, + BOSS_GOTHIK, + BOSS_HORSEMEN, + BOSS_SAPPHIRON, + BOSS_KELTHUZAD, + MAX_BOSS_NUMBER }; enum Data { DATA_HEIGAN_ERUPT, + DATA_GOTHIK_GATE, + DATA_SAPPHIRON_BIRTH, }; +#define GO_BIRTH 181356 + #endif diff --git a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp index dfa085f39be..e5913660c3f 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +/* Copyright (C) 2008 - 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 @@ -14,16 +14,38 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* ScriptData -SDName: Instance_Naxxramas -SD%Complete: 0 -SDComment: Place holder -SDCategory: Naxxramas -EndScriptData */ - #include "precompiled.h" #include "def_naxxramas.h" +const DoorData doorData[] = +{ + {181126, BOSS_ANUBREKHAN,DOOR_TYPE_ROOM}, + {181195, BOSS_ANUBREKHAN,DOOR_TYPE_PASSAGE}, + {194022, BOSS_FAERLINA, DOOR_TYPE_PASSAGE}, + {181209, BOSS_FAERLINA, DOOR_TYPE_PASSAGE}, + {181209, BOSS_MAEXXNA, DOOR_TYPE_ROOM}, + {181200, BOSS_NOTH, DOOR_TYPE_ROOM}, + {181201, BOSS_NOTH, DOOR_TYPE_PASSAGE}, + {181202, BOSS_NOTH, DOOR_TYPE_PASSAGE}, + {181202, BOSS_HEIGAN, DOOR_TYPE_ROOM}, + {181203, BOSS_HEIGAN, DOOR_TYPE_PASSAGE}, + {181241, BOSS_HEIGAN, DOOR_TYPE_PASSAGE}, + {181241, BOSS_LOATHEB, DOOR_TYPE_ROOM}, + {181123, BOSS_PATCHWERK, DOOR_TYPE_PASSAGE}, + {181123, BOSS_GROBBULUS, DOOR_TYPE_ROOM}, + {181120, BOSS_GLUTH, DOOR_TYPE_PASSAGE}, + {181121, BOSS_GLUTH, DOOR_TYPE_PASSAGE}, + {181121, BOSS_THADDIUS, DOOR_TYPE_ROOM}, + {181124, BOSS_RAZUVIOUS, DOOR_TYPE_PASSAGE}, + {181124, BOSS_GOTHIK, DOOR_TYPE_ROOM}, + {181125, BOSS_GOTHIK, DOOR_TYPE_PASSAGE}, + {181119, BOSS_GOTHIK, DOOR_TYPE_PASSAGE}, + {181119, BOSS_HORSEMEN, DOOR_TYPE_ROOM}, + {0, 0, DOOR_TYPE_ROOM}, // EOF +}; + +#define GO_GOTHIK_GATE 181170 + #define SPELL_ERUPTION 29371 const float HeiganPos[2] = {2796, -3707}; @@ -55,14 +77,28 @@ inline uint32 GetEruptionSection(float x, float y) return 3; } -struct TRINITY_DLL_DECL instance_naxxramas : public ScriptedInstance +struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData { - instance_naxxramas(Map *map) : ScriptedInstance(map) + instance_naxxramas(Map *map) : InstanceData(map) + , Sapphiron(NULL) { - SetBossNumber(15); + SetBossNumber(MAX_BOSS_NUMBER); + LoadDoorData(doorData); } + std::set<Creature*> Worshipper; std::set<GameObject*> HeiganEruption[4]; + GameObject *GothikGate; + Creature *Sapphiron; + + void OnCreatureCreate(Creature *creature, bool add) + { + switch(creature->GetEntry()) + { + case 15989: Sapphiron = add ? creature : NULL; break; + case 16506: if(add) Worshipper.insert(creature); else Worshipper.erase(creature); break; + } + } void OnObjectCreate(GameObject* go, bool add) { @@ -78,11 +114,24 @@ struct TRINITY_DLL_DECL instance_naxxramas : public ScriptedInstance switch(go->GetEntry()) { - case 181200: SetBossRoomDoor(BOSS_NOTH, go, add); break; - case 181201: SetBossPassageDoor(BOSS_NOTH, go, add); break; - case 181202: SetBossRoomDoor(BOSS_HEIGAN, go, add); break; - case 181203: SetBossPassageDoor(BOSS_HEIGAN, go, add); break; - case 181241: SetBossRoomDoor(BOSS_LOATHEB, go, add); break; + case GO_BIRTH: if(!add && Sapphiron) Sapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH); return; + case GO_GOTHIK_GATE: GothikGate = add ? go : NULL; break; + } + + AddDoor(go, add); + } + + void SetBossState(uint32 id, EncounterState state) + { + InstanceData::SetBossState(id, state); + switch(id) + { + case BOSS_FAERLINA: + if(state == NOT_STARTED) + for(std::set<Creature*>::iterator itr = Worshipper.begin(); itr != Worshipper.end(); ++itr) + if(!(*itr)->isAlive()) + (*itr)->Respawn(); + break; } } @@ -93,6 +142,10 @@ struct TRINITY_DLL_DECL instance_naxxramas : public ScriptedInstance case DATA_HEIGAN_ERUPT: HeiganErupt(value); break; + case DATA_GOTHIK_GATE: + if(GothikGate) + GothikGate->SetGoState(GOState(value)); + break; } } @@ -122,6 +175,6 @@ void AddSC_instance_naxxramas() Script *newscript; newscript = new Script; newscript->Name = "instance_naxxramas"; - newscript->GetInstanceData = GetInstanceData_instance_naxxramas; + newscript->GetInstanceData = &GetInstanceData_instance_naxxramas; newscript->RegisterSelf(); } diff --git a/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp b/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp index caf18778abb..30f843badb0 100644 --- a/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp +++ b/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp @@ -185,7 +185,7 @@ struct TRINITY_DLL_DECL instance_shadowfang_keep : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { return str_data.c_str(); } diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp index 8e42d074f88..e753d0b6047 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp @@ -306,7 +306,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI case 2:{ error_log("Summon Vapor case 2"); Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true); if(!target) target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_PLAYER_GUID)); if(target) { @@ -331,7 +331,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI error_log("Summon Vapor case3"); //m_creature->CastSpell(m_creature, SPELL_VAPOR_SELECT); need core support Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true); if(!target) target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_PLAYER_GUID)); if(target) { @@ -358,7 +358,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI break; case 5:{ Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true); if(!target) target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_PLAYER_GUID)); if(target) { @@ -471,7 +471,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI Timer[EVENT_GAS_NOVA] = 20000 + rand()%5 * 1000; break; case EVENT_ENCAPSULATE: - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true)) { m_creature->CastSpell(target, SPELL_ENCAPSULATE_CHANNEL, false); target->CastSpell(target, SPELL_ENCAPSULATE_EFFECT, true);// linked aura, need core patch to remove this hack diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp index 98cbfda7a7f..a0bd75cb156 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp @@ -540,7 +540,7 @@ struct TRINITY_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI float x,y,z; Unit* target; for(uint8 z = 0; z < 6; ++z){ - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!target->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } target->GetPosition(x,y,z); @@ -584,7 +584,7 @@ struct TRINITY_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI if(!m_creature->IsNonMeleeSpellCasted(false)){ m_creature->RemoveAurasDueToSpell(SPELL_SOUL_FLAY); for(uint8 z = 0; z < 6; ++z){ - randomPlayer = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + randomPlayer = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!randomPlayer->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } if(randomPlayer)DoCast(randomPlayer, SPELL_LEGION_LIGHTNING, false); @@ -658,7 +658,7 @@ struct TRINITY_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI case TIMER_ARMAGEDDON: //Phase 4 Unit* target; for(uint8 z = 0; z < 6; ++z){ - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!target->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } if(target){ @@ -1199,7 +1199,7 @@ struct TRINITY_DLL_DECL mob_sinster_reflectionAI : public ScriptedAI Timer[1] = 4000; } if(Timer[2] < diff){ - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_SR_CURSE_OF_AGONY, true); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_SR_CURSE_OF_AGONY, true); Timer[2] = 3000; } DoMeleeAttackIfReady(); 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 6000ee474e0..b38607e1a7f 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp @@ -155,7 +155,7 @@ struct TRINITY_DLL_DECL boss_entropiusAI : public ScriptedAI m_creature->SummonCreature(CREATURE_DARK_FIENDS, x,y,z,o, TEMPSUMMON_CORPSE_DESPAWN, 0); break; } - summoned->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM,0, 50, true)); + summoned->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM,0, 50, true)); Summons.Summon(summoned); } @@ -180,10 +180,10 @@ struct TRINITY_DLL_DECL boss_entropiusAI : public ScriptedAI }else EnrageTimer -= diff; if(BlackHoleSummonTimer < diff){ - Unit* random = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + Unit* random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if(!random)return; DoCast(random, SPELL_DARKNESS_E, false); - random = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if(!random)return; random->CastSpell(random, SPELL_BLACKHOLE, false); BlackHoleSummonTimer = 15000; @@ -260,7 +260,7 @@ struct TRINITY_DLL_DECL boss_muruAI : public Scripted_NoMovementAI summoned->CastSpell(summoned,SPELL_DARKFIEND_VISUAL,false); break; } - summoned->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM,0, 50, true)); + summoned->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM,0, 50, true)); Summons.Summon(summoned); } @@ -441,7 +441,7 @@ struct TRINITY_DLL_DECL npc_dark_fiendAI : public ScriptedAI if(!InAction){ m_creature->clearUnitState(UNIT_STAT_STUNNED); DoCastAOE(SPELL_DARKFIEND_SKIN, false); - AttackStart(SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true)); + AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)); InAction = true; WaitTimer = 500; }else{ 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 f8bba5acf21..597103b62cf 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 @@ -236,7 +236,7 @@ struct TRINITY_DLL_DECL instance_sunwell_plateau : public ScriptedInstance { } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; std::ostringstream stream; diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp index 168f0f48e3a..dfeb7fea3e6 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp @@ -352,7 +352,7 @@ struct TRINITY_DLL_DECL boss_alarAI : public ScriptedAI if(Charge_Timer < diff) { - Unit *target= SelectUnit(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_CHARGE), true); + Unit *target= SelectTarget(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_CHARGE), true); if(target) DoCast(target, SPELL_CHARGE); Charge_Timer = 30000; @@ -410,7 +410,8 @@ struct TRINITY_DLL_DECL boss_alarAI : public ScriptedAI else { Unit *target = NULL; - if(Phase1 && target && (target = m_creature->SelectNearestTarget(5))) + target = m_creature->SelectNearestTarget(5); + if(Phase1 && target) m_creature->AI()->AttackStart(target); else { 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 83cb789b189..6af14eceeed 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 @@ -230,7 +230,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI if( Wrath_Timer < diff) { m_creature->InterruptNonMeleeSpells(false); - DoCast(SelectUnit(SELECT_TARGET_RANDOM,1,100,true), SPELL_WRATH_OF_THE_ASTROMANCER, true); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,1,100,true), SPELL_WRATH_OF_THE_ASTROMANCER, true); Wrath_Timer = 20000+rand()%5000; }else Wrath_Timer -= diff; @@ -260,7 +260,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI 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 = SelectUnit(SELECT_TARGET_RANDOM, 1, 100, true); + 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); 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 6745c4fd9ec..7557e03f8e5 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 @@ -804,7 +804,7 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI if (FlameStrike_Timer < diff) { - if (Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0, 70, true)) + if (Unit* pUnit = SelectTarget(SELECT_TARGET_RANDOM, 0, 70, true)) DoCast(pUnit, SPELL_FLAME_STRIKE); FlameStrike_Timer = 30000; @@ -816,7 +816,7 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI for (uint32 i = 0; i < 3; i++) { - Unit* target =SelectUnit(SELECT_TARGET_RANDOM, 1, 70, true); + 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) @@ -1080,7 +1080,7 @@ struct TRINITY_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai //Gaze_Timer if(Gaze_Timer < diff) { - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) { DoResetThreat(); if(target) diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp index 66e595ab729..55ef8c60bbd 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/instance_the_eye.cpp @@ -129,7 +129,7 @@ struct TRINITY_DLL_DECL instance_the_eye : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; std::ostringstream stream; 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 c3d4d0f35eb..d2fff0e569f 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 @@ -465,7 +465,7 @@ struct TRINITY_DLL_DECL boss_veknilashAI : public boss_twinemperorsAI if (UpperCut_Timer < diff) { - Unit* randomMelee = SelectUnit(SELECT_TARGET_RANDOM, 0, NOMINAL_MELEE_RANGE, true); + Unit* randomMelee = SelectTarget(SELECT_TARGET_RANDOM, 0, NOMINAL_MELEE_RANGE, true); if (randomMelee) DoCast(randomMelee,SPELL_UPPERCUT); UpperCut_Timer = 15000+rand()%15000; @@ -560,7 +560,7 @@ struct TRINITY_DLL_DECL boss_veklorAI : public boss_twinemperorsAI if (Blizzard_Timer < diff) { Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 45, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45, true); if (target) DoCast(target,SPELL_BLIZZARD); Blizzard_Timer = 15000+rand()%15000; @@ -569,7 +569,7 @@ struct TRINITY_DLL_DECL boss_veklorAI : public boss_twinemperorsAI if (ArcaneBurst_Timer < diff) { Unit *mvic; - if ((mvic=SelectUnit(SELECT_TARGET_NEAREST, 0, NOMINAL_MELEE_RANGE, true))!=NULL) + if ((mvic=SelectTarget(SELECT_TARGET_NEAREST, 0, NOMINAL_MELEE_RANGE, true))!=NULL) { DoCast(mvic,SPELL_ARCANEBURST); ArcaneBurst_Timer = 5000; diff --git a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp index d6f5828d295..d483006642d 100644 --- a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp +++ b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp @@ -231,7 +231,7 @@ struct TRINITY_DLL_DECL instance_utgarde_keep : public ScriptedInstance return 0; } - const char* Save() + std::string GetSaveData() { OUT_SAVE_INST_DATA; diff --git a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/utgarde_keep.cpp b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/utgarde_keep.cpp index 3c2b898653d..923328627e4 100644 --- a/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/utgarde_keep.cpp +++ b/src/bindings/scripts/scripts/zone/utgarde_keep/utgarde_keep/utgarde_keep.cpp @@ -155,6 +155,6 @@ void AddSC_utgarde_keep() newscript = new Script; newscript->Name="npc_dragonflayer_forge_master"; - newscript->GetAI = GetAI_npc_dragonflayer_forge_master; + newscript->GetAI = &GetAI_npc_dragonflayer_forge_master; newscript->RegisterSelf(); -}
\ No newline at end of file +} diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp index f31f944a3d4..85ba26ef20d 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp @@ -297,7 +297,7 @@ struct TRINITY_DLL_DECL boss_akilzonAI : public ScriptedAI } if (ElectricalStorm_Timer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 50, true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true); if(!target) { EnterEvadeMode(); diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp index 7fb8dc9b321..26229261905 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp @@ -383,7 +383,7 @@ struct TRINITY_DLL_DECL boss_hex_lord_malacrassAI : public ScriptedAI if(SiphonSoul_Timer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 70, true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 70, true); Unit *trigger = DoSpawnCreature(MOB_TEMP_TRIGGER, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); if(!target || !trigger) { diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp index 9fc50e621ac..68b92590025 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp @@ -406,7 +406,7 @@ struct TRINITY_DLL_DECL boss_nalorakkAI : public ScriptedAI { DoYell(YELL_SURGE, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_YELL_SURGE); - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_SURGE), true); + Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_SURGE), true); if(target) DoCast(target, SPELL_SURGE); Surge_Timer = 15000 + rand()%5000; diff --git a/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp b/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp index 4ebf541515b..8ff01927908 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp @@ -179,7 +179,7 @@ struct TRINITY_DLL_DECL instance_zulaman : public ScriptedInstance instance->SendToPlayers(&data); } - const char* Save() + std::string GetSaveData() { std::ostringstream ss; ss << "S " << BossKilled << " " << ChestLooted << " " << QuestMinute; diff --git a/src/framework/Platform/Define.h b/src/framework/Platform/Define.h index 59c2418c745..35be370d65b 100644 --- a/src/framework/Platform/Define.h +++ b/src/framework/Platform/Define.h @@ -129,5 +129,11 @@ typedef uint32 DWORD; 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 + #endif //TRINITY_DEFINE_H diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 321922f821e..84ae9cb659e 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -407,7 +407,14 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri do { Field *fields = achievementResult->Fetch(); - CompletedAchievementData& ca = m_completedAchievements[fields[0].GetUInt32()]; + + uint32 achievement_id = fields[0].GetUInt32(); + + // don't must happen: cleanup at server startup in achievementmgr.LoadCompletedAchievements() + if(!sAchievementStore.LookupEntry(achievement_id)) + continue; + + CompletedAchievementData& ca = m_completedAchievements[achievement_id]; ca.date = time_t(fields[1].GetUInt64()); ca.changed = false; } while(achievementResult->NextRow()); @@ -425,7 +432,15 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri time_t date = time_t(fields[2].GetUInt64()); AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(id); - if (!criteria || (criteria->timeLimit && time_t(date + criteria->timeLimit) < time(NULL))) + 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); + CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE criteria = %u",id); + continue; + } + + if (criteria->timeLimit && time_t(date + criteria->timeLimit) < time(NULL)) continue; CriteriaProgress& progress = m_criteriaProgress[id]; @@ -1763,7 +1778,17 @@ void AchievementGlobalMgr::LoadCompletedAchievements() { bar.step(); Field *fields = result->Fetch(); - m_allCompletedAchievements.insert(fields[0].GetUInt32()); + + uint32 achievement_id = fields[0].GetUInt32(); + if(!sAchievementStore.LookupEntry(achievement_id)) + { + // we will remove not existed achievement for all characters + sLog.outError("Not existed achievement %u data removed from table `character_achievement`.",achievement_id); + CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE achievement = %u",achievement_id); + continue; + } + + m_allCompletedAchievements.insert(achievement_id); } while(result->NextRow()); delete result; diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index a637e7e40f0..22ebe87cdc6 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -19,16 +19,9 @@ */ #include "AggressorAI.h" -#include "Errors.h" -#include "Creature.h" -#include "ObjectAccessor.h" -#include "VMapFactory.h" -#include "World.h" +#include "SpellMgr.h" -#include <list> - -int -AggressorAI::Permissible(const Creature *creature) +int AggressorAI::Permissible(const Creature *creature) { // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight if( !creature->isCivilian() && !creature->IsNeutralToAll() ) @@ -37,79 +30,83 @@ AggressorAI::Permissible(const Creature *creature) return PERMIT_BASE_NO; } -AggressorAI::AggressorAI(Creature *c) : CreatureAI(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK) +void AggressorAI::UpdateAI(const uint32 /*diff*/) { + if(!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); } -void AggressorAI::EnterEvadeMode() +int SpellAI::Permissible(const Creature *creature) { - if( !m_creature->isAlive() ) - { - DEBUG_LOG("Creature stopped attacking cuz his dead [guid=%u]", m_creature->GetGUIDLow()); - i_victimGuid = 0; - m_creature->CombatStop(true); - m_creature->DeleteThreatList(); - return; - } + return PERMIT_BASE_NO; +} - Unit* victim = ObjectAccessor::GetUnit(*m_creature, i_victimGuid ); +void SpellAI::InitializeAI() +{ + for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) + if(me->m_spells[i] && GetSpellStore()->LookupEntry(me->m_spells[i])) + spells.push_back(me->m_spells[i]); +} - if( !victim ) - { - DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", m_creature->GetGUIDLow()); - } - else if( !victim->isAlive() ) - { - DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", m_creature->GetGUIDLow()); - } - else if( victim->HasStealthAura() ) - { - DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", m_creature->GetGUIDLow()); - } - else if( victim->isInFlight() ) - { - DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", m_creature->GetGUIDLow()); - } - else - { - DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", m_creature->GetGUIDLow()); - //i_state = STATE_LOOK_AT_VICTIM; - //i_tracker.Reset(TIME_INTERVAL_LOOK); - } +void SpellAI::Reset() +{ + events.Reset(); +} - if(!m_creature->GetCharmerOrOwner()) - { - m_creature->RemoveAllAuras(); +void SpellAI::JustDied(Unit *killer) +{ + for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) + if(AISpellInfo[*i].condition == AICOND_DIE) + me->CastSpell(killer, *i, true); +} - // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead - if( m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE ) - m_creature->GetMotionMaster()->MoveTargetedHome(); +void SpellAI::EnterCombat(Unit *who) +{ + for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i) + { + if(AISpellInfo[*i].condition == AICOND_AGGRO) + me->CastSpell(who, *i, true); + else if(AISpellInfo[*i].condition == AICOND_COMBAT) + events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown); } - else if (m_creature->GetOwner() && m_creature->GetOwner()->isAlive()) - m_creature->GetMotionMaster()->MoveFollow(m_creature->GetOwner(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE); - - m_creature->DeleteThreatList(); - i_victimGuid = 0; - m_creature->CombatStop(true); - m_creature->SetLootRecipient(NULL); } -void -AggressorAI::UpdateAI(const uint32 /*diff*/) +void SpellAI::UpdateAI(const uint32 diff) { - // update i_victimGuid if m_creature->getVictim() !=0 and changed if(!UpdateVictim()) return; - i_victimGuid = m_creature->getVictim()->GetGUID(); + events.Update(diff); - if( m_creature->isAttackReady() ) + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + if(uint32 spellId = events.ExecuteEvent()) { - if( m_creature->IsWithinMeleeRange(m_creature->getVictim())) + Unit *target = NULL; + //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target); + switch(AISpellInfo[spellId].target) { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); + default: + case AITARGET_SELF: target = me; break; + case AITARGET_VICTIM: target = me->getVictim(); break; + case AITARGET_ENEMY: target = SelectTarget(SELECT_TARGET_RANDOM); break; + case AITARGET_ALLY: target = me; break; + case AITARGET_BUFF: target = me; break; + case AITARGET_DEBUFF: + { + const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId); + bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY; + float range = GetSpellMaxRange(spellInfo, false); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId); + break; + } } + if(target) me->CastSpell(target, spellId, false); + events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown); } + else + DoMeleeAttackIfReady(); } - diff --git a/src/game/AggressorAI.h b/src/game/AggressorAI.h index 983498716e6..2c43ccf82b7 100644 --- a/src/game/AggressorAI.h +++ b/src/game/AggressorAI.h @@ -22,31 +22,35 @@ #define TRINITY_AGGRESSORAI_H #include "CreatureAI.h" -#include "Timer.h" +#include "CreatureAIImpl.h" class Creature; class TRINITY_DLL_DECL AggressorAI : public CreatureAI { - enum AggressorState - { - STATE_NORMAL = 1, - STATE_LOOK_AT_VICTIM = 2 - }; - public: - - explicit AggressorAI(Creature *c); - - void EnterEvadeMode(); + explicit AggressorAI(Creature *c) : CreatureAI(c) {} void UpdateAI(const uint32); static int Permissible(const Creature *); +}; + +typedef std::vector<uint32> SpellVct; +class TRINITY_DLL_SPEC SpellAI : public CreatureAI +{ + public: + explicit SpellAI(Creature *c) : CreatureAI(c) {} + + void InitializeAI(); + void Reset(); + void EnterCombat(Unit* who); + void JustDied(Unit *killer); + void UpdateAI(const uint32 diff); + static int Permissible(const Creature *); private: - uint64 i_victimGuid; - AggressorState i_state; - TimeTracker i_tracker; + EventMap events; + SpellVct spells; }; -#endif +#endif diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index d179ec33691..b76e0c7835c 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -726,12 +726,10 @@ void BattleGround::EndBattleGround(uint32 winner) if (team == winner) { RewardMark(plr,ITEM_WINNER_COUNT); - RewardQuest(plr); + RewardQuestComplete(plr); } - else if(winner !=0) - { + else if(winner) RewardMark(plr,ITEM_LOSER_COUNT); - } plr->CombatStopWithPets(true); @@ -785,13 +783,6 @@ uint32 BattleGround::GetBattlemasterEntry() const void BattleGround::RewardMark(Player *plr,uint32 count) { - // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) - return; - - if(!plr || !count) - return; - BattleGroundMarks mark; switch(GetTypeID()) { @@ -811,21 +802,53 @@ void BattleGround::RewardMark(Player *plr,uint32 count) return; } - if ( objmgr.GetItemPrototype( mark ) ) + //if (IsSpell) + // RewardSpellCast(plr,mark); + //else + RewardItem(plr,mark,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)) + return; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if(!spellInfo) { - ItemPosCountVec dest; - uint32 no_space_count = 0; - uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count ); - if( msg != EQUIP_ERR_OK ) // convert to possible store amount - count -= no_space_count; + sLog.outError("Battleground reward casting spell %u not exist.",spell_id); + return; + } - if(!dest.empty()) // can add some - if(Item* item = plr->StoreNewItem( dest, mark, true, 0)) - plr->SendNewItem(item,count,false,true); + plr->CastSpell(plr, spellInfo, true); +} + +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)) + return; - if (no_space_count > 0) - SendRewardMarkByMail(plr,mark,no_space_count); + ItemPosCountVec dest; + uint32 no_space_count = 0; + uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item_id, count, &no_space_count ); + + if( msg == EQUIP_ERR_ITEM_NOT_FOUND) + { + sLog.outErrorDb("Battleground reward item (Entry %u) not exist in `item_template`.",item_id); + return; } + + if( msg != EQUIP_ERR_OK ) // convert to possible store amount + count -= no_space_count; + + if( count != 0 && !dest.empty()) // can add some + if (Item* item = plr->StoreNewItem( dest, item_id, true, 0)) + plr->SendNewItem(item,count,false,true); + + if (no_space_count > 0) + SendRewardMarkByMail(plr,item_id,no_space_count); } void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count) @@ -865,12 +888,8 @@ void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count) } } -void BattleGround::RewardQuest(Player *plr) +void BattleGround::RewardQuestComplete(Player *plr) { - // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens - if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE)) - return; - uint32 quest; switch(GetTypeID()) { @@ -890,7 +909,7 @@ void BattleGround::RewardQuest(Player *plr) return; } - plr->CastSpell(plr, quest, true); + RewardSpellCast(plr, quest); } void BattleGround::BlockMovement(Player *plr) @@ -1739,7 +1758,7 @@ uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const if (itr->second.Team == Team) { Player * pl = objmgr.GetPlayer(itr->first); - if (pl && pl->isAlive()) + if (pl && pl->isAlive() && !pl->HasByteFlag(UNIT_FIELD_BYTES_2, 3, FORM_SPIRITOFREDEMPTION)) ++count; } } diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index 9788f264502..509ba6eb972 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -421,7 +421,9 @@ class BattleGround void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID); void RewardMark(Player *plr,uint32 count); void SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count); - void RewardQuest(Player *plr); + void RewardItem(Player *plr, uint32 item_id, uint32 count); + void RewardQuestComplete(Player *plr); + void RewardSpellCast(Player *plr, uint32 spell_id); void UpdateWorldState(uint32 Field, uint32 Value); void UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source); void EndBattleGround(uint32 winner); diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index 081d9669696..89a9e460968 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -68,6 +68,7 @@ SET(game_STAT_SRCS Corpse.h CreatureAI.cpp CreatureAI.h + CreatureAIFactory.h CreatureAIImpl.h CreatureAIRegistry.cpp CreatureAIRegistry.h @@ -208,8 +209,6 @@ SET(game_STAT_SRCS PointMovementGenerator.h PoolHandler.cpp PoolHandler.h - PossessedAI.cpp - PossessedAI.h QueryHandler.cpp QuestDef.cpp QuestDef.h @@ -262,6 +261,8 @@ SET(game_STAT_SRCS Traveller.h Unit.cpp Unit.h + UnitAI.cpp + UnitAI.h UnitEvents.h UpdateData.cpp UpdateData.h diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index ca6a96c3b08..29a54da5d06 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -173,7 +173,7 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ ) // 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, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, genitive " + "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, 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 " @@ -571,7 +571,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) uint64 playerGuid = holder->GetGuid(); Player* pCurrChar = new Player(this); - pCurrChar->GetMotionMaster()->Initialize(); // for send server info and strings (config) ChatHandler chH = ChatHandler(pCurrChar); @@ -585,6 +584,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) return; } + pCurrChar->GetMotionMaster()->Initialize(); + SetPlayer(pCurrChar); pCurrChar->SendDungeonDifficulty(false); @@ -769,7 +770,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) { sLog.outDebug( "WORLD: Restart character %u taxi flight", pCurrChar->GetGUIDLow() ); - uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam()); + uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam(),true); uint32 path = pCurrChar->m_taxi.GetCurrentTaxiPath(); // search appropriate start path node diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 1bc6eb304e4..bf8ee9d3a77 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -49,6 +49,7 @@ // |color|Hskill:skill_id|h[name]|h|r // |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click // |color|Htalent:talent_id,rank|h[name]|h|r - client, talent icon shift-click +// |color|Htaxinode:id|h[name]|h|r // |color|Htele:id|h[name]|h|r // |color|Htrade:spell_id,cur_value,max_value,unk3int,unk3str|h[name]|h|r - client, spellbook profession icon shift-click @@ -194,6 +195,7 @@ ChatCommand * ChatHandler::getCommandTable() { "graveyard", SEC_MODERATOR, false, &ChatHandler::HandleGoGraveyardCommand, "", NULL }, { "grid", SEC_MODERATOR, false, &ChatHandler::HandleGoGridCommand, "", NULL }, { "object", SEC_MODERATOR, false, &ChatHandler::HandleGoObjectCommand, "", NULL }, + { "taxinode", SEC_MODERATOR, false, &ChatHandler::HandleGoTaxinodeCommand, "", NULL }, { "trigger", SEC_MODERATOR, false, &ChatHandler::HandleGoTriggerCommand, "", NULL }, { "zonexy", SEC_MODERATOR, false, &ChatHandler::HandleGoZoneXYCommand, "", NULL }, { "xy", SEC_MODERATOR, false, &ChatHandler::HandleGoXYCommand, "", NULL }, @@ -301,6 +303,7 @@ ChatCommand * ChatHandler::getCommandTable() { "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable }, { "skill", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSkillCommand, "", NULL }, { "spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSpellCommand, "", NULL }, + { "taxinode", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupTaxiNodeCommand, "", NULL }, { "tele", SEC_MODERATOR, true, &ChatHandler::HandleLookupTeleCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; diff --git a/src/game/Chat.h b/src/game/Chat.h index cc7de6731a6..97570d2f250 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -195,6 +195,7 @@ class ChatHandler bool HandleGoGraveyardCommand(const char* args); bool HandleGoGridCommand(const char* args); bool HandleGoObjectCommand(const char* args); + bool HandleGoTaxinodeCommand(const char* args); bool HandleGoTriggerCommand(const char* args); bool HandleGoXYCommand(const char* args); bool HandleGoXYZCommand(const char* args); @@ -247,6 +248,7 @@ class ChatHandler bool HandleLookupQuestCommand(const char* args); bool HandleLookupSkillCommand(const char* args); bool HandleLookupSpellCommand(const char* args); + bool HandleLookupTaxiNodeCommand(const char * args); bool HandleLookupTeleCommand(const char * args); bool HandleModifyKnownTitlesCommand(const char* args); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 01f43ac8163..8d7b877d4f5 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -164,8 +164,8 @@ Creature::~Creature() i_AI = NULL; } - if(m_uint32Values) - sLog.outDetail("Deconstruct Creature Entry = %u", GetEntry()); + //if(m_uint32Values) + // sLog.outDetail("Deconstruct Creature Entry = %u", GetEntry()); } void Creature::AddToWorld() @@ -175,7 +175,7 @@ void Creature::AddToWorld() { ObjectAccessor::Instance().AddObject(this); Unit::AddToWorld(); - SearchFormation(); + SearchFormationAndPath(); AIM_Initialize(); } } @@ -194,7 +194,7 @@ void Creature::RemoveFromWorld() } } -void Creature::SearchFormation() +void Creature::SearchFormationAndPath() { if(isSummon()) return; @@ -203,9 +203,28 @@ void Creature::SearchFormation() if(!lowguid) return; + bool usePath = (GetDefaultMovementType() == WAYPOINT_MOTION_TYPE); CreatureGroupInfoType::iterator frmdata = CreatureGroupMap.find(lowguid); if(frmdata != CreatureGroupMap.end()) + { + if(usePath && lowguid != frmdata->second->leaderGUID) + { + SetDefaultMovementType(IDLE_MOTION_TYPE); + usePath = false; + } formation_mgr.AddCreatureToGroup(frmdata->second->leaderGUID, this); + } + + if(usePath) + { + if(WaypointMgr.GetPath(lowguid * 10)) + SetWaypointPathId(lowguid * 10); + else + { + sLog.outErrorDb("Creature DBGUID %u has waypoint motion type, but it does not have a waypoint path!", lowguid); + SetDefaultMovementType(IDLE_MOTION_TYPE); + } + } } void Creature::RemoveCorpse() @@ -436,6 +455,9 @@ void Creature::Update(uint32 diff) } else { + // for delayed spells + m_Events.Update( diff ); + m_deathTimer -= diff; if (m_groupLootTimer && lootingGroupLeaderGUID) { @@ -2036,12 +2058,12 @@ bool Creature::IsOutOfThreatArea(Unit* pVictim) const if(sMapStore.LookupEntry(GetMapId())->IsDungeon()) return false; - float length = pVictim->GetDistance(mHome_X, mHome_Y, mHome_Z); float AttackDist = GetAttackDistance(pVictim); uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS); //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick. - return ( length > (ThreatRadius > AttackDist ? ThreatRadius : AttackDist)); + return !pVictim->IsWithinDist3d(mHome_X,mHome_Y,mHome_Z, + ThreatRadius > AttackDist ? ThreatRadius : AttackDist); } CreatureDataAddon const* Creature::GetCreatureAddon() const @@ -2081,10 +2103,6 @@ bool Creature::LoadCreaturesAddon(bool reload) if (cainfo->move_flags != 0) SetUnitMovementFlags(cainfo->move_flags); - //Load Path - if (cainfo->path_id != 0) - m_path_id = cainfo->path_id; - if(cainfo->auras) { for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura) @@ -2105,7 +2123,7 @@ bool Creature::LoadCreaturesAddon(bool reload) continue; } - AddAuraEffect(AdditionalSpellInfo->Id, cAura->effect_idx, this); + AddAuraEffect(AdditionalSpellInfo, cAura->effect_idx, this); sLog.outDebug("Spell: %u with Aura %u added to creature (GUIDLow: %u Entry: %u )", cAura->spell_id, AdditionalSpellInfo->EffectApplyAuraName[cAura->effect_idx],GetGUIDLow(),GetEntry()); } } diff --git a/src/game/Creature.h b/src/game/Creature.h index 36cfee78c5f..f57f0592da5 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -108,6 +108,21 @@ enum Gossip_Guard_Skill GOSSIP_GUARD_SKILL_ENGINERING = 91 }; +enum GossipOptionIcon +{ + GOSSIP_ICON_CHAT = 0, //white chat bubble + GOSSIP_ICON_VENDOR = 1, //brown bag + GOSSIP_ICON_TAXI = 2, //flight + GOSSIP_ICON_TRAINER = 3, //book + GOSSIP_ICON_INTERACT_1 = 4, //interaction wheel + GOSSIP_ICON_INTERACT_2 = 5, //interaction wheel + GOSSIP_ICON_MONEY_BAG = 6, //brown bag with yellow dot + GOSSIP_ICON_TALK = 7, //white chat bubble with black dots + GOSSIP_ICON_TABARD = 8, //tabard + GOSSIP_ICON_BATTLE = 9, //two swords + GOSSIP_ICON_DOT = 10 //yellow dot +}; + struct GossipOption { uint32 Id; @@ -300,7 +315,6 @@ struct CreatureDataAddonAura struct CreatureDataAddon { uint32 guidOrEntry; - uint32 path_id; uint32 mount; uint32 bytes0; uint32 bytes1; @@ -635,6 +649,7 @@ class TRINITY_DLL_SPEC Creature : public Unit bool IsVisibleInGridForPlayer(Player const* pl) const; void RemoveCorpse(); + bool isDeadByDefault() const { return m_isDeadByDefault; }; time_t const& GetRespawnTime() const { return m_respawnTime; } time_t GetRespawnTimeEx() const; @@ -676,13 +691,13 @@ class TRINITY_DLL_SPEC Creature : public Unit uint32 GetGlobalCooldown() const { return m_GlobalCooldown; } - uint32 GetWaypointPath(){return m_path_id;} - void LoadPath(uint32 pathid) { m_path_id = pathid; } + uint32 GetWaypointPathId() const { return m_pathId; } + void SetWaypointPathId(uint32 pathid) { m_pathId = pathid; } uint32 GetCurrentWaypointID(){return m_waypointID;} void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;} - void SearchFormation(); + void SearchFormationAndPath(); CreatureGroup *GetFormation() {return m_formation;} void SetFormation(CreatureGroup *formation) {m_formation = formation;} @@ -743,7 +758,7 @@ class TRINITY_DLL_SPEC Creature : public Unit private: //WaypointMovementGenerator vars uint32 m_waypointID; - uint32 m_path_id; + uint32 m_pathId; //Formation var CreatureGroup *m_formation; diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index 5fd35150b52..0864bc973ab 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -19,49 +19,10 @@ */ #include "CreatureAI.h" +#include "CreatureAIImpl.h" #include "Creature.h" -#include "Player.h" -#include "Pet.h" -#include "SpellAuras.h" #include "World.h" - -void UnitAI::AttackStart(Unit *victim) -{ - if(!victim) - return; - - if(me->Attack(victim, true)) - { - //DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", me->GetName(), victim->GetGUIDLow()); - me->GetMotionMaster()->MoveChase(victim); - } -} - -void UnitAI::DoMeleeAttackIfReady() -{ - //Make sure our attack is ready and we aren't currently casting before checking distance - if (me->isAttackReady() && !me->hasUnitState(UNIT_STAT_CASTING)) - { - //If we are within range melee the target - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim()); - me->resetAttackTimer(); - } - } - if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK) && !me->hasUnitState(UNIT_STAT_CASTING)) - { - //If we are within range melee the target - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK); - me->resetAttackTimer(OFF_ATTACK); - } - } -} - -//Enable PlayerAI when charmed -void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; } +#include "SpellMgr.h" //Disable CreatureAI when charmed void CreatureAI::OnCharmed(bool apply) @@ -71,11 +32,16 @@ void CreatureAI::OnCharmed(bool apply) me->IsAIEnabled = false; } +AISpellInfoType * CreatureAI::AISpellInfo; + void CreatureAI::DoZoneInCombat(Creature* creature) { if (!creature) creature = me; + if(!creature->CanHaveThreatList()) + return; + Map *map = creature->GetMap(); if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated { @@ -83,37 +49,38 @@ void CreatureAI::DoZoneInCombat(Creature* creature) return; } - if(!creature->getVictim()) + if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim()) { if(Unit *target = creature->SelectNearestTarget()) - AttackStart(target); + creature->AI()->AttackStart(target); else if(creature->isSummon()) { if(Unit *summoner = ((TempSummon*)creature)->GetSummoner()) { - if(summoner->getVictim() - && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(summoner->getVictim()))) - AttackStart(summoner->getVictim()); + Unit *target = summoner->getAttackerForHelper(); + if(!target && summoner->CanHaveThreatList() && !summoner->getThreatManager().isThreatListEmpty()) + target = summoner->getThreatManager().getHostilTarget(); + if(target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target))) + creature->AI()->AttackStart(target); } } } - if (!creature->CanHaveThreatList() || !creature->getVictim()) + if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim()) { - sLog.outError("DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? ((Creature*)creature)->GetEntry() : 0); + sLog.outError("DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry()); return; } Map::PlayerList const &PlayerList = map->GetPlayers(); for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { - if (Player* i_pl = i->getSource()) - if (i_pl->isAlive()) - { - creature->SetInCombatWith(i_pl); - i_pl->SetInCombatWith(creature); - creature->AddThreat(i_pl, 0.0f); - } + if (i->getSource()->isAlive()) + { + creature->SetInCombatWith(i->getSource()); + i->getSource()->SetInCombatWith(creature); + creature->AddThreat(i->getSource(), 0.0f); + } } } @@ -139,40 +106,222 @@ bool CreatureAI::UpdateVictim() return me->getVictim(); } -void CreatureAI::EnterEvadeMode() +bool CreatureAI::_EnterEvadeMode() { + if(me->IsInEvadeMode() || !me->isAlive()) + return false; + me->RemoveAllAuras(); me->DeleteThreatList(); - me->CombatStop(); + me->CombatStop(true); me->LoadCreaturesAddon(); me->SetLootRecipient(NULL); - if(me->isAlive()) + return true; +} + +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(); + + Reset(); +} + +inline bool SelectTargetHelper(const Unit * me, const Unit * target, const bool &playerOnly, const float &dist, const int32 &aura) +{ + if(playerOnly && target->GetTypeId() != TYPEID_PLAYER) + return false; + + if(dist && !me->IsWithinCombatRange(target, dist)) + return false; + + if(aura) + { + if(aura > 0) + { + if(!target->HasAura(aura)) + return false; + } + else + { + if(target->HasAura(aura)) + return false; + } + } + + return true; +} + +struct TargetDistanceOrder : public std::binary_function<const Unit *, const Unit *, bool> +{ + const Unit * me; + TargetDistanceOrder(const Unit* Target) : me(Target) {}; + // functor for operator ">" + bool operator()(const Unit * _Left, const Unit * _Right) const + { + return (me->GetDistanceSq(_Left) < me->GetDistanceSq(_Right)); + } +}; + +Unit* CreatureAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura) +{ + if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + { + std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList(); + if(position >= m_threatlist.size()) + return NULL; + + std::list<Unit*> targetList; + for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura)) + targetList.push_back((*itr)->getTarget()); + + if(position >= targetList.size()) + return NULL; + + targetList.sort(TargetDistanceOrder(m_creature)); + + if(targetType == SELECT_TARGET_NEAREST) + { + std::list<Unit*>::iterator i = targetList.begin(); + advance(i, position); + return *i; + } + else + { + std::list<Unit*>::reverse_iterator i = targetList.rbegin(); + advance(i, position); + return *i; + } + } + else + { + std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList(); + std::list<HostilReference*>::iterator i; + while(position < m_threatlist.size()) + { + if(targetType == SELECT_TARGET_BOTTOMAGGRO) + { + i = m_threatlist.end(); + advance(i, - (int32)position - 1); + } + else + { + i = m_threatlist.begin(); + if(targetType == SELECT_TARGET_TOPAGGRO) + advance(i, position); + else // random + advance(i, position + rand()%(m_threatlist.size() - position)); + } + + if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura)) + return (*i)->getTarget(); + else + m_threatlist.erase(i); + } + } + + return NULL; } -void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) +void CreatureAI::SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura) { - Creature *charmer = (Creature*)me->GetCharmer(); + if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + { + std::list<HostilReference*> &m_threatlist = m_creature->getThreatManager().getThreatList(); + if(m_threatlist.empty()) + return; + + for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura)) + targetList.push_back((*itr)->getTarget()); - //kill self if charm aura has infinite duration - if(charmer->IsInEvadeMode()) + targetList.sort(TargetDistanceOrder(me)); + targetList.resize(num); + if(targetType == SELECT_TARGET_FARTHEST) + targetList.reverse(); + } + else { - Unit::AuraEffectList const& auras = me->GetAurasByType(SPELL_AURA_MOD_CHARM); - for(Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetParentAura()->IsPermanent()) + std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList(); + std::list<HostilReference*>::iterator i; + while(!m_threatlist.empty() && num) + { + if(targetType == SELECT_TARGET_BOTTOMAGGRO) { - charmer->Kill(me); - return; + i = m_threatlist.end(); + --i; } + else + { + i = m_threatlist.begin(); + if(targetType == SELECT_TARGET_RANDOM) + advance(i, rand()%m_threatlist.size()); + } + + if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura)) + { + targetList.push_back((*i)->getTarget()); + --num; + } + m_threatlist.erase(i); + } } +} + +void CreatureAI::FillAISpellInfo() +{ + AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()]; - if(!charmer->isInCombat()) - me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + AISpellInfoType *AIInfo = AISpellInfo; + const SpellEntry * spellInfo; - Unit *target = me->getVictim(); - if(!target || !charmer->canAttack(target)) - AttackStart(charmer->SelectNearestTarget()); + for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo) + { + spellInfo = GetSpellStore()->LookupEntry(i); + if(!spellInfo) + continue; + + if(spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD) + AIInfo->condition = AICOND_DIE; + else if(IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1) + AIInfo->condition = AICOND_AGGRO; + else + AIInfo->condition = AICOND_COMBAT; + + if(AIInfo->cooldown < spellInfo->RecoveryTime) + AIInfo->cooldown = spellInfo->RecoveryTime; + + for(uint32 j = 0; j < 3; ++j) + { + if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY + || spellInfo->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY) + { + if(AIInfo->target < AITARGET_VICTIM) + AIInfo->target = AITARGET_VICTIM; + } + + if(spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA) + { + if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY) + { + if(AIInfo->target < AITARGET_DEBUFF) + AIInfo->target = AITARGET_DEBUFF; + } + else if(IsPositiveSpell(i)) + { + if(AIInfo->target < AITARGET_BUFF) + AIInfo->target = AITARGET_BUFF; + } + } + } + } } /*void CreatureAI::AttackedBy( Unit* attacker ) diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h index e3a5a674e68..c46dd2a54f2 100644 --- a/src/game/CreatureAI.h +++ b/src/game/CreatureAI.h @@ -21,23 +21,21 @@ #ifndef TRINITY_CREATUREAI_H #define TRINITY_CREATUREAI_H +#include "UnitAI.h" #include "Common.h" -#include "Platform/Define.h" -#include "Policies/Singleton.h" -#include "Dynamic/ObjectRegistry.h" -#include "Dynamic/FactoryHolder.h" class WorldObject; class Unit; class Creature; class Player; struct SpellEntry; +struct AISpellInfoType; #define TIME_INTERVAL_LOOK 5000 #define VISIBILITY_RANGE 10000 //Spell targets used by SelectSpell -enum SelectTarget +enum SelectTargetType { SELECT_TARGET_DONTCARE = 0, //All target types allowed @@ -77,120 +75,11 @@ enum SCEquip EQUIP_UNEQUIP = 0 }; -class EventMap : private std::map<uint32, uint32> -{ - private: - uint32 m_time, m_phase; - public: - explicit EventMap() : m_phase(0), m_time(0) {} - - void Reset() { clear(); m_time = 0; m_phase = 0; } - - void Update(uint32 time) { m_time += time; } - - void SetPhase(uint32 phase) - { - if(phase && phase < 9) - m_phase = (1 << (phase + 24)); - } - - void ScheduleEvent(uint32 eventId, uint32 time, uint32 gcd = 0, uint32 phase = 0) - { - time += m_time; - if(gcd && gcd < 9) - eventId |= (1 << (gcd + 16)); - if(phase && phase < 9) - eventId |= (1 << (phase + 24)); - iterator itr = find(time); - while(itr != end()) - { - ++time; - itr = find(time); - } - insert(std::make_pair(time, eventId)); - } - - uint32 ExecuteEvent() - { - while(!empty()) - { - if(begin()->first > m_time) - return 0; - else if(m_phase && (begin()->second & 0xFF000000) && !(begin()->second & m_phase)) - erase(begin()); - else - { - uint32 eventId = (begin()->second & 0x0000FFFF); - erase(begin()); - return eventId; - } - } - return 0; - } - - void DelayEvents(uint32 time, uint32 gcd) - { - time += m_time; - gcd = (1 << (gcd + 16)); - for(iterator itr = begin(); itr != end();) - { - if(itr->first >= time) - break; - if(itr->second & gcd) - { - ScheduleEvent(time, itr->second); - erase(itr++); - } - else - ++itr; - } - } -}; - -class TRINITY_DLL_SPEC UnitAI -{ - protected: - Unit* const me; - public: - explicit UnitAI(Unit *u) : me(u) {} - virtual void AttackStart(Unit *); - virtual void UpdateAI(const uint32 diff) = 0; - - virtual void InitializeAI() { Reset(); } - - virtual void Reset() {}; - - // Called when unit is charmed - virtual void OnCharmed(bool apply) = 0; - - // Pass parameters between AI - virtual void DoAction(const int32 param) {} - - //Do melee swing of current victim if in rnage and ready and not casting - void DoMeleeAttackIfReady(); -}; - -class TRINITY_DLL_SPEC PlayerAI : public UnitAI -{ - protected: - Player* const me; - public: - explicit PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {} - - void OnCharmed(bool apply); -}; - -class TRINITY_DLL_SPEC SimpleCharmedAI : public PlayerAI -{ - public: - void UpdateAI(const uint32 diff); -}; - class TRINITY_DLL_SPEC CreatureAI : public UnitAI { protected: - Creature* const me; - Creature* const m_creature; + Creature * const me; + Creature * const m_creature; bool UpdateVictim(); public: @@ -235,7 +124,7 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI //virtual void AttackedBy(Unit* attacker); // Called when creature is spawned or respawned (for reseting variables) - virtual void JustRespawned() {} + virtual void JustRespawned() { Reset(); } // Called at waypoint reached or point movement finished virtual void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) {} @@ -273,22 +162,15 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI // Pointer to controlled by AI creature //Creature* const m_creature; -}; - -struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature> -{ - - SelectableAI(const char *id) : FactoryHolder<CreatureAI>(id) {} -}; -template<class REAL_AI> -struct CreatureAIFactory : public SelectableAI -{ - CreatureAIFactory(const char *name) : SelectableAI(name) {} + Unit* SelectTarget(SelectAggroTarget target, uint32 position = 0, float dist = 0, bool playerOnly = false, int32 aura = 0); + void SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget target, float dist = 0, bool playerOnly = false, int32 aura = 0); - CreatureAI* Create(void *) const; + static AISpellInfoType *AISpellInfo; + static void FillAISpellInfo(); - int Permit(const Creature *c) const { return REAL_AI::Permissible(c); } + protected: + bool _EnterEvadeMode(); }; enum Permitions @@ -301,8 +183,4 @@ enum Permitions PERMIT_BASE_SPECIAL = 800 }; -typedef FactoryHolder<CreatureAI> CreatureAICreator; -typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry; -typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository; #endif - diff --git a/src/game/CreatureAIFactory.h b/src/game/CreatureAIFactory.h new file mode 100644 index 00000000000..d546c2b1720 --- /dev/null +++ b/src/game/CreatureAIFactory.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-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 + */ +#ifndef TRINITY_CREATUREAIFACTORY_H +#define TRINITY_CREATUREAIFACTORY_H + +//#include "Policies/Singleton.h" +#include "Dynamic/ObjectRegistry.h" +#include "Dynamic/FactoryHolder.h" + +struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature> +{ + SelectableAI(const char *id) : FactoryHolder<CreatureAI>(id) {} +}; + +template<class REAL_AI> +struct CreatureAIFactory : public SelectableAI +{ + CreatureAIFactory(const char *name) : SelectableAI(name) {} + + CreatureAI* Create(void *) const; + + int Permit(const Creature *c) const { return REAL_AI::Permissible(c); } +}; + +template<class REAL_AI> +inline CreatureAI* +CreatureAIFactory<REAL_AI>::Create(void *data) const +{ + Creature* creature = reinterpret_cast<Creature *>(data); + return (new REAL_AI(creature)); +} + +typedef FactoryHolder<CreatureAI> CreatureAICreator; +typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry; +typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository; +#endif diff --git a/src/game/CreatureAIImpl.h b/src/game/CreatureAIImpl.h index a8b8271c5ff..7edebb709fd 100644 --- a/src/game/CreatureAIImpl.h +++ b/src/game/CreatureAIImpl.h @@ -20,14 +20,156 @@ #ifndef CREATUREAIIMPL_H #define CREATUREAIIMPL_H -#include "CreatureAI.h" +#include "Common.h" +#include "Platform/Define.h" -template<class REAL_AI> -inline CreatureAI* -CreatureAIFactory<REAL_AI>::Create(void *data) const +#define HEROIC(n,h) (HeroicMode ? h : n) + +template<class T> +inline +const T& RAND(const T& v1, const T& v2) +{ + return rand()%2 ? v1 : v2; +} + +template<class T> +inline +const T& RAND(const T& v1, const T& v2, const T& v3) +{ + switch(rand()%3) + { + default: + case 0: return v1; + case 1: return v2; + case 2: return v3; + } +} + +template<class T> +inline +const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4) { - Creature* creature = reinterpret_cast<Creature *>(data); - return (new REAL_AI(creature)); + switch(rand()%4) + { + default: + case 0: return v1; + case 1: return v2; + case 2: return v3; + case 3: return v4; + } } + +template<class T> +inline +const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) +{ + switch(rand()%4) + { + default: + case 0: return v1; + case 1: return v2; + case 2: return v3; + case 3: return v4; + case 4: return v5; + } +} + +class EventMap : private std::map<uint32, uint32> +{ + private: + uint32 m_time, m_phase; + public: + explicit EventMap() : m_phase(0), m_time(0) {} + + void Reset() { clear(); m_time = 0; m_phase = 0; } + + void Update(uint32 time) { m_time += time; } + + void SetPhase(uint32 phase) + { + if(phase && phase < 9) + m_phase = (1 << (phase + 24)); + } + + void ScheduleEvent(uint32 eventId, uint32 time, uint32 gcd = 0, uint32 phase = 0) + { + time += m_time; + if(gcd && gcd < 9) + eventId |= (1 << (gcd + 16)); + if(phase && phase < 9) + eventId |= (1 << (phase + 24)); + iterator itr = find(time); + while(itr != end()) + { + ++time; + itr = find(time); + } + insert(std::make_pair(time, eventId)); + } + + uint32 ExecuteEvent() + { + while(!empty()) + { + if(begin()->first > m_time) + return 0; + else if(m_phase && (begin()->second & 0xFF000000) && !(begin()->second & m_phase)) + erase(begin()); + else + { + uint32 eventId = (begin()->second & 0x0000FFFF); + erase(begin()); + return eventId; + } + } + return 0; + } + + void DelayEvents(uint32 time, uint32 gcd) + { + time += m_time; + gcd = (1 << (gcd + 16)); + for(iterator itr = begin(); itr != end();) + { + if(itr->first >= time) + break; + if(itr->second & gcd) + { + ScheduleEvent(time, itr->second); + erase(itr++); + } + else + ++itr; + } + } +}; + +enum AITarget +{ + AITARGET_SELF, + AITARGET_VICTIM, + AITARGET_ENEMY, + AITARGET_ALLY, + AITARGET_BUFF, + AITARGET_DEBUFF, +}; + +enum AICondition +{ + AICOND_AGGRO, + AICOND_COMBAT, + AICOND_DIE, +}; + +#define AI_DEFAULT_COOLDOWN 5000 + +struct AISpellInfoType +{ + AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT), cooldown(AI_DEFAULT_COOLDOWN) {} + AITarget target; + AICondition condition; + uint32 cooldown; +}; + #endif diff --git a/src/game/CreatureAIRegistry.cpp b/src/game/CreatureAIRegistry.cpp index 6253c06b8bc..162ebd9b47c 100644 --- a/src/game/CreatureAIRegistry.cpp +++ b/src/game/CreatureAIRegistry.cpp @@ -23,16 +23,16 @@ #include "AggressorAI.h" #include "GuardAI.h" #include "PetAI.h" -#include "PossessedAI.h" #include "TotemAI.h" #include "OutdoorPvPObjectiveAI.h" #include "CreatureEventAI.h" #include "RandomMovementGenerator.h" -#include "CreatureAIImpl.h" #include "MovementGeneratorImpl.h" #include "CreatureAIRegistry.h" #include "WaypointMovementGenerator.h" +#include "CreatureAIFactory.h" +#include "CreatureAIImpl.h" namespace AIRegistry { void Initialize() @@ -46,7 +46,7 @@ namespace AIRegistry (new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf(); (new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf(); (new CreatureAIFactory<OutdoorPvPObjectiveAI>("OutdoorPvPObjectiveAI"))->RegisterSelf(); - (new CreatureAIFactory<PossessedAI>("PossessedAI"))->RegisterSelf(); + (new CreatureAIFactory<SpellAI>("SpellAI"))->RegisterSelf(); (new CreatureAIFactory<CreatureEventAI>("EventAI"))->RegisterSelf(); (new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf(); diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index a698d094e18..bac4f3a4973 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -19,7 +19,6 @@ */ #include "Creature.h" -#include "CreatureAIImpl.h" #include "CreatureAISelector.h" #include "NullCreatureAI.h" #include "Policies/SingletonImp.h" @@ -27,6 +26,7 @@ #include "ScriptCalls.h" #include "Pet.h" #include "TemporarySummon.h" +#include "CreatureAIFactory.h" INSTANTIATE_SINGLETON_1(CreatureAIRegistry); INSTANTIATE_SINGLETON_1(MovementGeneratorRegistry); @@ -69,6 +69,18 @@ namespace FactorySelector ai_factory = ai_registry.GetRegistryItem("CritterAI"); } + if(!ai_factory) + { + for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) + { + if(creature->m_spells[i]) + { + ai_factory = ai_registry.GetRegistryItem("SpellAI"); + break; + } + } + } + // select by permit check if(!ai_factory) { diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index fb7b7119860..5a84d43e80f 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -1054,14 +1054,7 @@ void CreatureEventAI::JustReachedHome() void CreatureEventAI::EnterEvadeMode() { - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); - - if (m_creature->isAlive()) - m_creature->GetMotionMaster()->MoveTargetedHome(); - - m_creature->SetLootRecipient(NULL); + CreatureAI::EnterEvadeMode(); if (bEmptyList) return; @@ -1295,13 +1288,10 @@ void CreatureEventAI::UpdateAI(const uint32 diff) break; case EVENT_T_RANGE: if (Combat) - { - if (m_creature->IsWithinDistInMap(m_creature->getVictim(),(float)(*i).Event.event_param2)) - { - if (m_creature->GetDistance(m_creature->getVictim()) >= (float)(*i).Event.event_param1) + if (m_creature->IsInMap(m_creature->getVictim())) + if (m_creature->IsInRange(m_creature->getVictim(), + (float)(*i).Event.event_param1,(float)(*i).Event.event_param2)) ProcessEvent(*i); - } - } break; } } @@ -1555,8 +1545,7 @@ bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Trigge return false; //Unit is out of range of this spell - if (me->GetDistance(Target) > me->GetSpellMaxRangeForTarget(Target, TempRange) - || me->GetDistance(Target) < me->GetSpellMinRangeForTarget(Target, TempRange)) + if (!m_creature->IsInRange(Target,TempRange->minRangeHostile,TempRange->maxRangeHostile)) return false; return true; diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h index 655c9967989..44ab34d7a11 100644 --- a/src/game/DBCEnums.h +++ b/src/game/DBCEnums.h @@ -48,7 +48,7 @@ enum AchievementFlags ACHIEVEMENT_FLAG_SUMM = 0x00000008, // Use summ criteria value from all reqirements (and calculate max value) ACHIEVEMENT_FLAG_MAX_USED = 0x00000010, // Show max criteria (and calculate max value ??) ACHIEVEMENT_FLAG_REQ_COUNT = 0x00000020, // Use not zero req count (and calculate max value) - ACHIEVEMENT_FLAG_AVERANGE = 0x00000040, // Show as averange value (value / time_in_days) depend from other flag (by def use last criteria value) + ACHIEVEMENT_FLAG_AVERAGE = 0x00000040, // Show as average value (value / time_in_days) depend from other flag (by def use last criteria value) ACHIEVEMENT_FLAG_BAR = 0x00000080, // Show as progress bar (value / max vale) depend from other flag (by def use last criteria value) ACHIEVEMENT_FLAG_REALM_FIRST_REACH = 0x00000100, // ACHIEVEMENT_FLAG_REALM_FIRST_KILL = 0x00000200, // diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index 8c8195c018b..d5078e8b408 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -1143,7 +1143,7 @@ struct RandomPropertiesPointsEntry struct ScalingStatDistributionEntry { uint32 Id; - uint32 StatMod[10]; + int32 StatMod[10]; uint32 Modifier[10]; uint32 MaxLevel; }; @@ -1152,7 +1152,58 @@ struct ScalingStatValuesEntry { uint32 Id; uint32 Level; - uint32 Multiplier[17]; + uint32 ssdMultiplier[5]; // Multiplier for ScalingStatDistribution + uint32 armorMod[4]; // Armor for level + uint32 dpsMod[6]; // DPS mod for level + uint32 spellBonus; // not sure.. TODO: need more info about + uint32 feralBonus; // Feral AP bonus + + uint32 getssdMultiplier(uint32 mask) const + { + if (mask&0x001F) + { + if(mask & 0x00000001) return ssdMultiplier[0]; + if(mask & 0x00000002) return ssdMultiplier[1]; + if(mask & 0x00000004) return ssdMultiplier[2]; + if(mask & 0x00000008) return ssdMultiplier[3]; + if(mask & 0x00000010) return ssdMultiplier[4]; + } + return 0; + } + uint32 getArmorMod(uint32 mask) const + { + if (mask&0x01E0) + { + if(mask & 0x00000020) return armorMod[0]; + if(mask & 0x00000040) return armorMod[1]; + if(mask & 0x00000080) return armorMod[2]; + if(mask & 0x00000100) return armorMod[3]; + } + return 0; + } + uint32 getDPSMod(uint32 mask) const + { + if (mask&0x7E00) + { + if(mask & 0x00000200) return dpsMod[0]; + if(mask & 0x00000400) return dpsMod[1]; + if(mask & 0x00000800) return dpsMod[2]; + if(mask & 0x00001000) return dpsMod[3]; + if(mask & 0x00002000) return dpsMod[4]; + if(mask & 0x00004000) return dpsMod[5]; + } + return 0; + } + uint32 getSpellBonus(uint32 mask) const + { + if (mask & 0x00008000) return spellBonus; + return 0; + } + uint32 getFeralBonus(uint32 mask) const + { + if (mask & 0x00010000) return feralBonus; + return 0; + } }; //struct SkillLineCategoryEntry{ @@ -1517,7 +1568,7 @@ struct TaxiNodesEntry float x; // 2 m_x float y; // 3 m_y float z; // 4 m_z - //char* name[16]; // 5-21 m_Name_lang + char* name[16]; // 5-21 m_Name_lang // 22 string flags uint32 MountCreatureID[2]; // 23-24 m_MountCreatureID[2] }; diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h index ea2198ef22c..170fd25dd9f 100644 --- a/src/game/DBCfmt.h +++ b/src/game/DBCfmt.h @@ -96,7 +96,7 @@ const char StableSlotPricesfmt[] = "ni"; const char SummonPropertiesfmt[] = "niiiii"; const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxxxx"; const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiiix"; -const char TaxiNodesEntryfmt[]="nifffxxxxxxxxxxxxxxxxxii"; +const char TaxiNodesEntryfmt[]="nifffssssssssssssssssxii"; const char TaxiPathEntryfmt[]="niii"; const char TaxiPathNodeEntryfmt[]="diiifffiixx"; const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii"; diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index 2f1014eb769..540ea1e0dd7 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -174,7 +174,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa //Normally non-players do not teleport to other maps. if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) { - ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this); + ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this, true); } return true; @@ -198,7 +198,7 @@ void GameObject::Update(uint32 /*p_time*/) { // Arming Time for GAMEOBJECT_TYPE_TRAP (6) Unit* owner = GetOwner(); - if (owner && ((Player*)owner)->isInCombat()) + if (owner && owner->isInCombat()) m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay; m_lootState = GO_READY; break; diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index 03d8ea11b16..a9925f67406 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -489,7 +489,7 @@ namespace Trinity void Visit(PlayerMapType &m) { for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if(itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->GetDistance(i_searcher) <= i_dist) + if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist)) i_do(itr->getSource()); } @@ -499,6 +499,53 @@ namespace Trinity // CHECKS && DO classes // WorldObject check classes + class RaiseDeadObjectCheck + { + public: + RaiseDeadObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} + bool operator()(Creature* u) + { + if (i_funit->GetTypeId()!=TYPEID_PLAYER || !((Player*)i_funit)->isHonorOrXPTarget(u) || + u->getDeathState() != CORPSE || u->isDeadByDefault() || u->isInFlight() || + ( u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1)) )==0 || + (u->GetDisplayId() != u->GetNativeDisplayId())) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } + private: + Unit* const i_funit; + float i_range; + }; + + class ExplodeCorpseObjectCheck + { + public: + ExplodeCorpseObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {} + bool operator()(Player* u) + { + if (u->getDeathState()!=CORPSE || u->isInFlight() || + u->HasAuraType(SPELL_AURA_GHOST) || (u->GetDisplayId() != u->GetNativeDisplayId())) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + bool operator()(Creature* u) + { + if (u->getDeathState()!=CORPSE || u->isInFlight() || u->isDeadByDefault() || + (u->GetDisplayId() != u->GetNativeDisplayId()) || + (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL)!=0) + return false; + + return i_funit->IsWithinDistInMap(u, i_range); + } + template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } + private: + Unit* const i_funit; + float i_range; + }; + class CannibalizeObjectCheck { public: @@ -508,22 +555,16 @@ namespace Trinity if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ) return false; - if(i_funit->IsWithinDistInMap(u, i_range) ) - return true; - - return false; + return i_funit->IsWithinDistInMap(u, i_range); } bool operator()(Corpse* u); bool operator()(Creature* u) { - if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || + if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() || (u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD)==0) return false; - if(i_funit->IsWithinDistInMap(u, i_range) ) - return true; - - return false; + return i_funit->IsWithinDistInMap(u, i_range); } template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; } private: diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h index 7726d5647bd..12f3706c4e2 100644 --- a/src/game/GridNotifiersImpl.h +++ b/src/game/GridNotifiersImpl.h @@ -178,8 +178,11 @@ inline void Trinity::DynamicObjectUpdater::VisitHelper(Unit* target) if (i_dynobject.IsAffecting(target)) return; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_dynobject.GetSpellId()); uint32 eff_index = i_dynobject.GetEffIndex(); + if(target->HasAuraEffect(i_dynobject.GetSpellId(), eff_index, i_check->GetGUID())) + return; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_dynobject.GetSpellId()); if(spellInfo->EffectImplicitTargetB[eff_index] == TARGET_DEST_DYNOBJ_ALLY || spellInfo->EffectImplicitTargetB[eff_index] == TARGET_UNIT_AREA_ALLY_DST) { @@ -205,7 +208,9 @@ inline void Trinity::DynamicObjectUpdater::VisitHelper(Unit* target) if (target->IsImmunedToSpell(spellInfo) || target->IsImmunedToSpellEffect(spellInfo, eff_index)) return; // Apply PersistentAreaAura on target - target->AddAuraEffect(spellInfo->Id, eff_index, i_dynobject.GetCaster()); + if(Aura *aur = target->AddAuraEffect(spellInfo, eff_index, i_dynobject.GetCaster())) + aur->SetAuraDuration(i_dynobject.GetDuration()); + i_dynobject.AddAffected(target); } diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 02fc72f2022..d2c17680e52 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -571,7 +571,7 @@ void Group::GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature) continue; if ( i->AllowedForPlayer(member) ) { - if (member->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (member->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { r->playerVote[member->GetGUID()] = NOT_EMITED_YET; ++r->totalPlayersRolling; @@ -621,7 +621,7 @@ void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *crea if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) ) { - if (playerToRoll->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (playerToRoll->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; ++r->totalPlayersRolling; @@ -669,7 +669,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat if (!looter->IsInWorld()) continue; - if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { data << looter->GetGUID(); ++real_count; @@ -681,7 +681,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { Player *looter = itr->getSource(); - if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) looter->GetSession()->SendPacket(&data); } } @@ -1338,7 +1338,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed ) { // not update if only update if need and ok Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid); - if(looter && looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if(looter && looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) return; } ++guid_itr; @@ -1351,7 +1351,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed ) { if(Player* pl = ObjectAccessor::FindPlayer(itr->guid)) { - if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { bool refresh = pl->GetLootGUID()==creature->GetGUID(); @@ -1372,7 +1372,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed ) { if(Player* pl = ObjectAccessor::FindPlayer(itr->guid)) { - if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { bool refresh = pl->GetLootGUID()==creature->GetGUID(); diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index b0094989e19..cd7004f5a07 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -78,6 +78,12 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) return; } + // restrict invite to GMs + if (!sWorld.getConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->isGameMaster() && player->isGameMaster()) + { + SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_CANT_FIND_TARGET); + return; + } // can't group with if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam()) { diff --git a/src/game/GuardAI.cpp b/src/game/GuardAI.cpp index b716642ebd7..b7268758583 100644 --- a/src/game/GuardAI.cpp +++ b/src/game/GuardAI.cpp @@ -126,7 +126,7 @@ void GuardAI::UpdateAI(const uint32 /*diff*/) bool GuardAI::IsVisible(Unit *pl) const { - return m_creature->GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER) + return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) && pl->isVisibleForOrDetect(m_creature,true); } diff --git a/src/game/InstanceData.cpp b/src/game/InstanceData.cpp index 92e4b4afe3d..96c10f7b85c 100644 --- a/src/game/InstanceData.cpp +++ b/src/game/InstanceData.cpp @@ -26,8 +26,9 @@ void InstanceData::SaveToDB() { - if(!Save()) return; - std::string data = Save(); + std::string data = GetSaveData(); + if(data.empty()) + return; CharacterDatabase.escape_string(data); CharacterDatabase.PExecute("UPDATE instance SET data = '%s' WHERE id = '%d'", data.c_str(), instance->GetInstanceId()); } @@ -57,42 +58,66 @@ void InstanceData::OnCreatureCreate(Creature *creature, bool add) OnCreatureCreate(creature, creature->GetEntry()); } -void InstanceData::SetBossRoomDoor(uint32 id, GameObject *door, bool add) +void InstanceData::LoadDoorData(const DoorData *data) { - if(id < bosses.size()) + while(data->entry) { - if(add) + if(data->bossId < bosses.size()) + doors.insert(std::make_pair(data->entry, DoorInfo(&bosses[data->bossId], data->type))); + + ++data; + } + sLog.outDebug("InstanceData::LoadDoorData: %u doors loaded.", doors.size()); +} + +void InstanceData::UpdateDoorState(GameObject *door) +{ + DoorInfoMap::iterator lower = doors.lower_bound(door->GetEntry()); + DoorInfoMap::iterator upper = doors.upper_bound(door->GetEntry()); + if(lower == upper) + return; + + bool open = true; + for(DoorInfoMap::iterator itr = lower; itr != upper; ++itr) + { + if(itr->second.type == DOOR_TYPE_ROOM) { - BossInfo *bossInfo = &bosses[id]; - bossInfo->roomDoor.insert(door); - // Room door is only closed when encounter is in progress - if(bossInfo->state == IN_PROGRESS) - door->SetGoState(GO_STATE_READY); - else - door->SetGoState(GO_STATE_ACTIVE); + if(itr->second.bossInfo->state == IN_PROGRESS) + { + open = false; + break; + } + } + else if(itr->second.type == DOOR_TYPE_PASSAGE) + { + if(itr->second.bossInfo->state != DONE) + { + open = false; + break; + } } - else - bosses[id].roomDoor.erase(door); } + + door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY); } -void InstanceData::SetBossPassageDoor(uint32 id, GameObject *door, bool add) +void InstanceData::AddDoor(GameObject *door, bool add) { - if(id < bosses.size()) + DoorInfoMap::iterator lower = doors.lower_bound(door->GetEntry()); + DoorInfoMap::iterator upper = doors.upper_bound(door->GetEntry()); + if(lower == upper) + return; + + for(DoorInfoMap::iterator itr = lower; itr != upper; ++itr) { if(add) - { - BossInfo *bossInfo = &bosses[id]; - bossInfo->passageDoor.insert(door); - // Passage door is only opened when boss is defeated - if(bossInfo->state == DONE) - door->SetGoState(GO_STATE_ACTIVE); - else - door->SetGoState(GO_STATE_READY); - } + itr->second.bossInfo->door[itr->second.type].insert(door); else - bosses[id].passageDoor.erase(door); + itr->second.bossInfo->door[itr->second.type].erase(door); } + + if(add) + UpdateDoorState(door); } void InstanceData::SetBossState(uint32 id, EncounterState state) @@ -100,33 +125,41 @@ void InstanceData::SetBossState(uint32 id, EncounterState state) if(id < bosses.size()) { BossInfo *bossInfo = &bosses[id]; - bossInfo->state = state; - switch(state) + if(bossInfo->state == TO_BE_DECIDED) // loading + bossInfo->state = state; + else { - case NOT_STARTED: - // Open all room doors, close all passage doors - for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i) - (*i)->SetGoState(GO_STATE_ACTIVE); - for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i) - (*i)->SetGoState(GO_STATE_READY); - break; - case IN_PROGRESS: - // Close all doors - for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i) - (*i)->SetGoState(GO_STATE_READY); - for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i) - (*i)->SetGoState(GO_STATE_READY); - break; - case DONE: - // Open all doors - for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i) - (*i)->SetGoState(GO_STATE_ACTIVE); - for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i) - (*i)->SetGoState(GO_STATE_ACTIVE); - break; - default: - break; + if(bossInfo->state == state) + return; + bossInfo->state = state; + SaveToDB(); } + + for(uint32 type = 0; type < MAX_DOOR_TYPES; ++type) + for(DoorSet::iterator i = bossInfo->door[type].begin(); i != bossInfo->door[type].end(); ++i) + UpdateDoorState(*i); } } +std::string InstanceData::LoadBossState(const char * data) +{ + if(!data) return NULL; + std::istringstream loadStream(data); + uint32 buff; + uint32 bossId = 0; + for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i, ++bossId) + { + loadStream >> buff; + if(buff < TO_BE_DECIDED) + SetBossState(bossId, (EncounterState)buff); + } + return loadStream.str(); +} + +std::string InstanceData::GetBossSaveData() +{ + std::ostringstream saveStream; + for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i) + saveStream << (uint32)i->state << " "; + return saveStream.str(); +} diff --git a/src/game/InstanceData.h b/src/game/InstanceData.h index 2d7e5f84746..91f589384a0 100644 --- a/src/game/InstanceData.h +++ b/src/game/InstanceData.h @@ -37,16 +37,40 @@ enum EncounterState IN_PROGRESS = 1, FAIL = 2, DONE = 3, - SPECIAL = 4 + SPECIAL = 4, + TO_BE_DECIDED = 5, }; typedef std::set<GameObject*> DoorSet; +enum DoorType +{ + DOOR_TYPE_ROOM = 0, + DOOR_TYPE_PASSAGE, + MAX_DOOR_TYPES, +}; + struct BossInfo { - BossInfo() : state(NOT_STARTED) {} + BossInfo() : state(TO_BE_DECIDED) {} EncounterState state; - DoorSet roomDoor, passageDoor; + DoorSet door[MAX_DOOR_TYPES]; +}; + +struct DoorInfo +{ + explicit DoorInfo(BossInfo *_bossInfo, DoorType _type) + : bossInfo(_bossInfo), type(_type) {} + BossInfo *bossInfo; + DoorType type; +}; + +typedef std::multimap<uint32 /*entry*/, DoorInfo> DoorInfoMap; + +struct DoorData +{ + uint32 entry, bossId; + DoorType type; }; class TRINITY_DLL_SPEC InstanceData @@ -62,10 +86,10 @@ class TRINITY_DLL_SPEC InstanceData virtual void Initialize() {} //On load - virtual void Load(const char* /*data*/) {} + virtual void Load(const char * data) { LoadBossState(data); } //When save is needed, this function generates the data - virtual const char* Save() { return ""; } + virtual std::string GetSaveData() { return GetBossSaveData(); } void SaveToDB(); @@ -80,15 +104,10 @@ class TRINITY_DLL_SPEC InstanceData virtual void OnPlayerEnter(Player *) {} //Called when a gameobject is created - virtual void OnObjectCreate(GameObject *go, bool add) - { - OnObjectCreate(go); - } - virtual void OnObjectCreate(GameObject *) {} + virtual void OnObjectCreate(GameObject *go, bool add) { OnObjectCreate(go); } //called on creature creation virtual void OnCreatureCreate(Creature *, bool add); - virtual void OnCreatureCreate(Creature *, uint32 entry) {} //All-purpose data storage 64 bit virtual uint64 GetData64(uint32 /*Data*/) { return 0; } @@ -103,23 +122,22 @@ class TRINITY_DLL_SPEC InstanceData //use HandleGameObject(GUID,boolen,NULL); in any other script void HandleGameObject(uint64 GUID, bool open, GameObject *go = NULL); - void SetBossState(uint32 id, EncounterState state); + virtual void SetBossState(uint32 id, EncounterState state); protected: - void SetBossNumber(uint32 number) { bosses.resize(number); } - void SetBossRoomDoor(uint32 id, GameObject *door, bool add); - void SetBossPassageDoor(uint32 id, GameObject *door, bool add); + void LoadDoorData(const DoorData *data); - std::string GetBossSave() - { - std::ostringstream saveStream; - for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i) - saveStream << (uint32)i->state << " "; - return saveStream.str(); - } + void SetBossNumber(uint32 number) { bosses.resize(number); } + void AddDoor(GameObject *door, bool add); + void UpdateDoorState(GameObject *door); + std::string LoadBossState(const char * data); + std::string GetBossSaveData(); private: std::vector<BossInfo> bosses; + DoorInfoMap doors; + virtual void OnObjectCreate(GameObject *) {} + virtual void OnCreatureCreate(Creature *, uint32 entry) {} }; #endif diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp index 9332f4b8f0a..7e2ad67c518 100644 --- a/src/game/InstanceSaveMgr.cpp +++ b/src/game/InstanceSaveMgr.cpp @@ -40,6 +40,8 @@ #include "Group.h" #include "InstanceData.h" #include "ProgressBar.h" +#include "Policies/Singleton.h" +#include "Policies/SingletonImp.h" INSTANTIATE_SINGLETON_1( InstanceSaveManager ); @@ -163,11 +165,11 @@ void InstanceSave::SaveToDB() if(map) { assert(map->IsDungeon()); - InstanceData *iData = ((InstanceMap *)map)->GetInstanceData(); - if(iData && iData->Save()) + if(InstanceData *iData = ((InstanceMap*)map)->GetInstanceData()) { - data = iData->Save(); - CharacterDatabase.escape_string(data); + data = iData->GetSaveData(); + if(!data.empty()) + CharacterDatabase.escape_string(data); } } diff --git a/src/game/InstanceSaveMgr.h b/src/game/InstanceSaveMgr.h index 2a913e5cedf..29972210f3d 100644 --- a/src/game/InstanceSaveMgr.h +++ b/src/game/InstanceSaveMgr.h @@ -24,7 +24,7 @@ #include "Platform/Define.h" #include "Policies/Singleton.h" -#include "zthread/Mutex.h" +#include "ace/Thread_Mutex.h" #include <list> #include <map> #include "Utilities/UnorderedMap.h" @@ -113,7 +113,7 @@ class InstanceSave bool m_canReset; }; -class TRINITY_DLL_DECL InstanceSaveManager : public Trinity::Singleton<InstanceSaveManager, Trinity::ClassLevelLockable<InstanceSaveManager, ZThread::Mutex> > +class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSaveManager, MaNGOS::ClassLevelLockable<InstanceSaveManager, ACE_Thread_Mutex> > { friend class InstanceSave; public: diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h index f87e52b2e22..e7a37dc8e14 100644 --- a/src/game/ItemPrototype.h +++ b/src/game/ItemPrototype.h @@ -600,46 +600,6 @@ struct ItemPrototype return false; } - uint32 GetScalingStatValuesColumn() const - { - if(ScalingStatValue & 0x00000001) // stat mod - return 0; - if(ScalingStatValue & 0x00000002) // stat mod - return 1; - if(ScalingStatValue & 0x00000004) // stat mod - return 2; - if(ScalingStatValue & 0x00000008) // stat mod - return 3; - if(ScalingStatValue & 0x00000010) // stat mod - return 4; - if(ScalingStatValue & 0x00000020) // armor mod - return 5; - if(ScalingStatValue & 0x00000040) // armor mod - return 6; - if(ScalingStatValue & 0x00000080) // armor mod - return 7; - if(ScalingStatValue & 0x00000100) // armor mod - return 8; - if(ScalingStatValue & 0x00000200) // damage mod - return 9; - if(ScalingStatValue & 0x00000400) // damage mod - return 10; - if(ScalingStatValue & 0x00000800) // damage mod - return 11; - if(ScalingStatValue & 0x00001000) // damage mod - return 12; - if(ScalingStatValue & 0x00002000) // damage mod - return 13; - if(ScalingStatValue & 0x00004000) // damage mod - return 14; - if(ScalingStatValue & 0x00008000) // spell power - return 15; - if(ScalingStatValue & 0x00020000) // feral AP - return 16; - - return 0; - } - uint32 GetMaxStackSize() const { return Stackable > 0 ? uint32(Stackable) : uint32(0x7FFFFFFF-1); } float getDPS() const @@ -652,12 +612,12 @@ struct ItemPrototype return temp*500/Delay; } - int32 getFeralBonus() const + int32 getFeralBonus(int32 extraDPS = 0) const { // 0x02A5F3 - is mask for Melee weapon from ItemSubClassMask.dbc if (Class == ITEM_CLASS_WEAPON && (1<<SubClass)&0x02A5F3) { - int32 bonus = int32(getDPS()*14.0f) - 767; + int32 bonus = int32((extraDPS + getDPS())*14.0f) - 767; if (bonus < 0) return 0; return bonus; diff --git a/src/game/Language.h b/src/game/Language.h index 69bfbf00159..8bc01a7deea 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -328,7 +328,8 @@ enum TrinityStrings LANG_YOU_ALREADY_HAVE_PET = 344, LANG_CUSTOMIZE_PLAYER = 345, LANG_CUSTOMIZE_PLAYER_GUID = 346, - // Room for more level 2 345-399 not used + LANG_COMMAND_GOTAXINODENOTFOUND = 347, + // Room for more level 2 348-399 not used // level 3 chat LANG_SCRIPTS_RELOADED = 400, @@ -403,8 +404,7 @@ enum TrinityStrings LANG_COMMAND_TP_ADDED = 463, LANG_COMMAND_TP_ADDEDERR = 464, LANG_COMMAND_TP_DELETED = 465, - // 466, // not used - + LANG_COMMAND_NOTAXINODEFOUND = 466, LANG_COMMAND_TARGET_LISTAURAS = 467, LANG_COMMAND_TARGET_AURADETAIL = 468, LANG_COMMAND_TARGET_LISTAURATYPE = 469, @@ -765,7 +765,9 @@ enum TrinityStrings LANG_COMMAND_LEARN_PET_TALENTS = 1125, LANG_RESET_PET_TALENTS = 1126, LANG_RESET_PET_TALENTS_ONLINE = 1127, - // Room for more level 3 1128-1199 not used + LANG_TAXINODE_ENTRY_LIST_CHAT = 1128, + LANG_TAXINODE_ENTRY_LIST_CONSOLE = 1129, + // Room for more level 3 1130-1199 not used // Debug commands LANG_CINEMATIC_NOT_EXIST = 1200, diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 963e79f8829..45137c5b214 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -2091,12 +2091,12 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args) uint32 moneyuser = chr->GetMoney(); - if(addmoney < 0) + if (addmoney < 0) { - int32 newmoney = moneyuser + addmoney; + int32 newmoney = int32(moneyuser) + addmoney; sLog.outDetail(GetTrinityString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney); - if(newmoney <= 0 ) + if (newmoney <= 0 ) { PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, GetNameLink(chr).c_str()); if (needReportToTarget(chr)) @@ -2106,6 +2106,9 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args) } else { + if (newmoney > MAX_MONEY_AMOUNT) + newmoney = MAX_MONEY_AMOUNT; + PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), GetNameLink(chr).c_str()); if (needReportToTarget(chr)) ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, GetNameLink().c_str(), abs(addmoney)); @@ -2117,7 +2120,11 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args) PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, GetNameLink(chr).c_str()); if (needReportToTarget(chr)) ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, GetNameLink().c_str(), addmoney); - chr->ModifyMoney( addmoney ); + + if (addmoney >=MAX_MONEY_AMOUNT) + chr->SetMoney(MAX_MONEY_AMOUNT); + else + chr->ModifyMoney( addmoney ); } sLog.outDetail(GetTrinityString(LANG_NEW_MONEY), moneyuser, addmoney, chr->GetMoney() ); @@ -2753,6 +2760,51 @@ bool ChatHandler::HandleGroupgoCommand(const char* args) return true; } +bool ChatHandler::HandleGoTaxinodeCommand(const char* args) +{ + Player* _player = m_session->GetPlayer(); + + if (!*args) + return false; + + char* cNodeId = extractKeyFromLink((char*)args,"Htaxinode"); + if (!cNodeId) + return false; + + int32 i_nodeId = atoi(cNodeId); + if (!i_nodeId) + return false; + + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i_nodeId); + if (!node) + { + PSendSysMessage(LANG_COMMAND_GOTAXINODENOTFOUND,i_nodeId); + SetSentErrorMessage(true); + return false; + } + + if (node->x == 0.0f && node->y == 0.0f && node->z == 0.0f || + !MapManager::IsValidMapCoord(node->map_id,node->x,node->y,node->z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,node->x,node->y,node->map_id); + SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (_player->isInFlight()) + { + _player->GetMotionMaster()->MovementExpired(); + _player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + _player->SaveRecallPosition(); + + _player->TeleportTo(node->map_id, node->x, node->y, node->z, _player->GetOrientation()); + return true; +} + //teleport at coordinates bool ChatHandler::HandleGoXYCommand(const char* args) { diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index bc83aa7a352..782b0f9c44e 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -1288,7 +1288,7 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args) // update movement type WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid); - if(pCreature && pCreature->GetWaypointPath()) + if(pCreature && pCreature->GetWaypointPathId()) { pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); pCreature->GetMotionMaster()->Initialize(); @@ -1609,7 +1609,7 @@ bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args) { // update movement type if(doNotDelete == false) - pCreature->LoadPath(0); + pCreature->SetWaypointPathId(0); pCreature->SetDefaultMovementType(move_type); pCreature->GetMotionMaster()->Initialize(); @@ -2639,7 +2639,7 @@ bool ChatHandler::HandleWpAddCommand(const char* args) if (!path_number) { if(target) - pathid = target->GetWaypointPath(); + pathid = target->GetWaypointPathId(); else { QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(id) FROM waypoint_data"); @@ -2694,7 +2694,6 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args) if(*args) path_number = strtok((char*)args, " "); - uint32 pathid = 0; uint32 guidlow = 0; Creature* target = getSelectedCreature(); @@ -2725,6 +2724,7 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args) return true; } + /* guidlow = target->GetDBTableGUIDLow(); QueryResult *result = WorldDatabase.PQuery( "SELECT guid FROM creature_addon WHERE guid = '%u'",guidlow); @@ -2735,10 +2735,11 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args) } else WorldDatabase.PExecute("INSERT INTO creature_addon(guid,path_id) VALUES ('%u','%u')", guidlow, pathid); + */ WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE, guidlow); - target->LoadPath(pathid); + target->SetWaypointPathId(pathid); target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); target->GetMotionMaster()->Initialize(); target->MonsterSay("Path loaded.",0,0); @@ -2746,20 +2747,19 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args) return true; } - bool ChatHandler::HandleReloadAllPaths(const char* args) { -if(!*args) - return false; + if(!*args) + return false; -uint32 id = atoi(args); + uint32 id = atoi(args); -if(!id) - return false; + if(!id) + return false; PSendSysMessage("%s%s|r|cff00ffff%u|r", "|cff00ff00", "Loading Path: ", id); WaypointMgr.UpdatePath(id); - return true; + return true; } bool ChatHandler::HandleWpUnLoadPathCommand(const char *args) @@ -2773,24 +2773,39 @@ bool ChatHandler::HandleWpUnLoadPathCommand(const char *args) return true; } - if(target->GetCreatureAddon()) + if(target->GetWaypointPathId()) { - if(target->GetCreatureAddon()->path_id != 0) + uint32 pathId = target->GetDBTableGUIDLow() * 10; + if(target->GetWaypointPathId() == pathId) { - WorldDatabase.PExecute("DELETE FROM creature_addon WHERE guid = %u", target->GetGUIDLow()); - target->UpdateWaypointID(0); - WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow); - target->LoadPath(0); - target->SetDefaultMovementType(IDLE_MOTION_TYPE); - target->GetMotionMaster()->MoveTargetedHome(); - target->GetMotionMaster()->Initialize(); - target->MonsterSay("Path unloaded.",0,0); - return true; + for(uint32 i = 1; i < 11; ++i) + { + if(i == 10) + { + PSendSysMessage("%s%s|r", "|cffff33ff", "Target cannot have more than 9 script paths. Unloading failed."); + break; + } + + if(WaypointMgr.GetPath(++pathId)) + continue; + + WorldDatabase.PExecute("UPDATE waypoint_data SET id = %u WHERE id = %u", pathId, target->GetDBTableGUIDLow() * 10); + WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow); + target->SetWaypointPathId(0); + target->UpdateWaypointID(0); + target->SetDefaultMovementType(IDLE_MOTION_TYPE); + target->GetMotionMaster()->Initialize(); + target->GetMotionMaster()->MoveTargetedHome(); + PSendSysMessage("Path unloaded."); + break; + } } - PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path."); - return true; + else + PSendSysMessage("%s%s|r", "|cffff33ff", "Target has path but that path is not its default path. Unloading failed."); } - PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path."); + else + PSendSysMessage("%s%s|r", "|cffff33ff", "Target has no loaded path."); + return true; } @@ -3264,7 +3279,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args) return false; } - pathid = target->GetWaypointPath(); + pathid = target->GetWaypointPathId(); } else @@ -4629,7 +4644,7 @@ bool ChatHandler::HandleNpcAddFormationCommand(const char* args) group_member->groupAI = 0; CreatureGroupMap[lowguid] = group_member; - pCreature->SearchFormation(); + pCreature->SearchFormationAndPath(); WorldDatabase.PExecuteLog("INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES ('%u','%u','%f', '%f', '%u')", leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 474a79c5680..9d43c348831 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -1612,11 +1612,7 @@ bool ChatHandler::HandleCooldownCommand(const char* args) return false; } - WorldPacket data( SMSG_CLEAR_COOLDOWN, (4+8) ); - data << uint32(spell_id); - data << uint64(target->GetGUID()); - target->GetSession()->SendPacket(&data); - target->RemoveSpellCooldown(spell_id); + target->RemoveSpellCooldown(spell_id,true); PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : tNameLink.c_str()); } return true; @@ -3694,6 +3690,68 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args) return true; } +bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args) +{ + if(!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if(!Utf8toWStr(namepart,wnamepart)) + return false; + + // converting string that we try to find to lower case + wstrToLower( wnamepart ); + + uint32 counter = 0; // Counter for figure out that we found smth. + + // Search in TaxiNodes.dbc + for (uint32 id = 0; id < sTaxiNodesStore.GetNumRows(); id++) + { + TaxiNodesEntry const *nodeEntry = sTaxiNodesStore.LookupEntry(id); + if(nodeEntry) + { + int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale(); + std::string name = nodeEntry->name[loc]; + if(name.empty()) + continue; + + if (!Utf8FitTo(name, wnamepart)) + { + loc = 0; + for(; loc < MAX_LOCALE; ++loc) + { + if(m_session && loc==m_session->GetSessionDbcLocale()) + continue; + + name = nodeEntry->name[loc]; + if(name.empty()) + continue; + + if (Utf8FitTo(name, wnamepart)) + break; + } + } + + if(loc < MAX_LOCALE) + { + // send taxinode in "id - [name] (Map:m X:x Y:y Z:z)" format + if (m_session) + PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CHAT, id, id, name.c_str(),localeNames[loc], + nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z); + else + PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CONSOLE, id, name.c_str(), localeNames[loc], + nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z); + ++counter; + } + } + } + if (counter == 0) // if counter == 0 then we found nth + SendSysMessage(LANG_COMMAND_NOSPELLFOUND); + return true; +} + /** \brief GM command level 3 - Create a guild. * * This command allows a GM (level 3) to create a guild. @@ -3966,31 +4024,34 @@ bool ChatHandler::HandleDamageCommand(const char * args) Unit* target = getSelectedUnit(); - if(!target || !m_session->GetPlayer()->GetSelection()) + if (!target || !m_session->GetPlayer()->GetSelection()) { SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); SetSentErrorMessage(true); return false; } - if( !target->isAlive() ) + if (!target->isAlive()) return true; char* damageStr = strtok((char*)args, " "); - if(!damageStr) + if (!damageStr) return false; - int32 damage = atoi((char*)damageStr); - if(damage <=0) + int32 damage_int = atoi((char*)damageStr); + if(damage_int <=0) return true; + uint32 damage = damage_int; + char* schoolStr = strtok((char*)NULL, " "); // flat melee damage without resistence/etc reduction - if(!schoolStr) + if (!schoolStr) { m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0); + if (target != m_session->GetPlayer()) + m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0); return true; } @@ -4006,7 +4067,7 @@ bool ChatHandler::HandleDamageCommand(const char * args) char* spellStr = strtok((char*)NULL, " "); // melee damage by specific school - if(!spellStr) + if (!spellStr) { uint32 absorb = 0; uint32 resist = 0; @@ -4018,6 +4079,7 @@ bool ChatHandler::HandleDamageCommand(const char * args) damage -= absorb + resist; + m_session->GetPlayer()->DealDamageMods(target,damage,&absorb); m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false); m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0); return true; @@ -4027,7 +4089,7 @@ bool ChatHandler::HandleDamageCommand(const char * args) // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form uint32 spellid = extractSpellIdFromLink((char*)args); - if(!spellid || !sSpellStore.LookupEntry(spellid)) + if (!spellid || !sSpellStore.LookupEntry(spellid)) return false; m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage); diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp index f8e2a6cde15..172a6ef46c2 100644 --- a/src/game/LootHandler.cpp +++ b/src/game/LootHandler.cpp @@ -224,7 +224,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ ) Player* playerGroup = itr->getSource(); if(!playerGroup) continue; - if (player->GetDistance2d(playerGroup) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (player->IsWithinDist(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) playersNear.push_back(playerGroup); } diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 3884f39f5a4..140904bfb19 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -120,7 +120,7 @@ void Map::LoadVMap(int gx,int gy) } } -void Map::LoadMap(int gx,int gy) +void Map::LoadMap(int gx,int gy, bool reload) { if( i_InstanceId != 0 ) { @@ -138,6 +138,9 @@ void Map::LoadMap(int gx,int gy) return; } + if(GridMaps[gx][gy] && !reload) + return; + //map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?) if(GridMaps[gx][gy]) { @@ -2503,7 +2506,7 @@ void InstanceMap::CreateInstanceData(bool load) { Field* fields = result->Fetch(); const char* data = fields[0].GetString(); - if(data) + if(data && data != "") { sLog.outDebug("Loading instance data for `%s` with id %u", objmgr.GetScriptName(i_script_id), i_InstanceId); i_data->Load(data); diff --git a/src/game/Map.h b/src/game/Map.h index d85eb459171..c69fe5f7345 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -23,9 +23,9 @@ #include "Platform/Define.h" #include "Policies/ThreadingModel.h" -#include "zthread/Lockable.h" -#include "zthread/Mutex.h" -#include "zthread/FairReadWriteLock.h" +#include "ace/RW_Thread_Mutex.h" +#include "ace/Thread_Mutex.h" + #include "DBCStructure.h" #include "GridDefines.h" #include "Cell.h" @@ -46,13 +46,8 @@ class WorldObject; class TempSummon; class CreatureGroup; -namespace ZThread -{ - class Lockable; - class ReadWriteLock; -} -typedef ZThread::FairReadWriteLock GridRWLock; +typedef ACE_RW_Thread_Mutex GridRWLock; template<class MUTEX, class LOCK_TYPE> struct RGuard @@ -68,9 +63,9 @@ struct WGuard Trinity::GeneralLock<LOCK_TYPE> i_lock; }; -typedef RGuard<GridRWLock, ZThread::Lockable> GridReadGuard; -typedef WGuard<GridRWLock, ZThread::Lockable> GridWriteGuard; -typedef Trinity::SingleThreaded<GridRWLock>::Lock NullGuard; +typedef RGuard<GridRWLock, ACE_Thread_Mutex> GridReadGuard; +typedef WGuard<GridRWLock, ACE_Thread_Mutex> GridWriteGuard; +typedef MaNGOS::SingleThreaded<GridRWLock>::Lock NullGuard; //****************************************** // Map file format defines @@ -251,7 +246,7 @@ typedef UNORDERED_MAP<Creature*, CreatureMover> CreatureMoveList; typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType; -class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::ObjectLevelLockable<Map, ZThread::Mutex> +class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex> { friend class MapReference; public: @@ -426,7 +421,7 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O private: void LoadMapAndVMap(int gx, int gy); void LoadVMap(int gx, int gy); - void LoadMap(int gx,int gy); + void LoadMap(int gx,int gy, bool reload = false); GridMap *GetGrid(float x, float y); void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } @@ -466,7 +461,7 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O protected: void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } - typedef Trinity::ObjectLevelLockable<Map, ZThread::Mutex>::Lock Guard; + typedef MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex>::Lock Guard; MapEntry const* i_mapEntry; uint8 i_spawnMode; diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 061e0252a13..d75ba22b19a 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -34,9 +34,9 @@ #include "ObjectMgr.h" #include "Language.h" -#define CLASS_LOCK Trinity::ClassLevelLockable<MapManager, ZThread::Mutex> +#define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex> INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK); -INSTANTIATE_CLASS_MUTEX(MapManager, ZThread::Mutex); +INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Thread_Mutex); extern GridState* si_GridStates[]; // debugging code, should be deleted some day diff --git a/src/game/MapManager.h b/src/game/MapManager.h index 143248de162..b54c1cfbfa1 100644 --- a/src/game/MapManager.h +++ b/src/game/MapManager.h @@ -23,14 +23,14 @@ #include "Platform/Define.h" #include "Policies/Singleton.h" -#include "zthread/Mutex.h" +#include "ace/Thread_Mutex.h" #include "Common.h" #include "Map.h" #include "GridStates.h" class Transport; -class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinity::ClassLevelLockable<MapManager, ZThread::Mutex> > +class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex> > { friend class Trinity::OperatorNew<MapManager>; @@ -149,7 +149,7 @@ class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinit return (iter == i_maps.end() ? NULL : iter->second); } - typedef Trinity::ClassLevelLockable<MapManager, ZThread::Mutex>::Lock Guard; + typedef MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>::Lock Guard; uint32 i_gridCleanUpDelay; MapMapType i_maps; IntervalTimer i_timer; diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index a75141e2937..f7c53e536c4 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -44,6 +44,7 @@ #include "Pet.h" #include "SocialMgr.h" #include "CellImpl.h" +#include "AccountMgr.h" #include "Vehicle.h" #include "CreatureAI.h" @@ -561,12 +562,13 @@ void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data ) sLog.outDebug( "WORLD: %s asked to add friend : '%s'", GetPlayer()->GetName(), friendName.c_str() ); - CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race FROM characters WHERE name = '%s'", friendName.c_str()); + CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race, account FROM characters WHERE name = '%s'", friendName.c_str()); } void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 accountId, std::string friendNote) { uint64 friendGuid; + uint64 friendAcctid; uint32 team; FriendsResult friendResult; @@ -582,30 +584,33 @@ void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 acc { friendGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); team = Player::TeamForRace((*result)[1].GetUInt8()); + friendAcctid = (*result)[2].GetUInt32(); delete result; - if(friendGuid) + if ( session->GetSecurity() >= SEC_MODERATOR || sWorld.getConfig(CONFIG_ALLOW_GM_FRIEND) || accmgr.GetSecurity(friendAcctid) < SEC_MODERATOR) { - if(friendGuid==session->GetPlayer()->GetGUID()) - friendResult = FRIEND_SELF; - else if(session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR) - friendResult = FRIEND_ENEMY; - else if(session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid))) - friendResult = FRIEND_ALREADY; - else + if(friendGuid) { - Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); - if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer())) - friendResult = FRIEND_ADDED_ONLINE; + if(friendGuid==session->GetPlayer()->GetGUID()) + friendResult = FRIEND_SELF; + else if(session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR) + friendResult = FRIEND_ENEMY; + else if(session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid))) + friendResult = FRIEND_ALREADY; else - friendResult = FRIEND_ADDED_OFFLINE; - if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false)) { - friendResult = FRIEND_LIST_FULL; - sLog.outDebug( "WORLD: %s's friend list is full.", session->GetPlayer()->GetName()); + Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); + if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer())) + friendResult = FRIEND_ADDED_ONLINE; + else + friendResult = FRIEND_ADDED_OFFLINE; + if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false)) + { + friendResult = FRIEND_LIST_FULL; + sLog.outDebug( "WORLD: %s's friend list is full.", session->GetPlayer()->GetName()); + } } - session->GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote); } } @@ -775,9 +780,7 @@ void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data) if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL)) return; - float dist = corpse->GetDistance2d(GetPlayer()); - sLog.outDebug("Corpse 2D Distance: \t%f",dist); - if (dist > CORPSE_RECLAIM_RADIUS) + if (!corpse->IsWithinDist(GetPlayer(),CORPSE_RECLAIM_RADIUS,false)) return; uint64 guid; diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index b31d3231a3b..52b9ba56e3e 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -203,14 +203,7 @@ MotionMaster::MoveTargetedHome() Clear(false); - if(Unit *target = i_owner->GetCharmerOrOwner()) - { - DEBUG_LOG("Pet or controlled unit (Entry: %u GUID: %u) targeting home", - i_owner->GetEntry(), i_owner->GetGUIDLow() ); - - MoveFollow(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE); - } - else if(i_owner->GetTypeId() == TYPEID_UNIT) + if(i_owner->GetTypeId() == TYPEID_UNIT) { DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow()); Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE); @@ -218,7 +211,6 @@ MotionMaster::MoveTargetedHome() else { sLog.outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow() ); - return; } } diff --git a/src/game/NullCreatureAI.h b/src/game/NullCreatureAI.h index d5c12d8c9a0..347f52228b4 100644 --- a/src/game/NullCreatureAI.h +++ b/src/game/NullCreatureAI.h @@ -22,40 +22,47 @@ #define TRINITY_NULLCREATUREAI_H #include "CreatureAI.h" +#include "CreatureAIImpl.h" class TRINITY_DLL_DECL PassiveAI : public CreatureAI { public: explicit PassiveAI(Creature *c) : CreatureAI(c) {} - ~PassiveAI() {} void MoveInLineOfSight(Unit *) {} void AttackStart(Unit *) {} - void UpdateAI(const uint32); + static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } }; -class TRINITY_DLL_DECL PossessedAI : public PassiveAI +class TRINITY_DLL_DECL PossessedAI : public CreatureAI { public: - explicit PossessedAI(Creature *c) : PassiveAI(c) {} + explicit PossessedAI(Creature *c) : CreatureAI(c) {} + void MoveInLineOfSight(Unit *) {} void AttackStart(Unit *target); void UpdateAI(const uint32); void EnterEvadeMode() {} void JustDied(Unit*); void KilledUnit(Unit* victim); + + static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } }; -class TRINITY_DLL_DECL NullCreatureAI : public PassiveAI +class TRINITY_DLL_DECL NullCreatureAI : public CreatureAI { public: - explicit NullCreatureAI(Creature *c) : PassiveAI(c) {} + explicit NullCreatureAI(Creature *c) : CreatureAI(c) {} + void MoveInLineOfSight(Unit *) {} + void AttackStart(Unit *) {} void UpdateAI(const uint32) {} void EnterEvadeMode() {} + + static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; } }; class TRINITY_DLL_DECL CritterAI : public PassiveAI diff --git a/src/game/Object.cpp b/src/game/Object.cpp index f649164e21b..5c186921524 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1148,7 +1148,6 @@ InstanceData* WorldObject::GetInstanceData() Map *map = GetMap(); return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL; } - //slow float WorldObject::GetDistance(const WorldObject* obj) const { @@ -1176,7 +1175,7 @@ float WorldObject::GetExactDistance2d(const float x, const float y) const return sqrt((dx*dx) + (dy*dy)); } -float WorldObject::GetDistance(const float x, const float y, const float z) const +float WorldObject::GetDistance(float x, float y, float z) const { float dx = GetPositionX() - x; float dy = GetPositionY() - y; @@ -1194,6 +1193,14 @@ float WorldObject::GetDistanceSq(const float &x, const float &y, const float &z) return dx*dx + dy*dy + dz*dz; } +float WorldObject::GetDistanceSq(const WorldObject *obj) const +{ + float dx = GetPositionX() - obj->GetPositionX(); + float dy = GetPositionY() - obj->GetPositionY(); + float dz = GetPositionZ() - obj->GetPositionZ(); + return dx*dx + dy*dy + dz*dz; +} + float WorldObject::GetDistance2d(const WorldObject* obj) const { float dx = GetPositionX() - obj->GetPositionX(); @@ -1211,10 +1218,33 @@ float WorldObject::GetDistanceZ(const WorldObject* obj) const return ( dist > 0 ? dist : 0); } -bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D) const +bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist2compare) const { - if (!obj || !IsInMap(obj)) return false; + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float dz = GetPositionZ() - z; + float distsq = dx*dx + dy*dy + dz*dz; + + float sizefactor = GetObjectSize(); + float maxdist = dist2compare + sizefactor; + + return distsq < maxdist * maxdist; +} + +bool WorldObject::IsWithinDist2d(float x, float y, float dist2compare) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float distsq = dx*dx + dy*dy; + + float sizefactor = GetObjectSize(); + float maxdist = dist2compare + sizefactor; + return distsq < maxdist * maxdist; +} + +bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const +{ float dx = GetPositionX() - obj->GetPositionX(); float dy = GetPositionY() - obj->GetPositionY(); float distsq = dx*dx + dy*dy; @@ -1237,7 +1267,7 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const return(IsWithinLOS(ox, oy, oz )); } -bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const +bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const { float x,y,z; GetPosition(x,y,z); @@ -1245,6 +1275,83 @@ bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) c return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f); } +bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const +{ + float dx1 = GetPositionX() - obj1->GetPositionX(); + float dy1 = GetPositionY() - obj1->GetPositionY(); + float distsq1 = dx1*dx1 + dy1*dy1; + if(is3D) + { + float dz1 = GetPositionZ() - obj1->GetPositionZ(); + distsq1 += dz1*dz1; + } + + float dx2 = GetPositionX() - obj2->GetPositionX(); + float dy2 = GetPositionY() - obj2->GetPositionY(); + float distsq2 = dx2*dx2 + dy2*dy2; + if(is3D) + { + float dz2 = GetPositionZ() - obj2->GetPositionZ(); + distsq2 += dz2*dz2; + } + + return distsq1 < distsq2; +} + +bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D /* = true */) const +{ + float dx = GetPositionX() - obj->GetPositionX(); + float dy = GetPositionY() - obj->GetPositionY(); + float distsq = dx*dx + dy*dy; + if(is3D) + { + float dz = GetPositionZ() - obj->GetPositionZ(); + distsq += dz*dz; + } + + float sizefactor = GetObjectSize() + obj->GetObjectSize(); + + float mindist = minRange + sizefactor; + if(distsq < mindist * mindist) + return false; + + float maxdist = maxRange + sizefactor; + return distsq < maxdist * maxdist; +} + +bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float distsq = dx*dx + dy*dy; + + float sizefactor = GetObjectSize(); + + float mindist = minRange + sizefactor; + if(distsq < mindist * mindist) + return false; + + float maxdist = maxRange + sizefactor; + return distsq < maxdist * maxdist; +} + +bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float maxRange) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float dz = GetPositionZ() - z; + float distsq = dx*dx + dy*dy + dz*dz; + + float sizefactor = GetObjectSize(); + + float mindist = minRange + sizefactor; + if(distsq < mindist * mindist) + return false; + + float maxdist = maxRange + sizefactor; + return distsq < maxdist * maxdist; +} + float WorldObject::GetAngle(const WorldObject* obj) const { if(!obj) return 0; @@ -1309,6 +1416,21 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const return (( angle >= lborder ) && ( angle <= rborder )); } +bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size) const +{ + if(GetPositionX() > std::max(obj1->GetPositionX(), obj2->GetPositionX()) + || GetPositionX() < std::min(obj1->GetPositionX(), obj2->GetPositionX()) + || GetPositionY() > std::max(obj1->GetPositionY(), obj2->GetPositionY()) + || GetPositionY() < std::min(obj1->GetPositionY(), obj2->GetPositionY())) + return false; + + if(!size) + size = GetObjectSize() / 2; + + float angle = obj1->GetAngle(this) - obj1->GetAngle(obj2); + return abs(sin(angle)) * GetExactDistance2d(obj1->GetPositionX(), obj1->GetPositionY()) < size; +} + void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const { if(distance==0) @@ -1658,6 +1780,8 @@ TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float a return NULL; } + summon->SetHomePosition(x, y, z, angle); + summon->InitStats(duration); Add((Creature*)summon); summon->InitSummon(); @@ -1680,7 +1804,6 @@ TempSummon* WorldObject::SummonCreature(uint32 entry, float x, float y, float z, if(!pCreature) return NULL; - pCreature->SetHomePosition(x, y, z, ang); pCreature->SetTempSummonType(spwtype); return pCreature; @@ -1890,6 +2013,81 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3 return summon; } +/* +namespace MaNGOS +{ + class NearUsedPosDo + { + public: + NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector) + : i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) {} + + void operator()(Corpse*) const {} + void operator()(DynamicObject*) const {} + + void operator()(Creature* c) const + { + // skip self or target + if(c==i_searcher || c==&i_object) + return; + + float x,y,z; + + if( !c->isAlive() || c->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) || + !c->GetMotionMaster()->GetDestination(x,y,z) ) + { + x = c->GetPositionX(); + y = c->GetPositionY(); + } + + add(c,x,y); + } + + template<class T> + void operator()(T* u) const + { + // skip self or target + if(u==i_searcher || u==&i_object) + return; + + float x,y; + + x = u->GetPositionX(); + y = u->GetPositionY(); + + add(u,x,y); + } + + // we must add used pos that can fill places around center + void add(WorldObject* u, float x, float y) const + { + // u is too nearest/far away to i_object + if(!i_object.IsInRange2d(x,y,i_selector.m_dist - i_selector.m_size,i_selector.m_dist + i_selector.m_size)) + return; + + float angle = i_object.GetAngle(u)-i_angle; + + // move angle to range -pi ... +pi + while( angle > M_PI) + angle -= 2.0f * M_PI; + while(angle < -M_PI) + angle += 2.0f * M_PI; + + // dist include size of u + float dist2d = i_object.GetDistance2d(x,y); + i_selector.AddUsedPos(u->GetObjectSize(),angle,dist2d + i_object.GetObjectSize()); + } + private: + WorldObject const& i_object; + WorldObject const* i_searcher; + float i_angle; + ObjectPosSelector& i_selector; + }; +} // namespace MaNGOS +*/ + +//=================================================================================================== + void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const { x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle); @@ -1902,10 +2100,127 @@ void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float abs void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const { GetNearPoint2D(x,y,distance2d+searcher_size,absAngle); - z = GetPositionZ(); - UpdateGroundPositionZ(x,y,z); + + /* + // if detection disabled, return first point + if(!sWorld.getConfig(CONFIG_DETECT_POS_COLLISION)) + { + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + return; + } + + // or remember first point + float first_x = x; + float first_y = y; + bool first_los_conflict = false; // first point LOS problems + + // prepare selector for work + ObjectPosSelector selector(GetPositionX(),GetPositionY(),GetObjectSize(),distance2d+searcher_size); + + // adding used positions around object + { + CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::NearUsedPosDo u_do(*this,searcher,absAngle,selector); + MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this,u_do); + + TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker); + TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker); + + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap()); + cell_lock->Visit(cell_lock, world_obj_worker, *GetMap()); + } + + // maybe can just place in primary position + if( selector.CheckOriginal() ) + { + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + + first_los_conflict = true; // first point have LOS problems + } + + float angle; // candidate of angle for free pos + + // special case when one from list empty and then empty side preferred + if(selector.FirstAngle(angle)) + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + + // set first used pos in lists + selector.InitializeAngle(); + + // select in positions after current nodes (selection one by one) + while(selector.NextAngle(angle)) // angle for free pos + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + + // BAD NEWS: not free pos (or used or have LOS problems) + // Attempt find _used_ pos without LOS problem + + if(!first_los_conflict) + { + x = first_x; + y = first_y; + + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + return; + } + + // special case when one from list empty and then empty side preferred + if( selector.IsNonBalanced() ) + { + if(!selector.FirstAngle(angle)) // _used_ pos + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + } + + // set first used pos in lists + selector.InitializeAngle(); + + // select in positions after current nodes (selection one by one) + while(selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + + // BAD BAD NEWS: all found pos (free and used) have LOS problem :( + x = first_x; + y = first_y; + + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + */ } void WorldObject::GetGroundPoint(float &x, float &y, float &z, float dist, float angle) diff --git a/src/game/Object.h b/src/game/Object.h index 68438c4df85..326b09cfb73 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -461,10 +461,11 @@ class TRINITY_DLL_SPEC WorldObject : public Object virtual const char* GetNameForLocaleIdx(int32 /*locale_idx*/) const { return GetName(); } float GetDistance( const WorldObject* obj ) const; - float GetDistance(const float x, const float y, const float z) const; + float GetDistance(float x, float y, float z) const; float GetDistanceSq(const float &x, const float &y, const float &z) const; + float GetDistanceSq(const WorldObject *obj) const; float GetDistance2d(const WorldObject* obj) const; - float GetDistance2d(const float x, const float y) const; + float GetDistance2d(float x, float y) const; float GetExactDistance2d(const float x, const float y) const; float GetDistanceZ(const WorldObject* obj) const; bool IsInMap(const WorldObject* obj) const @@ -472,14 +473,30 @@ class TRINITY_DLL_SPEC WorldObject : public Object return IsInWorld() && obj->IsInWorld() && GetMapId()==obj->GetMapId() && GetInstanceId()==obj->GetInstanceId() && InSamePhase(obj); } - bool IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D = true) const; - bool IsWithinLOS(const float x, const float y, const float z ) const; + bool IsWithinDist3d(float x, float y, float z, float dist2compare) const; + bool IsWithinDist2d(float x, float y, float dist2compare) const; + bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const; + bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const + // use only if you will sure about placing both object at same map + { + return obj && _IsWithinDist(obj,dist2compare,is3D); + } + bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const + { + return obj && IsInMap(obj) && _IsWithinDist(obj,dist2compare,is3D); + } + bool IsWithinLOS(float x, float y, float z) const; bool IsWithinLOSInMap(const WorldObject* obj) const; + bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const; + bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const; + bool IsInRange2d(float x, float y, float minRange, float maxRange) const; + bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const; float GetAngle( const WorldObject* obj ) const; float GetAngle( const float x, const float y ) const; void GetSinCos(const float x, const float y, float &vsin, float &vcos); bool HasInArc( const float arcangle, const WorldObject* obj ) const; + bool IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size = 0) const; virtual void SendMessageToSet(WorldPacket *data, bool self, bool to_possessor = true); virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor = true); diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 1fa0bd6d1ca..da6279e068a 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -41,9 +41,9 @@ #include <cmath> -#define CLASS_LOCK Trinity::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex> +#define CLASS_LOCK MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex> INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK); -INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ZThread::FastMutex); +INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex); ObjectAccessor::ObjectAccessor() {} ObjectAccessor::~ObjectAccessor() {} @@ -470,7 +470,7 @@ ObjectAccessor::UpdateObjectVisibility(WorldObject *obj) /// Define the static member of HashMapHolder template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap; -template <class T> ZThread::FastMutex HashMapHolder<T>::i_lock; +template <class T> ACE_Thread_Mutex HashMapHolder<T>::i_lock; /// Global definitions for the hashmap storage diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index dd8e02b81ab..f4452b81cab 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -23,7 +23,7 @@ #include "Platform/Define.h" #include "Policies/Singleton.h" -#include "zthread/FastMutex.h" +#include <ace/Thread_Mutex.h> #include "Utilities/UnorderedMap.h" #include "Policies/ThreadingModel.h" @@ -51,8 +51,8 @@ class HashMapHolder public: typedef UNORDERED_MAP< uint64, T* > MapType; - typedef ZThread::FastMutex LockType; - typedef Trinity::GeneralLock<LockType > Guard; + typedef ACE_Thread_Mutex LockType; + typedef MaNGOS::GeneralLock<LockType > Guard; static void Insert(T* o) { m_objectMap[o->GetGUID()] = o; } @@ -80,7 +80,7 @@ class HashMapHolder static MapType m_objectMap; }; -class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor, Trinity::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex> > +class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex> > { friend class Trinity::OperatorNew<ObjectAccessor>; @@ -228,8 +228,8 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor friend struct WorldObjectChangeAccumulator; Player2CorpsesMapType i_player2corpse; - typedef ZThread::FastMutex LockType; - typedef Trinity::GeneralLock<LockType > Guard; + typedef ACE_Thread_Mutex LockType; + typedef MaNGOS::GeneralLock<LockType > Guard; static void _buildChangeObjectForPlayer(WorldObject *, UpdateDataMapType &); static void _buildPacket(Player *, Object *, UpdateDataMapType &); diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 12fb26f0ad8..a448a73f1dc 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -4837,7 +4837,7 @@ void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, ui path = dest_i->second.ID; } -uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team ) +uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team, bool allowed_alt_team /* = false */) { uint16 mount_entry = 0; uint16 mount_id = 0; @@ -4848,6 +4848,9 @@ uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team ) if (team == ALLIANCE) { mount_entry = node->MountCreatureID[1]; + if(!mount_entry && allowed_alt_team) + mount_entry = node->MountCreatureID[0]; + CreatureInfo const *ci = GetCreatureTemplate(mount_entry); if(ci) mount_id = ci->Modelid_A1; @@ -4855,6 +4858,10 @@ uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team ) if (team == HORDE) { mount_entry = node->MountCreatureID[0]; + + if(!mount_entry && allowed_alt_team) + mount_entry = node->MountCreatureID[1]; + CreatureInfo const *ci = GetCreatureTemplate(mount_entry); if(ci) mount_id = ci->Modelid_H1; diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index eff1f3812a1..3fe373f6a34 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -418,7 +418,7 @@ class ObjectMgr uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid, uint32 team ); void GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost); - uint16 GetTaxiMount( uint32 id, uint32 team ); + uint16 GetTaxiMount( uint32 id, uint32 team, bool allowed_alt_team = false); void GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds ); void GetTransportPathNodes( uint32 path, TransportPath &pathnodes ); diff --git a/src/game/OutdoorPvPEP.cpp b/src/game/OutdoorPvPEP.cpp index f0ff85574c0..fc688314e0c 100644 --- a/src/game/OutdoorPvPEP.cpp +++ b/src/game/OutdoorPvPEP.cpp @@ -768,7 +768,7 @@ bool OutdoorPvPObjectiveEP_PWT::HandleGossipOption(Player *plr, uint64 guid, uin nodes[1] = dst; plr->PlayerTalkClass->CloseGossip(); - plr->ActivateTaxiPathTo(nodes, 0, cr); + plr->ActivateTaxiPathTo(nodes, cr); // leave the opvp, seems like moveinlineofsight isn't called when entering a taxi HandlePlayerLeave(plr); } diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index e846f7004c0..7edc9144bdc 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -190,10 +190,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool return true; } - if (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK)) - m_charmInfo->SetPetNumber(pet_number, true); - else - m_charmInfo->SetPetNumber(pet_number, false); + m_charmInfo->SetPetNumber(pet_number, IsPermanentPetFor(owner)); // set current pet as current // 0=current @@ -1685,6 +1682,27 @@ void Pet::ToggleAutocast(uint32 spellid, bool apply) } } +bool Pet::IsPermanentPetFor(Player* owner) +{ + switch(getPetType()) + { + case SUMMON_PET: + switch(owner->getClass()) + { + case CLASS_WARLOCK: + return GetCreatureInfo()->type == CREATURE_TYPE_DEMON; + case CLASS_DEATH_KNIGHT: + return GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD; + default: + return false; + } + case HUNTER_PET: + return true; + default: + return false; + } +} + bool Pet::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number) { SetMapId(map->GetId()); @@ -1735,10 +1753,10 @@ void Pet::LearnPetPassives() void Pet::CastPetAuras(bool current) { Unit* owner = GetOwner(); - if(!owner) + if(!owner || owner->GetTypeId()!=TYPEID_PLAYER) return; - if(getPetType() != HUNTER_PET && (getPetType() != SUMMON_PET || owner->getClass() != CLASS_WARLOCK)) + if(!IsPermanentPetFor((Player*)owner)) return; for(PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();) diff --git a/src/game/Pet.h b/src/game/Pet.h index 90414a321de..b76b53ab554 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -121,11 +121,13 @@ typedef std::vector<uint32> AutoSpellList; #define ACTIVE_SPELLS_MAX 4 -#define OWNER_MAX_DISTANCE 100 +#define OWNER_MAX_DISTANCE 100.0f #define PET_FOLLOW_DIST 1 #define PET_FOLLOW_ANGLE (M_PI/2) +class Player; + class Pet : public Guardian { public: @@ -140,6 +142,8 @@ class Pet : public Guardian bool isControlled() const { return getPetType()==SUMMON_PET || getPetType()==HUNTER_PET; } bool isTemporarySummoned() const { return m_duration > 0; } + bool IsPermanentPetFor(Player* owner); // pet have tab in character windows and set UNIT_FIELD_PETNUMBER + bool Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number); bool CreateBaseAtCreature(Creature* creature); bool LoadPetFromDB( Player* owner,uint32 petentry = 0,uint32 petnumber = 0, bool current = false ); diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 42d0093510b..bfbe8ca7df4 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -89,10 +89,6 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid switch(flag) { case ACT_COMMAND: //0x0700 - // Possessed or shared vision pets are only able to attack - if ((pet->isPossessed() || pet->HasAuraType(SPELL_AURA_BIND_SIGHT)) && spellid != COMMAND_ATTACK) - return; - switch(spellid) { case COMMAND_STAY: //flat=1792 //STAY @@ -162,10 +158,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid } case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet) if(pet->GetCharmerGUID() == GetPlayer()->GetGUID()) - { - if(GetPlayer()->m_seer != pet) - _player->StopCastingCharm(); - } + _player->StopCastingCharm(); else if(pet->GetOwnerGUID() == GetPlayer()->GetGUID()) { assert(pet->GetTypeId() == TYPEID_UNIT); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 494334466f4..a68002445bc 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -230,7 +230,7 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString( const std::string& values, uint } // can't load taxi path without mount set (quest taxi path?) - if(!objmgr.GetTaxiMount(GetTaxiSource(),team)) + if(!objmgr.GetTaxiMount(GetTaxiSource(),team,true)) return false; return true; @@ -897,6 +897,8 @@ void Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) damage-=absorb+resist; + DealDamageMods(this,damage,&absorb); + WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21)); data << uint64(GetGUID()); data << uint8(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL); @@ -1490,7 +1492,12 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) char_flags |= CHARACTER_FLAG_GHOST; if(HasAtLoginFlag(AT_LOGIN_RENAME)) char_flags |= CHARACTER_FLAG_RENAME; - if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && (fields[14].GetCppString() != "")) + if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED)) + { + if(!fields[14].GetCppString().empty()) + char_flags |= CHARACTER_FLAG_DECLINED; + } + else char_flags |= CHARACTER_FLAG_DECLINED; *p_data << uint32(char_flags); // character flags @@ -1505,7 +1512,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) 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)) + if (result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT)) { uint32 entry = fields[10].GetUInt32(); CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry); @@ -1666,7 +1673,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { //same map, only remove pet if out of range for new position - if(pet && pet->GetDistance(x,y,z) >= OWNER_MAX_DISTANCE) + if(pet && !pet->IsWithinDist3d(x,y,z, OWNER_MAX_DISTANCE)) UnsummonPetTemporaryIfAny(); } @@ -1798,7 +1805,7 @@ void Player::AddToWorld() ///- The player should only be added when logging in Unit::AddToWorld(); - for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++) + for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) { if(m_items[i]) m_items[i]->AddToWorld(); @@ -1815,7 +1822,7 @@ void Player::RemoveFromWorld() StopCastingBindSight(); } - for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++) + for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) { if(m_items[i]) m_items[i]->RemoveFromWorld(); @@ -3287,6 +3294,20 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_ } } + +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); + } +} + void Player::RemoveArenaSpellCooldowns() { // remove cooldowns on spells that has < 15 min CD @@ -5729,23 +5750,26 @@ ReputationRank Player::GetReputationRank(uint32 faction) const } //Calculate total reputation percent player gain with quest/creature level -int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest) +int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest) { float percent = 100.0f; float rate = for_quest ? sWorld.getRate(RATE_REPUTATION_LOWLEVEL_QUEST) : sWorld.getRate(RATE_REPUTATION_LOWLEVEL_KILL); - if(rate != 1.0f && creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel())) + if (rate != 1.0f && creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel())) percent *= rate; - int32 repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN); + float repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN); + + if (!for_quest) + repMod += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_FACTION_REPUTATION_GAIN, faction); percent += rep > 0 ? repMod : -repMod; - if(percent <= 0.0f) + if (percent <= 0.0f) return 0; - return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100); + return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100.0f); } //Calculates how many reputation points player gains in victim's enemy factions @@ -5764,7 +5788,7 @@ void Player::RewardReputation(Unit *pVictim, float rate) if(Rep->repfaction1 && (!Rep->team_dependent || GetTeam()==ALLIANCE)) { - int32 donerep1 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue1,false); + int32 donerep1 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue1, Rep->repfaction1, false); donerep1 = int32(donerep1*rate); FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(Rep->repfaction1); uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1); @@ -5782,7 +5806,7 @@ void Player::RewardReputation(Unit *pVictim, float rate) if(Rep->repfaction2 && (!Rep->team_dependent || GetTeam()==HORDE)) { - int32 donerep2 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue2,false); + int32 donerep2 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue2, Rep->repfaction2, false); donerep2 = int32(donerep2*rate); FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(Rep->repfaction2); uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2); @@ -5807,7 +5831,7 @@ void Player::RewardReputation(Quest const *pQuest) { if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] ) { - int32 rep = CalculateReputationGain(GetQuestLevel(pQuest),pQuest->RewRepValue[i],true); + int32 rep = CalculateReputationGain(GetQuestLevel(pQuest), pQuest->RewRepValue[i], pQuest->RewRepFaction[i], true); FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]); if(factionEntry) GetReputationMgr().ModifyReputation(factionEntry, rep); @@ -6425,8 +6449,8 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply) if(slot >= INVENTORY_SLOT_BAG_END || !item) return; - // not apply/remove mods for broken item - if(item->IsBroken()) + // not apply mods for broken item + if(item->IsBroken() && apply) return; ItemPrototype const *proto = item->GetProto(); @@ -6464,30 +6488,25 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl 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; + for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i) { uint32 statType = 0; - int32 val = 0; - - if(proto->ScalingStatDistribution) + int32 val = 0; + // If set ScalingStatDistribution need get stats and values from it + if (ssd && ssv) { - if(ScalingStatDistributionEntry const *ssd = sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution)) - { - statType = ssd->StatMod[i]; - - if(uint32 modifier = ssd->Modifier[i]) - { - uint32 level = ((getLevel() > ssd->MaxLevel) ? ssd->MaxLevel : getLevel()); - if(ScalingStatValuesEntry const *ssv = sScalingStatValuesStore.LookupEntry(level)) - { - uint32 multiplier = ssv->Multiplier[proto->GetScalingStatValuesColumn()]; - val = (multiplier * modifier) / 10000; - } - } - } + if (ssd->StatMod[i] < 0) + continue; + statType = ssd->StatMod[i]; + val = (ssv->getssdMultiplier(proto->ScalingStatValue) * ssd->Modifier[i]) / 10000; } else { + if (i >= proto->StatsCount) + continue; statType = proto->ItemStat[i].ItemStatType; val = proto->ItemStat[i].ItemStatValue; } @@ -6642,8 +6661,18 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl } } - if (proto->Armor) - HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(proto->Armor), apply); + // If set ScalingStatValue armor get it or use item armor + uint32 armor = proto->Armor; + if (ssv) + { + if (uint32 ssvarmor = ssv->getArmorMod(proto->ScalingStatValue)) + armor = ssvarmor; + } + // Add armor bonus from ArmorDamageModifier if > 0 + if (proto->ArmorDamageModifier > 0) + armor+=proto->ArmorDamageModifier; + if (armor) + HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply); if (proto->Block) HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply); @@ -6680,23 +6709,42 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl attType = OFF_ATTACK; } - if (proto->Damage[0].DamageMin > 0 ) + float minDamage = proto->Damage[0].DamageMin; + float maxDamage = proto->Damage[0].DamageMax; + int32 extraDPS = 0; + // If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage + if (ssv) + { + if (extraDPS = ssv->getDPSMod(proto->ScalingStatValue)) + { + float average = extraDPS * proto->Delay / 1000.0f; + minDamage = 0.7f * average; + maxDamage = 1.3f * average; + } + } + if (minDamage > 0 ) { - damage = apply ? proto->Damage[0].DamageMin : BASE_MINDAMAGE; + damage = apply ? minDamage : BASE_MINDAMAGE; SetBaseWeaponDamage(attType, MINDAMAGE, damage); //sLog.outError("applying mindam: assigning %f to weapon mindamage, now is: %f", damage, GetWeaponDamageRange(attType, MINDAMAGE)); } - if (proto->Damage[0].DamageMax > 0 ) + if (maxDamage > 0 ) { - damage = apply ? proto->Damage[0].DamageMax : BASE_MAXDAMAGE; + damage = apply ? maxDamage : BASE_MAXDAMAGE; SetBaseWeaponDamage(attType, MAXDAMAGE, damage); } - // Druids get feral AP bonus from weapon dps + // Apply feral bonus from ScalingStatValue if set + if (ssv) + { + if (int32 feral_bonus = ssv->getFeralBonus(proto->ScalingStatValue)) + ApplyFeralAPBonus(feral_bonus, apply); + } + // Druids get feral AP bonus from weapon dps (lso use DPS from ScalingStatValue) if(getClass() == CLASS_DRUID) { - int32 feral_bonus = proto->getFeralBonus(); + int32 feral_bonus = proto->getFeralBonus(extraDPS); if (feral_bonus > 0) ApplyFeralAPBonus(feral_bonus, apply); } @@ -9825,18 +9873,22 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo return EQUIP_ERR_CANT_DO_RIGHT_NOW; } + ScalingStatDistributionEntry const *ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : 0; + if (ssd && ssd->MaxLevel < getLevel()) + return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; + uint8 eslot = FindEquipSlot( pProto, slot, swap ); - if( eslot == NULL_SLOT ) + if (eslot == NULL_SLOT) return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; - uint8 msg = CanUseItem( pItem , not_loading ); - if( msg != EQUIP_ERR_OK ) + uint8 msg = CanUseItem(pItem , not_loading); + if (msg != EQUIP_ERR_OK) return msg; - if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) ) + if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot)) return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE; // if swap ignore item (equipped also) - if(uint8 res2 = CanEquipUniqueItem(pItem, swap ? eslot : NULL_SLOT)) + if (uint8 res2 = CanEquipUniqueItem(pItem, swap ? eslot : NULL_SLOT)) return res2; // check unique-equipped special item classes @@ -9844,16 +9896,16 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo { for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) { - if( Item* pBag = GetItemByPos( INVENTORY_SLOT_BAG_0, i ) ) + if (Item* pBag = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) { - if( ItemPrototype const* pBagProto = pBag->GetProto() ) + if (pBag != pItem) { - if( pBagProto->Class==pProto->Class && (!swap || pBag->GetSlot() != eslot ) ) + if (ItemPrototype const* pBagProto = pBag->GetProto()) { - if(pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH) - return EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH; - else - return EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER; + if (pBagProto->Class==pProto->Class && (!swap || pBag->GetSlot() != eslot)) + return (pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH) + ? EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH + : EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER; } } } @@ -9862,25 +9914,25 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo uint32 type = pProto->InventoryType; - if(eslot == EQUIPMENT_SLOT_OFFHAND) + if (eslot == EQUIPMENT_SLOT_OFFHAND) { if (type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND) { - if(!CanDualWield()) + if (!CanDualWield()) return EQUIP_ERR_CANT_DUAL_WIELD; } else if (type == INVTYPE_2HWEAPON) { - if(!CanDualWield() || !CanTitanGrip()) + if (!CanDualWield() || !CanTitanGrip()) return EQUIP_ERR_CANT_DUAL_WIELD; } - if(IsTwoHandUsed()) + if (IsTwoHandUsed()) return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED; } // equip two-hand weapon case (with possible unequip 2 items) - if( type == INVTYPE_2HWEAPON ) + if (type == INVTYPE_2HWEAPON) { if (eslot == EQUIPMENT_SLOT_OFFHAND) { @@ -9895,9 +9947,9 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo // offhand item must can be stored in inventory for offhand item and it also must be unequipped Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND ); ItemPosCountVec off_dest; - if( offItem && (!not_loading || + if (offItem && (!not_loading || CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND,false) != EQUIP_ERR_OK || - CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK ) ) + CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK )) return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL; } } @@ -9905,10 +9957,8 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo return EQUIP_ERR_OK; } } - if( !swap ) - return EQUIP_ERR_ITEM_NOT_FOUND; - else - return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED; + + return !swap ? EQUIP_ERR_ITEM_NOT_FOUND : EQUIP_ERR_ITEMS_CANT_BE_SWAPPED; } uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const @@ -10127,38 +10177,49 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const { - if( pItem ) + if (pItem) { sLog.outDebug( "STORAGE: CanUseItem item = %u", pItem->GetEntry()); - if( !isAlive() && not_loading ) + + if (!isAlive() && not_loading) return EQUIP_ERR_YOU_ARE_DEAD; - //if( isStunned() ) + + //if (isStunned()) // return EQUIP_ERR_YOU_ARE_STUNNED; + ItemPrototype const *pProto = pItem->GetProto(); - if( pProto ) + if (pProto) { - if( pItem->IsBindedNotWith(GetGUID()) ) + if (pItem->IsBindedNotWith(GetGUID())) return EQUIP_ERR_DONT_OWN_THAT_ITEM; - if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 ) + + if ((pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0) return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; - if( pItem->GetSkill() != 0 ) + + if (pItem->GetSkill() != 0) { - if( GetSkillValue( pItem->GetSkill() ) == 0 ) + if (GetSkillValue( pItem->GetSkill() ) == 0) return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; } - if( pProto->RequiredSkill != 0 ) + + if (pProto->RequiredSkill != 0) { - if( GetSkillValue( pProto->RequiredSkill ) == 0 ) + if (GetSkillValue( pProto->RequiredSkill ) == 0) return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; - else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank ) + + if (GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank) return EQUIP_ERR_ERR_CANT_EQUIP_SKILL; } - if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) ) + + if (pProto->RequiredSpell != 0 && !HasSpell(pProto->RequiredSpell)) return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; - if( pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank ) + + if (pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank) return EQUIP_ERR_CANT_EQUIP_REPUTATION; - if( getLevel() < pProto->RequiredLevel ) + + if (getLevel() < pProto->RequiredLevel) return EQUIP_ERR_CANT_EQUIP_LEVEL_I; + return EQUIP_ERR_OK; } } @@ -16712,7 +16773,7 @@ void Player::PetSpellInitialize() uint8 addlist = 0; data << uint8(addlist); // placeholder - if(pet->isControlled() && ((pet->getPetType() == HUNTER_PET) || ((pet->GetCreatureInfo()->type == CREATURE_TYPE_DEMON) && (getClass() == CLASS_WARLOCK)))) + if (pet->IsPermanentPetFor(this)) { // spells loop for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr) @@ -17114,43 +17175,68 @@ void Player::HandleStealthedUnitsDetection() } } -bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_id, Creature* npc) +bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= NULL*/, uint32 spellid /*= 0*/) { if(nodes.size() < 2) return false; - // not let cheating with start flight mounted - if(IsMounted()) + // 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()) { WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIPLAYERALREADYMOUNTED); + data << uint32(ERR_TAXIPLAYERBUSY); GetSession()->SendPacket(&data); return false; } - if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW ) - { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIPLAYERSHAPESHIFTED); - GetSession()->SendPacket(&data); + if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) 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() || - (!m_currentSpells[CURRENT_GENERIC_SPELL] || - m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Effect[0] != SPELL_EFFECT_SEND_TAXI)&& - IsNonMeleeSpellCasted(false) || - isInCombat()) + // taximaster case + if(npc) { - WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); - data << uint32(ERR_TAXIPLAYERBUSY); - GetSession()->SendPacket(&data); - return false; + // not let cheating with start flight mounted + if(IsMounted()) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIPLAYERALREADYMOUNTED); + GetSession()->SendPacket(&data); + return false; + } + + if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW ) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIPLAYERSHAPESHIFTED); + GetSession()->SendPacket(&data); + 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(IsNonMeleeSpellCasted(false)) + { + WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); + data << uint32(ERR_TAXIPLAYERBUSY); + GetSession()->SendPacket(&data); + return false; + } } + // cast case or scripted call case + else + { + RemoveAurasByType(SPELL_AURA_MOUNTED); - if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) - return false; + if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW ) + RemoveAurasDueToSpell(m_ShapeShiftFormSpellId); + + if(m_currentSpells[CURRENT_GENERIC_SPELL] && m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id != spellid) + InterruptSpell(CURRENT_GENERIC_SPELL,false); + + InterruptSpell(CURRENT_AUTOREPEAT_SPELL,false); + + if(m_currentSpells[CURRENT_CHANNELED_SPELL] && m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id != spellid) + InterruptSpell(CURRENT_CHANNELED_SPELL,true); + } uint32 sourcenode = nodes[0]; @@ -17179,8 +17265,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i return false; } } - // node must have pos if not spell case (npc!=0) - else if(npc) + // node must have pos if taxi master case (npc != NULL) + else if (npc) { WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR); @@ -17232,10 +17318,11 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i prevnode = lastnode; } - if(!mount_id) // if not provide then attempt use default. - mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam()); + // get mount model (in case non taximaster (npc==NULL) allow more wide lookup) + uint16 mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam(), npc == NULL); - if (mount_id == 0 || sourcepath == 0) + // in spell case allow 0 model + if (mount_id == 0 && spellid == 0 || sourcepath == 0) { WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4); data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR); @@ -17277,6 +17364,21 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i return true; } +bool Player::ActivateTaxiPathTo( uint32 taxi_path_id, uint32 spellid /*= 0*/ ) +{ + TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(taxi_path_id); + if(!entry) + return false; + + std::vector<uint32> nodes; + + nodes.resize(2); + nodes[0] = entry->from; + nodes[1] = entry->to; + + return ActivateTaxiPathTo(nodes,NULL,spellid); +} + void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ) { // last check 2.0.10 @@ -20509,12 +20611,14 @@ void Player::ResummonPetTemporaryUnSummonedIfAny() bool Player::canSeeSpellClickOn(Creature const *c) const { - SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap; - if(map.empty()) + SpellClickInfoMap::const_iterator lower = objmgr.mSpellClickInfoMap.lower_bound(c->GetEntry()); + SpellClickInfoMap::const_iterator upper = objmgr.mSpellClickInfoMap.upper_bound(c->GetEntry()); + if(lower == upper) return true; - for(SpellClickInfoMap::const_iterator itr = map.lower_bound(c->GetEntry()); itr != map.upper_bound(c->GetEntry()); ++itr) + for(SpellClickInfoMap::const_iterator itr = lower; itr != upper; ++itr) { + sLog.outError("%u %u %u %u", (uint32)itr->second.castFlags, itr->second.questId, itr->second.spellId); if(itr->second.questId == 0 || GetQuestStatus(itr->second.questId) == QUEST_STATUS_INCOMPLETE) return true; } diff --git a/src/game/Player.h b/src/game/Player.h index ecab25122bf..0223364cce0 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -867,7 +867,8 @@ class TRINITY_DLL_SPEC Player : public Unit PlayerTaxi m_taxi; void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); } - bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_id = 0 , Creature* npc = NULL); + bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = NULL, uint32 spellid = 0); + bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0); // 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; } @@ -1383,7 +1384,7 @@ class TRINITY_DLL_SPEC Player : public Unit void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time); void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL); void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs ); - void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); } + void RemoveSpellCooldown(uint32 spell_id, bool update = false); void RemoveArenaSpellCooldowns(); void RemoveAllSpellCooldown(); void _LoadSpellCooldowns(QueryResult *result); @@ -1668,6 +1669,8 @@ class TRINITY_DLL_SPEC Player : public Unit //End of PvP System + inline SpellCooldowns GetSpellCooldowns() const { return m_spellCooldowns; } + void SetDrunkValue(uint16 newDrunkValue, uint32 itemid=0); uint16 GetDrunkValue() const { return m_drunk; } static DrunkenState GetDrunkenstateByValue(uint16 value); @@ -2151,7 +2154,6 @@ class TRINITY_DLL_SPEC Player : public Unit PlayerMails m_mail; PlayerSpellMap m_spells; - SpellCooldowns m_spellCooldowns; uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use ActionButtonList m_actionButtons; @@ -2256,7 +2258,7 @@ class TRINITY_DLL_SPEC Player : public Unit Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ); void UpdateKnownCurrencies(uint32 itemId, bool apply); - int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest); + int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest); void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData ); GridReference<Player> m_gridRef; @@ -2284,6 +2286,8 @@ class TRINITY_DLL_SPEC Player : public Unit AchievementMgr m_achievementMgr; ReputationMgr m_reputationMgr; + + SpellCooldowns m_spellCooldowns; }; void AddItemsSetItem(Player*player,Item *item); diff --git a/src/game/PossessedAI.cpp b/src/game/PossessedAI.cpp deleted file mode 100644 index 8fd2e5ca014..00000000000 --- a/src/game/PossessedAI.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> - * - * Thanks to the original authors: 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 - */ - diff --git a/src/game/PossessedAI.h b/src/game/PossessedAI.h deleted file mode 100644 index bef7853246e..00000000000 --- a/src/game/PossessedAI.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/> - * - * Thanks to the original authors: 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 - */ - -#ifndef MANGOS_POSSESSEDAI_H -#define MANGOS_POSSESSEDAI_H - - -#endif diff --git a/src/game/RandomMovementGenerator.cpp b/src/game/RandomMovementGenerator.cpp index 6d147f15b8d..93e10ad6115 100644 --- a/src/game/RandomMovementGenerator.cpp +++ b/src/game/RandomMovementGenerator.cpp @@ -58,6 +58,9 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) bool is_water_ok = creature.canSwim(); bool is_air_ok = creature.canFly(); + for(uint32 i = 0;; ++i) + { + const float angle = rand_norm()*(M_PI*2); const float range = rand_norm()*wander_distance; const float distanceX = range * cos(angle); @@ -72,6 +75,12 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y); + if(i == 5) + { + nz = Z; + break; + } + if (is_air_ok) // 3D system above ground and above water (flying mode) { const float distanceZ = rand_norm() * sqrtf(dist)/2; // Limit height change @@ -79,12 +88,13 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height. float wz = map->GetWaterLevel(nx, ny); if (tz >= nz || wz >= nz) - return; // Problem here, we must fly above the ground and water, not under. Let's try on next tick + continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick } //else if (is_water_ok) // 3D system under water and above ground (swimming mode) else // 2D only { dist = dist>=100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE) + // The fastest way to get an accurate result 90% of the time. // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. nz = map->GetHeight(nx,ny,Z+dist-2.0f,false); // Map check @@ -95,11 +105,14 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { nz = map->GetHeight(nx,ny,Z+dist-2.0f,true); // Vmap Higher if (fabs(nz-Z)>dist) - return; // let's forget this bad coords where a z cannot be find and retry at next tick + continue; // let's forget this bad coords where a z cannot be find and retry at next tick } } } + break; + } + Traveller<Creature> traveller(creature); creature.SetOrientation(creature.GetAngle(nx,ny)); i_destinationHolder.SetDestination(traveller, nx, ny, nz); @@ -130,7 +143,8 @@ RandomMovementGenerator<Creature>::Initialize(Creature &creature) if(!creature.isAlive()) return; - wander_distance = creature.GetRespawnRadius(); + if(!wander_distance) + wander_distance = creature.GetRespawnRadius(); if (creature.canFly()) creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); @@ -181,7 +195,7 @@ RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff creature.SetUnitMovementFlags(irand(0,RUNNING_CHANCE_RANDOMMV) > 0 ? MOVEMENTFLAG_WALK_MODE : MOVEMENTFLAG_NONE); _setRandomLocation(creature); } - else if(creature.isPet() && creature.GetOwner() && creature.GetDistance(creature.GetOwner()) > PET_FOLLOW_DIST+2.5f) + else if(creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(),PET_FOLLOW_DIST+2.5f)) { creature.SetUnitMovementFlags(MOVEMENTFLAG_NONE); _setRandomLocation(creature); diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index cc8db7c30f8..a068815bb1c 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -24,9 +24,6 @@ #include "Platform/Define.h" #include <cassert> -#define MaNGOS Trinity -#define GetMangosString GetTrinityString - enum Gender { GENDER_MALE = 0, @@ -1109,9 +1106,10 @@ enum SpellHitType { SPELL_HIT_TYPE_UNK1 = 0x00001, SPELL_HIT_TYPE_CRIT = 0x00002, - SPELL_HIT_TYPE_UNK2 = 0x00004, - SPELL_HIT_TYPE_UNK3 = 0x00008, - SPELL_HIT_TYPE_UNK4 = 0x00020 + SPELL_HIT_TYPE_UNK3 = 0x00004, + SPELL_HIT_TYPE_UNK4 = 0x00008, + SPELL_HIT_TYPE_UNK5 = 0x00010, // replace caster? + SPELL_HIT_TYPE_UNK6 = 0x00020 }; enum SpellDmgClass @@ -1819,6 +1817,7 @@ enum CreatureType }; uint32 const CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD = (1 << (CREATURE_TYPE_HUMANOID-1)) | (1 << (CREATURE_TYPE_UNDEAD-1)); +uint32 const CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL = (1 << (CREATURE_TYPE_MECHANICAL-1)) | (1 << (CREATURE_TYPE_ELEMENTAL-1)); // CreatureFamily.dbc enum CreatureFamily diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 5934542f64f..2c778616d78 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -476,6 +476,35 @@ Spell::~Spell() delete m_spellValue; } +template<typename T> +WorldObject* Spell::FindCorpseUsing() +{ + // non-standard target selection + float max_range = GetSpellMaxRange(m_spellInfo, false); + + CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + WorldObject* result = NULL; + + T u_check(m_caster, max_range); + MaNGOS::WorldObjectSearcher<T> searcher(m_caster, result, u_check); + + TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, GridTypeMapContainer > grid_searcher(searcher); + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_searcher, *m_caster->GetMap()); + + if (!result) + { + TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, WorldTypeMapContainer > world_searcher(searcher); + cell_lock->Visit(cell_lock, world_searcher, *m_caster->GetMap()); + } + + return result; +} + void Spell::FillTargetMap() { for(uint32 i = 0; i < 3; ++i) @@ -535,17 +564,7 @@ void Spell::FillTargetMap() { case 20577: // Cannibalize { - // non-standard target selection - SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); - float max_range = GetSpellMaxRangeForHostile(srange); - WorldObject* result = NULL; - - Trinity::CannibalizeObjectCheck u_check(m_caster, max_range); - Trinity::WorldObjectSearcher<Trinity::CannibalizeObjectCheck > searcher(m_caster, result, u_check); - m_caster->VisitNearbyGridObject(max_range, searcher); - if(!result) - m_caster->VisitNearbyWorldObject(max_range, searcher); - + WorldObject* result = FindCorpseUsing<MaNGOS::CannibalizeObjectCheck> (); if(result) { @@ -566,15 +585,7 @@ void Spell::FillTargetMap() { // clear cooldown at fail if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(m_spellInfo->Id); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - + ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true); SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES); finish(false); } @@ -598,6 +609,7 @@ void Spell::FillTargetMap() case SPELL_EFFECT_SELF_RESURRECT: case SPELL_EFFECT_REPUTATION: case SPELL_EFFECT_LEARN_SPELL: + case SPELL_EFFECT_SEND_TAXI: if(m_targets.getUnitTarget()) AddUnitTarget(m_targets.getUnitTarget(), i); // Triggered spells have additional spell targets - cast them even if no explicit unit target is given (required for spell 50516 for example) @@ -1027,6 +1039,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) // Add bonuses and fill damageInfo struct caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo); + caster->DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb); // Send log damage message to client caster->SendSpellNonMeleeDamageLog(&damageInfo); @@ -1186,8 +1199,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) if (aura_effmask) { - Unit * caster = m_originalCaster ? m_originalCaster : m_caster; - Aura * Aur= new Aura(m_spellInfo, aura_effmask, &m_currentBasePoints[0], unit, caster , m_CastItem, m_caster); + Unit * caster = m_originalCaster ? m_originalCaster : m_caster; + Aura * Aur = new Aura(m_spellInfo, aura_effmask, m_currentBasePoints, unit, caster, m_CastItem, m_caster); if (!Aur->IsAreaAura()) { @@ -1412,7 +1425,7 @@ struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, // functor for operator ">" bool operator()(const Unit* _Left, const Unit* _Right) const { - return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); + return MainTarget->GetDistanceOrder(_Left,_Right); } }; @@ -1477,7 +1490,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin if(cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) break; while(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE - && !m_caster->isInFront(*next, max_range) + && !m_caster->isInFrontInMap(*next, max_range) || !m_caster->canSeeOrDetect(*next, false) || !cur->IsWithinLOSInMap(*next)) { @@ -1595,6 +1608,8 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType) break; } case SPELL_TARGET_TYPE_CREATURE: + if(m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetEntry() == i_spellST->second.targetEntry) + return m_targets.getUnitTarget(); case SPELL_TARGET_TYPE_DEAD: default: { @@ -1752,15 +1767,15 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) if(!target) return; - else if(target->GetTypeId() == TYPEID_UNIT) + else if(target->GetTypeId() == TYPEID_GAMEOBJECT) + AddGOTarget((GameObject*)target, i); + else { pushType = PUSH_CHAIN; - if(!m_targets.getUnitTarget()) + if(m_targets.getUnitTarget() != target) m_targets.setUnitTarget((Unit*)target); } - else if(target->GetTypeId() == TYPEID_GAMEOBJECT) - AddGOTarget((GameObject*)target, i); break; } @@ -1923,7 +1938,13 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); } else - sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); + { + sLog.outError( "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id ); + Unit *target = NULL; + if(uint64 guid = m_caster->GetUInt64Value(UNIT_FIELD_TARGET)) + target = ObjectAccessor::GetUnit(*m_caster, guid); + m_targets.setDestination(target ? target : m_caster); + } break; case TARGET_DST_HOME: if(m_caster->GetTypeId() == TYPEID_PLAYER) @@ -2043,7 +2064,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) else if(pushType) { // Dummy, just for client - if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] == SPELL_REQUIRE_DEST) + if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] != SPELL_REQUIRE_UNIT) return; float radius; @@ -2225,9 +2246,20 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura if(!m_targets.getUnitTargetGUID() && m_spellInfo->Targets & TARGET_FLAG_UNIT) { - if(Unit *target = ObjectAccessor::GetUnit(*m_caster, m_caster->GetUInt64Value(UNIT_FIELD_TARGET))) - if(IsValidSingleTargetSpell(target)) - m_targets.setUnitTarget(target); + Unit *target = NULL; + if(m_caster->GetTypeId() == TYPEID_UNIT) + target = m_caster->getVictim(); + else + target = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection()); + + if(target && IsValidSingleTargetSpell(target)) + m_targets.setUnitTarget(target); + else + { + SendCastResult(SPELL_FAILED_BAD_TARGETS); + finish(false); + return; + } } m_spellState = SPELL_STATE_PREPARING; @@ -2835,8 +2867,7 @@ void Spell::finish(bool ok) m_caster->clearUnitState(UNIT_STAT_CASTING); // Unsummon summon as possessed creatures on spell cancel - if(IsChanneledSpell(m_spellInfo) - && m_caster->GetTypeId() == TYPEID_PLAYER) + if(IsChanneledSpell(m_spellInfo) && m_caster->GetTypeId() == TYPEID_PLAYER) { if (Unit * charm = m_caster->GetCharm()) for(int i = 0; i < 3; ++i) @@ -2854,7 +2885,12 @@ void Spell::finish(bool ok) } } } - else if (m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isSummon()) + + // other code related only to successfully finished spells + if(!ok) + return; + + if (m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isSummon()) { // Unsummon statue uint32 spell = m_caster->GetUInt32Value(UNIT_CREATED_BY_SPELL); @@ -2867,10 +2903,6 @@ void Spell::finish(bool ok) } } - // other code related only to successfully finished spells - if(!ok) - return; - //remove spell mods if (m_caster->GetTypeId() == TYPEID_PLAYER) ((Player*)m_caster)->RemoveSpellMods(this); @@ -3969,13 +4001,16 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_NOT_IN_ARENA; // zone check - uint32 zone, area; - m_caster->GetZoneAndAreaId(zone,area); + if(m_caster->GetTypeId() == TYPEID_UNIT || !((Player*)m_caster)->isGameMaster()) + { + uint32 zone, area; + m_caster->GetZoneAndAreaId(zone,area); - SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, - m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL); - if(locRes != SPELL_CAST_OK) - return locRes; + SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, + m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL); + if(locRes != SPELL_CAST_OK) + return locRes; + } // not let players cast spells at mount (and let do it to creatures) if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && @@ -4822,10 +4857,9 @@ SpellCastResult Spell::CheckRange(bool strict) if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0) { - float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); - if(dist > max_range) + 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(dist < min_range) + if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,min_range)) return SPELL_FAILED_TOO_CLOSE; } diff --git a/src/game/Spell.h b/src/game/Spell.h index 6dc8477dcdb..694bcf11277 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -412,6 +412,8 @@ class Spell void SetTargetMap(uint32 i, uint32 cur); + template<typename T> WorldObject* FindCorpseUsing(); + bool CheckTarget( Unit* target, uint32 eff ); bool CanAutoCast(Unit* target); void CheckSrc() { if(!m_targets.HasSrc()) m_targets.setSrc(m_caster); } @@ -607,7 +609,7 @@ class Spell void SpellDamageWeaponDmg(uint32 i); void SpellDamageHeal(uint32 i); - void GetSummonPosition(float &x, float &y, float &z, float radius = 0.0f, uint32 count = 0); + void GetSummonPosition(uint32 i, float &x, float &y, float &z, float radius = 0.0f, uint32 count = 0); void SummonGuardian (uint32 entry, SummonPropertiesEntry const *properties); SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue); @@ -666,6 +668,10 @@ namespace Trinity { Unit *target = (Unit*)itr->getSource(); + // mostly phase check + if(!itr->getSource()->IsInMap(i_source)) + continue; + switch (i_TargetType) { case SPELL_TARGETS_ENEMY: @@ -706,11 +712,11 @@ namespace Trinity i_data->push_back(target); break; case PUSH_IN_FRONT: - if(i_source->isInFront(target, i_radius, M_PI/3)) + if(i_source->isInFrontInMap(target, i_radius, M_PI/3)) i_data->push_back(target); break; case PUSH_IN_BACK: - if(i_source->isInBack(target, i_radius, M_PI/3)) + if(i_source->isInBackInMap(target, i_radius, M_PI/3)) i_data->push_back(target); break; case PUSH_IN_LINE: diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f7f13acc3f8..f7643747a21 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -196,7 +196,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &AuraEffect::HandleRangedAmmoHaste, //141 SPELL_AURA_MOD_RANGED_AMMO_HASTE &AuraEffect::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT &AuraEffect::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE - &AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes + &AuraEffect::HandleAuraSafeFall, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes &AuraEffect::HandleAuraModPetTalentsPoints, //145 SPELL_AURA_MOD_PET_TALENT_POINTS &AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE &AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK @@ -242,7 +242,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance &AuraEffect::HandleNoImmediateEffect, //188 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance &AuraEffect::HandleModRating, //189 SPELL_AURA_MOD_RATING - &AuraEffect::HandleNULL, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN + &AuraEffect::HandleNoImmediateEffect, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN implemented in Player::CalculateReputationGain &AuraEffect::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED &AuraEffect::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE &AuraEffect::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct) @@ -721,28 +721,28 @@ void AreaAuraEffect::Update(uint32 diff) } } - for(std::list<Unit *>::iterator tIter = targets.begin(); tIter != targets.end(); tIter++) + for(std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end(); tIter++) { - bool skip=false; - for(Unit::AuraMap::iterator iter = (*tIter)->GetAuras().begin(); iter != (*tIter)->GetAuras().end();++iter) + if(Aura *aur = (*tIter)->GetAura(GetId(), m_formalCasterGUID)) { - bool samecaster = iter->second->GetCasterGUID() == GetCasterGUID(); - if (samecaster && iter->first == GetId()) + if(aur->HasEffect(GetEffIndex())) + continue; + } + else + { + bool skip = false; + for(Unit::AuraMap::iterator iter = (*tIter)->GetAuras().begin(); iter != (*tIter)->GetAuras().end();++iter) { - if (AuraEffect * aurEff = iter->second->GetPartAura(m_effIndex)) + bool samecaster = iter->second->GetCasterGUID() == m_formalCasterGUID; + if(spellmgr.IsNoStackSpellDueToSpell(GetId(), iter->first, samecaster)) { - skip=true; + skip = true; + break; } - break; - } - if (spellmgr.IsNoStackSpellDueToSpell(GetId(), iter->first,samecaster)) - { - skip=true; - break; } + if(skip) + continue; } - if(skip) - continue; if(SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(GetSpellProto(), (*tIter)->getLevel())) { @@ -750,7 +750,7 @@ void AreaAuraEffect::Update(uint32 diff) // recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?) //if(actualSpellInfo != GetSpellProto()) // actualBasePoints = actualSpellInfo->EffectBasePoints[m_effIndex]; - Aura * aur = (*tIter)->AddAuraEffect(actualSpellInfo->Id, GetEffIndex(), caster, &m_currentBasePoints); + (*tIter)->AddAuraEffect(actualSpellInfo, GetEffIndex(), caster, &m_currentBasePoints); if(m_areaAuraType == AREA_AURA_ENEMY) caster->CombatStart(*tIter); @@ -1000,7 +1000,7 @@ void Aura::_AddAura() for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr) { if(*itr < 0) - m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), m_target); + m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), true); else if(Unit* caster = GetCaster()) caster->AddAura(*itr, m_target); } @@ -2667,25 +2667,6 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real) } case SPELLFAMILY_HUNTER: { - // Improved Aspect of the Viper - if( GetId()==38390 && m_target->GetTypeId()==TYPEID_PLAYER ) - { - if(apply) - { - // + effect value for Aspect of the Viper - SpellModifier *mod = new SpellModifier; - mod->op = SPELLMOD_EFFECT1; - mod->value = m_amount; - mod->type = SPELLMOD_FLAT; - mod->spellId = GetId(); - mod->mask[1] = 0x40000; - - m_spellmod = mod; - } - - ((Player*)m_target)->AddSpellMod(m_spellmod, apply); - return; - } // Glyph of Aspect of the Monkey if(m_spellProto->Id==56833) { @@ -3880,25 +3861,11 @@ void AuraEffect::HandleAuraModSilence(bool apply, bool Real) if (m_target->m_currentSpells[i] && m_target->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) m_target->InterruptSpell(i,false); // Stop spells on prepare or casting state + /* switch (GetId()) { - // Arcane Torrent (Energy) - case 25046: - { - Unit * caster = GetCaster(); - if (!caster) - return; - - // Search Mana Tap auras on caster - AuraEffect * dummy = caster->GetDummyAura(28734); - if (dummy) - { - int32 bp = dummy->GetParentAura()->GetStackAmount() * 10; - caster->CastCustomSpell(caster, 25048, &bp, NULL, NULL, true); - m_target->RemoveAurasDueToSpell(28734); - } - } } + */ } else { @@ -5698,6 +5665,7 @@ void AuraEffect::PeriodicTick() if(!pCaster) return; + // Consecrate ticks can miss and will not show up in the combat log if( GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_PERSISTENT_AREA_AURA && pCaster->SpellHitResult(m_target,GetSpellProto(),false)!=SPELL_MISS_NONE) return; @@ -5746,7 +5714,8 @@ void AuraEffect::PeriodicTick() } } m_amount = 100 * m_tickNumber; - }break; + break; + } default: break; } @@ -5800,6 +5769,8 @@ void AuraEffect::PeriodicTick() sLog.outDetail("PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u", GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId(),absorb); + pCaster->DealDamageMods(m_target,pdamage,&absorb); + WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size data.append(m_target->GetPackGUID()); data.appendPackGUID(GetCasterGUID()); @@ -5983,10 +5954,13 @@ void AuraEffect::PeriodicTick() } else { - pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), gain, GetSpellSchoolMask(GetSpellProto()), 0, 0, false, 0, false); + uint32 damage = gain; + uint32 absorb = 0; + 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 ); - pCaster->DealDamage(pCaster, gain, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); + pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); } } @@ -6202,6 +6176,9 @@ void AuraEffect::PeriodicTick() SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask); //no SpellDamageBonus for burn mana pCaster->CalculateSpellDamageTaken(&damageInfo, gain, spellProto); + + pCaster->DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb); + pCaster->SendSpellNonMeleeDamageLog(&damageInfo); // Set trigger flag @@ -6973,3 +6950,12 @@ void Aura::UnregisterSingleCastAura() m_isSingleTargetAura = false; } } + +void AuraEffect::HandleAuraSafeFall( bool Apply, bool Real ) +{ + // implemented in WorldSession::HandleMovementOpcodes + + // only special case + if(Apply && Real && GetId()==32474 && m_target->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_target)->ActivateTaxiPathTo(506,GetId()); +} diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index f0120596ce9..973272a75d2 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -217,6 +217,7 @@ class TRINITY_DLL_SPEC AuraEffect void HandlePeriodicTriggerSpellWithValue(bool apply, bool Real); void HandlePeriodicEnergize(bool Apply, bool Real); void HandleAuraModResistanceExclusive(bool Apply, bool Real); + void HandleAuraSafeFall(bool Apply, bool Real); void HandleAuraModPetTalentsPoints(bool Apply, bool Real); void HandleModStealth(bool Apply, bool Real); void HandleInvisibility(bool Apply, bool Real); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 14b012b6f73..330b0b9027b 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -286,8 +286,7 @@ void Spell::EffectInstaKill(uint32 /*i*/) if(m_caster==unitTarget) // prevent interrupt message finish(); - uint32 health = unitTarget->GetHealth(); - m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } void Spell::EffectEnvirinmentalDMG(uint32 i) @@ -652,9 +651,9 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) else if(m_spellInfo->SpellFamilyFlags[1]&0x00040000) { // Add main hand dps * effect[2] amount - float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; + float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2; int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget); - damage += count * int32(averange * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK); + damage += count * int32(average * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK); } // Shield of Righteousness else if(m_spellInfo->SpellFamilyFlags[1]&0x00100000) @@ -1012,17 +1011,6 @@ void Spell::EffectDummy(uint32 i) m_caster->CastSpell(unitTarget,29294,true); return; } - case 28730: // Arcane Torrent (Mana) - { - Aura * dummy = m_caster->GetAura(28734, m_caster->GetGUID()); - if (dummy) - { - int32 bp = damage * dummy->GetStackAmount(); - m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true); - m_caster->RemoveAurasDueToSpell(28734); - } - return; - } case 29200: // Purify Helboar Meat { if( m_caster->GetTypeId() != TYPEID_PLAYER ) @@ -1324,12 +1312,7 @@ void Spell::EffectDummy(uint32 i) (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) && spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 ) { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); + ((Player*)m_caster)->RemoveSpellCooldown(classspell,true); } } return; @@ -1367,24 +1350,29 @@ void Spell::EffectDummy(uint32 i) if(!unitTarget) return; - uint32 rage = m_caster->GetPower(POWER_RAGE); + uint32 rage=0; // Glyph of Execution bonus if (AuraEffect *aura = m_caster->GetDummyAura(58367)) rage+=aura->GetAmount(); spell_id = 20647; - bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] + - m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); // Sudden death cost modifier if (Aura * aur = m_caster->GetAura(52437)) { + rage += m_powerCost; m_caster->ModifyPower(POWER_RAGE,- m_powerCost); if (m_caster->GetPower(POWER_RAGE)<100) m_caster->SetPower(POWER_RAGE,100); m_caster->RemoveAura(aur); } else + { + rage += m_caster->GetPower(POWER_RAGE); m_caster->SetPower(POWER_RAGE,0); + } + + bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] + + m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f); break; } // Slam @@ -1580,14 +1568,7 @@ void Spell::EffectDummy(uint32 i) SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags[1] & 0x00000240 || spellInfo->SpellFamilyFlags[0] & 0x00000860)) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } + ((Player*)m_caster)->RemoveSpellCooldown(classspell,true); } return; } @@ -1614,14 +1595,7 @@ void Spell::EffectDummy(uint32 i) SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell); if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 ) - { - ((Player*)m_caster)->RemoveSpellCooldown(classspell); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(classspell); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } + ((Player*)m_caster)->RemoveSpellCooldown(classspell,true); } return; } @@ -1716,17 +1690,8 @@ void Spell::EffectDummy(uint32 i) // non-standard cast requirement check if (!unitTarget || unitTarget->getAttackers().empty()) { - // clear cooldown at fail if(m_caster->GetTypeId()==TYPEID_PLAYER) - { - ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id); - - WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8)); - data << uint32(m_spellInfo->Id); - data << uint64(m_caster->GetGUID()); - ((Player*)m_caster)->GetSession()->SendPacket(&data); - } - + ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true); SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT); return; } @@ -3230,7 +3195,7 @@ void Spell::EffectSummonType(uint32 i) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); float x, y, z; - GetSummonPosition(x, y, z); + GetSummonPosition(i, x, y, z); /*//totem must be at same Z in case swimming caster and etc. if( fabs( z - m_caster->GetPositionZ() ) > 5 ) @@ -3315,7 +3280,7 @@ void Spell::EffectSummonType(uint32 i) summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - summon->GetMotionMaster()->MoveTargetedHome(); + summon->AI()->EnterEvadeMode(); std::string name = m_originalCaster->GetName(); name.append(petTypeSuffix[3]); @@ -3331,7 +3296,7 @@ void Spell::EffectSummonType(uint32 i) for(int32 count = 0; count < amount; ++count) { float px, py, pz; - GetSummonPosition(px, py, pz, radius, count); + GetSummonPosition(i, px, py, pz, radius, count); TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN; @@ -4776,17 +4741,17 @@ void Spell::EffectScriptEffect(uint32 effIndex) unitTarget->CastSpell(unitTarget, 44870, true); break; } - // spell of Brutallus - Stomp - case 45185: - { - if(!unitTarget) - return; - - if(unitTarget->HasAura(46394)) // spell of Brutallus - Burn - unitTarget->RemoveAurasDueToSpell(46394); + // spell of Brutallus - Stomp + case 45185: + { + if(!unitTarget) + return; - break; - } + if(unitTarget->HasAura(46394)) // spell of Brutallus - Burn + unitTarget->RemoveAurasDueToSpell(46394); + + break; + } // Negative Energy case 46289: { @@ -5891,47 +5856,7 @@ void Spell::EffectSendTaxi(uint32 i) if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]); - if(!entry) - return; - - std::vector<uint32> nodes; - - nodes.resize(2); - nodes[0] = entry->from; - nodes[1] = entry->to; - - uint32 mountid = 0; - switch(m_spellInfo->Id) - { - case 31606: //Stormcrow Amulet - mountid = 17447; - break; - case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run - case 45113: //Quest - Sunwell Daily - Ship Bombing Run - case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return - mountid = 22840; - break; - case 34905: //Stealth Flight - mountid = 6851; - break; - case 45883: //Amber Ledge to Beryl Point - mountid = 23524; - break; - case 46064: //Amber Ledge to Coldarra - mountid = 6371; - break; - case 53335: //Stormwind Harbor Flight - Peaceful - mountid = 6852; - break; - case 41533: //Fly of the Netherwing - case 41540: //Fly of the Netherwing - mountid = 23468; - break; - } - - ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid); - + ((Player*)unitTarget)->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id); } void Spell::EffectPlayerPull(uint32 i) @@ -6292,7 +6217,7 @@ void Spell::EffectSummonDemon(uint32 i) for(int32 count = 0; count < amount; ++count) { float px, py, pz; - GetSummonPosition(px, py, pz, radius, count); + GetSummonPosition(i, px, py, pz, radius, count); int32 duration = GetSpellDuration(m_spellInfo); @@ -6492,7 +6417,7 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties for(int32 count = 0; count < amount; ++count) { float px, py, pz; - GetSummonPosition(px, py, pz, radius, count); + GetSummonPosition(0, px, py, pz, radius, count); TempSummon *summon = map->SummonCreature(entry, px, py, pz, m_caster->GetOrientation(), properties, duration, caster); if(!summon) @@ -6503,11 +6428,11 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id); - summon->GetMotionMaster()->MoveTargetedHome(); + summon->AI()->EnterEvadeMode(); } } -void Spell::GetSummonPosition(float &x, float &y, float &z, float radius, uint32 count) +void Spell::GetSummonPosition(uint32 i, float &x, float &y, float &z, float radius, uint32 count) { if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) { @@ -6520,7 +6445,25 @@ void Spell::GetSummonPosition(float &x, float &y, float &z, float radius, uint32 } // Summon in random point all other units if location present else - m_caster->GetRandomPoint(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ,radius,x,y,z); + { + //This is a workaround. Do not have time to write much about it + switch(m_spellInfo->EffectImplicitTargetA[i]) + { + case TARGET_MINION: + case TARGET_DEST_CASTER_RANDOM: + m_caster->GetGroundPointAroundUnit(x, y, z, radius * rand_norm(), rand_norm()*2*M_PI); + break; + case TARGET_DEST_DEST_RANDOM: + case TARGET_DEST_TARGET_RANDOM: + m_caster->GetRandomPoint(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ,radius,x,y,z); + break; + default: + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + break; + } + } } // Summon if dest location not present near caster else @@ -6534,4 +6477,4 @@ void Spell::EffectRenamePet(uint32 /*eff_idx*/) return; unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED); -} +}
\ No newline at end of file diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 945255f883a..4e5a4744e9a 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -27,6 +27,7 @@ #include "Chat.h" #include "Spell.h" #include "BattleGroundMgr.h" +#include "CreatureAI.h" bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS]; @@ -1472,6 +1473,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool //if spells have exactly the same effect they cannot stack for(uint32 i = 0; i < 3; ++i) if(spellInfo_1->Effect[i] != spellInfo_2->Effect[i] + // Overkill and master of subtlety need this + || spellInfo_1->EffectApplyAuraName[i] == SPELL_AURA_DUMMY + || spellInfo_1->EffectApplyAuraName[i] == SPELL_AURA_PERIODIC_DUMMY + || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i] || spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura return false; // need itemtype check? need an example to add that check @@ -2426,31 +2431,32 @@ void SpellMgr::LoadSpellCustomAttr() case 45976: // Muru Portal Channel case 39365: // Thundering Storm case 41071: // Raise Dead (HACK) - case 28542: // Life Drain - Sapphiron spellInfo->MaxAffectedTargets = 1; break; case 41376: // Spite case 39992: // Needle Spine - case 29576: //Multi-Shot - case 40816: //Saber Lash - case 37790: //Spread Shot - case 46771: //Flame Sear - case 45248: //Shadow Blades + case 29576: // Multi-Shot + case 40816: // Saber Lash + case 37790: // Spread Shot + case 46771: // Flame Sear + case 45248: // Shadow Blades case 41303: // Soul Drain case 54172: // Divine Storm (heal) - case 29213: // Curse of the Plaguebringer + case 29213: // Curse of the Plaguebringer - Noth + case 28542: // Life Drain - Sapphiron spellInfo->MaxAffectedTargets = 3; break; case 38310: //Multi-Shot spellInfo->MaxAffectedTargets = 4; break; case 42005: // Bloodboil - case 38296: //Spitfire Totem - case 37676: //Insidious Whisper - case 46009: //Negative Energy - case 45641: //Fire Bloom - case 54937: //Glyph of Holy Light - case 55665: // Life Drain - Sapphiron + case 38296: // Spitfire Totem + case 37676: // Insidious Whisper + case 46009: // Negative Energy + case 45641: // Fire Bloom + case 54937: // Glyph of Holy Light + case 55665: // Life Drain - Sapphiron (H) + case 28796: // Poison Bolt Volly - Faerlina spellInfo->MaxAffectedTargets = 5; break; case 40827: // Sinful Beam @@ -2458,7 +2464,8 @@ void SpellMgr::LoadSpellCustomAttr() case 40860: // Vile Beam case 40861: // Wicked Beam case 57669: // Replenishment - case 54835: // Curse of the Plaguebringer + case 54835: // Curse of the Plaguebringer - Noth (H) + case 54098: // Poison Bolt Volly - Faerlina (H) spellInfo->MaxAffectedTargets = 10; break; case 8122: case 8124: case 10888: case 10890: // Psychic Scream @@ -2516,6 +2523,8 @@ void SpellMgr::LoadSpellCustomAttr() SummonPropertiesEntry *properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121)); properties->Type = SUMMON_TYPE_TOTEM; + + CreatureAI::FillAISpellInfo(); } void SpellMgr::LoadSpellLinked() diff --git a/src/game/TaxiHandler.cpp b/src/game/TaxiHandler.cpp index 24c6aca147a..5ba65c00660 100644 --- a/src/game/TaxiHandler.cpp +++ b/src/game/TaxiHandler.cpp @@ -128,7 +128,8 @@ void WorldSession::SendDoFlight( uint16 MountId, uint32 path, uint32 pathNode ) while(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()==FLIGHT_MOTION_TYPE) GetPlayer()->GetMotionMaster()->MovementExpired(false); - GetPlayer()->Mount( MountId ); + if (MountId) + GetPlayer()->Mount( MountId ); GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path,pathNode); } @@ -190,7 +191,7 @@ void WorldSession::HandleActivateTaxiFarOpcode ( WorldPacket & recv_data ) sLog.outDebug( "WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d" ,nodes.front(),nodes.back()); - GetPlayer()->ActivateTaxiPathTo(nodes, 0, npc); + GetPlayer()->ActivateTaxiPathTo(nodes, npc); } void WorldSession::HandleTaxiNextDestinationOpcode(WorldPacket& /*recv_data*/) @@ -275,6 +276,6 @@ void WorldSession::HandleActivateTaxiOpcode( WorldPacket & recv_data ) return; } - GetPlayer()->ActivateTaxiPathTo(nodes, 0, npc); + GetPlayer()->ActivateTaxiPathTo(nodes, npc); } diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp index 170e590fd9c..993ece988a0 100644 --- a/src/game/TemporarySummon.cpp +++ b/src/game/TemporarySummon.cpp @@ -208,10 +208,8 @@ void TempSummon::InitSummon() if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && m_spells[0]) { setFaction(owner->getFaction()); - if(m_spells[1] && GetMap()->IsHeroic()) - CastSpell(this, m_spells[1], false, 0, 0, m_summonerGUID); - else - CastSpell(this, m_spells[0], false, 0, 0, m_summonerGUID); + SetLevel(owner->getLevel()); + CastSpell(this, m_spells[0], false, 0, 0, m_summonerGUID); } } } @@ -309,6 +307,8 @@ void Guardian::InitStats(uint32 duration) { Minion::InitStats(duration); + InitStatsForLevel(m_owner->getLevel()); + if(m_owner->GetTypeId() == TYPEID_PLAYER) m_charmInfo->InitCharmCreateSpells(); diff --git a/src/game/TemporarySummon.h b/src/game/TemporarySummon.h index 09e7f22afb0..e089c77c96e 100644 --- a/src/game/TemporarySummon.h +++ b/src/game/TemporarySummon.h @@ -23,7 +23,7 @@ #include "Creature.h" -class TempSummon : public Creature +class TRINITY_DLL_SPEC TempSummon : public Creature { public: explicit TempSummon(SummonPropertiesEntry const *properties, Unit *owner); diff --git a/src/game/TradeHandler.cpp b/src/game/TradeHandler.cpp index 439626861fd..3cead4551c1 100644 --- a/src/game/TradeHandler.cpp +++ b/src/game/TradeHandler.cpp @@ -461,30 +461,30 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,8); - if( GetPlayer()->pTrader ) + if (GetPlayer()->pTrader) return; uint64 ID; - if( !GetPlayer()->isAlive() ) + if (!GetPlayer()->isAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } - if( GetPlayer()->hasUnitState(UNIT_STAT_STUNNED) ) + if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } - if( isLogingOut() ) + if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } - if( GetPlayer()->isInFlight() ) + if (GetPlayer()->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; @@ -494,43 +494,43 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) Player* pOther = ObjectAccessor::FindPlayer( ID ); - if( !pOther ) + if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } - if( pOther == GetPlayer() || pOther->pTrader ) + if (pOther == GetPlayer() || pOther->pTrader) { SendTradeStatus(TRADE_STATUS_BUSY); return; } - if( !pOther->isAlive() ) + if (!pOther->isAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } - if( pOther->isInFlight() ) + if (pOther->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } - if( pOther->hasUnitState(UNIT_STAT_STUNNED) ) + if (pOther->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } - if( pOther->GetSession()->isLogingOut() ) + if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } - if( pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()) ) + if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; @@ -542,7 +542,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) return; } - if( pOther->GetDistance2d( _player ) > 10.0f ) + if (!pOther->IsWithinDistInMap(_player,10.0f,false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index bb2f8e98f4b..e36c25883d4 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -413,7 +413,7 @@ void Unit::resetAttackTimer(WeaponAttackType type) m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); } -bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const +bool Unit::IsWithinCombatRange(const Unit *obj, float dist2compare) const { if (!obj || !IsInMap(obj)) return false; @@ -428,7 +428,7 @@ bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const return distsq < maxdist * maxdist; } -bool Unit::IsWithinMeleeRange(Unit *obj, float dist) const +bool Unit::IsWithinMeleeRange(const Unit *obj, float dist) const { if (!obj || !IsInMap(obj)) return false; @@ -535,10 +535,15 @@ void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell) } } -uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss) +void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb) { if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode()) - return 0; + { + if(absorb) + absorb += damage; + damage = 0; + return; + } //You don't lose health from damage taken from another player while in a sanctuary //You still see it in the combat log though @@ -546,14 +551,30 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa { const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId()); if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary - return 0; + { + if(absorb) + absorb += damage; + damage = 0; + } } + uint32 originalDamage = damage; + + //Script Event damage Deal + //if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI()) + // ((Creature *)this)->AI()->DamageDeal(pVictim, damage); //Script Event damage taken if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->IsAIEnabled ) - { ((Creature *)pVictim)->AI()->DamageTaken(this, damage); + if(absorb && originalDamage > damage) + absorb += (originalDamage - damage); +} + +uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss) +{ + if( pVictim->GetTypeId()== TYPEID_UNIT) + { // Set tagging if(!pVictim->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER) && !((Creature*)pVictim)->isPet()) { @@ -1203,6 +1224,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask); damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE); CalculateSpellDamageTaken(&damageInfo, damage, spellInfo); + DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb); SendSpellNonMeleeDamageLog(&damageInfo); DealSpellDamage(&damageInfo, true); return damageInfo.damage; @@ -1706,6 +1728,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) //CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist); //damage-=absorb + resist; + pVictim->DealDamageMods(this,damage,NULL); + WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4+4+4)); data << uint64(pVictim->GetGUID()); data << uint64(GetGUID()); @@ -2085,8 +2109,12 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe int32 canabsorb = caster->GetHealth(); if (canabsorb < absorbed) absorbed = canabsorb; - DealDamage(caster, absorbed, NULL, damagetype, schoolMask, 0, false); + RemainingDamage -= absorbed; + + uint32 ab_damage = absorbed; + DealDamageMods(caster,ab_damage,NULL); + DealDamage(caster, ab_damage, NULL, damagetype, schoolMask, 0, false); continue; } break; @@ -2195,10 +2223,15 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe RemainingDamage -= currentAbsorb; - SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, currentAbsorb, schoolMask, 0, 0, false, 0, false); - CleanDamage cleanDamage = CleanDamage(currentAbsorb, BASE_ATTACK, MELEE_HIT_NORMAL); - DealDamage(caster, currentAbsorb, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); + uint32 splitted = currentAbsorb; + uint32 splitted_absorb = 0; + DealDamageMods(caster,splitted,&splitted_absorb); + + SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false); + + CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); + DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); } AuraEffectList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT); @@ -2215,11 +2248,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive()) continue; - int32 splitted = int32(RemainingDamage * (*i)->GetAmount() / 100.0f); + uint32 splitted = uint32(RemainingDamage * (*i)->GetAmount() / 100.0f); - RemainingDamage -= splitted; + RemainingDamage -= int32(splitted); - SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, 0, 0, false, 0, false); + uint32 split_absorb = 0; + DealDamageMods(caster,splitted,&split_absorb); + + SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false); CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL); DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false); @@ -2354,6 +2390,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex CalcDamageInfo damageInfo; CalculateMeleeDamage(pVictim, 0, &damageInfo, attType); // 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); @@ -2775,7 +2812,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell) return SPELL_MISS_NONE; // Ranged attack cannot be parry/dodge only deflect - if (attType == RANGED_ATTACK) + // 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) { // only if in front if (pVictim->HasInArc(M_PI,this)) @@ -3526,7 +3565,7 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const return NULL; } -bool Unit::isInFront(Unit const* target, float distance, float arc) const +bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const { return IsWithinDistInMap(target, distance) && HasInArc( arc, target ); } @@ -3536,7 +3575,7 @@ void Unit::SetInFront(Unit const* target) SetOrientation(GetAngle(target)); } -bool Unit::isInBack(Unit const* target, float distance, float arc) const +bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const { return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target ); } @@ -4272,7 +4311,7 @@ bool Unit::HasAura(Aura * aur) const bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const { if (Aura * aur = GetAura(spellId, caster)) - return bool(aur->HasEffect(effIndex)); + return aur->HasEffect(effIndex); return false; } @@ -4486,38 +4525,32 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log) data.append(log->target->GetPackGUID()); data.append(log->attacker->GetPackGUID()); data << uint32(log->SpellID); - data << uint32(log->damage); //damage amount + data << uint32(log->damage); // damage amount data << uint32(int32 (log->target->GetHealth()-log->damage ) >0 ? 0 : log->damage - log->target->GetHealth()); - data << uint8 (log->schoolMask); //damage school - data << uint32(log->absorb); //AbsorbedDamage - data << uint32(log->resist); //resist - data << uint8 (log->phusicalLog); // damsge type? flag - data << uint8 (log->unused); //unused - data << uint32(log->blocked); //blocked + //data << uint32(log->overkill); // overkill + data << uint8 (log->schoolMask); // damage school + data << uint32(log->absorb); // AbsorbedDamage + data << uint32(log->resist); // resist + data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name + data << uint8 (log->unused); // unused + data << uint32(log->blocked); // blocked data << uint32(log->HitInfo); - data << uint8 (0); // flag to use extend data + data << uint8 (0); // flag to use extend data SendMessageToSet( &data, true ); } void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit) { - sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG"); - WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size - data.append(target->GetPackGUID()); - data.append(GetPackGUID()); - data << uint32(SpellID); - int32 damageDone = Damage-AbsorbedDamage-Resist-Blocked; - data << uint32(damageDone); - data << uint32(int32 (target->GetHealth()-damageDone ) >0 ? 0 : damageDone - target->GetHealth());// wotlk - data << uint8(damageSchoolMask); // spell school - data << uint32(AbsorbedDamage); // AbsorbedDamage - data << uint32(Resist); // resist - data << uint8(PhysicalDamage); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name - data << uint8(0); // unk isFromAura - data << uint32(Blocked); // blocked - data << uint32(CriticalHit ? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster? - data << uint8(0); // isDebug? - SendMessageToSet( &data, true ); + SpellNonMeleeDamage log(this,target,SpellID,damageSchoolMask); + log.damage = Damage-AbsorbedDamage-Resist-Blocked; + log.absorb = AbsorbedDamage; + log.resist = Resist; + log.physicalLog = PhysicalDamage; + log.blocked = Blocked; + log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6; + if(CriticalHit) + log.HitInfo |= SPELL_HIT_TYPE_CRIT; + SendSpellNonMeleeDamageLog(&log); } void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const *procSpell) @@ -5301,6 +5334,25 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger CastSpell(this, 28682, true, castItem, triggeredByAura); return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns } + // Glyph of Ice Block + case 56372: + { + if(GetTypeId() != TYPEID_PLAYER) + return false; + + SpellCooldowns SpellCDs = ((Player*)this)->GetSpellCooldowns(); + // remove cooldowns on all ranks of Frost Nova + for(SpellCooldowns::const_iterator itr = SpellCDs.begin(); itr != SpellCDs.end(); itr++) + { + SpellEntry const* SpellCDs_entry = sSpellStore.LookupEntry(itr->first); + // Frost Nova + if(SpellCDs_entry && SpellCDs_entry->SpellFamilyName == SPELLFAMILY_MAGE && SpellCDs_entry->SpellFamilyFlags[0] & 0x00000040) + { + ((Player*)this)->RemoveSpellCooldown(SpellCDs_entry->Id, true); + } + } + break; + } } break; } @@ -5579,6 +5631,31 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 56160; break; } + // Glyph of Prayer of Healing + case 55680: + { + triggered_spell_id = 56161; + + SpellEntry const* GoPoH = sSpellStore.LookupEntry(triggered_spell_id); + if(!GoPoH) + return false; + + int EffIndex = 0; + for(int i = 0; i < MAX_SPELL_EFFECTS; i++) + { + if(GoPoH->Effect[i] == SPELL_EFFECT_APPLY_AURA) + { + EffIndex = i; + break; + } + } + int32 tickcount = GetSpellMaxDuration(GoPoH) / GoPoH->EffectAmplitude[EffIndex]; + if(!tickcount) + return false; + + basepoints0 = damage * triggerAmount / tickcount / 100; + break; + } // Improved Shadowform case 47570: case 47569: @@ -6750,6 +6827,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig // Set trigger spell id, target, custom basepoints uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()]; + if(procSpell && procSpell->Id == trigger_spell_id) + return false; + Unit* target = NULL; int32 basepoints0 = 0; @@ -9918,7 +9998,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy) ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); if(enemy) { - if(!((Creature*)this)->HasReactState(REACT_PASSIVE) && ((Creature*)this)->IsAIEnabled) + if(((Creature*)this)->IsAIEnabled) ((Creature*)this)->AI()->EnterCombat(enemy); if(((Creature*)this)->GetFormation()) ((Creature*)this)->GetFormation()->MemberAttackStart((Creature*)this, enemy); @@ -11579,11 +11659,14 @@ void CharmInfo::InitPossessCreateSpells() { for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i) { - uint32 spellid = ((Creature*)m_unit)->m_spells[i]; - if(IsPassiveSpell(spellid)) - m_unit->CastSpell(m_unit, spellid, true); + uint32 spellId = ((Creature*)m_unit)->m_spells[i]; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD) + spellId = 0; + if(IsPassiveSpell(spellId)) + m_unit->CastSpell(m_unit, spellId, true); else - AddSpellToAB(0, spellid, ACT_DISABLED); + AddSpellToAB(0, spellId, ACT_DISABLED); } } } @@ -11601,6 +11684,10 @@ void CharmInfo::InitCharmCreateSpells() for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x) { uint32 spellId = ((Creature*)m_unit)->m_spells[x]; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD) + spellId = 0; + m_charmspells[x].spellId = spellId; if(!spellId) @@ -11615,7 +11702,6 @@ void CharmInfo::InitCharmCreateSpells() { ActiveStates newstate; bool onlyselfcast = true; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if(!spellInfo) onlyselfcast = false; for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away @@ -11925,6 +12011,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask); uint32 damage = SpellDamageBonus(pTarget, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE); CalculateSpellDamageTaken(&damageInfo, damage, spellInfo); + DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb); SendSpellNonMeleeDamageLog(&damageInfo); DealSpellDamage(&damageInfo, true); break; @@ -12166,6 +12253,13 @@ void Unit::StopMoving() SendMessageToSet(&data,false); } +void Unit::SendMovementFlagUpdate() +{ + WorldPacket data; + BuildHeartBeatMsg(&data); + SendMessageToSet(&data, false); +} + /* void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID) { @@ -13574,16 +13668,14 @@ void Unit::AddAura(uint32 spellId, Unit* target) target->AddAura(Aur); } -Aura * Unit::AddAuraEffect(uint32 spellId, uint8 effIndex, Unit* caster, int32 * basePoints) +Aura * Unit::AddAuraEffect(const SpellEntry * spellInfo, uint8 effIndex, Unit* caster, int32 * basePoints) { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); - if(!spellInfo || !caster) - return NULL; - // can't do that for passive auras - they stack from same caster so there is no way to get exact aura which should get effect //assert (!IsPassiveSpell(spellInfo)); - Aura * aur = GetAura(spellId, caster->GetGUID()); + sLog.outDebug("AddAuraEffect: spell id: %u, effect index: %u", spellInfo->Id, (uint32)effIndex); + + Aura *aur = GetAura(spellInfo->Id, caster->GetGUID()); if (aur) { @@ -13600,10 +13692,10 @@ Aura * Unit::AddAuraEffect(uint32 spellId, uint8 effIndex, Unit* caster, int32 * aur = new Aura(spellInfo, 1<<effIndex, amount, this ,caster); } else - { aur = new Aura(spellInfo, 1<<effIndex, NULL, this ,caster); - } - AddAura(aur); + + if(!AddAura(aur)) + return NULL; } return aur; } @@ -13901,7 +13993,7 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca DestroyForNearbyPlayers(); GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation); - ObjectAccessor::UpdateObjectVisibility(this); + //ObjectAccessor::UpdateObjectVisibility(this); //WorldPacket data; // Work strange for many spells: triggered active mover set for targeted player to creature diff --git a/src/game/Unit.h b/src/game/Unit.h index fcfc14b5394..bbd7471b1b8 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -745,24 +745,25 @@ struct CalcDamageInfo // Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode struct SpellNonMeleeDamage{ - SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask) - : target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), schoolMask(_schoolMask), - absorb(0), resist(0), phusicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) - {} - - Unit *target; - Unit *attacker; - uint32 SpellID; - uint32 damage; - uint32 schoolMask; - uint32 absorb; - uint32 resist; - bool phusicalLog; - bool unused; - uint32 blocked; - uint32 HitInfo; - // Used for help - uint32 cleanDamage; + SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask) + : target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask), + absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) + {} + + Unit *target; + Unit *attacker; + uint32 SpellID; + uint32 damage; + uint32 overkill; + uint32 schoolMask; + uint32 absorb; + uint32 resist; + bool physicalLog; + bool unused; + uint32 blocked; + uint32 HitInfo; + // Used for help + uint32 cleanDamage; }; uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition); @@ -939,8 +940,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SetCanDualWield(bool value) { m_canDualWield = value; } float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; } float GetMeleeReach() const { float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; } - bool IsWithinCombatRange(Unit *obj, float dist2compare) const; - bool IsWithinMeleeRange(Unit *obj, float dist = MELEE_RANGE) const; + bool IsWithinCombatRange(const Unit *obj, float dist2compare) const; + bool IsWithinMeleeRange(const Unit *obj, float dist = MELEE_RANGE) const; void GetRandomContactPoint( const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax ) const; uint32 m_extraAttacks; bool m_canDualWield; @@ -1072,6 +1073,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject 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); int32 DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical = false); @@ -1186,7 +1188,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0); void AddAura(uint32 spellId, Unit *target); void HandleAuraEffect(AuraEffect * aureff, bool apply); - Aura *AddAuraEffect(uint32 spellId, uint8 effIndex, Unit* caster, int32 * basePoints=NULL); + Aura *AddAuraEffect(const SpellEntry * spellInfo, uint8 effIndex, Unit* caster, int32 * basePoints=NULL); bool IsDamageToThreatSpell(SpellEntry const * spellInfo) const; @@ -1212,6 +1214,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end); void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL); void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL); + void SendMovementFlagUpdate(); bool isAlive() const { return (m_deathState == ALIVE); }; bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); }; @@ -1400,9 +1403,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const; void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } - bool isInFront(Unit const* target,float distance, float arc = M_PI) const; + bool isInFrontInMap(Unit const* target,float distance, float arc = M_PI) const; void SetInFront(Unit const* target); - bool isInBack(Unit const* target, float distance, float arc = M_PI) const; + bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const; bool isInLine(Unit const* target, float distance) const; // Visibility system diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp new file mode 100644 index 00000000000..12dc20692c6 --- /dev/null +++ b/src/game/UnitAI.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-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 "UnitAI.h" +#include "Player.h" +#include "Creature.h" +#include "SpellAuras.h" + +void UnitAI::AttackStart(Unit *victim) +{ + if(!victim) + return; + + if(me->Attack(victim, true)) + { + //DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", me->GetName(), victim->GetGUIDLow()); + me->GetMotionMaster()->MoveChase(victim); + } +} + +void UnitAI::DoMeleeAttackIfReady() +{ + if(me->hasUnitState(UNIT_STAT_CASTING)) + return; + + //Make sure our attack is ready and we aren't currently casting before checking distance + if (me->isAttackReady()) + { + //If we are within range melee the target + if (me->IsWithinMeleeRange(me->getVictim())) + { + me->AttackerStateUpdate(me->getVictim()); + me->resetAttackTimer(); + } + } + if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK)) + { + //If we are within range melee the target + if (me->IsWithinMeleeRange(me->getVictim())) + { + me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK); + me->resetAttackTimer(OFF_ATTACK); + } + } +} + +//Enable PlayerAI when charmed +void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; } + +void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) +{ + Creature *charmer = (Creature*)me->GetCharmer(); + + //kill self if charm aura has infinite duration + if(charmer->IsInEvadeMode()) + { + Unit::AuraEffectList const& auras = me->GetAurasByType(SPELL_AURA_MOD_CHARM); + for(Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) + if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetParentAura()->IsPermanent()) + { + charmer->Kill(me); + return; + } + } + + if(!charmer->isInCombat()) + me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + + Unit *target = me->getVictim(); + if(!target || !charmer->canAttack(target)) + AttackStart(charmer->SelectNearestTarget()); +} diff --git a/src/game/UnitAI.h b/src/game/UnitAI.h new file mode 100644 index 00000000000..04de74f480e --- /dev/null +++ b/src/game/UnitAI.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-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 + */ + +#ifndef TRINITY_UNITAI_H +#define TRINITY_UNITAI_H + +#include "Platform/Define.h" + +class Unit; +class Player; + +class TRINITY_DLL_SPEC UnitAI +{ + protected: + Unit * const me; + public: + explicit UnitAI(Unit *u) : me(u) {} + virtual void AttackStart(Unit *); + virtual void UpdateAI(const uint32 diff) = 0; + + virtual void InitializeAI() { Reset(); } + + virtual void Reset() {}; + + // Called when unit is charmed + virtual void OnCharmed(bool apply) = 0; + + // Pass parameters between AI + virtual void DoAction(const int32 param) {} + + //Do melee swing of current victim if in rnage and ready and not casting + void DoMeleeAttackIfReady(); +}; + +class TRINITY_DLL_SPEC PlayerAI : public UnitAI +{ + protected: + Player* const me; + public: + explicit PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {} + + void OnCharmed(bool apply); +}; + +class TRINITY_DLL_SPEC SimpleCharmedAI : public PlayerAI +{ + public: + void UpdateAI(const uint32 diff); +}; + +#endif diff --git a/src/game/WaypointManager.cpp b/src/game/WaypointManager.cpp index a677fd5b6d2..26be14d89fa 100644 --- a/src/game/WaypointManager.cpp +++ b/src/game/WaypointManager.cpp @@ -24,12 +24,12 @@ #include "ProgressBar.h" #include "MapManager.h" -UNORDERED_MAP<uint32, WaypointPath*> waypoint_map; +WaypointPathMap WaypointPathHolder; WaypointStore WaypointMgr; void WaypointStore::Free() { - waypoint_map.clear(); + WaypointPathHolder.clear(); } void WaypointStore::Load() @@ -37,7 +37,7 @@ void WaypointStore::Load() QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`id`) FROM `waypoint_data`"); if(!result) { - sLog.outError(" an error occured while loading the table `waypoint_data` ( maybe it doesn't exist ?)\n"); + sLog.outError("an error occured while loading the table `waypoint_data` (maybe it doesn't exist ?)"); exit(1); // Stop server at loading non exited table or not accessable table } @@ -47,7 +47,7 @@ void WaypointStore::Load() result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`action`,`action_chance` FROM `waypoint_data` ORDER BY `id`, `point`"); if(!result) { - sLog.outErrorDb("The table `creature_addon` is empty or corrupted"); + sLog.outErrorDb("The table `waypoint_data` is empty or corrupted"); return; } @@ -87,22 +87,21 @@ void WaypointStore::Load() path_data->push_back(wp); - if(id != last_id) - waypoint_map[id] = path_data; + if(id != last_id) + WaypointPathHolder[id] = path_data; last_id = id; } while(result->NextRow()) ; - delete result; } void WaypointStore::UpdatePath(uint32 id) { - - if(waypoint_map.find(id)!= waypoint_map.end()) - waypoint_map[id]->clear(); + // TODO: this will cause memory leak + if(WaypointPathHolder.find(id) != WaypointPathHolder.end()) + WaypointPathHolder[id]->clear(); QueryResult *result; @@ -145,7 +144,7 @@ void WaypointStore::UpdatePath(uint32 id) }while (result->NextRow()); - waypoint_map[id] = path_data; + WaypointPathHolder[id] = path_data; delete result; } diff --git a/src/game/WaypointManager.h b/src/game/WaypointManager.h index 85f8b765d45..a8f2d5746e9 100644 --- a/src/game/WaypointManager.h +++ b/src/game/WaypointManager.h @@ -34,7 +34,9 @@ struct WaypointData }; typedef std::vector<WaypointData*> WaypointPath; -extern UNORDERED_MAP<uint32, WaypointPath*> waypoint_map; +typedef UNORDERED_MAP<uint32, WaypointPath*> WaypointPathMap; + +extern WaypointPathMap WaypointPathHolder; class WaypointStore { @@ -48,9 +50,10 @@ class WaypointStore WaypointPath* GetPath(uint32 id) { - if(waypoint_map.find(id) != waypoint_map.end()) - return waypoint_map[id]; - else return 0; + WaypointPathMap::iterator itr = WaypointPathHolder.find(id); + if(itr != WaypointPathHolder.end()) + return itr->second; + return NULL; } inline uint32 GetRecordsCount() { return records; } diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index 7cabd63acf1..effc78d8026 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -100,7 +100,7 @@ WaypointMovementGenerator<Creature>::Initialize(Creature &u) //i_nextMoveTime.Reset(0); StopedByPlayer = false; if(!path_id) - path_id = u.GetWaypointPath(); + path_id = u.GetWaypointPathId(); waypoints = WaypointMgr.GetPath(path_id); i_currentNode = 0; if(waypoints && waypoints->size()) @@ -226,7 +226,7 @@ template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 & template void WaypointMovementGenerator<Player>::MovementInform(Player &); //----------------------------------------------------// -void FlightPathMovementGenerator::LoadPath(Player &) +void FlightPathMovementGenerator::SetWaypointPathId(Player &) { objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds); } @@ -251,7 +251,8 @@ void FlightPathMovementGenerator::Initialize(Player &player) player.getHostilRefManager().setOnlineOfflineState(false); player.addUnitState(UNIT_STAT_IN_FLIGHT); player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - LoadPath(player); + player.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); + SetWaypointPathId(player); Traveller<Player> traveller(player); // do not send movement, it was sent already i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false); @@ -270,6 +271,7 @@ void FlightPathMovementGenerator::Finalize(Player & player) player.Unmount(); player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + player.RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING2); if(player.m_taxi.empty()) { diff --git a/src/game/WaypointMovementGenerator.h b/src/game/WaypointMovementGenerator.h index 9804c150d63..9c93486a675 100644 --- a/src/game/WaypointMovementGenerator.h +++ b/src/game/WaypointMovementGenerator.h @@ -50,7 +50,7 @@ class TRINITY_DLL_SPEC PathMovementBase bool MovementInProgress(void) const { return i_currentNode < i_path.Size(); } - void LoadPath(T &); + void SetWaypointPathId(T &); void ReloadPath(T &); uint32 GetCurrentNode() const { return i_currentNode; } @@ -104,7 +104,7 @@ public PathMovementBase<Player> bool Update(Player &, const uint32 &); MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; } - void LoadPath(Player &); + void SetWaypointPathId(Player &); void ReloadPath(Player &) { /* don't reload flight path */ } Path& GetPath() { return i_path; } diff --git a/src/game/World.cpp b/src/game/World.cpp index fa44e527da5..665fb6d4bdc 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -792,7 +792,9 @@ void World::LoadConfigSettings(bool reload) 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_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false); - m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1); + m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1); + m_configs[CONFIG_ALLOW_GM_GROUP] = sConfig.GetBoolDefault("GM.AllowInvite", false); + m_configs[CONFIG_ALLOW_GM_FRIEND] = sConfig.GetBoolDefault("GM.AllowFriend", false); if(m_configs[CONFIG_START_GM_LEVEL] < m_configs[CONFIG_START_PLAYER_LEVEL]) { sLog.outError("GM.StartLevel (%i) must be in range StartPlayerLevel(%u)..%u. Set to %u.", diff --git a/src/game/World.h b/src/game/World.h index 27075885368..62648ebce2c 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -141,6 +141,8 @@ enum WorldConfigs CONFIG_GM_IN_GM_LIST, CONFIG_GM_IN_WHO_LIST, CONFIG_GM_LOG_TRADE, + CONFIG_ALLOW_GM_GROUP, + CONFIG_ALLOW_GM_FRIEND, CONFIG_START_GM_LEVEL, CONFIG_GM_LOWER_SECURITY, CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS, @@ -626,7 +628,7 @@ class World static float m_VisibleObjectGreyDistance; // CLI command holder to be thread safe - ZThread::LockedQueue<CliCommandHolder*, ZThread::FastMutex> cliCmdQueue; + ACE_Based::LockedQueue<CliCommandHolder*,ACE_Thread_Mutex> cliCmdQueue; SqlResultQueue *m_resultQueue; // next daily quests reset time @@ -637,7 +639,7 @@ class World //sessions that are added async void AddSession_(WorldSession* s); - ZThread::LockedQueue<WorldSession*, ZThread::FastMutex> addSessQueue; + ACE_Based::LockedQueue<WorldSession*, ACE_Thread_Mutex> addSessQueue; //used versions std::string m_DBVersion; diff --git a/src/game/WorldLog.cpp b/src/game/WorldLog.cpp index 52eb1e8b59c..978514ac7d7 100644 --- a/src/game/WorldLog.cpp +++ b/src/game/WorldLog.cpp @@ -27,9 +27,9 @@ #include "Config/ConfigEnv.h" #include "Log.h" -#define CLASS_LOCK Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex> +#define CLASS_LOCK MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex> INSTANTIATE_SINGLETON_2(WorldLog, CLASS_LOCK); -INSTANTIATE_CLASS_MUTEX(WorldLog, ZThread::FastMutex); +INSTANTIATE_CLASS_MUTEX(WorldLog, ACE_Thread_Mutex); #define WORLD_LOG_FILE_STRING "world.log" diff --git a/src/game/WorldLog.h b/src/game/WorldLog.h index 01f34535dd9..e6b72e654f7 100644 --- a/src/game/WorldLog.h +++ b/src/game/WorldLog.h @@ -32,13 +32,13 @@ #include <stdarg.h> /// %Log packets to a file -class TRINITY_DLL_DECL WorldLog : public Trinity::Singleton<WorldLog, Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex> > +class MANGOS_DLL_DECL WorldLog : public MaNGOS::Singleton<WorldLog, MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex> > { friend class Trinity::OperatorNew<WorldLog>; WorldLog(); WorldLog(const WorldLog &); WorldLog& operator=(const WorldLog &); - typedef Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex>::Lock Guard; + typedef MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex>::Lock Guard; /// Close the file in destructor ~WorldLog(); diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index d514586957a..a8d6db72809 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -719,8 +719,7 @@ class TRINITY_DLL_SPEC WorldSession uint32 m_latency; AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; AddonsList m_addonsList; - - ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> _recvQueue; + ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue; }; #endif /// @} diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt index 8ecfccad34f..b271e2b9545 100644 --- a/src/shared/CMakeLists.txt +++ b/src/shared/CMakeLists.txt @@ -14,6 +14,7 @@ SET(shared_STAT_SRCS Log.h ProgressBar.cpp ProgressBar.h + Threading.cpp Timer.h Util.cpp Util.h @@ -22,3 +23,7 @@ SET(shared_STAT_SRCS ) add_library(shared STATIC ${shared_STAT_SRCS}) +target_link_libraries( +shared +${ACE_LIBRARY} +) diff --git a/src/shared/Common.h b/src/shared/Common.h index abe804bb3a4..37ced4c8e11 100644 --- a/src/shared/Common.h +++ b/src/shared/Common.h @@ -62,26 +62,17 @@ #include "Platform/Define.h" #if COMPILER == COMPILER_MICROSOFT - -#pragma warning(disable:4996) - +# pragma warning(disable:4996) // 'function': was declared deprecated #ifndef __SHOW_STUPID_WARNINGS__ - -#pragma warning(disable:4244) - -#pragma warning(disable:4267) - -#pragma warning(disable:4800) - -#pragma warning(disable:4018) - -#pragma warning(disable:4311) - -#pragma warning(disable:4305) - -#pragma warning(disable:4005) - -#pragma warning(disable:4522)//warning when class has 2 constructosr +# pragma warning(disable:4005) // 'identifier' : macro redefinition +# pragma warning(disable:4018) // 'expression' : signed/unsigned mismatch +# pragma warning(disable:4244) // 'argument' : conversion from 'type1' to 'type2', possible loss of data +# pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data +# pragma warning(disable:4305) // 'identifier' : truncation from 'type1' to 'type2' +# pragma warning(disable:4311) // 'variable' : pointer truncation from 'type' to 'type' +# pragma warning(disable:4355) // 'this' : used in base member initializer list +# pragma warning(disable:4800) // 'type' : forcing value to bool 'true' or 'false' (performance warning) +# pragma warning(disable:4522) //warning when class has 2 constructosr #endif // __SHOW_STUPID_WARNINGS__ #endif // __GNUC__ @@ -93,6 +84,7 @@ #include <math.h> #include <errno.h> #include <signal.h> +#include <assert.h> #if PLATFORM == PLATFORM_WINDOWS #define STRCASECMP stricmp @@ -108,10 +100,13 @@ #include <sstream> #include <algorithm> -#include <zthread/FastMutex.h> -#include <zthread/LockedQueue.h> -#include <zthread/Runnable.h> -#include <zthread/Thread.h> +#include "LockedQueue.h" +#include "Threading.h" + +#include <ace/Guard_T.h> +#include <ace/RW_Thread_Mutex.h> +#include <ace/Thread_Mutex.h> + #if PLATFORM == PLATFORM_WINDOWS # define FD_SETSIZE 4096 diff --git a/src/shared/Database/Database.cpp b/src/shared/Database/Database.cpp index 07ece3b0cd9..d5ccc581232 100644 --- a/src/shared/Database/Database.cpp +++ b/src/shared/Database/Database.cpp @@ -110,7 +110,8 @@ bool Database::PExecuteLog(const char * format,...) void Database::SetResultQueue(SqlResultQueue * queue) { - m_queryQueues[ZThread::ThreadImpl::current()] = queue; + m_queryQueues[ACE_Based::Thread::current()] = queue; + } QueryResult* Database::PQuery(const char *format,...) diff --git a/src/shared/Database/Database.h b/src/shared/Database/Database.h index 92a1c991dcc..a9f7285c223 100644 --- a/src/shared/Database/Database.h +++ b/src/shared/Database/Database.h @@ -21,8 +21,7 @@ #ifndef DATABASE_H #define DATABASE_H -#include "zthread/Thread.h" -#include "../src/zthread/ThreadImpl.h" +#include "Threading.h" #include "Utilities/UnorderedMap.h" #include "Database/SqlDelayThread.h" @@ -30,8 +29,8 @@ class SqlTransaction; class SqlResultQueue; class SqlQueryHolder; -typedef UNORDERED_MAP<ZThread::ThreadImpl*, SqlTransaction*> TransactionQueues; -typedef UNORDERED_MAP<ZThread::ThreadImpl*, SqlResultQueue*> QueryQueues; +typedef UNORDERED_MAP<ACE_Based::Thread* , SqlTransaction*> TransactionQueues; +typedef UNORDERED_MAP<ACE_Based::Thread* , SqlResultQueue*> QueryQueues; #define MAX_QUERY_LEN 32*1024 @@ -43,7 +42,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 - ZThread::Thread* m_delayThread; ///< Pointer to executer thread + ACE_Based::Thread* m_delayThread; ///< Pointer to executer thread public: diff --git a/src/shared/Database/DatabaseImpl.h b/src/shared/Database/DatabaseImpl.h index 3d3c53f0873..7cbd0ed8ba5 100644 --- a/src/shared/Database/DatabaseImpl.h +++ b/src/shared/Database/DatabaseImpl.h @@ -29,7 +29,7 @@ QueryQueues::iterator queue_itr; \ \ { \ - ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current(); \ + ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \ queue_itr = m_queryQueues.find(queryThread); \ if (queue_itr == m_queryQueues.end()) return false; \ } @@ -59,7 +59,7 @@ QueryQueues::iterator queue_itr; \ \ { \ - ZThread::ThreadImpl * queryThread = ZThread::ThreadImpl::current(); \ + ACE_Based::Thread * queryThread = ACE_Based::Thread::current(); \ queue_itr = m_queryQueues.find(queryThread); \ if (queue_itr == m_queryQueues.end()) return false; \ } diff --git a/src/shared/Database/DatabaseMysql.cpp b/src/shared/Database/DatabaseMysql.cpp index 5dc02c0a738..9574d3dc2ac 100644 --- a/src/shared/Database/DatabaseMysql.cpp +++ b/src/shared/Database/DatabaseMysql.cpp @@ -23,7 +23,7 @@ #include "Util.h" #include "Policies/SingletonImp.h" #include "Platform/Define.h" -#include "../src/zthread/ThreadImpl.h" +#include "Threading.h" #include "DatabaseEnv.h" #include "Database/MySQLDelayThread.h" #include "Database/SqlOperations.h" @@ -203,8 +203,8 @@ QueryResult* DatabaseMysql::Query(const char *sql) { // guarded block for thread-safe mySQL request - ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex); - #ifdef TRINITY_DEBUG + ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex); + #ifdef MANGOS_DEBUG uint32 _s = getMSTime(); #endif if(mysql_query(mMysql, sql)) @@ -251,7 +251,7 @@ bool DatabaseMysql::Execute(const char *sql) // don't use queued execution if it has not been initialized if (!m_threadBody) return DirectExecute(sql); - tranThread = ZThread::ThreadImpl::current(); // owner of this transaction + tranThread = ACE_Based::Thread::current(); // owner of this transaction TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) { // Statement for transaction @@ -273,8 +273,9 @@ bool DatabaseMysql::DirectExecute(const char* sql) { // guarded block for thread-safe mySQL request - ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex); - #ifdef TRINITY_DEBUG + ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex); + + #ifdef MANGOS_DEBUG uint32 _s = getMSTime(); #endif if(mysql_query(mMysql, sql)) @@ -318,8 +319,9 @@ bool DatabaseMysql::BeginTransaction() // don't use queued execution if it has not been initialized if (!m_threadBody) { - if (tranThread==ZThread::ThreadImpl::current()) + if (tranThread == ACE_Based::Thread::current()) return false; // huh? this thread already started transaction + mMutex.acquire(); if (!_TransactionCmd("START TRANSACTION")) { @@ -329,7 +331,7 @@ bool DatabaseMysql::BeginTransaction() return true; // transaction started } - tranThread = ZThread::ThreadImpl::current(); // owner of this transaction + tranThread = ACE_Based::Thread::current(); // owner of this transaction TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) // If for thread exists queue and also contains transaction @@ -349,7 +351,7 @@ bool DatabaseMysql::CommitTransaction() // don't use queued execution if it has not been initialized if (!m_threadBody) { - if (tranThread!=ZThread::ThreadImpl::current()) + if (tranThread != ACE_Based::Thread::current()) return false; bool _res = _TransactionCmd("COMMIT"); tranThread = NULL; @@ -357,7 +359,7 @@ bool DatabaseMysql::CommitTransaction() return _res; } - tranThread = ZThread::ThreadImpl::current(); + tranThread = ACE_Based::Thread::current(); TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) { @@ -377,7 +379,7 @@ bool DatabaseMysql::RollbackTransaction() // don't use queued execution if it has not been initialized if (!m_threadBody) { - if (tranThread!=ZThread::ThreadImpl::current()) + if (tranThread != ACE_Based::Thread::current()) return false; bool _res = _TransactionCmd("ROLLBACK"); tranThread = NULL; @@ -385,7 +387,7 @@ bool DatabaseMysql::RollbackTransaction() return _res; } - tranThread = ZThread::ThreadImpl::current(); + tranThread = ACE_Based::Thread::current(); TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) { @@ -408,7 +410,8 @@ void DatabaseMysql::InitDelayThread() assert(!m_delayThread); //New delay thread for delay execute - m_delayThread = new ZThread::Thread(m_threadBody = new MySQLDelayThread(this)); + m_threadBody = new MySQLDelayThread(this); + m_delayThread = new ACE_Based::Thread(*m_threadBody); } void DatabaseMysql::HaltDelayThread() diff --git a/src/shared/Database/DatabaseMysql.h b/src/shared/Database/DatabaseMysql.h index 2fa157e75a5..7f5730f9579 100644 --- a/src/shared/Database/DatabaseMysql.h +++ b/src/shared/Database/DatabaseMysql.h @@ -25,7 +25,8 @@ #include "Database.h" #include "Policies/Singleton.h" -#include "zthread/FastMutex.h" +#include "ace/Thread_Mutex.h" +#include "ace/Guard_T.h" #ifdef WIN32 #define FD_SETSIZE 1024 @@ -65,9 +66,9 @@ class TRINITY_DLL_SPEC DatabaseMysql : public Database // must be call before finish thread run void ThreadEnd(); private: - ZThread::FastMutex mMutex; + ACE_Thread_Mutex mMutex; - ZThread::ThreadImpl* tranThread; + ACE_Based::Thread * tranThread; MYSQL *mMysql; diff --git a/src/shared/Database/DatabasePostgre.cpp b/src/shared/Database/DatabasePostgre.cpp index 79e1c87f5e3..12875b33200 100644 --- a/src/shared/Database/DatabasePostgre.cpp +++ b/src/shared/Database/DatabasePostgre.cpp @@ -23,7 +23,7 @@ #include "Util.h" #include "Policies/SingletonImp.h" #include "Platform/Define.h" -#include "../src/zthread/ThreadImpl.h" +#include "Threading.h" #include "DatabaseEnv.h" #include "Database/PGSQLDelayThread.h" #include "Database/SqlOperations.h" @@ -126,8 +126,8 @@ QueryResult* DatabasePostgre::Query(const char *sql) uint32 fieldCount = 0; // guarded block for thread-safe request - ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex); - #ifdef TRINITY_DEBUG + ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex); + #ifdef MANGOS_DEBUG uint32 _s = getMSTime(); #endif // Send the query @@ -174,9 +174,10 @@ bool DatabasePostgre::Execute(const char *sql) return false; // don't use queued execution if it has not been initialized - if (!m_threadBody) return DirectExecute(sql); + if (!m_threadBody) + return DirectExecute(sql); - tranThread = ZThread::ThreadImpl::current(); // owner of this transaction + tranThread = ACE_Based::Thread::current(); // owner of this transaction TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) { // Statement for transaction @@ -197,8 +198,8 @@ bool DatabasePostgre::DirectExecute(const char* sql) return false; { // guarded block for thread-safe request - ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex); - #ifdef TRINITY_DEBUG + ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex); + #ifdef MANGOS_DEBUG uint32 _s = getMSTime(); #endif PGresult *res = PQexec(mPGconn, sql); @@ -247,7 +248,7 @@ bool DatabasePostgre::BeginTransaction() // don't use queued execution if it has not been initialized if (!m_threadBody) { - if (tranThread==ZThread::ThreadImpl::current()) + if (tranThread == ACE_Based::Thread::current()) return false; // huh? this thread already started transaction mMutex.acquire(); if (!_TransactionCmd("START TRANSACTION")) @@ -258,7 +259,7 @@ bool DatabasePostgre::BeginTransaction() return true; } // transaction started - tranThread = ZThread::ThreadImpl::current(); // owner of this transaction + tranThread = ACE_Based::Thread::current(); // owner of this transaction TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) // If for thread exists queue and also contains transaction @@ -278,14 +279,14 @@ bool DatabasePostgre::CommitTransaction() // don't use queued execution if it has not been initialized if (!m_threadBody) { - if (tranThread!=ZThread::ThreadImpl::current()) + if (tranThread != ACE_Based::Thread::current()) return false; bool _res = _TransactionCmd("COMMIT"); tranThread = NULL; mMutex.release(); return _res; } - tranThread = ZThread::ThreadImpl::current(); + tranThread = ACE_Based::Thread::current(); TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) { @@ -304,14 +305,14 @@ bool DatabasePostgre::RollbackTransaction() // don't use queued execution if it has not been initialized if (!m_threadBody) { - if (tranThread!=ZThread::ThreadImpl::current()) + if (tranThread != ACE_Based::Thread::current()) return false; bool _res = _TransactionCmd("ROLLBACK"); tranThread = NULL; mMutex.release(); return _res; } - tranThread = ZThread::ThreadImpl::current(); + tranThread = ACE_Based::Thread::current(); TransactionQueues::iterator i = m_tranQueues.find(tranThread); if (i != m_tranQueues.end() && i->second != NULL) { @@ -334,7 +335,8 @@ void DatabasePostgre::InitDelayThread() assert(!m_delayThread); //New delay thread for delay execute - m_delayThread = new ZThread::Thread(m_threadBody = new PGSQLDelayThread(this)); + m_threadBody = new PGSQLDelayThread(this); + m_delayThread = new ACE_Based::Thread(*m_threadBody); } void DatabasePostgre::HaltDelayThread() diff --git a/src/shared/Database/DatabasePostgre.h b/src/shared/Database/DatabasePostgre.h index c7242add572..53f0802f86c 100644 --- a/src/shared/Database/DatabasePostgre.h +++ b/src/shared/Database/DatabasePostgre.h @@ -22,7 +22,6 @@ #define _DatabasePostgre_H #include "Policies/Singleton.h" -#include "zthread/FastMutex.h" #include <stdarg.h> #ifdef WIN32 @@ -63,10 +62,8 @@ class DatabasePostgre : public Database // must be call before finish thread run void ThreadEnd(); private: - ZThread::FastMutex mMutex; - ZThread::FastMutex tranMutex; - - ZThread::ThreadImpl* tranThread; + ACE_Thread_Mutex mMutex; + ACE_Based::Thread * tranThread; PGconn *mPGconn; diff --git a/src/shared/Database/QueryResult.h b/src/shared/Database/QueryResult.h index 01da45ed281..39228dd4ba9 100644 --- a/src/shared/Database/QueryResult.h +++ b/src/shared/Database/QueryResult.h @@ -40,7 +40,7 @@ class TRINITY_DLL_SPEC QueryResult if(iter->second == name) return iter->first; } - assert(false && "unknown field name"); + ASSERT(false && "unknown field name"); return uint32(-1); } diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp index 8561afc4a33..67091174c77 100644 --- a/src/shared/Database/SQLStorage.cpp +++ b/src/shared/Database/SQLStorage.cpp @@ -29,9 +29,9 @@ extern DatabaseMysql WorldDatabase; const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifflliiis"; const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiifflliiii"; -const char CreatureDataAddonInfofmt[]="iiiiiiiis"; +const char CreatureDataAddonInfofmt[]="iiiiiiis"; const char CreatureModelfmt[]="iffbi"; -const char CreatureInfoAddonInfofmt[]="iiiiiiiis"; +const char CreatureInfoAddonInfofmt[]="iiiiiiis"; const char EquipmentInfofmt[]="iiii"; const char GameObjectInfosrcfmt[]="iiisssiifiiiiiiiiiiiiiiiiiiiiiiiis"; const char GameObjectInfodstfmt[]="iiisssiifiiiiiiiiiiiiiiiiiiiiiiiii"; diff --git a/src/shared/Database/SqlDelayThread.cpp b/src/shared/Database/SqlDelayThread.cpp index 27f58510a0a..9a92fd5dd63 100644 --- a/src/shared/Database/SqlDelayThread.cpp +++ b/src/shared/Database/SqlDelayThread.cpp @@ -37,7 +37,7 @@ void SqlDelayThread::run() { // if the running state gets turned off while sleeping // empty the queue before exiting - ZThread::Thread::sleep(10); + ACE_Based::Thread::Sleep(10); while (!m_sqlQueue.empty()) { s = m_sqlQueue.next(); diff --git a/src/shared/Database/SqlDelayThread.h b/src/shared/Database/SqlDelayThread.h index cbae0c1e5eb..3c24d3525b7 100644 --- a/src/shared/Database/SqlDelayThread.h +++ b/src/shared/Database/SqlDelayThread.h @@ -21,21 +21,22 @@ #ifndef __SQLDELAYTHREAD_H #define __SQLDELAYTHREAD_H -#include "zthread/Thread.h" -#include "zthread/Runnable.h" -#include "zthread/FastMutex.h" -#include "zthread/LockedQueue.h" +#include "ace/Thread_Mutex.h" +#include "LockedQueue.h" +#include "Threading.h" + class Database; class SqlOperation; -class SqlDelayThread : public ZThread::Runnable +class SqlDelayThread : public ACE_Based::Runnable { - typedef ZThread::LockedQueue<SqlOperation*, ZThread::FastMutex> SqlQueue; + typedef ACE_Based::LockedQueue<SqlOperation*, ACE_Thread_Mutex> SqlQueue; + private: SqlQueue m_sqlQueue; ///< Queue of SQL statements Database* m_dbEngine; ///< Pointer to used Database engine - bool m_running; + volatile bool m_running; SqlDelayThread(); public: diff --git a/src/shared/Database/SqlOperations.h b/src/shared/Database/SqlOperations.h index 61eef4bb7c4..e91d83b6611 100644 --- a/src/shared/Database/SqlOperations.h +++ b/src/shared/Database/SqlOperations.h @@ -23,9 +23,8 @@ #include "Common.h" -#include "zthread/LockedQueue.h" -#include "zthread/FastMutex.h" -#include "zthread/Thread.h" +#include "ace/Thread_Mutex.h" +#include "LockedQueue.h" #include <queue> #include "Utilities/Callback.h" @@ -72,7 +71,7 @@ class SqlResultQueue; /// queue for thread class SqlQueryHolder; /// groups several async quries class SqlQueryHolderEx; /// points to a holder, added to the delay thread -class SqlResultQueue : public ZThread::LockedQueue<Trinity::IQueryCallback*, ZThread::FastMutex> +class SqlResultQueue : public ACE_Based::LockedQueue<MaNGOS::IQueryCallback* , ACE_Thread_Mutex> { public: SqlResultQueue() {} diff --git a/src/shared/LockedQueue.h b/src/shared/LockedQueue.h new file mode 100644 index 00000000000..b085dd09b83 --- /dev/null +++ b/src/shared/LockedQueue.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 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 + */ + +#ifndef LOCKEDQUEUE_H +#define LOCKEDQUEUE_H + +#include <ace/Guard_T.h> +#include <ace/Thread_Mutex.h> +#include <deque> +#include <assert.h> +#include "Errors.h" + +namespace ACE_Based +{ + + template <class T, class LockType, typename StorageType=std::deque<T> > + class LockedQueue + { + + //! Serialize access to the Queue + LockType _lock; + + //! Storage backing the queue + StorageType _queue; + + //! Cancellation flag + volatile bool _canceled; + + public: + + //! Create a LockedQueue + LockedQueue() : _canceled(false) {} + + //! Destroy a LockedQueue + virtual ~LockedQueue() { } + + /** + * @see Queue::add(const T& item) + */ + void add(const T& item) + { + + ACE_Guard<LockType> g(_lock); + + ASSERT(!_canceled); + // throw Cancellation_Exception(); + + _queue.push_back(item); + + } + + /** + * @see Queue::next() + */ + T next() + { + + ACE_Guard<LockType> g(_lock); + + ASSERT (!_queue.empty() || !_canceled); + // throw Cancellation_Exception(); + + T item = _queue.front(); + _queue.pop_front(); + + return item; + + } + + T front() + { + ACE_Guard<LockType> g(_lock); + + ASSERT (!_queue.empty()); + // throw NoSuchElement_Exception(); + + return _queue.front(); + } + + /** + * @see Queue::cancel() + */ + void cancel() + { + + ACE_Guard<LockType> g(_lock); + + _canceled = true; + + } + + /** + * @see Queue::isCanceled() + */ + bool isCanceled() + { + + // Faster check since the queue will not become un-canceled + if(_canceled) + return true; + + ACE_Guard<LockType> g(_lock); + + return _canceled; + + } + + /** + * @see Queue::size() + */ + size_t size() + { + + ACE_Guard<LockType> g(_lock); + return _queue.size(); + + } + + bool empty() + { + + ACE_Guard<LockType> g(_lock); + return _queue.empty(); + } + + }; + +} +#endif diff --git a/src/shared/Log.h b/src/shared/Log.h index 654f3c0f04c..23555995020 100644 --- a/src/shared/Log.h +++ b/src/shared/Log.h @@ -82,7 +82,7 @@ enum ColorTypes const int Colors = int(WHITE)+1; -class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThread::FastMutex> > +class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ACE_Thread_Mutex> > { friend class Trinity::OperatorNew<Log>; Log(); diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am index 6b99351cb26..60af5b8a4b5 100644 --- a/src/shared/Makefile.am +++ b/src/shared/Makefile.am @@ -38,6 +38,7 @@ libmangosshared_a_SOURCES = \ Common.cpp \ Common.h \ Errors.h \ + LockedQueue.h \ Log.cpp \ Log.h \ MemoryLeaks.cpp \ @@ -45,6 +46,8 @@ libmangosshared_a_SOURCES = \ ProgressBar.cpp \ ProgressBar.h \ Timer.h \ + Threading.cpp \ + Threading.h \ Util.cpp \ Util.h \ WorldPacket.h \ diff --git a/src/shared/MemoryLeaks.h b/src/shared/MemoryLeaks.h index fcea1f557b1..c8b8fb8e1b1 100644 --- a/src/shared/MemoryLeaks.h +++ b/src/shared/MemoryLeaks.h @@ -31,9 +31,9 @@ //# include <stdlib.h> //# include <crtdbg.h> #else -# define _CRTDBG_MAP_ALLOC -# include <stdlib.h> -# include <crtdbg.h> +//# define _CRTDBG_MAP_ALLOC +//# include <stdlib.h> +//# include <crtdbg.h> #endif #endif diff --git a/src/shared/Threading.cpp b/src/shared/Threading.cpp new file mode 100644 index 00000000000..496e86353ca --- /dev/null +++ b/src/shared/Threading.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 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 "Threading.h" +#include <ace/OS_NS_unistd.h> +#include <ace/Sched_Params.h> +#include <vector> + +using namespace ACE_Based; + +ThreadPriority::ThreadPriority() +{ + for (int i = Idle; i < MAXPRIORITYNUM; ++i) + m_priority[i] = ACE_THR_PRI_OTHER_DEF; + + m_priority[Idle] = ACE_Sched_Params::priority_min(ACE_SCHED_OTHER); + m_priority[Realtime] = ACE_Sched_Params::priority_max(ACE_SCHED_OTHER); + + std::vector<int> _tmp; + + ACE_Sched_Params::Policy _policy = ACE_SCHED_OTHER; + ACE_Sched_Priority_Iterator pr_iter(_policy); + + while (pr_iter.more()) + { + _tmp.push_back(pr_iter.priority()); + pr_iter.next(); + } + + ASSERT (!_tmp.empty()); + + if(_tmp.size() >= MAXPRIORITYNUM) + { + const size_t max_pos = _tmp.size(); + size_t min_pos = 1; + size_t norm_pos = 0; + for (size_t i = 0; i < max_pos; ++i) + { + if(_tmp[i] == ACE_THR_PRI_OTHER_DEF) + { + norm_pos = i + 1; + break; + } + } + + //since we have only 7(seven) values in enum Priority + //and 3 we know already (Idle, Normal, Realtime) so + //we need to split each list [Idle...Normal] and [Normal...Realtime] + //into ¹ piesces + const size_t _divider = 4; + size_t _div = (norm_pos - min_pos) / _divider; + if(_div == 0) + _div = 1; + + min_pos = (norm_pos - 1); + + m_priority[Low] = _tmp[min_pos -= _div]; + m_priority[Lowest] = _tmp[min_pos -= _div ]; + + _div = (max_pos - norm_pos) / _divider; + if(_div == 0) + _div = 1; + + min_pos = norm_pos - 1; + + m_priority[High] = _tmp[min_pos += _div]; + m_priority[Highest] = _tmp[min_pos += _div]; + } +} + +int ThreadPriority::getPriority(Priority p) const +{ + if(p < Idle) + p = Idle; + + if(p > Realtime) + p = Realtime; + + return m_priority[p]; +} + +#define THREADFLAG (THR_NEW_LWP | THR_SCHED_DEFAULT| THR_JOINABLE) + +Thread::Thread() : m_task(0), m_iThreadId(0), m_hThreadHandle(0) +{ + +} + +Thread::Thread(Runnable& instance) : m_task(&instance), m_iThreadId(0), m_hThreadHandle(0) +{ + bool _start = start(); + ASSERT (_start); +} + +Thread::~Thread() +{ + //Wait(); +} + +//initialize Thread's class static member +Thread::ThreadStorage Thread::m_ThreadStorage; +ThreadPriority Thread::m_TpEnum; + +bool Thread::start() +{ + 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 Thread::wait() +{ + if(!m_hThreadHandle || !m_task) + return false; + + ACE_THR_FUNC_RETURN _value = ACE_THR_FUNC_RETURN(-1); + int _res = ACE_Thread::join(m_hThreadHandle, &_value); + + m_iThreadId = 0; + m_hThreadHandle = 0; + + return (_res == 0); +} + +void Thread::destroy() +{ + ACE_Thread::kill(m_iThreadId, -1); +} + +void Thread::suspend() +{ + ACE_Thread::suspend(m_hThreadHandle); +} + +void Thread::resume() +{ + ACE_Thread::resume(m_hThreadHandle); +} + +ACE_THR_FUNC_RETURN Thread::ThreadTask(void * param) +{ + Runnable * _task = (Runnable*)param; + _task->run(); + + return (ACE_THR_FUNC_RETURN)0; +} + +ACE_thread_t Thread::currentId() +{ + return ACE_Thread::self(); +} + +ACE_hthread_t Thread::currentHandle() +{ + ACE_hthread_t _handle; + ACE_Thread::self(_handle); + + return _handle; +} + +Thread * Thread::current() +{ + Thread * _thread = m_ThreadStorage.ts_object(); + if(!_thread) + { + _thread = new Thread(); + _thread->m_iThreadId = Thread::currentId(); + _thread->m_hThreadHandle = Thread::currentHandle(); + + Thread * _oldValue = m_ThreadStorage.ts_object(_thread); + if(_oldValue) + delete _oldValue; + } + + return _thread; +} + +void Thread::setPriority(Priority type) +{ + int _priority = m_TpEnum.getPriority(type); + int _ok = ACE_Thread::setprio(m_hThreadHandle, _priority); + //remove this ASSERT in case you don't want to know is thread priority change was successful or not + ASSERT (_ok == 0); +} + +void Thread::Sleep(unsigned long msecs) +{ + ACE_OS::sleep(ACE_Time_Value(0, 1000 * msecs)); +} diff --git a/src/shared/Threading.h b/src/shared/Threading.h new file mode 100644 index 00000000000..eac3c0e8efb --- /dev/null +++ b/src/shared/Threading.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 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 + */ + +#ifndef THREADING_H +#define THREADING_H + +#include <ace/Thread.h> +#include <ace/TSS_T.h> +#include <assert.h> +#include "Errors.h" + +namespace ACE_Based +{ + + class Runnable + { + public: + virtual ~Runnable() {} + virtual void run() = 0; + }; + + enum Priority + { + Idle, + Lowest, + Low, + Normal, + High, + Highest, + Realtime, + }; + +#define MAXPRIORITYNUM (Realtime + 1) + + class ThreadPriority + { + public: + ThreadPriority(); + int getPriority(Priority p) const; + + private: + int m_priority[MAXPRIORITYNUM]; + }; + + class Thread + { + public: + Thread(); + Thread(Runnable& instance); + ~Thread(); + + bool start(); + bool wait(); + void destroy(); + + void suspend(); + void resume(); + + void setPriority(Priority type); + + static void Sleep(unsigned long msecs); + static ACE_thread_t currentId(); + static ACE_hthread_t currentHandle(); + static Thread * current(); + + private: + Thread(const Thread&); + Thread& operator=(const Thread&); + + static ACE_THR_FUNC_RETURN ThreadTask(void * param); + + ACE_thread_t m_iThreadId; + ACE_hthread_t m_hThreadHandle; + Runnable * m_task; + + typedef ACE_TSS<Thread> ThreadStorage; + //global object - container for Thread class representation of every thread + static ThreadStorage m_ThreadStorage; + //use this object to determine current OS thread priority values mapped to enum Priority{} + static ThreadPriority m_TpEnum; + }; + +} +#endif diff --git a/src/shared/Util.cpp b/src/shared/Util.cpp index 767b65e441c..ac57fc3c9e9 100644 --- a/src/shared/Util.cpp +++ b/src/shared/Util.cpp @@ -23,40 +23,34 @@ #include "sockets/socket_include.h" #include "utf8cpp/utf8.h" #include "mersennetwister/MersenneTwister.h" -#include "zthread/ThreadLocal.h" +#include <ace/TSS_T.h> -typedef ZThread::ThreadLocal<MTRand> MTRandTSS; - -/* NOTE: Not sure if static initialization is ok for TSS objects , - * as I see zthread uses custom implementation of the TSS - * ,and in the consturctor there is no code ,so I suppose its ok - * If its not ok ,change it to use singleton. - */ +typedef ACE_TSS<MTRand> MTRandTSS; static MTRandTSS mtRand; int32 irand (int32 min, int32 max) { - return int32 (mtRand.get ().randInt (max - min)) + min; + return int32 (mtRand->randInt (max - min)) + min; } uint32 urand (uint32 min, uint32 max) { - return mtRand.get ().randInt (max - min) + min; + return mtRand->randInt (max - min) + min; } int32 rand32 () { - return mtRand.get ().randInt (); + return mtRand->randInt (); } double rand_norm(void) { - return mtRand.get ().randExc (); + return mtRand->randExc (); } double rand_chance (void) { - return mtRand.get ().randExc (100.0); + return mtRand->randExc (100.0); } Tokens StrSplit(const std::string &src, const std::string &sep) diff --git a/src/trinitycore/CliRunnable.cpp b/src/trinitycore/CliRunnable.cpp index 91f37cd1b48..d53ee8c24be 100644 --- a/src/trinitycore/CliRunnable.cpp +++ b/src/trinitycore/CliRunnable.cpp @@ -155,7 +155,7 @@ bool ChatHandler::HandleCharacterDeleteCommand(const char* args) } /// Exit the realm -bool ChatHandler::HandleServerExitCommand(const char* args) +bool ChatHandler::HandleServerExitCommand(const char* /*args*/) { SendSysMessage(LANG_COMMAND_EXIT); World::StopNow(SHUTDOWN_EXIT_CODE); @@ -163,7 +163,7 @@ bool ChatHandler::HandleServerExitCommand(const char* args) } /// Display info on users currently in the realm -bool ChatHandler::HandleAccountOnlineListCommand(const char* args) +bool ChatHandler::HandleAccountOnlineListCommand(const char* /*args*/) { ///- Get the list of accounts ID logged to the realm QueryResult *resultDB = CharacterDatabase.Query("SELECT name,account FROM characters WHERE online > 0"); diff --git a/src/trinitycore/CliRunnable.h b/src/trinitycore/CliRunnable.h index 20ff58f27ba..cf745bbb195 100644 --- a/src/trinitycore/CliRunnable.h +++ b/src/trinitycore/CliRunnable.h @@ -26,7 +26,7 @@ #define __CLIRUNNABLE_H /// Command Line Interface handling thread -class CliRunnable : public ZThread::Runnable +class CliRunnable : public ACE_Based::Runnable { public: void run(); diff --git a/src/trinitycore/Makefile.am b/src/trinitycore/Makefile.am index 7e1cd086d3c..f0ac432dab1 100644 --- a/src/trinitycore/Makefile.am +++ b/src/trinitycore/Makefile.am @@ -35,8 +35,13 @@ trinity_worldd_SOURCES = \ WorldRunnable.h ## Link world daemon against the shared library +<<<<<<< HEAD:src/mangosd/Makefile.am trinity_worldd_LDADD = ../bindings/scripts/libtrinityscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a trinity_worldd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/scripts/ -L$(libdir) $(TRINI_LIBS) -export-dynamic +======= +mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/g3dlite/libg3dlite.a +mangos_worldd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/g3dlite -L../bindings/universal/ -L$(libdir) $(MANGOS_LIBS) -export-dynamic +>>>>>>> 00c7d15a78b1dcdbf888b768c55424183b2231e4:src/mangosd/Makefile.am ## Additional files to include when running 'make dist' # Include world daemon configuration diff --git a/src/trinitycore/Master.cpp b/src/trinitycore/Master.cpp index 6a952b936d3..2e2d75d5c3c 100644 --- a/src/trinitycore/Master.cpp +++ b/src/trinitycore/Master.cpp @@ -60,7 +60,7 @@ INSTANTIATE_SINGLETON_1( Master ); volatile uint32 Master::m_masterLoopCounter = 0; -class FreezeDetectorRunnable : public ZThread::Runnable +class FreezeDetectorRunnable : public ACE_Based::Runnable { public: FreezeDetectorRunnable() { _delaytime = 0; } @@ -79,7 +79,7 @@ public: w_lastchange = 0; while(!World::IsStopped()) { - ZThread::Thread::sleep(1000); + ACE_Based::Thread::Sleep(1000); uint32 curtime = getMSTime(); //DEBUG_LOG("anti-freeze: time=%u, counters=[%u; %u]",curtime,Master::m_masterLoopCounter,World::m_worldLoopCounter); @@ -115,7 +115,7 @@ public: } }; -class RARunnable : public ZThread::Runnable +class RARunnable : public ACE_Based::Runnable { public: uint32 numLoops, loopCounter; @@ -181,7 +181,7 @@ public: { while (!World::IsStopped()) { - ZThread::Thread::sleep (static_cast<unsigned long> (socketSelecttime / 1000)); + ACE_Based::Thread::Sleep (static_cast<unsigned long> (socketSelecttime / 1000)); checkping (); } } @@ -237,8 +237,8 @@ int Master::Run() _HookSignals(); ///- Launch WorldRunnable thread - ZThread::Thread t(new WorldRunnable); - t.setPriority ((ZThread::Priority )2); + ACE_Based::Thread t(*new WorldRunnable); + t.setPriority ((ACE_Based::Priority )2); // set server online LoginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID); @@ -250,10 +250,10 @@ int Master::Run() #endif { ///- Launch CliRunnable thread - ZThread::Thread td1(new CliRunnable); + ACE_Based::Thread td1(*new CliRunnable); } - ZThread::Thread td2(new RARunnable); + ACE_Based::Thread td2(*new RARunnable); ///- Handle affinity for multiple processors and process priority on Windows #ifdef WIN32 @@ -314,8 +314,8 @@ int Master::Run() { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); - ZThread::Thread t(fdr); - t.setPriority(ZThread::High); + ACE_Based::Thread t(*fdr); + t.setPriority(ACE_Based::High); } ///- Launch the world listener socket diff --git a/src/trinitycore/WorldRunnable.cpp b/src/trinitycore/WorldRunnable.cpp index e49e4ad74b8..bd4d3170c52 100644 --- a/src/trinitycore/WorldRunnable.cpp +++ b/src/trinitycore/WorldRunnable.cpp @@ -76,7 +76,7 @@ void WorldRunnable::run() if (diff <= WORLD_SLEEP_CONST+prevSleepTime) { prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff; - ZThread::Thread::sleep(prevSleepTime); + ACE_Based::Thread::Sleep(prevSleepTime); } else prevSleepTime = 0; diff --git a/src/trinitycore/WorldRunnable.h b/src/trinitycore/WorldRunnable.h index 8df3a6a0c89..07ce246b04f 100644 --- a/src/trinitycore/WorldRunnable.h +++ b/src/trinitycore/WorldRunnable.h @@ -26,7 +26,7 @@ #define __WORLDRUNNABLE_H /// Heartbeat thread for the World -class WorldRunnable : public ZThread::Runnable +class WorldRunnable : public ACE_Based::Runnable { public: void run(); diff --git a/src/trinitycore/trinitycore.conf.dist b/src/trinitycore/trinitycore.conf.dist index 018ddf378b5..2748c92529a 100644 --- a/src/trinitycore/trinitycore.conf.dist +++ b/src/trinitycore/trinitycore.conf.dist @@ -1006,6 +1006,16 @@ Channel.SilentlyGMJoin = 0 # GM starting level (1-100) # Default: 1 # +# GM.AllowInvite +# Is GM accepting invites from players by default or not +# Default: 0 (false) +# 1 (true) +# +# GM.AllowFriend +# Are players allowed to add GMs to their friend list +# Default: 0 (false) +# 1 (true) +# # GM.LowerSecurity # Disallow a lower security member to interact with a higher one using commands # Default: 0 (disable) @@ -1027,6 +1037,8 @@ GM.InGMList = 0 GM.InWhoList = 0 GM.LogTrade = 1 GM.StartLevel = 80 +GM.AllowInvite = 0 +GM.AllowFriend = 0 GM.LowerSecurity = 0 GM.AllowAchievementGain = 1 diff --git a/src/trinityrealm/AuthSocket.cpp b/src/trinityrealm/AuthSocket.cpp index c5c81593737..8c9eab653ec 100644 --- a/src/trinityrealm/AuthSocket.cpp +++ b/src/trinityrealm/AuthSocket.cpp @@ -173,7 +173,7 @@ typedef struct AuthHandler #endif /// Launch a thread to transfer a patch to the client -class PatcherRunnable: public ZThread::Runnable +class PatcherRunnable: public ACE_Based::Runnable { public: PatcherRunnable(class AuthSocket *); @@ -236,7 +236,8 @@ AuthSocket::AuthSocket(ISocketHandler &h) : TcpSocket(h) /// Close patch file descriptor before leaving AuthSocket::~AuthSocket() { - ZThread::Guard<ZThread::Mutex> g(patcherLock); + ACE_Guard<ACE_Thread_Mutex> g(patcherLock); + if(pPatch) fclose(pPatch); } @@ -912,7 +913,7 @@ bool AuthSocket::_HandleXferResume() ibuf.Read((char*)&start,sizeof(start)); fseek(pPatch,start,0); - ZThread::Thread u(new PatcherRunnable(this)); + ACE_Based::Thread u(*new PatcherRunnable(this)); return true; } @@ -924,7 +925,6 @@ bool AuthSocket::_HandleXferCancel() ///- Close and delete the socket ibuf.Remove(1); //clear input buffer - //ZThread::Thread::sleep(15); SetCloseAndDelete(); return true; @@ -946,8 +946,7 @@ bool AuthSocket::_HandleXferAccept() ibuf.Remove(1); //clear input buffer fseek(pPatch,0,0); - ZThread::Thread u(new PatcherRunnable(this)); - + ACE_Based::Thread u(*new PatcherRunnable(this)); return true; } @@ -965,7 +964,8 @@ PatcherRunnable::PatcherRunnable(class AuthSocket * as) /// Send content of patch file to the client void PatcherRunnable::run() { - ZThread::Guard<ZThread::Mutex> g(mySocket->patcherLock); + ACE_Guard<ACE_Thread_Mutex> g(mySocket->patcherLock); + XFER_DATA_STRUCT xfdata; xfdata.opcode = XFER_DATA; @@ -974,7 +974,7 @@ void PatcherRunnable::run() ///- Wait until output buffer is reasonably empty while(mySocket->Ready() && mySocket->IsLag()) { - ZThread::Thread::sleep(1); + 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); diff --git a/src/trinityrealm/AuthSocket.h b/src/trinityrealm/AuthSocket.h index 3cae54c7789..43b880a1e74 100644 --- a/src/trinityrealm/AuthSocket.h +++ b/src/trinityrealm/AuthSocket.h @@ -33,7 +33,6 @@ #include "sockets/Utility.h" #include "sockets/Parse.h" #include "sockets/Socket.h" -#include "zthread/Mutex.h" /// Handle login commands class AuthSocket: public TcpSocket @@ -61,7 +60,7 @@ class AuthSocket: public TcpSocket void _SetVSFields(const std::string& rI); FILE *pPatch; - ZThread::Mutex patcherLock; + ACE_Thread_Mutex patcherLock; bool IsLag(); private: diff --git a/src/trinityrealm/Makefile.am b/src/trinityrealm/Makefile.am index a14b50c847a..197d6ebf8c4 100644 --- a/src/trinityrealm/Makefile.am +++ b/src/trinityrealm/Makefile.am @@ -32,8 +32,13 @@ trinity_realmd_SOURCES = \ RealmList.h ## Link realm list daemon against the shared library +<<<<<<< HEAD:src/realmd/Makefile.am trinity_realmd_LDADD = ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a ../../dep/src/zthread/libZThread.la trinity_realmd_LDFLAGS = -L../../dep/src/sockets -L../../dep/src/zthread -L$(libdir) $(TRINI_LIBS) +======= +mangos_realmd_LDADD = ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../framework/libmangosframework.a ../../dep/src/sockets/libmangossockets.a +mangos_realmd_LDFLAGS = -L../../dep/src/sockets -L$(libdir) $(MANGOS_LIBS) +>>>>>>> 00c7d15a78b1dcdbf888b768c55424183b2231e4:src/realmd/Makefile.am ## Additional files to include when running 'make dist' # Include realm list daemon configuration |