mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Merge branch '3.3.5-goshdangitsmartai' into 3.3.5 (PR #17738)
This commit is contained in:
27
sql/updates/world/3.3.5/2016_09_02_03_world.sql
Normal file
27
sql/updates/world/3.3.5/2016_09_02_03_world.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
-- set "execute event while charmed" flag on all events except:
|
||||
-- -) movement actions
|
||||
-- -) nontriggered cast actions
|
||||
-- -) talk/emote/sound actions
|
||||
-- -) ally summon actions
|
||||
ALTER TABLE `smart_scripts` MODIFY COLUMN `event_flags` SMALLINT(3) UNSIGNED NOT NULL DEFAULT '0';
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND
|
||||
(`action_type` not in (1,4,5,10,11,12,17,25,27,38,39,40,49,62,69,84,85,86,89,92,97,103,107,114) OR
|
||||
(`action_type` in (11,86) AND (`action_param2`&2)=2));
|
||||
|
||||
|
||||
-- assorted quest fixes (no claim to completeness)
|
||||
-- Seeds of Chaos (13172)
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=31157;
|
||||
UPDATE `smart_scripts` SET `event_type`=29, `comment`="Skeletal Assault Gryphon - On Charmed - Start Waypoint" WHERE `source_type`=0 AND `entryorguid`=31157 AND `id`=0;
|
||||
-- Generosity Abounds (13146)
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30894;
|
||||
-- Battling the Elements (12967)
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30124;
|
||||
-- Krolmir, Hammer of Storms (13010)
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30331;
|
||||
UPDATE `smart_scripts` SET `event_type`=29 WHERE `source_type`=0 AND `entryorguid`=30331 AND `id`=0;
|
||||
UPDATE `smart_scripts` SET `target_type`=23 WHERE `source_type`=0 AND `entryorguid`=30331 AND `id`=1;
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=9 AND `entryorguid`=3033100;
|
||||
-- Spy Hunter (12994)
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=0 AND `entryorguid`=30219;
|
||||
UPDATE `smart_scripts` SET `event_flags`=(`event_flags`|0x200) WHERE `source_type`=9 AND `entryorguid` IN (3021900,3021901,3021902);
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
SmartAI::SmartAI(Creature* c) : CreatureAI(c)
|
||||
{
|
||||
mIsCharmed = false;
|
||||
// copy script to local (protection for table reload)
|
||||
|
||||
mWayPoints = nullptr;
|
||||
@@ -70,6 +71,15 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
|
||||
mJustReset = false;
|
||||
}
|
||||
|
||||
bool SmartAI::IsAIControlled() const
|
||||
{
|
||||
if (me->IsControlledByPlayer())
|
||||
return false;
|
||||
if (mIsCharmed)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmartAI::UpdateDespawn(const uint32 diff)
|
||||
{
|
||||
if (mDespawnState <= 1 || mDespawnState > 3)
|
||||
@@ -155,7 +165,7 @@ void SmartAI::PausePath(uint32 delay, bool forced)
|
||||
return;
|
||||
if (HasEscortState(SMART_ESCORT_PAUSED))
|
||||
{
|
||||
TC_LOG_ERROR("misc", "SmartAI::StartPath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry());
|
||||
TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry());
|
||||
return;
|
||||
}
|
||||
mForcedPaused = forced;
|
||||
@@ -199,7 +209,10 @@ void SmartAI::EndPath(bool fail)
|
||||
mLastWP = nullptr;
|
||||
|
||||
if (mCanRepeatPath)
|
||||
StartPath(mRun, GetScript()->GetPathId(), true);
|
||||
{
|
||||
if (IsAIControlled())
|
||||
StartPath(mRun, GetScript()->GetPathId(), true);
|
||||
}
|
||||
else
|
||||
GetScript()->SetPathId(0);
|
||||
|
||||
@@ -249,7 +262,6 @@ void SmartAI::EndPath(bool fail)
|
||||
|
||||
void SmartAI::ResumePath()
|
||||
{
|
||||
//mWPReached = false;
|
||||
SetRun(mRun);
|
||||
if (mLastWP)
|
||||
me->GetMotionMaster()->MovePoint(mLastWP->id, mLastWP->x, mLastWP->y, mLastWP->z);
|
||||
@@ -257,6 +269,9 @@ void SmartAI::ResumePath()
|
||||
|
||||
void SmartAI::ReturnToLastOOCPos()
|
||||
{
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
|
||||
SetRun(mRun);
|
||||
me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos);
|
||||
}
|
||||
@@ -347,6 +362,9 @@ void SmartAI::UpdateAI(uint32 diff)
|
||||
mFollowArrivedTimer -= diff;
|
||||
}
|
||||
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
@@ -413,19 +431,15 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
|
||||
|
||||
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
if (!me->IsAlive() || me->IsInEvadeMode())
|
||||
return;
|
||||
|
||||
if (mEvadeDisabled)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_EVADE);
|
||||
return;
|
||||
}
|
||||
|
||||
me->RemoveAurasOnEvade();
|
||||
|
||||
if (!_EnterEvadeMode())
|
||||
return;
|
||||
me->AddUnitState(UNIT_STATE_EVADE);
|
||||
_EnterEvadeMode();
|
||||
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_EVADE);//must be after aura clear so we can cast spells from db
|
||||
|
||||
@@ -446,7 +460,7 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
else
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))//dont mess up escort movement after combat
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING)) //dont mess up escort movement after combat
|
||||
SetRun(mRun);
|
||||
}
|
||||
|
||||
@@ -457,6 +471,9 @@ void SmartAI::MoveInLineOfSight(Unit* who)
|
||||
|
||||
GetScript()->OnMoveInLineOfSight(who);
|
||||
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
|
||||
if (AssistPlayerInCombatAgainst(who))
|
||||
return;
|
||||
|
||||
@@ -470,7 +487,7 @@ bool SmartAI::CanAIAttack(const Unit* /*who*/) const
|
||||
|
||||
bool SmartAI::AssistPlayerInCombatAgainst(Unit* who)
|
||||
{
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
if (me->HasReactState(REACT_PASSIVE) || !IsAIControlled())
|
||||
return false;
|
||||
|
||||
if (!who || !who->GetVictim())
|
||||
@@ -552,8 +569,13 @@ void SmartAI::JustReachedHome()
|
||||
|
||||
void SmartAI::EnterCombat(Unit* enemy)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false); // must be before ProcessEvents
|
||||
if (IsAIControlled())
|
||||
me->InterruptNonMeleeSpells(false); // must be before ProcessEvents
|
||||
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy);
|
||||
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
mLastOOCPos = me->GetPosition();
|
||||
SetRun(mRun);
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == POINT_MOTION_TYPE)
|
||||
@@ -603,6 +625,10 @@ void SmartAI::SpellHitTarget(Unit* target, const SpellInfo* spellInfo)
|
||||
void SmartAI::DamageTaken(Unit* doneBy, uint32& damage)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage);
|
||||
|
||||
if (!IsAIControlled()) // don't allow players to use unkillable units
|
||||
return;
|
||||
|
||||
if (mInvincibilityHpLevel && (damage >= me->GetHealth() - mInvincibilityHpLevel))
|
||||
damage = me->GetHealth() - mInvincibilityHpLevel; // damage should not be nullified, because of player damage req.
|
||||
}
|
||||
@@ -632,8 +658,6 @@ void SmartAI::SummonedCreatureDespawn(Creature* unit)
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_SUMMON_DESPAWNED, unit);
|
||||
}
|
||||
|
||||
void SmartAI::UpdateAIWhileCharmed(const uint32 /*diff*/) { }
|
||||
|
||||
void SmartAI::CorpseRemoved(uint32& respawnDelay)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_CORPSE_REMOVED, nullptr, respawnDelay);
|
||||
@@ -655,11 +679,26 @@ void SmartAI::InitializeAI()
|
||||
|
||||
void SmartAI::OnCharmed(bool apply)
|
||||
{
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, apply);
|
||||
if (apply) // do this before we change charmed state, as charmed state might prevent these things from processing
|
||||
{
|
||||
if (HasEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING))
|
||||
EndPath(true);
|
||||
me->StopMoving();
|
||||
}
|
||||
mIsCharmed = apply;
|
||||
|
||||
if (!apply && !me->IsInEvadeMode())
|
||||
{
|
||||
if (mCanRepeatPath)
|
||||
StartPath(mRun, GetScript()->GetPathId(), true);
|
||||
else
|
||||
me->SetWalk(!mRun);
|
||||
|
||||
if (Unit* charmer = me->GetCharmer())
|
||||
AttackStart(charmer);
|
||||
}
|
||||
|
||||
GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, apply);
|
||||
}
|
||||
|
||||
void SmartAI::DoAction(int32 param)
|
||||
@@ -738,6 +777,8 @@ void SmartAI::SetCombatMove(bool on)
|
||||
if (mCanCombatMove == on)
|
||||
return;
|
||||
mCanCombatMove = on;
|
||||
if (!IsAIControlled())
|
||||
return;
|
||||
if (!HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
{
|
||||
if (on && me->GetVictim())
|
||||
@@ -770,15 +811,15 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui
|
||||
return;
|
||||
}
|
||||
|
||||
SetRun(mRun);
|
||||
mFollowGuid = target->GetGUID();
|
||||
mFollowDist = dist >= 0.0f ? dist : PET_FOLLOW_DIST;
|
||||
mFollowAngle = angle >= 0.0f ? angle : me->GetFollowAngle();
|
||||
mFollowArrivedTimer = 1000;
|
||||
mFollowCredit = credit;
|
||||
mFollowArrivedEntry = end;
|
||||
me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle);
|
||||
mFollowCreditType = creditType;
|
||||
SetRun(mRun);
|
||||
me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle);
|
||||
}
|
||||
|
||||
void SmartAI::StopFollow()
|
||||
|
||||
@@ -48,6 +48,9 @@ class TC_GAME_API SmartAI : public CreatureAI
|
||||
~SmartAI(){ }
|
||||
explicit SmartAI(Creature* c);
|
||||
|
||||
// Check whether we are currently permitted to make the creature take action
|
||||
bool IsAIControlled() const;
|
||||
|
||||
// Start moving to the desired MovePoint
|
||||
void StartPath(bool run = false, uint32 path = 0, bool repeat = false, Unit* invoker = nullptr);
|
||||
bool LoadPath(uint32 entry);
|
||||
@@ -129,9 +132,6 @@ class TC_GAME_API SmartAI : public CreatureAI
|
||||
// called when the corpse of this creature gets removed
|
||||
void CorpseRemoved(uint32& respawnDelay) override;
|
||||
|
||||
// Called at World update tick if creature is charmed
|
||||
void UpdateAIWhileCharmed(const uint32 diff);
|
||||
|
||||
// Called when a Player/Creature enters the creature (vehicle)
|
||||
void PassengerBoarded(Unit* who, int8 seatId, bool apply) override;
|
||||
|
||||
@@ -197,6 +197,7 @@ class TC_GAME_API SmartAI : public CreatureAI
|
||||
void OnSpellClick(Unit* clicker, bool& result) override;
|
||||
|
||||
private:
|
||||
bool mIsCharmed;
|
||||
uint32 mFollowCreditType;
|
||||
uint32 mFollowArrivedTimer;
|
||||
uint32 mFollowCredit;
|
||||
|
||||
@@ -99,7 +99,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
//calc random
|
||||
if (e.GetEventType() != SMART_EVENT_LINK && e.event.event_chance < 100 && e.event.event_chance)
|
||||
{
|
||||
uint32 rnd = urand(0, 100);
|
||||
uint32 rnd = urand(1, 100);
|
||||
if (e.event.event_chance <= rnd)
|
||||
return;
|
||||
}
|
||||
@@ -769,6 +769,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
break;
|
||||
|
||||
me->DoFleeToGetAssistance();
|
||||
|
||||
if (e.action.flee.withEmote)
|
||||
{
|
||||
Trinity::BroadcastTextBuilder builder(me, CHAT_MSG_MONSTER_EMOTE, BROADCAST_TEXT_FLEE_FOR_ASSIST);
|
||||
@@ -1175,6 +1176,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (!IsCreature(*itr))
|
||||
continue;
|
||||
|
||||
if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && !IsCreatureInControlOfSelf(*itr))
|
||||
continue;
|
||||
|
||||
Position pos = (*itr)->GetPosition();
|
||||
|
||||
// Use forward/backward/left/right cartesian plane movement
|
||||
@@ -2848,6 +2852,9 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if ((e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask)) || ((e.event.event_flags & SMART_EVENT_FLAG_NOT_REPEATABLE) && e.runOnce))
|
||||
return;
|
||||
|
||||
if (!(e.event.event_flags & SMART_EVENT_FLAG_WHILE_CHARMED) && IsCreature(me) && !IsCreatureInControlOfSelf(me))
|
||||
return;
|
||||
|
||||
switch (e.GetEventType())
|
||||
{
|
||||
case SMART_EVENT_LINK://special handling
|
||||
@@ -2987,12 +2994,16 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_CHARMED:
|
||||
{
|
||||
if (bvar == (e.event.charm.onRemove != 1))
|
||||
ProcessAction(e, unit, var0, var1, bvar, spell, gob);
|
||||
}
|
||||
//no params
|
||||
case SMART_EVENT_AGGRO:
|
||||
case SMART_EVENT_DEATH:
|
||||
case SMART_EVENT_EVADE:
|
||||
case SMART_EVENT_REACHED_HOME:
|
||||
case SMART_EVENT_CHARMED:
|
||||
case SMART_EVENT_CHARMED_TARGET:
|
||||
case SMART_EVENT_CORPSE_REMOVED:
|
||||
case SMART_EVENT_AI_INIT:
|
||||
|
||||
@@ -63,22 +63,30 @@ class TC_GAME_API SmartScript
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool IsUnit(WorldObject* obj)
|
||||
static bool IsUnit(WorldObject* obj)
|
||||
{
|
||||
return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
|
||||
}
|
||||
|
||||
bool IsPlayer(WorldObject* obj)
|
||||
static bool IsPlayer(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
|
||||
bool IsCreature(WorldObject* obj)
|
||||
static bool IsCreature(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->GetTypeId() == TYPEID_UNIT;
|
||||
}
|
||||
|
||||
bool IsGameObject(WorldObject* obj)
|
||||
static bool IsCreatureInControlOfSelf(WorldObject* obj)
|
||||
{
|
||||
if (Creature* creatureObj = obj ? obj->ToCreature() : nullptr)
|
||||
return !creatureObj->IsCharmed() && !creatureObj->IsControlledByPlayer();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsGameObject(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ void SmartAIMgr::LoadSmartAIFromDB()
|
||||
temp.event.type = (SMART_EVENT)fields[4].GetUInt8();
|
||||
temp.event.event_phase_mask = fields[5].GetUInt8();
|
||||
temp.event.event_chance = fields[6].GetUInt8();
|
||||
temp.event.event_flags = fields[7].GetUInt8();
|
||||
temp.event.event_flags = fields[7].GetUInt16();
|
||||
|
||||
temp.event.raw.param1 = fields[8].GetUInt32();
|
||||
temp.event.raw.param2 = fields[9].GetUInt32();
|
||||
|
||||
@@ -129,7 +129,7 @@ enum SMART_EVENT
|
||||
SMART_EVENT_IC_LOS = 26, // NoHostile, MaxRnage, CooldownMin, CooldownMax
|
||||
SMART_EVENT_PASSENGER_BOARDED = 27, // CooldownMin, CooldownMax
|
||||
SMART_EVENT_PASSENGER_REMOVED = 28, // CooldownMin, CooldownMax
|
||||
SMART_EVENT_CHARMED = 29, // NONE
|
||||
SMART_EVENT_CHARMED = 29, // onRemove (0 - on apply, 1 - on remove)
|
||||
SMART_EVENT_CHARMED_TARGET = 30, // NONE
|
||||
SMART_EVENT_SPELLHIT_TARGET = 31, // SpellID, School, CooldownMin, CooldownMax
|
||||
SMART_EVENT_DAMAGED = 32, // MinDmg, MaxDmg, CooldownMin, CooldownMax
|
||||
@@ -292,6 +292,11 @@ struct SmartEvent
|
||||
uint32 repeatMax;
|
||||
} aura;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 onRemove;
|
||||
} charm;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 spell;
|
||||
@@ -1361,20 +1366,21 @@ enum SmartEventFlags
|
||||
SMART_EVENT_FLAG_RESERVED_6 = 0x040,
|
||||
SMART_EVENT_FLAG_DEBUG_ONLY = 0x080, //Event only occurs in debug build
|
||||
SMART_EVENT_FLAG_DONT_RESET = 0x100, //Event will not reset in SmartScript::OnReset()
|
||||
SMART_EVENT_FLAG_WHILE_CHARMED = 0x200, //Event occurs even if AI owner is charmed
|
||||
|
||||
SMART_EVENT_FLAG_DIFFICULTY_ALL = (SMART_EVENT_FLAG_DIFFICULTY_0|SMART_EVENT_FLAG_DIFFICULTY_1|SMART_EVENT_FLAG_DIFFICULTY_2|SMART_EVENT_FLAG_DIFFICULTY_3),
|
||||
SMART_EVENT_FLAGS_ALL = (SMART_EVENT_FLAG_NOT_REPEATABLE|SMART_EVENT_FLAG_DIFFICULTY_ALL|SMART_EVENT_FLAG_RESERVED_5|SMART_EVENT_FLAG_RESERVED_6|SMART_EVENT_FLAG_DEBUG_ONLY|SMART_EVENT_FLAG_DONT_RESET)
|
||||
SMART_EVENT_FLAGS_ALL = (SMART_EVENT_FLAG_NOT_REPEATABLE|SMART_EVENT_FLAG_DIFFICULTY_ALL|SMART_EVENT_FLAG_RESERVED_5|SMART_EVENT_FLAG_RESERVED_6|SMART_EVENT_FLAG_DEBUG_ONLY|SMART_EVENT_FLAG_DONT_RESET|SMART_EVENT_FLAG_WHILE_CHARMED)
|
||||
};
|
||||
|
||||
enum SmartCastFlags
|
||||
{
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x01, //Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time)
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x01, // Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x02, // Triggered (this makes spell cost zero mana and have no cast time)
|
||||
//SMARTCAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range
|
||||
//SMARTCAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range
|
||||
//SMARTCAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x40 //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x20, // Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x40 // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
};
|
||||
|
||||
// one line in DB is one event
|
||||
|
||||
Reference in New Issue
Block a user