Merge branch 'Playerbot' of https://github.com/ZhengPeiRu21/azerothcore-wotlk into Playerbot
This commit is contained in:
@@ -134,14 +134,6 @@ void CreatureAI::DoZoneInCombat(Creature* creature /*= nullptr*/, float maxRange
|
||||
{
|
||||
creature->AddThreat(player, 0.0f);
|
||||
}
|
||||
|
||||
/* Causes certain things to never leave the threat list (Priest Lightwell, etc):
|
||||
for (Unit::ControlSet::const_iterator itr = player->m_Controlled.begin(); itr != player->m_Controlled.end(); ++itr)
|
||||
{
|
||||
creature->SetInCombatWith(*itr);
|
||||
(*itr)->SetInCombatWith(creature);
|
||||
creature->AddThreat(*itr, 0.0f);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,7 +153,7 @@ void CreatureAI::MoveInLineOfSight_Safe(Unit* who)
|
||||
|
||||
void CreatureAI::MoveInLineOfSight(Unit* who)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
if (me->IsEngaged())
|
||||
return;
|
||||
|
||||
// pussywizard: civilian, non-combat pet or any other NOT HOSTILE TO ANYONE (!)
|
||||
@@ -182,7 +174,7 @@ void CreatureAI::TriggerAlert(Unit const* who) const
|
||||
if (!who || who->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
// If this unit isn't an NPC, is already distracted, is in combat, is confused, stunned or fleeing, do nothing
|
||||
if (me->GetTypeId() != TYPEID_UNIT || me->IsInCombat() || me->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING | UNIT_STATE_DISTRACTED))
|
||||
if (me->GetTypeId() != TYPEID_UNIT || me->IsEngaged() || me->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING | UNIT_STATE_DISTRACTED))
|
||||
return;
|
||||
// Only alert for hostiles!
|
||||
if (me->IsCivilian() || me->HasReactState(REACT_PASSIVE) || !me->IsHostileTo(who) || !me->_IsTargetAcceptable(who))
|
||||
@@ -253,7 +245,7 @@ void CreatureAI::SetGazeOn(Unit* target)
|
||||
|
||||
bool CreatureAI::UpdateVictimWithGaze()
|
||||
{
|
||||
if (!me->IsInCombat())
|
||||
if (!me->IsEngaged())
|
||||
return false;
|
||||
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
@@ -271,7 +263,7 @@ bool CreatureAI::UpdateVictimWithGaze()
|
||||
|
||||
bool CreatureAI::UpdateVictim()
|
||||
{
|
||||
if (!me->IsInCombat())
|
||||
if (!me->IsEngaged())
|
||||
return false;
|
||||
|
||||
if (!me->HasReactState(REACT_PASSIVE))
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
|
||||
|
||||
// Called for reaction at enter to combat if not in combat yet (enemy can be nullptr)
|
||||
// Called for reaction when initially engaged
|
||||
virtual void EnterCombat(Unit* /*victim*/) {}
|
||||
|
||||
// Called when the creature is killed
|
||||
@@ -196,6 +196,7 @@ public:
|
||||
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
|
||||
|
||||
virtual bool CanBeSeen(Player const* /*seer*/) { return true; }
|
||||
virtual bool CanAlwaysBeDetectable(WorldObject const* /*seer*/) { return false; }
|
||||
|
||||
virtual void PetStopAttack() { }
|
||||
|
||||
|
||||
@@ -574,7 +574,7 @@ void BossAI::TeleportCheaters()
|
||||
void BossAI::JustSummoned(Creature* summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (me->IsInCombat())
|
||||
if (me->IsEngaged())
|
||||
DoZoneInCombat(summon);
|
||||
}
|
||||
|
||||
|
||||
@@ -4044,18 +4044,18 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
break;
|
||||
case SMART_EVENT_UPDATE_OOC:
|
||||
if (me && me->IsInCombat())
|
||||
if (me && me->IsEngaged())
|
||||
return;
|
||||
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
break;
|
||||
case SMART_EVENT_UPDATE_IC:
|
||||
if (!me || !me->IsInCombat())
|
||||
if (!me || !me->IsEngaged())
|
||||
return;
|
||||
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
break;
|
||||
case SMART_EVENT_HEALTH_PCT:
|
||||
{
|
||||
if (!me || !me->IsInCombat() || !me->GetMaxHealth())
|
||||
if (!me || !me->IsEngaged() || !me->GetMaxHealth())
|
||||
return;
|
||||
uint32 perc = (uint32)me->GetHealthPct();
|
||||
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
|
||||
@@ -4065,7 +4065,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_TARGET_HEALTH_PCT:
|
||||
{
|
||||
if (!me || !me->IsInCombat() || !me->GetVictim() || !me->GetVictim()->GetMaxHealth())
|
||||
if (!me || !me->IsEngaged() || !me->GetVictim() || !me->GetVictim()->GetMaxHealth())
|
||||
return;
|
||||
uint32 perc = (uint32)me->GetVictim()->GetHealthPct();
|
||||
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
|
||||
@@ -4075,7 +4075,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_MANA_PCT:
|
||||
{
|
||||
if (!me || !me->IsInCombat() || !me->GetMaxPower(POWER_MANA))
|
||||
if (!me || !me->IsEngaged() || !me->GetMaxPower(POWER_MANA))
|
||||
return;
|
||||
uint32 perc = uint32(me->GetPowerPct(POWER_MANA));
|
||||
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
|
||||
@@ -4085,7 +4085,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_TARGET_MANA_PCT:
|
||||
{
|
||||
if (!me || !me->IsInCombat() || !me->GetVictim() || !me->GetVictim()->GetMaxPower(POWER_MANA))
|
||||
if (!me || !me->IsEngaged() || !me->GetVictim() || !me->GetVictim()->GetMaxPower(POWER_MANA))
|
||||
return;
|
||||
uint32 perc = uint32(me->GetVictim()->GetPowerPct(POWER_MANA));
|
||||
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
|
||||
@@ -4095,7 +4095,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_RANGE:
|
||||
{
|
||||
if (!me || !me->IsInCombat() || !me->GetVictim())
|
||||
if (!me || !me->IsEngaged() || !me->GetVictim())
|
||||
return;
|
||||
|
||||
if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max))
|
||||
@@ -4106,7 +4106,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_VICTIM_CASTING:
|
||||
{
|
||||
if (!me || !me->IsInCombat())
|
||||
if (!me || !me->IsEngaged())
|
||||
return;
|
||||
|
||||
Unit* victim = me->GetVictim();
|
||||
@@ -4124,7 +4124,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_FRIENDLY_HEALTH:
|
||||
{
|
||||
if (!me || !me->IsInCombat())
|
||||
if (!me || !me->IsEngaged())
|
||||
return;
|
||||
|
||||
Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealth.radius, e.event.friendlyHealth.hpDeficit);
|
||||
@@ -4139,7 +4139,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_FRIENDLY_IS_CC:
|
||||
{
|
||||
if (!me || !me->IsInCombat())
|
||||
if (!me || !me->IsEngaged())
|
||||
return;
|
||||
|
||||
std::list<Creature*> pList;
|
||||
@@ -4285,7 +4285,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_OOC_LOS:
|
||||
{
|
||||
if (!me || me->IsInCombat())
|
||||
if (!me || me->IsEngaged())
|
||||
return;
|
||||
//can trigger if closer than fMaxAllowedRange
|
||||
float range = (float)e.event.los.maxDist;
|
||||
@@ -4309,7 +4309,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_IC_LOS:
|
||||
{
|
||||
if (!me || !me->IsInCombat())
|
||||
if (!me || !me->IsEngaged())
|
||||
return;
|
||||
//can trigger if closer than fMaxAllowedRange
|
||||
float range = (float)e.event.los.maxDist;
|
||||
@@ -4507,7 +4507,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_EVENT_FRIENDLY_HEALTH_PCT:
|
||||
{
|
||||
if (!me || !me->IsInCombat())
|
||||
if (!me || !me->IsEngaged())
|
||||
return;
|
||||
|
||||
Unit* target = nullptr;
|
||||
@@ -4701,10 +4701,10 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
|
||||
if (e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask))
|
||||
return;
|
||||
|
||||
if (e.GetEventType() == SMART_EVENT_UPDATE_IC && (!me || !me->IsInCombat()))
|
||||
if (e.GetEventType() == SMART_EVENT_UPDATE_IC && (!me || !me->IsEngaged()))
|
||||
return;
|
||||
|
||||
if (e.GetEventType() == SMART_EVENT_UPDATE_OOC && (me && me->IsInCombat()))//can be used with me=nullptr (go script)
|
||||
if (e.GetEventType() == SMART_EVENT_UPDATE_OOC && (me && me->IsEngaged()))//can be used with me=nullptr (go script)
|
||||
return;
|
||||
|
||||
if (e.timer < diff)
|
||||
@@ -4982,7 +4982,7 @@ void SmartScript::OnMoveInLineOfSight(Unit* who)
|
||||
if (!me)
|
||||
return;
|
||||
|
||||
ProcessEventsFor(me->IsInCombat() ? SMART_EVENT_IC_LOS : SMART_EVENT_OOC_LOS, who);
|
||||
ProcessEventsFor(me->IsEngaged() ? SMART_EVENT_IC_LOS : SMART_EVENT_OOC_LOS, who);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -86,6 +86,8 @@ static FactionTeamMap sFactionTeamMap;
|
||||
DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
|
||||
DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt);
|
||||
|
||||
DBCStorage <GameObjectArtKitEntry> sGameObjectArtKitStore(GameObjectArtKitfmt);
|
||||
|
||||
DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt);
|
||||
DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt);
|
||||
DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore(GlyphPropertiesfmt);
|
||||
@@ -306,6 +308,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LOAD_DBC(sEmotesTextSoundStore, "EmotesTextSound.dbc", "emotetextsound_dbc");
|
||||
LOAD_DBC(sFactionStore, "Faction.dbc", "faction_dbc");
|
||||
LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc", "factiontemplate_dbc");
|
||||
LOAD_DBC(sGameObjectArtKitStore, "GameObjectArtKit.dbc", "gameobjectartkit_dbc");
|
||||
LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc", "gameobjectdisplayinfo_dbc");
|
||||
LOAD_DBC(sGemPropertiesStore, "GemProperties.dbc", "gemproperties_dbc");
|
||||
LOAD_DBC(sGlyphPropertiesStore, "GlyphProperties.dbc", "glyphproperties_dbc");
|
||||
|
||||
@@ -110,6 +110,7 @@ extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
|
||||
extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore;
|
||||
extern DBCStorage <FactionEntry> sFactionStore;
|
||||
extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
|
||||
extern DBCStorage <GameObjectArtKitEntry> sGameObjectArtKitStore;
|
||||
extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore;
|
||||
extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore;
|
||||
extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore;
|
||||
|
||||
@@ -704,7 +704,7 @@ void Creature::Update(uint32 diff)
|
||||
}
|
||||
|
||||
// periodic check to see if the creature has passed an evade boundary
|
||||
if (IsAIEnabled && !IsInEvadeMode() && IsInCombat())
|
||||
if (IsAIEnabled && !IsInEvadeMode() && IsEngaged())
|
||||
{
|
||||
if (diff >= m_boundaryCheckTime)
|
||||
{
|
||||
@@ -1810,6 +1810,21 @@ bool Creature::CanAlwaysSee(WorldObject const* obj) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Creature::IsAlwaysDetectableFor(WorldObject const* seer) const
|
||||
{
|
||||
if (Unit::IsAlwaysDetectableFor(seer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAIEnabled && AI()->CanAlwaysBeDetectable(seer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Creature::CanStartAttack(Unit const* who) const
|
||||
{
|
||||
if (IsCivilian())
|
||||
@@ -1839,7 +1854,7 @@ bool Creature::CanStartAttack(Unit const* who) const
|
||||
// pussywizard: at this point we are either hostile to who or friendly to who->getAttackerForHelper()
|
||||
// pussywizard: if who is in combat and has an attacker, help him if the distance is right (help because who is hostile or help because attacker is friendly)
|
||||
bool assist = false;
|
||||
if (who->IsInCombat() && IsWithinDist(who, ATTACK_DISTANCE))
|
||||
if (who->IsEngaged() && IsWithinDist(who, ATTACK_DISTANCE))
|
||||
if (Unit* victim = who->getAttackerForHelper())
|
||||
if (IsWithinDistInMap(victim, sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS)))
|
||||
assist = true;
|
||||
@@ -2358,7 +2373,7 @@ bool Creature::CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction /
|
||||
return false;
|
||||
|
||||
// skip fighting creature
|
||||
if (IsInCombat())
|
||||
if (IsEngaged())
|
||||
return false;
|
||||
|
||||
// only free creature
|
||||
@@ -2409,11 +2424,10 @@ bool Creature::_IsTargetAcceptable(Unit const* target) const
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit const* myVictim = getAttackerForHelper();
|
||||
Unit const* targetVictim = target->getAttackerForHelper();
|
||||
|
||||
// if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
|
||||
if (myVictim == target || targetVictim == this || IsHostileTo(target))
|
||||
if (IsEngagedBy(target) || IsHostileTo(target))
|
||||
return true;
|
||||
|
||||
// if the target's victim is friendly, and the target is neutral, the target is acceptable
|
||||
|
||||
@@ -386,6 +386,8 @@ public:
|
||||
|
||||
void ModifyThreatPercentTemp(Unit* victim, int32 percent, Milliseconds duration);
|
||||
|
||||
void ResetFaction() { SetFaction(GetCreatureTemplate()->faction); }
|
||||
|
||||
protected:
|
||||
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
|
||||
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);
|
||||
@@ -441,6 +443,7 @@ protected:
|
||||
|
||||
[[nodiscard]] bool IsInvisibleDueToDespawn() const override;
|
||||
bool CanAlwaysSee(WorldObject const* obj) const override;
|
||||
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
|
||||
|
||||
private:
|
||||
void ForcedDespawn(uint32 timeMSToDespawn = 0, Seconds forcedRespawnTimer = 0s);
|
||||
|
||||
@@ -190,7 +190,7 @@ void CreatureGroup::RemoveMember(Creature* member)
|
||||
member->SetFormation(nullptr);
|
||||
}
|
||||
|
||||
void CreatureGroup::MemberAttackStart(Creature* member, Unit* target)
|
||||
void CreatureGroup::MemberEngagingTarget(Creature* member, Unit* target)
|
||||
{
|
||||
uint8 const groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()].groupAI;
|
||||
if (member == m_leader)
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
void FormationReset(bool dismiss, bool initMotionMaster);
|
||||
|
||||
void LeaderMoveTo(float x, float y, float z, bool run);
|
||||
void MemberAttackStart(Creature* member, Unit* target);
|
||||
void MemberEngagingTarget(Creature* member, Unit* target);
|
||||
void MemberEvaded(Creature* member);
|
||||
|
||||
private:
|
||||
|
||||
@@ -701,8 +701,8 @@ void GameObject::Update(uint32 diff)
|
||||
// search unfriendly creature
|
||||
if (owner && goInfo->trap.autoCloseTime != -1) // hunter trap
|
||||
{
|
||||
Acore::AnyUnfriendlyNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
|
||||
Acore::UnitSearcher<Acore::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> searcher(this, target, checker);
|
||||
Acore::NearestAttackableNoTotemUnitInObjectRangeCheck checker(this, owner, radius);
|
||||
Acore::UnitSearcher<Acore::NearestAttackableNoTotemUnitInObjectRangeCheck> searcher(this, target, checker);
|
||||
Cell::VisitAllObjects(this, searcher, radius);
|
||||
}
|
||||
else // environmental trap
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Object.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
#include <array>
|
||||
|
||||
class GameObjectAI;
|
||||
class Transport;
|
||||
@@ -676,6 +677,7 @@ struct GameObjectTemplateAddon
|
||||
uint32 flags;
|
||||
uint32 mingold;
|
||||
uint32 maxgold;
|
||||
std::array<uint32, 4> artKits = {};
|
||||
};
|
||||
|
||||
// Benchmarked: Faster than std::map (insert/find)
|
||||
@@ -736,6 +738,35 @@ enum GOState
|
||||
|
||||
#define MAX_GO_STATE 3
|
||||
|
||||
enum class GameObjectActions : uint32
|
||||
{
|
||||
// Name from client executable // Comments
|
||||
None, // -NONE-
|
||||
AnimateCustom0, // Animate Custom0
|
||||
AnimateCustom1, // Animate Custom1
|
||||
AnimateCustom2, // Animate Custom2
|
||||
AnimateCustom3, // Animate Custom3
|
||||
Disturb, // Disturb // Triggers trap
|
||||
Unlock, // Unlock // Resets GO_FLAG_LOCKED
|
||||
Lock, // Lock // Sets GO_FLAG_LOCKED
|
||||
Open, // Open // Sets GO_STATE_ACTIVE
|
||||
OpenAndUnlock, // Open + Unlock // Sets GO_STATE_ACTIVE and resets GO_FLAG_LOCKED
|
||||
Close, // Close // Sets GO_STATE_READY
|
||||
ToggleOpen, // Toggle Open
|
||||
Destroy, // Destroy // Sets GO_STATE_DESTROYED
|
||||
Rebuild, // Rebuild // Resets from GO_STATE_DESTROYED
|
||||
Creation, // Creation
|
||||
Despawn, // Despawn
|
||||
MakeInert, // Make Inert // Disables interactions
|
||||
MakeActive, // Make Active // Enables interactions
|
||||
CloseAndLock, // Close + Lock // Sets GO_STATE_READY and sets GO_FLAG_LOCKED
|
||||
UseArtKit0, // Use ArtKit0 // 46904: 121
|
||||
UseArtKit1, // Use ArtKit1 // 36639: 81, 46903: 122
|
||||
UseArtKit2, // Use ArtKit2
|
||||
UseArtKit3, // Use ArtKit3
|
||||
SetTapList, // Set Tap List
|
||||
};
|
||||
|
||||
// from `gameobject`
|
||||
struct GameObjectData
|
||||
{
|
||||
|
||||
@@ -1234,7 +1234,7 @@ Position WorldObject::GetHitSpherePointFor(Position const& dest) const
|
||||
{
|
||||
G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ() + GetCollisionHeight());
|
||||
G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
|
||||
G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), GetObjectSize());
|
||||
G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), GetCombatReach());
|
||||
|
||||
return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y));
|
||||
}
|
||||
|
||||
@@ -1620,7 +1620,11 @@ void Player::ProcessDelayedOperations()
|
||||
SaveToDB(false, false);
|
||||
|
||||
if (m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
|
||||
CastSpell(this, 26013, true); // Deserter
|
||||
{
|
||||
Aura* aura = GetAura(26013);
|
||||
if (!aura || aura->GetDuration() <= 900000)
|
||||
CastSpell(this, 26013, true);
|
||||
}
|
||||
|
||||
if (m_DelayedOperations & DELAYED_BG_MOUNT_RESTORE)
|
||||
{
|
||||
@@ -2139,10 +2143,8 @@ void Player::SetInWater(bool apply)
|
||||
getHostileRefMgr().updateThreatTables();
|
||||
}
|
||||
|
||||
bool Player::IsInAreaTriggerRadius(const AreaTrigger* trigger) const
|
||||
bool Player::IsInAreaTriggerRadius(AreaTrigger const* trigger, float delta) const
|
||||
{
|
||||
static const float delta = 5.0f;
|
||||
|
||||
if (!trigger || GetMapId() != trigger->map)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1095,7 +1095,7 @@ public:
|
||||
|
||||
[[nodiscard]] bool IsInWater() const override { return m_isInWater; }
|
||||
[[nodiscard]] bool IsFalling() const;
|
||||
bool IsInAreaTriggerRadius(const AreaTrigger* trigger) const;
|
||||
bool IsInAreaTriggerRadius(AreaTrigger const* trigger, float delta = 0.f) const;
|
||||
|
||||
void SendInitialPacketsBeforeAddToMap();
|
||||
void SendInitialPacketsAfterAddToMap();
|
||||
@@ -2949,7 +2949,15 @@ template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T& bas
|
||||
return;
|
||||
}
|
||||
|
||||
totalflat += mod->value;
|
||||
int32 flatValue = mod->value;
|
||||
|
||||
// SPELL_MOD_THREAT - divide by 100 (in packets we send threat * 100)
|
||||
if (mod->op == SPELLMOD_THREAT)
|
||||
{
|
||||
flatValue /= 100;
|
||||
}
|
||||
|
||||
totalflat += flatValue;
|
||||
}
|
||||
else if (mod->type == SPELLMOD_PCT)
|
||||
{
|
||||
|
||||
@@ -277,10 +277,11 @@ void Player::Update(uint32 p_time)
|
||||
// supposed to be in one
|
||||
if (HasRestFlag(REST_FLAG_IN_TAVERN))
|
||||
{
|
||||
AreaTrigger const* atEntry =
|
||||
sObjectMgr->GetAreaTrigger(GetInnTriggerId());
|
||||
if (!atEntry || !IsInAreaTriggerRadius(atEntry))
|
||||
AreaTrigger const* atEntry = sObjectMgr->GetAreaTrigger(GetInnTriggerId());
|
||||
if (!atEntry || !IsInAreaTriggerRadius(atEntry, 5.f))
|
||||
{
|
||||
RemoveRestFlag(REST_FLAG_IN_TAVERN);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 newzone, newarea;
|
||||
|
||||
@@ -85,6 +85,8 @@ void Totem::InitStats(uint32 duration)
|
||||
|
||||
void Totem::InitSummon()
|
||||
{
|
||||
Minion::InitSummon();
|
||||
|
||||
if (m_type == TOTEM_PASSIVE && GetSpell())
|
||||
CastSpell(this, GetSpell(), true);
|
||||
|
||||
|
||||
@@ -316,6 +316,8 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
|
||||
|
||||
_oldFactionId = 0;
|
||||
|
||||
_isWalkingBeforeCharm = false;
|
||||
|
||||
_lastExtraAttackSpell = 0;
|
||||
}
|
||||
|
||||
@@ -10482,8 +10484,12 @@ void Unit::SetCharm(Unit* charm, bool apply)
|
||||
if (!charm->AddGuidValue(UNIT_FIELD_CHARMEDBY, GetGUID()))
|
||||
LOG_FATAL("entities.unit", "Unit {} is being charmed, but it already has a charmer {}", charm->GetEntry(), charm->GetCharmerGUID().ToString());
|
||||
|
||||
if (charm->HasUnitMovementFlag(MOVEMENTFLAG_WALKING))
|
||||
_isWalkingBeforeCharm = charm->IsWalking();
|
||||
if (_isWalkingBeforeCharm)
|
||||
{
|
||||
charm->SetWalk(false);
|
||||
charm->SendMovementFlagUpdate();
|
||||
}
|
||||
|
||||
m_Controlled.insert(charm);
|
||||
}
|
||||
@@ -10521,6 +10527,12 @@ void Unit::SetCharm(Unit* charm, bool apply)
|
||||
charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, 0);
|
||||
}
|
||||
|
||||
if (charm->IsWalking() != _isWalkingBeforeCharm)
|
||||
{
|
||||
charm->SetWalk(_isWalkingBeforeCharm);
|
||||
charm->SendMovementFlagUpdate(true); // send packet to self, to update movement state on player.
|
||||
}
|
||||
|
||||
m_Controlled.erase(charm);
|
||||
}
|
||||
}
|
||||
@@ -12422,7 +12434,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo)
|
||||
{
|
||||
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId);
|
||||
if (((itr->type & spellInfo->GetSchoolMask()) == spellInfo->GetSchoolMask())
|
||||
&& !(immuneSpellInfo && immuneSpellInfo->IsPositive()) && !spellInfo->IsPositive()
|
||||
&& (!immuneSpellInfo || immuneSpellInfo->IsPositive()) && !spellInfo->IsPositive()
|
||||
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
|
||||
return true;
|
||||
}
|
||||
@@ -13168,7 +13180,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy, uint32 duration)
|
||||
creature->AI()->EnterCombat(enemy);
|
||||
|
||||
if (creature->GetFormation())
|
||||
creature->GetFormation()->MemberAttackStart(creature, enemy);
|
||||
creature->GetFormation()->MemberEngagingTarget(creature, enemy);
|
||||
}
|
||||
|
||||
creature->RefreshSwimmingFlag();
|
||||
|
||||
@@ -1326,6 +1326,7 @@ public:
|
||||
bool IsWithinCombatRange(Unit const* obj, float dist2compare) const;
|
||||
bool IsWithinMeleeRange(Unit const* obj, float dist = 0.f) const;
|
||||
float GetMeleeRange(Unit const* target) const;
|
||||
[[nodiscard]] virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
|
||||
bool GetRandomContactPoint(Unit const* target, float& x, float& y, float& z, bool force = false) const;
|
||||
uint32 m_extraAttacks;
|
||||
bool m_canDualWield;
|
||||
@@ -1343,6 +1344,9 @@ public:
|
||||
if (GetVictim() != nullptr)
|
||||
return GetVictim();
|
||||
|
||||
if (!IsEngaged())
|
||||
return nullptr;
|
||||
|
||||
if (!m_attackers.empty())
|
||||
return *(m_attackers.begin());
|
||||
|
||||
@@ -1644,6 +1648,9 @@ public:
|
||||
|
||||
[[nodiscard]] bool IsInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); }
|
||||
|
||||
bool IsEngaged() const { return IsInCombat(); }
|
||||
bool IsEngagedBy(Unit const* who) const { return IsInCombatWith(who); }
|
||||
|
||||
[[nodiscard]] bool IsInCombat() const { return HasUnitFlag(UNIT_FLAG_IN_COMBAT); }
|
||||
bool IsInCombatWith(Unit const* who) const;
|
||||
|
||||
@@ -2105,6 +2112,7 @@ public:
|
||||
void TauntApply(Unit* victim);
|
||||
void TauntFadeOut(Unit* taunter);
|
||||
ThreatMgr& GetThreatMgr() { return m_ThreatMgr; }
|
||||
ThreatMgr const& GetThreatMgr() const { return m_ThreatMgr; }
|
||||
void addHatedBy(HostileReference* pHostileReference) { m_HostileRefMgr.insertFirst(pHostileReference); };
|
||||
void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ }
|
||||
HostileRefMgr& getHostileRefMgr() { return m_HostileRefMgr; }
|
||||
@@ -2478,8 +2486,6 @@ protected:
|
||||
CharmInfo* m_charmInfo;
|
||||
SharedVisionList m_sharedVision;
|
||||
|
||||
[[nodiscard]] virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
|
||||
|
||||
MotionMaster* i_motionMaster;
|
||||
|
||||
uint32 m_reactiveTimer[MAX_REACTIVE];
|
||||
@@ -2549,6 +2555,7 @@ private:
|
||||
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
|
||||
|
||||
uint32 _oldFactionId; ///< faction before charm
|
||||
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
|
||||
|
||||
[[nodiscard]] float processDummyAuras(float TakenTotalMod) const;
|
||||
|
||||
|
||||
@@ -7183,8 +7183,8 @@ void ObjectMgr::LoadGameObjectTemplateAddons()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2 3 4
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold FROM gameobject_template_addon");
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold, artkit0, artkit1, artkit2, artkit3 FROM gameobject_template_addon");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -7215,6 +7215,21 @@ void ObjectMgr::LoadGameObjectTemplateAddons()
|
||||
gameObjectAddon.mingold = fields[3].Get<uint32>();
|
||||
gameObjectAddon.maxgold = fields[4].Get<uint32>();
|
||||
|
||||
for (uint32 i = 0; i < gameObjectAddon.artKits.size(); i++)
|
||||
{
|
||||
uint32 artKitID = fields[5 + i].Get<uint32>();
|
||||
if (!artKitID)
|
||||
continue;
|
||||
|
||||
if (!sGameObjectArtKitStore.LookupEntry(artKitID))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "GameObject (Entry: {}) has invalid `artkit{}` {} defined, set to zero instead.", entry, i, artKitID);
|
||||
continue;
|
||||
}
|
||||
|
||||
gameObjectAddon.artKits[i] = artKitID;
|
||||
}
|
||||
|
||||
// checks
|
||||
if (gameObjectAddon.faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.faction))
|
||||
LOG_ERROR("sql.sql",
|
||||
|
||||
@@ -898,6 +898,47 @@ namespace Acore
|
||||
float i_range;
|
||||
};
|
||||
|
||||
class NearestAttackableNoTotemUnitInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
NearestAttackableNoTotemUnitInObjectRangeCheck(WorldObject const* obj, Unit const* owner, float range) : i_obj(obj), i_owner(owner), i_range(range) {}
|
||||
|
||||
bool operator()(Unit* u)
|
||||
{
|
||||
if (!u->IsAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (u->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (u->GetTypeId() == TYPEID_UNIT && u->ToCreature()->IsTotem())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!u->isTargetableForAttack(false, i_owner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!i_obj->IsWithinDistInMap(u, i_range) || !i_owner->IsValidAttackTarget(u) || !i_obj->IsWithinLOSInMap(u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
WorldObject const* i_obj;
|
||||
Unit const* i_owner;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
class AnyUnfriendlyAttackableVisibleUnitInObjectRangeCheck
|
||||
{
|
||||
public:
|
||||
@@ -1037,8 +1078,19 @@ namespace Acore
|
||||
bool operator()(Unit* u)
|
||||
{
|
||||
// Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems
|
||||
if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem())
|
||||
return false;
|
||||
if (Creature* creature = u->ToCreature())
|
||||
{
|
||||
if (creature->IsTotem())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (creature->IsAvoidingAOE())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range))
|
||||
return true;
|
||||
|
||||
@@ -731,7 +731,8 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->IsInAreaTriggerRadius(atEntry))
|
||||
bool isTavernAreatrigger = sObjectMgr->IsTavernAreaTrigger(triggerId);
|
||||
if (!player->IsInAreaTriggerRadius(atEntry, isTavernAreatrigger ? 5.f : 0.f))
|
||||
{
|
||||
LOG_DEBUG("network", "HandleAreaTriggerOpcode: Player {} ({}) too far (trigger map: {} player map: {}), ignore Area Trigger ID: {}",
|
||||
player->GetName(), player->GetGUID().ToString(), atEntry->map, player->GetMapId(), triggerId);
|
||||
@@ -749,7 +750,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||
if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
|
||||
player->AreaExploredOrEventHappens(questId);
|
||||
|
||||
if (sObjectMgr->IsTavernAreaTrigger(triggerId))
|
||||
if (isTavernAreatrigger)
|
||||
{
|
||||
// set resting flag we are in the inn
|
||||
player->SetRestFlag(REST_FLAG_IN_TAVERN, atEntry->entry);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#define MIN_QUIET_DISTANCE 28.0f
|
||||
#define MAX_QUIET_DISTANCE 43.0f
|
||||
#define MIN_PATH_LENGTH 2.0f
|
||||
|
||||
template<class T>
|
||||
void FleeingMovementGenerator<T>::DoInitialize(T* owner)
|
||||
@@ -144,6 +145,20 @@ void FleeingMovementGenerator<T>::SetTargetLocation(T* owner)
|
||||
return;
|
||||
}
|
||||
|
||||
// Same position - recheck
|
||||
if (_path->getPathLength() < MIN_PATH_LENGTH)
|
||||
{
|
||||
if (_fleeTargetGUID)
|
||||
{
|
||||
++_shortPathsCount;
|
||||
}
|
||||
|
||||
_timer.Reset(100);
|
||||
return;
|
||||
}
|
||||
|
||||
_shortPathsCount = 0;
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
init.MovebyPath(_path->GetPath());
|
||||
init.SetWalk(false);
|
||||
@@ -154,8 +169,13 @@ void FleeingMovementGenerator<T>::SetTargetLocation(T* owner)
|
||||
template<class T>
|
||||
void FleeingMovementGenerator<T>::GetPoint(T* owner, Position& position)
|
||||
{
|
||||
float casterDistance, casterAngle;
|
||||
if (Unit* fleeTarget = ObjectAccessor::GetUnit(*owner, _fleeTargetGUID))
|
||||
float casterDistance = 0.f;
|
||||
float casterAngle = 0.f;
|
||||
Unit* fleeTarget = nullptr;
|
||||
if (_shortPathsCount < 5)
|
||||
fleeTarget = ObjectAccessor::GetUnit(*owner, _fleeTargetGUID);
|
||||
|
||||
if (fleeTarget)
|
||||
{
|
||||
casterDistance = fleeTarget->GetDistance(owner);
|
||||
if (casterDistance > 0.2f)
|
||||
@@ -173,7 +193,8 @@ void FleeingMovementGenerator<T>::GetPoint(T* owner, Position& position)
|
||||
casterAngle = frand(0.0f, 2.0f * float(M_PI));
|
||||
}
|
||||
|
||||
float distance, angle;
|
||||
float distance = 0.f;
|
||||
float angle = 0.f;
|
||||
if (casterDistance < MIN_QUIET_DISTANCE)
|
||||
{
|
||||
distance = frand(0.4f, 1.3f) * (MIN_QUIET_DISTANCE - casterDistance);
|
||||
|
||||
@@ -24,7 +24,7 @@ template<class T>
|
||||
class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator<T> >
|
||||
{
|
||||
public:
|
||||
explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _path(nullptr), _fleeTargetGUID(fleeTargetGUID), _timer(0), _interrupt(false) {}
|
||||
explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _path(nullptr), _fleeTargetGUID(fleeTargetGUID), _timer(0), _interrupt(false), _shortPathsCount(0) { }
|
||||
|
||||
MovementGeneratorType GetMovementGeneratorType() override { return FLEEING_MOTION_TYPE; }
|
||||
|
||||
@@ -41,6 +41,7 @@ class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovem
|
||||
ObjectGuid _fleeTargetGUID;
|
||||
TimeTracker _timer;
|
||||
bool _interrupt;
|
||||
uint8 _shortPathsCount;
|
||||
};
|
||||
|
||||
class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature>
|
||||
|
||||
@@ -2842,9 +2842,10 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
||||
{
|
||||
if (!HasEffect(effIndex))
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = GetSpellInfo();
|
||||
UnitList targetList;
|
||||
if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY
|
||||
|| GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
|
||||
if (spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY || spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
|
||||
{
|
||||
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
|
||||
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
|
||||
@@ -2852,7 +2853,7 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
||||
}
|
||||
// pussywizard: TARGET_DEST_DYNOBJ_NONE is supposed to search for both friendly and unfriendly targets, so for any unit
|
||||
// what about EffectImplicitTargetA?
|
||||
else if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_NONE)
|
||||
else if (spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_NONE)
|
||||
{
|
||||
Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
|
||||
Acore::UnitListSearcher<Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
|
||||
@@ -2867,12 +2868,11 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
||||
|
||||
for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
|
||||
{
|
||||
// xinef: check z level and los dependence
|
||||
Unit* target = *itr;
|
||||
float zLevel = GetDynobjOwner()->GetPositionZ();
|
||||
if (target->GetPositionZ() + 3.0f < zLevel || target->GetPositionZ() - 5.0f > zLevel)
|
||||
if (!target->IsWithinLOSInMap(GetDynobjOwner()))
|
||||
continue;
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !target->IsWithinLOSInMap(GetDynobjOwner()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
|
||||
if (existing != targets.end())
|
||||
|
||||
@@ -5892,31 +5892,27 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
if ((!m_caster->IsTotem() || !m_spellInfo->IsPositive()) && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) &&
|
||||
!m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT))
|
||||
{
|
||||
WorldObject* losCenter = nullptr;
|
||||
bool castedByGameobject = false;
|
||||
uint32 losChecks = LINEOFSIGHT_ALL_CHECKS;
|
||||
if (m_originalCasterGUID.IsGameObject())
|
||||
{
|
||||
losCenter = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
|
||||
castedByGameobject = m_caster->GetMap()->GetGameObject(m_originalCasterGUID) != nullptr;
|
||||
}
|
||||
else if (m_caster->GetEntry() == WORLD_TRIGGER)
|
||||
{
|
||||
if (TempSummon* tempSummon = m_caster->ToTempSummon())
|
||||
{
|
||||
losCenter = tempSummon->GetSummonerGameObject();
|
||||
castedByGameobject = tempSummon->GetSummonerGameObject() != nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (losCenter)
|
||||
if (castedByGameobject)
|
||||
{
|
||||
// If spell casted by gameobject then ignore M2 models
|
||||
losChecks &= ~LINEOFSIGHT_CHECK_GOBJECT_M2;
|
||||
}
|
||||
else
|
||||
{
|
||||
losCenter = m_caster;
|
||||
}
|
||||
|
||||
if (!losCenter->IsWithinLOS(x, y, z, VMAP::ModelIgnoreFlags::M2, LineOfSightChecks((losChecks))))
|
||||
if (!m_caster->IsWithinLOS(x, y, z, VMAP::ModelIgnoreFlags::M2, LineOfSightChecks((losChecks))))
|
||||
{
|
||||
return SPELL_FAILED_LINE_OF_SIGHT;
|
||||
}
|
||||
|
||||
@@ -2677,7 +2677,7 @@ void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
|
||||
return;
|
||||
|
||||
// Check for possible target
|
||||
if (!unitTarget || unitTarget->IsInCombat())
|
||||
if (!unitTarget || unitTarget->IsEngaged())
|
||||
return;
|
||||
|
||||
// target must be OK to do this
|
||||
@@ -4263,7 +4263,7 @@ void Spell::EffectSummonPlayer(SpellEffIndex /*effIndex*/)
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/)
|
||||
void Spell::EffectActivateObject(SpellEffIndex effIndex)
|
||||
{
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
|
||||
return;
|
||||
@@ -4271,17 +4271,74 @@ void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/)
|
||||
if (!gameObjTarget)
|
||||
return;
|
||||
|
||||
Player* player = m_caster->GetTypeId() == TYPEID_PLAYER ? m_caster->ToPlayer() : m_caster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
gameObjTarget->Use(player ? player : m_caster);
|
||||
GameObjectActions action = GameObjectActions(m_spellInfo->Effects[effIndex].MiscValue);
|
||||
switch (action)
|
||||
{
|
||||
case GameObjectActions::AnimateCustom0:
|
||||
case GameObjectActions::AnimateCustom1:
|
||||
case GameObjectActions::AnimateCustom2:
|
||||
case GameObjectActions::AnimateCustom3:
|
||||
gameObjTarget->SendCustomAnim(uint32(action) - uint32(GameObjectActions::AnimateCustom0));
|
||||
break;
|
||||
case GameObjectActions::Disturb: // What's the difference with Open?
|
||||
case GameObjectActions::Open:
|
||||
if (Unit* unitCaster = m_caster->ToUnit())
|
||||
gameObjTarget->Use(unitCaster);
|
||||
break;
|
||||
case GameObjectActions::OpenAndUnlock:
|
||||
if (Unit* unitCaster = m_caster->ToUnit())
|
||||
gameObjTarget->UseDoorOrButton(0, false, unitCaster);
|
||||
[[fallthrough]];
|
||||
case GameObjectActions::Unlock:
|
||||
case GameObjectActions::Lock:
|
||||
gameObjTarget->ApplyModFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED, action == GameObjectActions::Lock);
|
||||
break;
|
||||
case GameObjectActions::Close:
|
||||
case GameObjectActions::Rebuild:
|
||||
gameObjTarget->ResetDoorOrButton();
|
||||
break;
|
||||
case GameObjectActions::Despawn:
|
||||
gameObjTarget->DespawnOrUnsummon();
|
||||
break;
|
||||
case GameObjectActions::MakeInert:
|
||||
case GameObjectActions::MakeActive:
|
||||
gameObjTarget->ApplyModFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE, action == GameObjectActions::MakeInert);
|
||||
break;
|
||||
case GameObjectActions::CloseAndLock:
|
||||
gameObjTarget->ResetDoorOrButton();
|
||||
gameObjTarget->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED);
|
||||
break;
|
||||
case GameObjectActions::Destroy:
|
||||
if (Unit* unitCaster = m_caster->ToUnit())
|
||||
gameObjTarget->UseDoorOrButton(0, true, unitCaster);
|
||||
break;
|
||||
case GameObjectActions::UseArtKit0:
|
||||
case GameObjectActions::UseArtKit1:
|
||||
case GameObjectActions::UseArtKit2:
|
||||
case GameObjectActions::UseArtKit3:
|
||||
{
|
||||
GameObjectTemplateAddon const* templateAddon = gameObjTarget->GetTemplateAddon();
|
||||
|
||||
//ScriptInfo activateCommand;
|
||||
//activateCommand.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
|
||||
uint32 artKitIndex = uint32(action) - uint32(GameObjectActions::UseArtKit0);
|
||||
|
||||
// int32 unk = m_spellInfo->Effects[effIndex].MiscValue; // This is set for EffectActivateObject spells; needs research
|
||||
uint32 artKitValue = 0;
|
||||
if (templateAddon)
|
||||
artKitValue = templateAddon->artKits[artKitIndex];
|
||||
|
||||
// xinef: pass player to allow gossip scripts to work
|
||||
//
|
||||
//gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, 0, player ? player : m_caster, gameObjTarget);
|
||||
if (artKitValue == 0)
|
||||
LOG_ERROR("sql.sql", "GameObject {} hit by spell {} needs `artkit{}` in `gameobject_template_addon`", gameObjTarget->GetEntry(), m_spellInfo->Id, artKitIndex);
|
||||
else
|
||||
gameObjTarget->SetGoArtKit(artKitValue);
|
||||
|
||||
break;
|
||||
}
|
||||
case GameObjectActions::None:
|
||||
LOG_FATAL("spell", "Spell {} has action type NONE in effect {}", m_spellInfo->Id, int32(effIndex));
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("spell", "Spell {} has unhandled action {} in effect {}", m_spellInfo->Id, int32(action), int32(effIndex));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectApplyGlyph(SpellEffIndex effIndex)
|
||||
|
||||
@@ -1363,6 +1363,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].Amplitude = 15000;
|
||||
});
|
||||
|
||||
// Threatening Gaze
|
||||
ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST;
|
||||
});
|
||||
|
||||
// Isle of Conquest
|
||||
ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user