Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -37,7 +37,7 @@ void GuardAI::Reset()
|
||||
me->CastSpell(me, 18950 /*SPELL_INVISIBILITY_AND_STEALTH_DETECTION*/, true);
|
||||
}
|
||||
|
||||
void GuardAI::EnterEvadeMode()
|
||||
void GuardAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
static int Permissible(Creature const* creature);
|
||||
|
||||
void Reset() override;
|
||||
void EnterEvadeMode() override;
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override;
|
||||
void JustDied(Unit* killer) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -26,7 +26,7 @@ NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c) { me->SetReactState(
|
||||
void PassiveAI::UpdateAI(uint32)
|
||||
{
|
||||
if (me->IsInCombat() && me->getAttackers().empty())
|
||||
EnterEvadeMode();
|
||||
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
|
||||
}
|
||||
|
||||
void PossessedAI::AttackStart(Unit* target)
|
||||
@@ -66,11 +66,11 @@ void CritterAI::DamageTaken(Unit*, uint32&, DamageEffectType, SpellSchoolMask)
|
||||
_combatTimer = 1;
|
||||
}
|
||||
|
||||
void CritterAI::EnterEvadeMode()
|
||||
void CritterAI::EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
if (me->HasUnitState(UNIT_STATE_FLEEING))
|
||||
me->SetControlled(false, UNIT_STATE_FLEEING);
|
||||
CreatureAI::EnterEvadeMode();
|
||||
CreatureAI::EnterEvadeMode(why);
|
||||
_combatTimer = 0;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ void CritterAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
_combatTimer += diff;
|
||||
if (_combatTimer >= 5000)
|
||||
EnterEvadeMode();
|
||||
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
void MoveInLineOfSight(Unit*) override {}
|
||||
void AttackStart(Unit* target) override;
|
||||
void UpdateAI(uint32) override;
|
||||
void EnterEvadeMode() override {}
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override {}
|
||||
|
||||
void JustDied(Unit*) override;
|
||||
void KilledUnit(Unit* victim) override;
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
void MoveInLineOfSight(Unit*) override {}
|
||||
void AttackStart(Unit*) override {}
|
||||
void UpdateAI(uint32) override {}
|
||||
void EnterEvadeMode() override {}
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override {}
|
||||
void OnCharmed(bool /*apply*/) override {}
|
||||
|
||||
static int Permissible(Creature const*) { return PERMIT_BASE_IDLE; }
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
explicit CritterAI(Creature* c) : PassiveAI(c) { _combatTimer = 0; }
|
||||
|
||||
void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override;
|
||||
void EnterEvadeMode() override;
|
||||
void EnterEvadeMode(EvadeReason why) override;
|
||||
void UpdateAI(uint32) override;
|
||||
|
||||
// Xinef: Added
|
||||
|
||||
@@ -64,7 +64,8 @@ public:
|
||||
//
|
||||
void MoveInLineOfSight(Unit* /*who*/) override {} // CreatureAI interferes with returning pets
|
||||
void MoveInLineOfSight_Safe(Unit* /*who*/) {} // CreatureAI interferes with returning pets
|
||||
void EnterEvadeMode() override {} // For fleeing, pets don't use this type of Evade mechanic
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override {} // For fleeing, pets don't use this type of Evade mechanic
|
||||
void SpellHit(Unit* caster, SpellInfo const* spellInfo) override;
|
||||
|
||||
void PetStopAttack() override;
|
||||
|
||||
@@ -50,7 +50,7 @@ void TotemAI::MoveInLineOfSight(Unit* /*who*/)
|
||||
{
|
||||
}
|
||||
|
||||
void TotemAI::EnterEvadeMode()
|
||||
void TotemAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
me->CombatStop(true);
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ public:
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override;
|
||||
void AttackStart(Unit* victim) override;
|
||||
void EnterEvadeMode() override;
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override;
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* /*spellInfo*/) override;
|
||||
|
||||
void DoAction(int32 param) override;
|
||||
|
||||
void UpdateAI(uint32 diff) override;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AreaBoundary.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "MapReference.h"
|
||||
#include "Player.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Language.h"
|
||||
|
||||
class PhasedRespawn : public BasicEvent
|
||||
{
|
||||
@@ -196,9 +198,9 @@ void CreatureAI::TriggerAlert(Unit const* who) const
|
||||
me->GetMotionMaster()->MoveDistract(5 * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
void CreatureAI::EnterEvadeMode()
|
||||
void CreatureAI::EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
if (!_EnterEvadeMode())
|
||||
if (!_EnterEvadeMode(why))
|
||||
return;
|
||||
|
||||
LOG_DEBUG("entities.unit", "Creature {} enters evade mode.", me->GetEntry());
|
||||
@@ -290,7 +292,7 @@ bool CreatureAI::UpdateVictim()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreatureAI::_EnterEvadeMode()
|
||||
bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
{
|
||||
@@ -357,6 +359,44 @@ void CreatureAI::MoveBackwardsChecks() {
|
||||
me->GetMotionMaster()->MoveBackwards(victim, moveDist);
|
||||
}
|
||||
|
||||
bool CreatureAI::IsInBoundary(Position const* who) const
|
||||
{
|
||||
if (!_boundary)
|
||||
return true;
|
||||
|
||||
if (!who)
|
||||
who = me;
|
||||
|
||||
return (CreatureAI::IsInBounds(*_boundary, who) != _negateBoundary);
|
||||
}
|
||||
|
||||
bool CreatureAI::IsInBounds(CreatureBoundary const& boundary, Position const* pos)
|
||||
{
|
||||
for (AreaBoundary const* areaBoundary : boundary)
|
||||
if (!areaBoundary->IsWithinBoundary(pos))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreatureAI::CheckInRoom()
|
||||
{
|
||||
if (IsInBoundary())
|
||||
return true;
|
||||
else
|
||||
{
|
||||
EnterEvadeMode(EVADE_REASON_BOUNDARY);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureAI::SetBoundary(CreatureBoundary const* boundary, bool negateBoundaries /*= false*/)
|
||||
{
|
||||
_boundary = boundary;
|
||||
_negateBoundary = negateBoundaries;
|
||||
me->DoImmediateBoundaryCheck();
|
||||
}
|
||||
|
||||
Creature* CreatureAI::DoSummon(uint32 entry, const Position& pos, uint32 despawnTime, TempSummonType summonType)
|
||||
{
|
||||
return me->SummonCreature(entry, pos, summonType, despawnTime);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef ACORE_CREATUREAI_H
|
||||
#define ACORE_CREATUREAI_H
|
||||
|
||||
#include "AreaBoundary.h"
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "UnitAI.h"
|
||||
@@ -29,6 +30,8 @@ class Creature;
|
||||
class Player;
|
||||
class SpellInfo;
|
||||
|
||||
typedef std::vector<AreaBoundary const*> CreatureBoundary;
|
||||
|
||||
#define TIME_INTERVAL_LOOK 5000
|
||||
#define VISIBILITY_RANGE 10000
|
||||
|
||||
@@ -78,10 +81,19 @@ protected:
|
||||
Creature* DoSummon(uint32 entry, Position const& pos, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
Creature* DoSummon(uint32 entry, WorldObject* obj, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
Creature* DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
|
||||
public:
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
enum EvadeReason
|
||||
{
|
||||
EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty
|
||||
EVADE_REASON_BOUNDARY, // the creature has moved outside its evade boundary
|
||||
EVADE_REASON_SEQUENCE_BREAK, // this is a boss and the pre-requisite encounters for engaging it are not defeated yet
|
||||
EVADE_REASON_OTHER
|
||||
};
|
||||
|
||||
void Talk(uint8 id, WorldObject const* whisperTarget = nullptr);
|
||||
explicit CreatureAI(Creature* creature) : UnitAI(creature), me(creature), m_MoveInLineOfSight_locked(false) {}
|
||||
|
||||
explicit CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), _negateBoundary(false), m_MoveInLineOfSight_locked(false) { }
|
||||
|
||||
~CreatureAI() override {}
|
||||
|
||||
@@ -100,7 +112,7 @@ public:
|
||||
virtual bool CanRespawn() { return true; }
|
||||
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
virtual void EnterEvadeMode();
|
||||
virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
|
||||
|
||||
// Called for reaction at enter to combat if not in combat yet (enemy can be nullptr)
|
||||
virtual void EnterCombat(Unit* /*victim*/) {}
|
||||
@@ -187,10 +199,20 @@ public:
|
||||
|
||||
virtual void PetStopAttack() { }
|
||||
|
||||
// boundary system methods
|
||||
virtual bool CheckInRoom();
|
||||
CreatureBoundary const* GetBoundary() const { return _boundary; }
|
||||
void SetBoundary(CreatureBoundary const* boundary, bool negativeBoundaries = false);
|
||||
|
||||
static bool IsInBounds(CreatureBoundary const& boundary, Position const* who);
|
||||
bool IsInBoundary(Position const* who = nullptr) const;
|
||||
protected:
|
||||
virtual void MoveInLineOfSight(Unit* /*who*/);
|
||||
|
||||
bool _EnterEvadeMode();
|
||||
bool _EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
|
||||
|
||||
CreatureBoundary const* _boundary;
|
||||
bool _negateBoundary;
|
||||
|
||||
private:
|
||||
bool m_MoveInLineOfSight_locked;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AreaBoundary.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
@@ -171,7 +172,6 @@ bool SummonList::IsAnyCreatureInCombat() const
|
||||
ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
|
||||
me(creature),
|
||||
IsFleeing(false),
|
||||
_evadeCheckCooldown(2500),
|
||||
_isCombatMovementAllowed(true)
|
||||
{
|
||||
_isHeroic = me->GetMap()->IsHeroic();
|
||||
@@ -489,23 +489,6 @@ enum eNPCs
|
||||
NPC_FREYA = 32906,
|
||||
};
|
||||
|
||||
bool ScriptedAI::EnterEvadeIfOutOfCombatArea()
|
||||
{
|
||||
if (me->IsInEvadeMode() || !me->IsInCombat())
|
||||
return false;
|
||||
|
||||
if (_evadeCheckCooldown == GameTime::GetGameTime().count())
|
||||
return false;
|
||||
|
||||
_evadeCheckCooldown = GameTime::GetGameTime().count();
|
||||
|
||||
if (!CheckEvadeIfOutOfCombatArea())
|
||||
return false;
|
||||
|
||||
EnterEvadeMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* ScriptedAI::SelectTargetFromPlayerList(float maxdist, uint32 excludeAura, bool mustBeInLOS) const
|
||||
{
|
||||
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
|
||||
@@ -531,9 +514,10 @@ Player* ScriptedAI::SelectTargetFromPlayerList(float maxdist, uint32 excludeAura
|
||||
BossAI::BossAI(Creature* creature, uint32 bossId) : ScriptedAI(creature),
|
||||
instance(creature->GetInstanceScript()),
|
||||
summons(creature),
|
||||
_boundary(instance ? instance->GetBossBoundary(bossId) : nullptr),
|
||||
_bossId(bossId)
|
||||
{
|
||||
if (instance)
|
||||
SetBoundary(instance->GetBossBoundary(bossId));
|
||||
}
|
||||
|
||||
void BossAI::_Reset()
|
||||
@@ -583,59 +567,10 @@ void BossAI::TeleportCheaters()
|
||||
ThreatContainer::StorageType threatList = me->getThreatMgr().getThreatList();
|
||||
for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
|
||||
if (Unit* target = (*itr)->getTarget())
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && !CheckBoundary(target))
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && !IsInBoundary(target))
|
||||
target->NearTeleportTo(x, y, z, 0);
|
||||
}
|
||||
|
||||
bool BossAI::CheckBoundary(Unit* who)
|
||||
{
|
||||
if (!GetBoundary() || !who)
|
||||
return true;
|
||||
|
||||
for (BossBoundaryMap::const_iterator itr = GetBoundary()->begin(); itr != GetBoundary()->end(); ++itr)
|
||||
{
|
||||
switch (itr->first)
|
||||
{
|
||||
case BOUNDARY_N:
|
||||
if (who->GetPositionX() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_S:
|
||||
if (who->GetPositionX() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_E:
|
||||
if (who->GetPositionY() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_W:
|
||||
if (who->GetPositionY() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_NW:
|
||||
if (who->GetPositionX() + who->GetPositionY() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_SE:
|
||||
if (who->GetPositionX() + who->GetPositionY() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_NE:
|
||||
if (who->GetPositionX() - who->GetPositionY() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_SW:
|
||||
if (who->GetPositionX() - who->GetPositionY() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BossAI::JustSummoned(Creature* summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
|
||||
@@ -344,7 +344,6 @@ struct ScriptedAI : public CreatureAI
|
||||
void SetCombatMovement(bool allowMovement);
|
||||
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
|
||||
|
||||
bool EnterEvadeIfOutOfCombatArea();
|
||||
virtual bool CheckEvadeIfOutOfCombatArea() const { return false; }
|
||||
|
||||
// return true for heroic mode. i.e.
|
||||
@@ -416,7 +415,6 @@ struct ScriptedAI : public CreatureAI
|
||||
|
||||
private:
|
||||
Difficulty _difficulty;
|
||||
uint32 _evadeCheckCooldown;
|
||||
bool _isCombatMovementAllowed;
|
||||
bool _isHeroic;
|
||||
};
|
||||
@@ -428,7 +426,6 @@ public:
|
||||
~BossAI() override {}
|
||||
|
||||
InstanceScript* const instance;
|
||||
BossBoundaryMap const* GetBoundary() const { return _boundary; }
|
||||
|
||||
void JustSummoned(Creature* summon) override;
|
||||
void SummonedCreatureDespawn(Creature* summon) override;
|
||||
@@ -453,23 +450,12 @@ protected:
|
||||
void _JustDied();
|
||||
void _JustReachedHome() { me->setActive(false); }
|
||||
|
||||
bool CheckInRoom()
|
||||
{
|
||||
if (CheckBoundary(me))
|
||||
return true;
|
||||
|
||||
EnterEvadeMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckBoundary(Unit* who);
|
||||
void TeleportCheaters();
|
||||
|
||||
EventMap events;
|
||||
SummonList summons;
|
||||
|
||||
private:
|
||||
BossBoundaryMap const* const _boundary;
|
||||
uint32 const _bossId;
|
||||
};
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ void npc_escortAI::ReturnToLastPoint()
|
||||
me->GetMotionMaster()->MovePoint(POINT_LAST_POINT, x, y, z);
|
||||
}
|
||||
|
||||
void npc_escortAI::EnterEvadeMode()
|
||||
void npc_escortAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
|
||||
void ReturnToLastPoint();
|
||||
|
||||
void EnterEvadeMode() override;
|
||||
void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override;
|
||||
|
||||
void UpdateAI(uint32 diff) override; //the "internal" update, calls UpdateEscortAI()
|
||||
virtual void UpdateEscortAI(uint32 diff); //used when it's needed to add code in update (abilities, scripted events, etc)
|
||||
|
||||
@@ -150,7 +150,7 @@ void FollowerAI::JustRespawned()
|
||||
Reset();
|
||||
}
|
||||
|
||||
void FollowerAI::EnterEvadeMode()
|
||||
void FollowerAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
|
||||
void MoveInLineOfSight(Unit*) override;
|
||||
|
||||
void EnterEvadeMode() override;
|
||||
void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override;
|
||||
|
||||
void JustDied(Unit*) override;
|
||||
|
||||
|
||||
@@ -618,7 +618,7 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
|
||||
MovepointReached(Data);
|
||||
}
|
||||
|
||||
void SmartAI::EnterEvadeMode()
|
||||
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
// xinef: fixes strange jumps when charming SmartAI npc
|
||||
if (!me->IsAlive() || me->IsInEvadeMode())
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
void EnterCombat(Unit* enemy) override;
|
||||
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
void EnterEvadeMode() override;
|
||||
void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER) override;
|
||||
|
||||
// Called when the creature is killed
|
||||
void JustDied(Unit* killer) override;
|
||||
|
||||
@@ -105,7 +105,7 @@ void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint3
|
||||
if (eventType == SMART_EVENT_LINK)//special handling
|
||||
continue;
|
||||
|
||||
if (eventType == e/* && (!(*i).event.event_phase_mask || IsInPhase((*i).event.event_phase_mask)) && !((*i).event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE && (*i).runOnce)*/)
|
||||
if (eventType == e)
|
||||
{
|
||||
ConditionList conds = sConditionMgr->GetConditionsForSmartEvent((*i).entryOrGuid, (*i).event_id, (*i).source_type);
|
||||
ConditionSourceInfo info = ConditionSourceInfo(unit, GetBaseObject(), me ? me->GetVictim() : nullptr);
|
||||
@@ -1496,6 +1496,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
unitTarget->AttackStop();
|
||||
}
|
||||
}
|
||||
|
||||
delete targets;
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_SUMMON_CREATURE:
|
||||
@@ -1584,7 +1586,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
z += e.target.z;
|
||||
o += e.target.o;
|
||||
if (!e.action.summonGO.targetsummon)
|
||||
GetBaseObject()->SummonGameObject(e.action.summonGO.entry, x, y, z, o, 0, 0, 0, 0, e.action.summonGO.despawnTime);
|
||||
GetBaseObject()->SummonGameObject(e.action.summonGO.entry, x, y, z, o, 0, 0, 0, 0, e.action.summonGO.despawnTime, GOSummonType(e.action.summonGO.summonType));
|
||||
else
|
||||
(*itr)->SummonGameObject(e.action.summonGO.entry, GetBaseObject()->GetPositionX(), GetBaseObject()->GetPositionY(), GetBaseObject()->GetPositionZ(), GetBaseObject()->GetOrientation(), 0, 0, 0, 0, e.action.summonGO.despawnTime);
|
||||
}
|
||||
@@ -1595,7 +1597,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (e.GetTargetType() != SMART_TARGET_POSITION)
|
||||
break;
|
||||
|
||||
GetBaseObject()->SummonGameObject(e.action.summonGO.entry, e.target.x, e.target.y, e.target.z, e.target.o, 0, 0, 0, 0, e.action.summonGO.despawnTime);
|
||||
GetBaseObject()->SummonGameObject(e.action.summonGO.entry, e.target.x, e.target.y, e.target.z, e.target.o, 0, 0, 0, 0, e.action.summonGO.despawnTime, GOSummonType(e.action.summonGO.summonType));
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_KILL_UNIT:
|
||||
@@ -3561,48 +3563,48 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*
|
||||
case SMART_TARGET_HOSTILE_SECOND_AGGRO:
|
||||
if (me)
|
||||
{
|
||||
if (e.target.hostilRandom.powerType)
|
||||
if (e.target.hostileRandom.powerType)
|
||||
{
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, PowerUsersSelector(me, Powers(e.target.hostilRandom.powerType - 1), (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly)))
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
l->push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
l->push_back(u);
|
||||
}
|
||||
break;
|
||||
case SMART_TARGET_HOSTILE_LAST_AGGRO:
|
||||
if (me)
|
||||
{
|
||||
if (e.target.hostilRandom.powerType)
|
||||
if (e.target.hostileRandom.powerType)
|
||||
{
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, PowerUsersSelector(me, Powers(e.target.hostilRandom.powerType - 1), (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly)))
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
l->push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
l->push_back(u);
|
||||
}
|
||||
break;
|
||||
case SMART_TARGET_HOSTILE_RANDOM:
|
||||
if (me)
|
||||
{
|
||||
if (e.target.hostilRandom.powerType)
|
||||
if (e.target.hostileRandom.powerType)
|
||||
{
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, Powers(e.target.hostilRandom.powerType - 1), (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly)))
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
l->push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
l->push_back(u);
|
||||
}
|
||||
break;
|
||||
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP:
|
||||
if (me)
|
||||
{
|
||||
if (e.target.hostilRandom.powerType)
|
||||
if (e.target.hostileRandom.powerType)
|
||||
{
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, PowerUsersSelector(me, Powers(e.target.hostilRandom.powerType - 1), (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly)))
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
l->push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostilRandom.maxDist, e.target.hostilRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
l->push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -4456,6 +4458,16 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
ProcessAction(e, unit, var0, var1);
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_EVENT_PHASE_CHANGE:
|
||||
{
|
||||
if (!IsInPhase(e.event.eventPhaseChange.phasemask))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessAction(e, GetLastInvoker());
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_GAME_EVENT_START:
|
||||
case SMART_EVENT_GAME_EVENT_END:
|
||||
{
|
||||
@@ -5063,6 +5075,12 @@ void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry)
|
||||
return;
|
||||
}
|
||||
|
||||
// Do NOT allow to start a new actionlist if a previous one is already running. We need to always finish the current actionlist
|
||||
if (!mTimedActionList.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mTimedActionList.clear();
|
||||
mTimedActionList = sSmartScriptMgr->GetScript(entry, SMART_SCRIPT_TYPE_TIMED_ACTIONLIST);
|
||||
if (mTimedActionList.empty())
|
||||
@@ -5092,3 +5110,43 @@ Unit* SmartScript::GetLastInvoker(Unit* invoker)
|
||||
return ObjectAccessor::GetUnit(*invoker, mLastInvoker);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SmartScript::IncPhase(uint32 p)
|
||||
{
|
||||
// protect phase from overflowing
|
||||
SetPhase(std::min<uint32>(SMART_EVENT_PHASE_12, mEventPhase + p));
|
||||
}
|
||||
|
||||
void SmartScript::DecPhase(uint32 p)
|
||||
{
|
||||
if (p >= mEventPhase)
|
||||
{
|
||||
SetPhase(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPhase(mEventPhase - p);
|
||||
}
|
||||
}
|
||||
|
||||
void SmartScript::SetPhase(uint32 p)
|
||||
{
|
||||
uint32 oldPhase = mEventPhase;
|
||||
|
||||
mEventPhase = p;
|
||||
|
||||
if (oldPhase != mEventPhase)
|
||||
{
|
||||
ProcessEventsFor(SMART_EVENT_EVENT_PHASE_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
bool SmartScript::IsInPhase(uint32 p) const
|
||||
{
|
||||
if (mEventPhase == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((1 << (mEventPhase - 1)) & p) != 0;
|
||||
}
|
||||
|
||||
@@ -258,26 +258,10 @@ public:
|
||||
void SetPhaseReset(bool allow) { _allowPhaseReset = allow; }
|
||||
|
||||
private:
|
||||
void IncPhase(uint32 p)
|
||||
{
|
||||
// Xinef: protect phase from overflowing
|
||||
mEventPhase = std::min<uint32>(SMART_EVENT_PHASE_12, mEventPhase + p);
|
||||
}
|
||||
|
||||
void DecPhase(uint32 p)
|
||||
{
|
||||
if (p >= mEventPhase)
|
||||
mEventPhase = 0;
|
||||
else
|
||||
mEventPhase -= p;
|
||||
}
|
||||
bool IsInPhase(uint32 p) const
|
||||
{
|
||||
if (mEventPhase == 0)
|
||||
return false;
|
||||
return (1 << (mEventPhase - 1)) & p;
|
||||
}
|
||||
void SetPhase(uint32 p = 0) { mEventPhase = p; }
|
||||
void IncPhase(uint32 p);
|
||||
void DecPhase(uint32 p);
|
||||
void SetPhase(uint32 p);
|
||||
bool IsInPhase(uint32 p) const;
|
||||
|
||||
SmartAIEventList mEvents;
|
||||
SmartAIEventList mInstallEvents;
|
||||
|
||||
@@ -410,7 +410,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
|
||||
case SMART_TARGET_HOSTILE_LAST_AGGRO:
|
||||
case SMART_TARGET_HOSTILE_RANDOM:
|
||||
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.hostilRandom.playerOnly);
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.hostileRandom.playerOnly);
|
||||
break;
|
||||
case SMART_TARGET_FARTHEST:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.farthest.playerOnly);
|
||||
@@ -528,7 +528,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
|
||||
case SMART_EVENT_JUST_CREATED: return NO_PARAMS;
|
||||
case SMART_EVENT_GOSSIP_HELLO: return sizeof(SmartEvent::gossipHello);
|
||||
case SMART_EVENT_FOLLOW_COMPLETED: return NO_PARAMS;
|
||||
// case SMART_EVENT_EVENT_PHASE_CHANGE: return sizeof(SmartEvent::eventPhaseChange);
|
||||
case SMART_EVENT_EVENT_PHASE_CHANGE: return sizeof(SmartEvent::eventPhaseChange);
|
||||
case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::behindTarget);
|
||||
case SMART_EVENT_GAME_EVENT_START: return sizeof(SmartEvent::gameEvent);
|
||||
case SMART_EVENT_GAME_EVENT_END: return sizeof(SmartEvent::gameEvent);
|
||||
@@ -756,10 +756,10 @@ bool SmartAIMgr::CheckUnusedTargetParams(SmartScriptHolder const& e)
|
||||
case SMART_TARGET_NONE: return NO_PARAMS;
|
||||
case SMART_TARGET_SELF: return NO_PARAMS;
|
||||
case SMART_TARGET_VICTIM: return NO_PARAMS;
|
||||
case SMART_TARGET_HOSTILE_SECOND_AGGRO: return sizeof(SmartTarget::hostilRandom);
|
||||
case SMART_TARGET_HOSTILE_LAST_AGGRO: return sizeof(SmartTarget::hostilRandom);
|
||||
case SMART_TARGET_HOSTILE_RANDOM: return sizeof(SmartTarget::hostilRandom);
|
||||
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP: return sizeof(SmartTarget::hostilRandom);
|
||||
case SMART_TARGET_HOSTILE_SECOND_AGGRO: return sizeof(SmartTarget::hostileRandom);
|
||||
case SMART_TARGET_HOSTILE_LAST_AGGRO: return sizeof(SmartTarget::hostileRandom);
|
||||
case SMART_TARGET_HOSTILE_RANDOM: return sizeof(SmartTarget::hostileRandom);
|
||||
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP: return sizeof(SmartTarget::hostileRandom);
|
||||
case SMART_TARGET_ACTION_INVOKER: return NO_PARAMS;
|
||||
case SMART_TARGET_POSITION: return NO_PARAMS; //uses x,y,z,o
|
||||
case SMART_TARGET_CREATURE_RANGE: return sizeof(SmartTarget::unitRange);
|
||||
@@ -1076,6 +1076,27 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_EVENT_PHASE_CHANGE:
|
||||
{
|
||||
if (!e.event.eventPhaseChange.phasemask)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has no param set, event won't be executed!.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.event.eventPhaseChange.phasemask > SMART_EVENT_PHASE_ALL)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid phasemask {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.eventPhaseChange.phasemask);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.event.event_phase_mask && !(e.event.event_phase_mask & e.event.eventPhaseChange.phasemask))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses event phasemask {} and incompatible event_param1 {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.event_phase_mask, e.event.eventPhaseChange.phasemask);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax))
|
||||
return false;
|
||||
|
||||
@@ -170,7 +170,7 @@ enum SMART_EVENT
|
||||
SMART_EVENT_JUST_CREATED = 63, // none
|
||||
SMART_EVENT_GOSSIP_HELLO = 64, // event_para_1 (only) 0 = no filter set, always execute action, 1 = GossipHello only filter set, skip action if reportUse, 2 = reportUse only filter set, skip action if GossipHello
|
||||
SMART_EVENT_FOLLOW_COMPLETED = 65, // none
|
||||
SMART_EVENT_UNUSED_66 = 66, // UNUSED
|
||||
SMART_EVENT_EVENT_PHASE_CHANGE = 66, // event phase mask (<= SMART_EVENT_PHASE_ALL)
|
||||
SMART_EVENT_IS_BEHIND_TARGET = 67, // cooldownMin, CooldownMax
|
||||
SMART_EVENT_GAME_EVENT_START = 68, // game_event.Entry
|
||||
SMART_EVENT_GAME_EVENT_END = 69, // game_event.Entry
|
||||
@@ -376,6 +376,17 @@ struct SmartEvent
|
||||
uint32 action;
|
||||
} gossip;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 spell;
|
||||
uint32 effIndex;
|
||||
} dummy;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 phasemask;
|
||||
} eventPhaseChange;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 cooldownMin;
|
||||
@@ -923,6 +934,7 @@ struct SmartAction
|
||||
uint32 entry;
|
||||
uint32 despawnTime;
|
||||
uint32 targetsummon;
|
||||
uint32 summonType;
|
||||
} summonGO;
|
||||
|
||||
struct
|
||||
@@ -1410,7 +1422,7 @@ struct SmartTarget
|
||||
uint32 maxDist;
|
||||
SAIBool playerOnly;
|
||||
uint32 powerType;
|
||||
} hostilRandom;
|
||||
} hostileRandom;
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -1677,7 +1689,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_AC_END][2] =
|
||||
{SMART_EVENT_JUST_CREATED, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
|
||||
{SMART_EVENT_GOSSIP_HELLO, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
|
||||
{SMART_EVENT_FOLLOW_COMPLETED, SMART_SCRIPT_TYPE_MASK_CREATURE },
|
||||
{SMART_EVENT_UNUSED_66, 0},
|
||||
{SMART_EVENT_EVENT_PHASE_CHANGE, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
|
||||
{SMART_EVENT_IS_BEHIND_TARGET, SMART_SCRIPT_TYPE_MASK_CREATURE },
|
||||
{SMART_EVENT_GAME_EVENT_START, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
|
||||
{SMART_EVENT_GAME_EVENT_END, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "BattlegroundAV.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
#include "Formulas.h"
|
||||
#include "GameEventMgr.h"
|
||||
#include "GameGraveyard.h"
|
||||
@@ -391,9 +392,13 @@ void BattlegroundAV::PostUpdateImpl(uint32 diff)
|
||||
for (uint8 i = 0; i <= 1; i++) //0=alliance, 1=horde
|
||||
{
|
||||
if (!m_CaptainAlive[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (m_CaptainBuffTimer[i] > diff)
|
||||
{
|
||||
m_CaptainBuffTimer[i] -= diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i == 0)
|
||||
@@ -401,14 +406,20 @@ void BattlegroundAV::PostUpdateImpl(uint32 diff)
|
||||
CastSpellOnTeam(AV_BUFF_A_CAPTAIN, TEAM_ALLIANCE);
|
||||
Creature* creature = GetBGCreature(AV_CPLACE_MAX + 61);
|
||||
if (creature)
|
||||
YellToAll(creature, LANG_BG_AV_A_CAPTAIN_BUFF, LANG_COMMON);
|
||||
{
|
||||
std::string creatureText = sCreatureTextMgr->GetLocalizedChatString(creature->GetEntry(), creature->getGender(), 0, 0, DEFAULT_LOCALE);
|
||||
YellToAll(creature, creatureText.c_str(), LANG_COMMON);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CastSpellOnTeam(AV_BUFF_H_CAPTAIN, TEAM_HORDE);
|
||||
Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59); //TODO: make the captains a dynamic creature
|
||||
if (creature)
|
||||
YellToAll(creature, LANG_BG_AV_H_CAPTAIN_BUFF, LANG_ORCISH);
|
||||
{
|
||||
std::string creatureText = sCreatureTextMgr->GetLocalizedChatString(creature->GetEntry(), creature->getGender(), 2, 0, DEFAULT_LOCALE);
|
||||
YellToAll(creature, creatureText.c_str(), LANG_ORCISH);
|
||||
}
|
||||
}
|
||||
m_CaptainBuffTimer[i] = 120000 + urand(0, 4) * 60000; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times
|
||||
}
|
||||
@@ -729,7 +740,10 @@ void BattlegroundAV::ChangeMineOwner(uint8 mine, TeamId teamId, bool initial)
|
||||
if (mine == AV_SOUTH_MINE) //i think this gets called all the time
|
||||
{
|
||||
if (Creature* creature = GetBGCreature(AV_CPLACE_MINE_S_3))
|
||||
YellToAll(creature, LANG_BG_AV_S_MINE_BOSS_CLAIMS, LANG_UNIVERSAL);
|
||||
{
|
||||
std::string creatureText = sCreatureTextMgr->GetLocalizedChatString(creature->GetEntry(), creature->getGender(), 0, 0, DEFAULT_LOCALE);
|
||||
YellToAll(creature, creatureText.c_str(), LANG_UNIVERSAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
#include "Battleground.h"
|
||||
#include "BattlegroundScore.h"
|
||||
|
||||
#define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!"
|
||||
#define LANG_BG_AV_H_CAPTAIN_BUFF "Now is the time to attack! For the Horde!"
|
||||
#define LANG_BG_AV_S_MINE_BOSS_CLAIMS "Snivvle is here! Snivvle claims the Coldtooth Mine!"
|
||||
|
||||
#define BG_AV_CAPTIME 240000 //4:00
|
||||
#define BG_AV_SNOWFALL_FIRSTCAP 300000 //5:00 but i also have seen 4:05
|
||||
|
||||
|
||||
@@ -472,7 +472,7 @@ void ThreatMgr::modifyThreatPercent(Unit* victim, int32 percent)
|
||||
|
||||
//============================================================
|
||||
|
||||
Unit* ThreatMgr::getHostilTarget()
|
||||
Unit* ThreatMgr::getHostileTarget()
|
||||
{
|
||||
iThreatContainer.update();
|
||||
HostileReference* nextVictim = iThreatContainer.selectNextVictim(GetOwner()->ToCreature(), getCurrentVictim());
|
||||
@@ -546,49 +546,49 @@ void ThreatMgr::processThreatEvent(ThreatRefStatusChangeEvent* threatRefStatusCh
|
||||
{
|
||||
threatRefStatusChangeEvent->setThreatMgr(this); // now we can set the threat manager
|
||||
|
||||
HostileReference* hostilRef = threatRefStatusChangeEvent->getReference();
|
||||
HostileReference* hostileRef = threatRefStatusChangeEvent->getReference();
|
||||
|
||||
switch (threatRefStatusChangeEvent->getType())
|
||||
{
|
||||
case UEV_THREAT_REF_THREAT_CHANGE:
|
||||
if ((getCurrentVictim() == hostilRef && threatRefStatusChangeEvent->getFValue() < 0.0f) ||
|
||||
(getCurrentVictim() != hostilRef && threatRefStatusChangeEvent->getFValue() > 0.0f))
|
||||
if ((getCurrentVictim() == hostileRef && threatRefStatusChangeEvent->getFValue() < 0.0f) ||
|
||||
(getCurrentVictim() != hostileRef && threatRefStatusChangeEvent->getFValue() > 0.0f))
|
||||
setDirty(true); // the order in the threat list might have changed
|
||||
break;
|
||||
case UEV_THREAT_REF_ONLINE_STATUS:
|
||||
if (!hostilRef->isOnline())
|
||||
if (!hostileRef->isOnline())
|
||||
{
|
||||
if (hostilRef == getCurrentVictim())
|
||||
if (hostileRef == getCurrentVictim())
|
||||
{
|
||||
setCurrentVictim(nullptr);
|
||||
setDirty(true);
|
||||
}
|
||||
if (GetOwner() && GetOwner()->IsInWorld())
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*GetOwner(), hostilRef->getUnitGuid()))
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*GetOwner(), hostileRef->getUnitGuid()))
|
||||
if (GetOwner()->IsInMap(target))
|
||||
GetOwner()->SendRemoveFromThreatListOpcode(hostilRef);
|
||||
iThreatContainer.remove(hostilRef);
|
||||
iThreatOfflineContainer.addReference(hostilRef);
|
||||
GetOwner()->SendRemoveFromThreatListOpcode(hostileRef);
|
||||
iThreatContainer.remove(hostileRef);
|
||||
iThreatOfflineContainer.addReference(hostileRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getCurrentVictim() && hostilRef->getThreat() > (1.1f * getCurrentVictim()->getThreat()))
|
||||
if (getCurrentVictim() && hostileRef->getThreat() > (1.1f * getCurrentVictim()->getThreat()))
|
||||
setDirty(true);
|
||||
iThreatContainer.addReference(hostilRef);
|
||||
iThreatOfflineContainer.remove(hostilRef);
|
||||
iThreatContainer.addReference(hostileRef);
|
||||
iThreatOfflineContainer.remove(hostileRef);
|
||||
}
|
||||
break;
|
||||
case UEV_THREAT_REF_REMOVE_FROM_LIST:
|
||||
if (hostilRef == getCurrentVictim())
|
||||
if (hostileRef == getCurrentVictim())
|
||||
{
|
||||
setCurrentVictim(nullptr);
|
||||
setDirty(true);
|
||||
}
|
||||
iOwner->SendRemoveFromThreatListOpcode(hostilRef);
|
||||
if (hostilRef->isOnline())
|
||||
iThreatContainer.remove(hostilRef);
|
||||
iOwner->SendRemoveFromThreatListOpcode(hostileRef);
|
||||
if (hostileRef->isOnline())
|
||||
iThreatContainer.remove(hostileRef);
|
||||
else
|
||||
iThreatOfflineContainer.remove(hostilRef);
|
||||
iThreatOfflineContainer.remove(hostileRef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ public:
|
||||
|
||||
[[nodiscard]] Unit* GetOwner() const { return iOwner; }
|
||||
|
||||
Unit* getHostilTarget();
|
||||
Unit* getHostileTarget();
|
||||
|
||||
void tauntApply(Unit* taunter);
|
||||
void tauntFadeOut(Unit* taunter);
|
||||
|
||||
@@ -202,7 +202,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
}
|
||||
|
||||
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootRecipientGroup(0),
|
||||
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f),
|
||||
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500),
|
||||
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
|
||||
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
|
||||
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
|
||||
@@ -689,6 +689,17 @@ void Creature::Update(uint32 diff)
|
||||
SelectVictim();
|
||||
}
|
||||
|
||||
// periodic check to see if the creature has passed an evade boundary
|
||||
if (IsAIEnabled && !IsInEvadeMode() && IsInCombat())
|
||||
{
|
||||
if (diff >= m_boundaryCheckTime)
|
||||
{
|
||||
AI()->CheckInRoom();
|
||||
m_boundaryCheckTime = 2500;
|
||||
} else
|
||||
m_boundaryCheckTime -= diff;
|
||||
}
|
||||
|
||||
Unit* owner = GetCharmerOrOwner();
|
||||
if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange(), true, false))
|
||||
{
|
||||
|
||||
@@ -285,6 +285,8 @@ public:
|
||||
[[nodiscard]] float GetWanderDistance() const { return m_wanderDistance; }
|
||||
void SetWanderDistance(float dist) { m_wanderDistance = dist; }
|
||||
|
||||
void DoImmediateBoundaryCheck() { m_boundaryCheckTime = 0; }
|
||||
|
||||
uint32 m_groupLootTimer; // (msecs)timer used for group loot
|
||||
uint32 lootingGroupLowGUID; // used to find group which is looting corpse
|
||||
|
||||
@@ -401,6 +403,7 @@ protected:
|
||||
uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning
|
||||
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
|
||||
float m_wanderDistance;
|
||||
uint32 m_boundaryCheckTime; // (msecs) remaining time for next evade boundary check
|
||||
uint16 m_transportCheckTimer;
|
||||
uint32 lootPickPocketRestoreTime;
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Define.h"
|
||||
#include "Item.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
@@ -2304,7 +2304,7 @@ TempSummon* WorldObject::SummonCreature(uint32 entry, const Position& pos, TempS
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport)
|
||||
GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport, GOSummonType summonType)
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return nullptr;
|
||||
@@ -2330,7 +2330,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float
|
||||
if (respawnTime)
|
||||
go->SetSpellId(1);
|
||||
|
||||
if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this
|
||||
if (GetTypeId() == TYPEID_PLAYER || (GetTypeId() == TYPEID_UNIT && summonType == GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)) //not sure how to handle this
|
||||
ToUnit()->AddGameObject(go);
|
||||
else
|
||||
go->SetSpawnedByDefault(false);
|
||||
|
||||
@@ -65,6 +65,12 @@ enum NotifyFlags
|
||||
NOTIFY_ALL = 0xFF
|
||||
};
|
||||
|
||||
enum GOSummonType
|
||||
{
|
||||
GO_SUMMON_TIMED_OR_CORPSE_DESPAWN = 0, // despawns after a specified time OR when the summoner dies
|
||||
GO_SUMMON_TIMED_DESPAWN = 1 // despawns after a specified time
|
||||
};
|
||||
|
||||
class WorldPacket;
|
||||
class UpdateData;
|
||||
class ByteBuffer;
|
||||
@@ -516,7 +522,7 @@ public:
|
||||
|
||||
TempSummon* SummonCreature(uint32 id, const Position& pos, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, uint32 vehId = 0, SummonPropertiesEntry const* properties = nullptr) const;
|
||||
TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, SummonPropertiesEntry const* properties = nullptr);
|
||||
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport = true);
|
||||
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport = true, GOSummonType summonType = GO_SUMMON_TIMED_OR_CORPSE_DESPAWN);
|
||||
Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, bool setLevel = false, CreatureAI * (*GetAI)(Creature*) = nullptr);
|
||||
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = nullptr);
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@
|
||||
#include "PlayerSettings.h"
|
||||
#include "PlayerTaxi.h"
|
||||
#include "QuestDef.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "TradeData.h"
|
||||
#include "Unit.h"
|
||||
#include "WorldSession.h"
|
||||
@@ -2923,32 +2925,28 @@ template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& bas
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float totalmul = 1.0f;
|
||||
int32 totalflat = 0;
|
||||
|
||||
// Drop charges for triggering spells instead of triggered ones
|
||||
if (m_spellModTakingSpell)
|
||||
spell = m_spellModTakingSpell;
|
||||
|
||||
for (auto mod : m_spellMods[op])
|
||||
auto calculateSpellMod = [&](SpellModifier* mod)
|
||||
{
|
||||
// Charges can be set only for mods with auras
|
||||
if (!mod->ownerAura)
|
||||
ASSERT(mod->charges == 0);
|
||||
|
||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||
continue;
|
||||
|
||||
// xinef: temporary pets cannot use charged mods of owner, needed for mirror image QQ they should use their own auras
|
||||
if (temporaryPet && mod->charges != 0)
|
||||
continue;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mod->type == SPELLMOD_FLAT)
|
||||
{
|
||||
// xinef: do not allow to consume more than one 100% crit increasing spell
|
||||
if (mod->op == SPELLMOD_CRITICAL_CHANCE && totalflat >= 100)
|
||||
continue;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
totalflat += mod->value;
|
||||
}
|
||||
@@ -2956,32 +2954,88 @@ template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& bas
|
||||
{
|
||||
// skip percent mods for null basevalue (most important for spell mods with charges)
|
||||
if (basevalue == T(0) || totalmul == 0.0f)
|
||||
continue;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// special case (skip > 10sec spell casts for instant cast setting)
|
||||
if (mod->op == SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100)
|
||||
continue;
|
||||
{
|
||||
return;
|
||||
}
|
||||
// xinef: special exception for surge of light, dont affect crit chance if previous mods were not applied
|
||||
else if (mod->op == SPELLMOD_CRITICAL_CHANCE && spell && !HasSpellMod(mod, spell))
|
||||
continue;
|
||||
{
|
||||
return;
|
||||
}
|
||||
// xinef: special case for backdraft gcd reduce with backlast time reduction, dont affect gcd if cast time was not applied
|
||||
else if (mod->op == SPELLMOD_GLOBAL_COOLDOWN && spell && !HasSpellMod(mod, spell))
|
||||
continue;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// xinef: those two mods should be multiplicative (Glyph of Renew)
|
||||
if (mod->op == SPELLMOD_DAMAGE || mod->op == SPELLMOD_DOT)
|
||||
{
|
||||
totalmul *= CalculatePct(1.0f, 100.0f + mod->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
totalmul += CalculatePct(1.0f, mod->value);
|
||||
}
|
||||
}
|
||||
|
||||
DropModCharge(mod, spell);
|
||||
};
|
||||
|
||||
// Drop charges for triggering spells instead of triggered ones
|
||||
if (m_spellModTakingSpell)
|
||||
{
|
||||
spell = m_spellModTakingSpell;
|
||||
}
|
||||
|
||||
SpellModifier* chargedMod = nullptr;
|
||||
for (auto mod : m_spellMods[op])
|
||||
{
|
||||
// Charges can be set only for mods with auras
|
||||
if (!mod->ownerAura)
|
||||
{
|
||||
ASSERT(!mod->charges);
|
||||
}
|
||||
|
||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mod->ownerAura->IsUsingCharges())
|
||||
{
|
||||
if (!chargedMod || (chargedMod->ownerAura->GetSpellInfo()->SpellPriority < mod->ownerAura->GetSpellInfo()->SpellPriority))
|
||||
{
|
||||
chargedMod = mod;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
calculateSpellMod(mod);
|
||||
}
|
||||
|
||||
if (chargedMod)
|
||||
{
|
||||
calculateSpellMod(chargedMod);
|
||||
}
|
||||
|
||||
float diff = 0.0f;
|
||||
if (op == SPELLMOD_CASTING_TIME || op == SPELLMOD_DURATION)
|
||||
{
|
||||
diff = ((float)basevalue + totalflat) * (totalmul - 1.0f) + (float)totalflat;
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = (float)basevalue * (totalmul - 1.0f) + (float)totalflat;
|
||||
}
|
||||
|
||||
basevalue = T((float)basevalue + diff);
|
||||
return T(diff);
|
||||
}
|
||||
|
||||
@@ -1616,24 +1616,24 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver)
|
||||
continue;
|
||||
|
||||
QuestStatus status = GetQuestStatus(questId);
|
||||
if ((status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(questId)) || (quest->IsAutoComplete() && CanTakeQuest(quest, false)))
|
||||
if (status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(questId))
|
||||
{
|
||||
if (quest->IsRepeatable() || quest->IsDailyOrWeekly())
|
||||
{
|
||||
result2 = DIALOG_STATUS_REWARD_REP;
|
||||
}
|
||||
else
|
||||
{
|
||||
result2 = DIALOG_STATUS_REWARD;
|
||||
}
|
||||
result2 = DIALOG_STATUS_REWARD;
|
||||
}
|
||||
else if (status == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
result2 = DIALOG_STATUS_INCOMPLETE;
|
||||
}
|
||||
|
||||
if (quest->IsAutoComplete() && CanTakeQuest(quest, false) && quest->IsRepeatable() && !quest->IsDailyOrWeekly())
|
||||
{
|
||||
result2 = DIALOG_STATUS_REWARD_REP;
|
||||
}
|
||||
|
||||
if (result2 > result)
|
||||
{
|
||||
result = result2;
|
||||
}
|
||||
}
|
||||
|
||||
for (QuestRelations::const_iterator i = qr.first; i != qr.second; ++i)
|
||||
|
||||
@@ -14056,7 +14056,7 @@ void Unit::TauntFadeOut(Unit* taunter)
|
||||
if (m_ThreatMgr.isThreatListEmpty())
|
||||
{
|
||||
if (creature->IsAIEnabled)
|
||||
creature->AI()->EnterEvadeMode();
|
||||
creature->AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_HOSTILES);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14094,7 +14094,7 @@ Unit* Creature::SelectVictim()
|
||||
if (CanHaveThreatList())
|
||||
{
|
||||
if (!target && !m_ThreatMgr.isThreatListEmpty())
|
||||
target = m_ThreatMgr.getHostilTarget();
|
||||
target = m_ThreatMgr.getHostileTarget();
|
||||
}
|
||||
else if (!HasReactState(REACT_PASSIVE))
|
||||
{
|
||||
@@ -14142,7 +14142,7 @@ Unit* Creature::SelectVictim()
|
||||
for (Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
|
||||
if ((*itr)->GetBase()->IsPermanent())
|
||||
{
|
||||
AI()->EnterEvadeMode();
|
||||
AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_HOSTILES);
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -17916,6 +17916,8 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
|
||||
// Set charmed
|
||||
charmer->SetCharm(this, true);
|
||||
|
||||
StopAttackingInvalidTarget();
|
||||
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE))
|
||||
@@ -18080,6 +18082,8 @@ void Unit::RemoveCharmedBy(Unit* charmer)
|
||||
|
||||
charmer->SetCharm(this, false);
|
||||
|
||||
StopAttackingInvalidTarget();
|
||||
|
||||
Player* playerCharmer = charmer->ToPlayer();
|
||||
if (playerCharmer)
|
||||
{
|
||||
@@ -19623,6 +19627,37 @@ void Unit::StopAttackFaction(uint32 faction_id)
|
||||
(*itr)->StopAttackFaction(faction_id);
|
||||
}
|
||||
|
||||
void Unit::StopAttackingInvalidTarget()
|
||||
{
|
||||
AttackerSet const& attackers = getAttackers();
|
||||
for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
|
||||
{
|
||||
Unit* attacker = (*itr);
|
||||
if (!attacker->IsValidAttackTarget(this))
|
||||
{
|
||||
attacker->AttackStop();
|
||||
if (attacker->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
attacker->ToPlayer()->SendAttackSwingCancelAttack();
|
||||
}
|
||||
|
||||
for (Unit* controled : attacker->m_Controlled)
|
||||
{
|
||||
if (controled->GetVictim() == this && !controled->IsValidAttackTarget(this))
|
||||
{
|
||||
controled->AttackStop();
|
||||
}
|
||||
}
|
||||
|
||||
itr = attackers.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::OutDebugInfo() const
|
||||
{
|
||||
LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
|
||||
|
||||
@@ -1360,6 +1360,7 @@ public:
|
||||
void CombatStop(bool includingCast = false);
|
||||
void CombatStopWithPets(bool includingCast = false);
|
||||
void StopAttackFaction(uint32 faction_id);
|
||||
void StopAttackingInvalidTarget();
|
||||
Unit* SelectNearbyTarget(Unit* exclude = nullptr, float dist = NOMINAL_MELEE_RANGE) const;
|
||||
Unit* SelectNearbyNoTotemTarget(Unit* exclude = nullptr, float dist = NOMINAL_MELEE_RANGE) const;
|
||||
void SendMeleeAttackStop(Unit* victim = nullptr);
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Unit.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include "Unit.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Acore::Impl::EnumUtilsImpl
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
#include "Spell.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
BossBoundaryData::~BossBoundaryData()
|
||||
{
|
||||
for (const_iterator it = begin(); it != end(); ++it)
|
||||
delete it->boundary;
|
||||
}
|
||||
|
||||
void InstanceScript::SaveToDB()
|
||||
{
|
||||
std::string data = GetSaveData();
|
||||
@@ -120,6 +126,13 @@ bool InstanceScript::IsEncounterInProgress() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void InstanceScript::LoadBossBoundaries(const BossBoundaryData& data)
|
||||
{
|
||||
for (BossBoundaryEntry const& entry : data)
|
||||
if (entry.bossId < bosses.size())
|
||||
bosses[entry.bossId].boundary.push_back(entry.boundary);
|
||||
}
|
||||
|
||||
void InstanceScript::LoadMinionData(const MinionData* data)
|
||||
{
|
||||
while (data->entry)
|
||||
@@ -137,7 +150,7 @@ void InstanceScript::LoadDoorData(const DoorData* data)
|
||||
while (data->entry)
|
||||
{
|
||||
if (data->bossId < bosses.size())
|
||||
doors.insert(std::make_pair(data->entry, DoorInfo(&bosses[data->bossId], data->type, BoundaryType(data->boundary))));
|
||||
doors.insert(std::make_pair(data->entry, DoorInfo(&bosses[data->bossId], data->type)));
|
||||
|
||||
++data;
|
||||
}
|
||||
@@ -268,28 +281,6 @@ void InstanceScript::AddDoor(GameObject* door, bool add)
|
||||
if (add)
|
||||
{
|
||||
data.bossInfo->door[data.type].insert(door);
|
||||
switch (data.boundary)
|
||||
{
|
||||
default:
|
||||
case BOUNDARY_NONE:
|
||||
break;
|
||||
case BOUNDARY_N:
|
||||
case BOUNDARY_S:
|
||||
data.bossInfo->boundary[data.boundary] = door->GetPositionX();
|
||||
break;
|
||||
case BOUNDARY_E:
|
||||
case BOUNDARY_W:
|
||||
data.bossInfo->boundary[data.boundary] = door->GetPositionY();
|
||||
break;
|
||||
case BOUNDARY_NW:
|
||||
case BOUNDARY_SE:
|
||||
data.bossInfo->boundary[data.boundary] = door->GetPositionX() + door->GetPositionY();
|
||||
break;
|
||||
case BOUNDARY_NE:
|
||||
case BOUNDARY_SW:
|
||||
data.bossInfo->boundary[data.boundary] = door->GetPositionX() - door->GetPositionY();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
data.bossInfo->door[data.type].erase(door);
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
#ifndef ACORE_INSTANCE_DATA_H
|
||||
#define ACORE_INSTANCE_DATA_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "ZoneScript.h"
|
||||
#include <set>
|
||||
|
||||
#define OUT_SAVE_INST_DATA LOG_DEBUG("scripts.ai", "Saving Instance Data for Instance {} (Map {}, Instance Id {})", instance->GetMapName(), instance->GetId(), instance->GetInstanceId())
|
||||
#define OUT_SAVE_INST_DATA_COMPLETE LOG_DEBUG("scripts.ai", "Saving Instance Data for Instance {} (Map {}, Instance Id {}) completed.", instance->GetMapName(), instance->GetId(), instance->GetInstanceId())
|
||||
@@ -67,30 +69,30 @@ enum DoorType
|
||||
MAX_DOOR_TYPES,
|
||||
};
|
||||
|
||||
enum BoundaryType
|
||||
{
|
||||
BOUNDARY_NONE = 0,
|
||||
BOUNDARY_N,
|
||||
BOUNDARY_S,
|
||||
BOUNDARY_E,
|
||||
BOUNDARY_W,
|
||||
BOUNDARY_NE,
|
||||
BOUNDARY_NW,
|
||||
BOUNDARY_SE,
|
||||
BOUNDARY_SW,
|
||||
BOUNDARY_MAX_X = BOUNDARY_N,
|
||||
BOUNDARY_MIN_X = BOUNDARY_S,
|
||||
BOUNDARY_MAX_Y = BOUNDARY_W,
|
||||
BOUNDARY_MIN_Y = BOUNDARY_E,
|
||||
};
|
||||
|
||||
typedef std::map<BoundaryType, float> BossBoundaryMap;
|
||||
|
||||
struct DoorData
|
||||
{
|
||||
uint32 entry, bossId;
|
||||
DoorType type;
|
||||
uint32 boundary;
|
||||
};
|
||||
|
||||
struct BossBoundaryEntry
|
||||
{
|
||||
uint32 const bossId;
|
||||
AreaBoundary const* const boundary;
|
||||
};
|
||||
|
||||
struct BossBoundaryData
|
||||
{
|
||||
typedef std::vector<BossBoundaryEntry> StorageType;
|
||||
typedef StorageType::const_iterator const_iterator;
|
||||
|
||||
BossBoundaryData(std::initializer_list<BossBoundaryEntry> data) : _data(data) { }
|
||||
~BossBoundaryData();
|
||||
const_iterator begin() const { return _data.begin(); }
|
||||
const_iterator end() const { return _data.end(); }
|
||||
|
||||
private:
|
||||
StorageType _data;
|
||||
};
|
||||
|
||||
struct MinionData
|
||||
@@ -110,16 +112,15 @@ struct BossInfo
|
||||
EncounterState state;
|
||||
DoorSet door[MAX_DOOR_TYPES];
|
||||
MinionSet minion;
|
||||
BossBoundaryMap boundary;
|
||||
CreatureBoundary boundary;
|
||||
};
|
||||
|
||||
struct DoorInfo
|
||||
{
|
||||
explicit DoorInfo(BossInfo* _bossInfo, DoorType _type, BoundaryType _boundary)
|
||||
: bossInfo(_bossInfo), type(_type), boundary(_boundary) {}
|
||||
explicit DoorInfo(BossInfo* _bossInfo, DoorType _type)
|
||||
: bossInfo(_bossInfo), type(_type) { }
|
||||
BossInfo* bossInfo;
|
||||
DoorType type;
|
||||
BoundaryType boundary;
|
||||
};
|
||||
|
||||
struct MinionInfo
|
||||
@@ -225,7 +226,7 @@ public:
|
||||
virtual bool SetBossState(uint32 id, EncounterState state);
|
||||
EncounterState GetBossState(uint32 id) const { return id < bosses.size() ? bosses[id].state : TO_BE_DECIDED; }
|
||||
static std::string GetBossStateName(uint8 state);
|
||||
BossBoundaryMap const* GetBossBoundary(uint32 id) const { return id < bosses.size() ? &bosses[id].boundary : nullptr; }
|
||||
CreatureBoundary const* GetBossBoundary(uint32 id) const { return id < bosses.size() ? &bosses[id].boundary : nullptr; }
|
||||
BossInfo const* GetBossInfo(uint32 id) const { return &bosses[id]; }
|
||||
|
||||
// Achievement criteria additional requirements check
|
||||
@@ -255,6 +256,7 @@ public:
|
||||
virtual void DoAction(int32 /*action*/) {}
|
||||
protected:
|
||||
void SetBossNumber(uint32 number) { bosses.resize(number); }
|
||||
void LoadBossBoundaries(BossBoundaryData const& data);
|
||||
void LoadDoorData(DoorData const* data);
|
||||
void LoadMinionData(MinionData const* data);
|
||||
void LoadObjectData(ObjectData const* creatureData, ObjectData const* gameObjectData);
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AreaBoundary.h"
|
||||
#include "Unit.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
// ---== RECTANGLE ==---
|
||||
RectangleBoundary::RectangleBoundary(float southX, float northX, float eastY, float westY, bool isInverted) :
|
||||
AreaBoundary(isInverted), _minX(southX), _maxX(northX), _minY(eastY), _maxY(westY) { }
|
||||
bool RectangleBoundary::IsWithinBoundaryArea(Position const* pos) const
|
||||
{
|
||||
return !(
|
||||
pos->GetPositionX() < _minX ||
|
||||
pos->GetPositionX() > _maxX ||
|
||||
pos->GetPositionY() < _minY ||
|
||||
pos->GetPositionY() > _maxY
|
||||
);
|
||||
}
|
||||
|
||||
// ---== CIRCLE ==---
|
||||
CircleBoundary::CircleBoundary(Position const& center, double radius, bool isInverted) :
|
||||
AreaBoundary(isInverted), _center(center), _radiusSq(radius*radius) { }
|
||||
|
||||
CircleBoundary::CircleBoundary(Position const& center, Position const& pointOnCircle, bool isInverted) :
|
||||
AreaBoundary(isInverted), _center(center), _radiusSq(_center.GetDoubleExactDist2dSq(pointOnCircle)) { }
|
||||
|
||||
bool CircleBoundary::IsWithinBoundaryArea(Position const* pos) const
|
||||
{
|
||||
double offX = _center.GetDoublePositionX() - pos->GetPositionX();
|
||||
double offY = _center.GetDoublePositionY() - pos->GetPositionY();
|
||||
return offX * offX + offY * offY <= _radiusSq;
|
||||
}
|
||||
|
||||
// ---== ELLIPSE ==---
|
||||
EllipseBoundary::EllipseBoundary(Position const& center, double radiusX, double radiusY, bool isInverted) :
|
||||
AreaBoundary(isInverted), _center(center), _radiusYSq(radiusY*radiusY), _scaleXSq(_radiusYSq / (radiusX*radiusX)) { }
|
||||
|
||||
bool EllipseBoundary::IsWithinBoundaryArea(Position const* pos) const
|
||||
{
|
||||
double offX = _center.GetDoublePositionX() - pos->GetPositionX();
|
||||
double offY = _center.GetDoublePositionY() - pos->GetPositionY();
|
||||
return (offX*offX)*_scaleXSq + (offY*offY) <= _radiusYSq;
|
||||
}
|
||||
|
||||
// ---== TRIANGLE ==---
|
||||
TriangleBoundary::TriangleBoundary(Position const& pointA, Position const& pointB, Position const& pointC, bool isInverted) :
|
||||
AreaBoundary(isInverted), _a(pointA), _b(pointB), _c(pointC), _abx(_b.GetDoublePositionX()-_a.GetDoublePositionX()), _bcx(_c.GetDoublePositionX()-_b.GetDoublePositionX()), _cax(_a.GetDoublePositionX() - _c.GetDoublePositionX()), _aby(_b.GetDoublePositionY()-_a.GetDoublePositionY()), _bcy(_c.GetDoublePositionY()-_b.GetDoublePositionY()), _cay(_a.GetDoublePositionY() - _c.GetDoublePositionY()) { }
|
||||
bool TriangleBoundary::IsWithinBoundaryArea(Position const* pos) const
|
||||
{
|
||||
// half-plane signs
|
||||
bool sign1 = ((-_b.GetDoublePositionX() + pos->GetPositionX()) * _aby - (-_b.GetDoublePositionY() + pos->GetPositionY()) * _abx) < 0;
|
||||
bool sign2 = ((-_c.GetDoublePositionX() + pos->GetPositionX()) * _bcy - (-_c.GetDoublePositionY() + pos->GetPositionY()) * _bcx) < 0;
|
||||
bool sign3 = ((-_a.GetDoublePositionX() + pos->GetPositionX()) * _cay - (-_a.GetDoublePositionY() + pos->GetPositionY()) * _cax) < 0;
|
||||
|
||||
// if all signs are the same, the point is inside the triangle
|
||||
return ((sign1 == sign2) && (sign2 == sign3));
|
||||
}
|
||||
|
||||
// ---== PARALLELOGRAM ==---
|
||||
ParallelogramBoundary::ParallelogramBoundary(Position const& cornerA, Position const& cornerB, Position const& cornerD, bool isInverted) :
|
||||
AreaBoundary(isInverted), _a(cornerA), _b(cornerB), _d(cornerD), _c(DoublePosition(_d.GetDoublePositionX() + (_b.GetDoublePositionX() - _a.GetDoublePositionX()), _d.GetDoublePositionY() + (_b.GetDoublePositionY() - _a.GetDoublePositionY()))), _abx(_b.GetDoublePositionX() - _a.GetDoublePositionX()), _dax(_a.GetDoublePositionX() - _d.GetDoublePositionX()), _aby(_b.GetDoublePositionY() - _a.GetDoublePositionY()), _day(_a.GetDoublePositionY() - _d.GetDoublePositionY()) { }
|
||||
bool ParallelogramBoundary::IsWithinBoundaryArea(Position const* pos) const
|
||||
{
|
||||
// half-plane signs
|
||||
bool sign1 = ((-_b.GetDoublePositionX() + pos->GetPositionX()) * _aby - (-_b.GetDoublePositionY() + pos->GetPositionY()) * _abx) < 0;
|
||||
bool sign2 = ((-_a.GetDoublePositionX() + pos->GetPositionX()) * _day - (-_a.GetDoublePositionY() + pos->GetPositionY()) * _dax) < 0;
|
||||
bool sign3 = ((-_d.GetDoublePositionY() + pos->GetPositionY()) * _abx - (-_d.GetDoublePositionX() + pos->GetPositionX()) * _aby) < 0; // AB = -CD
|
||||
bool sign4 = ((-_c.GetDoublePositionY() + pos->GetPositionY()) * _dax - (-_c.GetDoublePositionX() + pos->GetPositionX()) * _day) < 0; // DA = -BC
|
||||
|
||||
// if all signs are equal, the point is inside
|
||||
return ((sign1 == sign2) && (sign2 == sign3) && (sign3 == sign4));
|
||||
}
|
||||
|
||||
// ---== Z RANGE ==---
|
||||
ZRangeBoundary::ZRangeBoundary(float minZ, float maxZ, bool isInverted) :
|
||||
AreaBoundary(isInverted), _minZ(minZ), _maxZ(maxZ) { }
|
||||
bool ZRangeBoundary::IsWithinBoundaryArea(Position const* pos) const
|
||||
{
|
||||
return (_minZ <= pos->GetPositionZ() && pos->GetPositionZ() <= _maxZ);
|
||||
}
|
||||
|
||||
// ---== UNION OF 2 BOUNDARIES ==---
|
||||
BoundaryUnionBoundary::BoundaryUnionBoundary(AreaBoundary const* b1, AreaBoundary const* b2, bool isInverted) :
|
||||
AreaBoundary(isInverted), _b1(b1), _b2(b2)
|
||||
{
|
||||
ASSERT(b1 && b2);
|
||||
}
|
||||
|
||||
BoundaryUnionBoundary::~BoundaryUnionBoundary()
|
||||
{
|
||||
delete _b1;
|
||||
delete _b2;
|
||||
}
|
||||
|
||||
bool BoundaryUnionBoundary::IsWithinBoundaryArea(Position const* pos) const
|
||||
{
|
||||
return (_b1->IsWithinBoundary(pos) || _b2->IsWithinBoundary(pos));
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACORE_AREA_BOUNDARY_H
|
||||
#define ACORE_AREA_BOUNDARY_H
|
||||
|
||||
#include "Position.h"
|
||||
|
||||
class AC_GAME_API AreaBoundary
|
||||
{
|
||||
public:
|
||||
bool IsWithinBoundary(Position const* pos) const { return pos && (IsWithinBoundaryArea(pos) != _isInvertedBoundary); }
|
||||
bool IsWithinBoundary(Position const& pos) const { return IsWithinBoundary(&pos); }
|
||||
|
||||
virtual ~AreaBoundary() { }
|
||||
|
||||
protected:
|
||||
explicit AreaBoundary(bool isInverted) : _isInvertedBoundary(isInverted) { }
|
||||
|
||||
struct DoublePosition : Position
|
||||
{
|
||||
DoublePosition(double x = 0.0, double y = 0.0, double z = 0.0, float o = 0.0f)
|
||||
: Position(float(x), float(y), float(z), o), DoublePosX(x), DoublePosY(y), DoublePosZ(z) { }
|
||||
|
||||
DoublePosition(float x, float y = 0.0f, float z = 0.0f, float o = 0.0f)
|
||||
: Position(x, y, z, o), DoublePosX(x), DoublePosY(y), DoublePosZ(z) { }
|
||||
|
||||
DoublePosition(Position const& pos)
|
||||
: Position(pos), DoublePosX(pos.m_positionX), DoublePosY(pos.m_positionY), DoublePosZ(pos.m_positionZ) { }
|
||||
|
||||
double GetDoublePositionX() const { return DoublePosX; }
|
||||
double GetDoublePositionY() const { return DoublePosY; }
|
||||
double GetDoublePositionZ() const { return DoublePosZ; }
|
||||
|
||||
double GetDoubleExactDist2dSq(DoublePosition const& pos) const
|
||||
{
|
||||
double const offX = GetDoublePositionX() - pos.GetDoublePositionX();
|
||||
double const offY = GetDoublePositionY() - pos.GetDoublePositionY();
|
||||
return (offX * offX) + (offY * offY);
|
||||
}
|
||||
|
||||
Position* sync()
|
||||
{
|
||||
m_positionX = float(DoublePosX);
|
||||
m_positionY = float(DoublePosY);
|
||||
m_positionZ = float(DoublePosZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
double DoublePosX;
|
||||
double DoublePosY;
|
||||
double DoublePosZ;
|
||||
};
|
||||
|
||||
virtual bool IsWithinBoundaryArea(Position const* pos) const = 0;
|
||||
|
||||
private:
|
||||
bool _isInvertedBoundary;
|
||||
};
|
||||
|
||||
class AC_GAME_API RectangleBoundary : public AreaBoundary
|
||||
{
|
||||
public:
|
||||
// X axis is north/south, Y axis is east/west, larger values are northwest
|
||||
RectangleBoundary(float southX, float northX, float eastY, float westY, bool isInverted = false);
|
||||
|
||||
protected:
|
||||
bool IsWithinBoundaryArea(Position const* pos) const override;
|
||||
|
||||
private:
|
||||
float const _minX, _maxX, _minY, _maxY;
|
||||
};
|
||||
|
||||
class AC_GAME_API CircleBoundary : public AreaBoundary
|
||||
{
|
||||
public:
|
||||
CircleBoundary(Position const& center, double radius, bool isInverted = false);
|
||||
CircleBoundary(Position const& center, Position const& pointOnCircle, bool isInverted = false);
|
||||
|
||||
protected:
|
||||
bool IsWithinBoundaryArea(Position const* pos) const override;
|
||||
|
||||
private:
|
||||
DoublePosition const _center;
|
||||
double const _radiusSq;
|
||||
};
|
||||
|
||||
class AC_GAME_API EllipseBoundary : public AreaBoundary
|
||||
{
|
||||
public:
|
||||
EllipseBoundary(Position const& center, double radiusX, double radiusY, bool isInverted = false);
|
||||
|
||||
protected:
|
||||
bool IsWithinBoundaryArea(Position const* pos) const override;
|
||||
|
||||
private:
|
||||
DoublePosition const _center;
|
||||
double const _radiusYSq, _scaleXSq;
|
||||
};
|
||||
|
||||
class AC_GAME_API TriangleBoundary : public AreaBoundary
|
||||
{
|
||||
public:
|
||||
TriangleBoundary(Position const& pointA, Position const& pointB, Position const& pointC, bool isInverted = false);
|
||||
|
||||
protected:
|
||||
bool IsWithinBoundaryArea(Position const* pos) const override;
|
||||
|
||||
private:
|
||||
DoublePosition const _a, _b, _c;
|
||||
double const _abx, _bcx, _cax, _aby, _bcy, _cay;
|
||||
};
|
||||
|
||||
class AC_GAME_API ParallelogramBoundary : public AreaBoundary
|
||||
{
|
||||
public:
|
||||
// Note: AB must be orthogonal to AD
|
||||
ParallelogramBoundary(Position const& cornerA, Position const& cornerB, Position const& cornerD, bool isInverted = false);
|
||||
|
||||
protected:
|
||||
bool IsWithinBoundaryArea(Position const* pos) const override;
|
||||
|
||||
private:
|
||||
DoublePosition const _a, _b, _d, _c;
|
||||
double const _abx, _dax, _aby, _day;
|
||||
};
|
||||
|
||||
class AC_GAME_API ZRangeBoundary : public AreaBoundary
|
||||
{
|
||||
public:
|
||||
ZRangeBoundary(float minZ, float maxZ, bool isInverted = false);
|
||||
|
||||
protected:
|
||||
bool IsWithinBoundaryArea(Position const* pos) const override;
|
||||
|
||||
private:
|
||||
float const _minZ, _maxZ;
|
||||
};
|
||||
|
||||
class AC_GAME_API BoundaryUnionBoundary : public AreaBoundary
|
||||
{
|
||||
public:
|
||||
BoundaryUnionBoundary(AreaBoundary const* b1, AreaBoundary const* b2, bool isInverted = false);
|
||||
|
||||
protected:
|
||||
virtual ~BoundaryUnionBoundary();
|
||||
bool IsWithinBoundaryArea(Position const* pos) const override;
|
||||
|
||||
private:
|
||||
AreaBoundary const* const _b1;
|
||||
AreaBoundary const* const _b2;
|
||||
};
|
||||
|
||||
#endif //ACORE_AREA_BOUNDARY_H
|
||||
@@ -1965,9 +1965,9 @@ inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float
|
||||
|
||||
if (delta > collisionHeight)
|
||||
liquidData.Status = LIQUID_MAP_UNDER_WATER;
|
||||
else if (delta > 0.2f)
|
||||
else if (delta > 0.0f)
|
||||
liquidData.Status = LIQUID_MAP_IN_WATER;
|
||||
else if (delta > -0.2f)
|
||||
else if (delta > -0.1f)
|
||||
liquidData.Status = LIQUID_MAP_WATER_WALK;
|
||||
else
|
||||
liquidData.Status = LIQUID_MAP_ABOVE_WATER;
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Define.h"
|
||||
#include "QuestDef.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
@@ -4495,13 +4495,25 @@ void Spell::SendSpellStart()
|
||||
if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE)
|
||||
castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
|
||||
|
||||
PackedGuid realCasterGUID = m_caster->GetPackGUID();
|
||||
if (TempSummon const* tempSummon = m_caster->ToTempSummon())
|
||||
{
|
||||
if (tempSummon->GetEntry() == WORLD_TRIGGER)
|
||||
{
|
||||
if (GameObject* casterGameobject = tempSummon->GetSummonerGameObject())
|
||||
{
|
||||
realCasterGUID = casterGameobject->GetPackGUID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_SPELL_START, (8 + 8 + 4 + 4 + 2));
|
||||
if (m_CastItem)
|
||||
data << m_CastItem->GetPackGUID();
|
||||
else
|
||||
data << m_caster->GetPackGUID();
|
||||
data << realCasterGUID;
|
||||
|
||||
data << m_caster->GetPackGUID();
|
||||
data << realCasterGUID;
|
||||
data << uint8(m_cast_count); // pending spell cast?
|
||||
data << uint32(m_spellInfo->Id); // spellId
|
||||
data << uint32(castFlags); // cast flags
|
||||
@@ -4581,14 +4593,26 @@ void Spell::SendSpellGo()
|
||||
if (!m_spellInfo->StartRecoveryTime)
|
||||
castFlags |= CAST_FLAG_NO_GCD;
|
||||
|
||||
PackedGuid realCasterGUID = m_caster->GetPackGUID();
|
||||
if (TempSummon const* tempSummon = m_caster->ToTempSummon())
|
||||
{
|
||||
if (tempSummon->GetEntry() == WORLD_TRIGGER)
|
||||
{
|
||||
if (GameObject* casterGameobject = tempSummon->GetSummonerGameObject())
|
||||
{
|
||||
realCasterGUID = casterGameobject->GetPackGUID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_SPELL_GO, 150); // guess size
|
||||
|
||||
if (m_CastItem)
|
||||
data << m_CastItem->GetPackGUID();
|
||||
else
|
||||
data << m_caster->GetPackGUID();
|
||||
data << realCasterGUID;
|
||||
|
||||
data << m_caster->GetPackGUID();
|
||||
data << realCasterGUID;
|
||||
data << uint8(m_cast_count); // pending spell cast?
|
||||
data << uint32(m_spellInfo->Id); // spellId
|
||||
data << uint32(castFlags); // cast flags
|
||||
|
||||
@@ -3808,25 +3808,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
|
||||
m_caster->CastSpell(unitTarget, 22682, true);
|
||||
return;
|
||||
}
|
||||
// Mirren's Drinking Hat
|
||||
case 29830:
|
||||
{
|
||||
uint32 itemId = 23586; // Aerie Peak Pale Ale
|
||||
switch (urand(0, 5))
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
itemId = 23584;
|
||||
break; // Loch Modan Lager
|
||||
case 3:
|
||||
case 4:
|
||||
itemId = 23585;
|
||||
break; // Stouthammer Lite
|
||||
}
|
||||
DoCreateItem(effIndex, itemId);
|
||||
break;
|
||||
}
|
||||
case 20589: // Escape artist
|
||||
case 30918: // Improved Sprint
|
||||
{
|
||||
|
||||
@@ -831,6 +831,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
|
||||
SpellVisual = spellEntry->SpellVisual;
|
||||
SpellIconID = spellEntry->SpellIconID;
|
||||
ActiveIconID = spellEntry->ActiveIconID;
|
||||
SpellPriority = spellEntry->SpellPriority;
|
||||
SpellName = spellEntry->SpellName;
|
||||
Rank = spellEntry->Rank;
|
||||
MaxTargetLevel = spellEntry->MaxTargetLevel;
|
||||
|
||||
@@ -377,6 +377,7 @@ public:
|
||||
std::array<uint32, 2> SpellVisual;
|
||||
uint32 SpellIconID;
|
||||
uint32 ActiveIconID;
|
||||
uint32 SpellPriority;
|
||||
std::array<char const*, 16> SpellName;
|
||||
std::array<char const*, 16> Rank;
|
||||
uint32 MaxTargetLevel;
|
||||
|
||||
@@ -244,7 +244,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
48108, // Hot Streak
|
||||
51124, // Killing Machine
|
||||
54741, // Firestarter
|
||||
57761, // Fireball!
|
||||
64823, // Item - Druid T8 Balance 4P Bonus
|
||||
34477, // Misdirection
|
||||
44401, // Missile Barrage
|
||||
@@ -254,6 +253,13 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->ProcCharges = 1;
|
||||
});
|
||||
|
||||
// Fireball
|
||||
ApplySpellFix({ 57761 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->ProcCharges = 1;
|
||||
spellInfo->SpellPriority = 50;
|
||||
});
|
||||
|
||||
// Tidal Wave
|
||||
ApplySpellFix({ 53390 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Acore::Impl::EnumUtilsImpl
|
||||
|
||||
Reference in New Issue
Block a user