feat(Core/SmartScripts): SMART_EVENT_FLAG_WHILE_CHARMED (#10286)

This commit is contained in:
IntelligentQuantum
2022-04-23 18:56:42 +04:30
committed by GitHub
parent 6aebf22cb2
commit 9fa3436cbe
10 changed files with 186 additions and 56 deletions

View File

@@ -0,0 +1,52 @@
INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1642750721076432402');
-- set "execute event while charmed" flag on all events except:
-- -) movement actions
-- -) nontriggered cast actions
-- -) talk/emote/sound actions
-- -) ally summon actions
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);
-- Always for SMART_EVENT_JUST_SUMMONED (Creature can be summoned already charmed by player ie TempSummons)
UPDATE `smart_scripts` SET `event_flags`=`event_flags`|0x200 WHERE `source_type` = 0 AND `event_type`=54;
-- Event linked actions (Many levels of linked calls, do 8 times)
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
UPDATE `smart_scripts` `ss` LEFT JOIN `smart_scripts` `ssl` ON `ss`.`entryorguid` = `ssl`.`entryorguid` AND `ss`.`source_type` = `ssl`.`source_type` AND `ss`.`id` = `ssl`.`link` SET `ss`.`event_flags`=`ss`.`event_flags`|0x200 WHERE `ss`.`source_type`=0 AND
`ss`.`event_type` = 61 AND (`ssl`.`event_flags` & 0x200) != 0;
-- Vehicles
UPDATE `smart_scripts` SET `event_flags`=`event_flags`|0x200 WHERE `source_type` = 0 AND `entryorguid` IN (SELECT `entry` FROM `creature_template` WHERE `AIName` = "SmartAI" AND `VehicleId` != 0);

View File

@@ -70,7 +70,7 @@ void npc_escortAI::AttackStart(Unit* who)
}
//see followerAI
bool npc_escortAI::AssistPlayerInCombat(Unit* who)
bool npc_escortAI::AssistPlayerInCombatAgainst(Unit* who)
{
if (!who || !who->GetVictim())
{
@@ -138,7 +138,7 @@ void npc_escortAI::MoveInLineOfSight(Unit* who)
return;
if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack(true, me) && who->isInAccessiblePlaceFor(me))
if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombat(who))
if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombatAgainst(who))
return;
if (me->CanStartAttack(who))

View File

@@ -114,7 +114,7 @@ protected:
Player* GetPlayerForEscort() { return ObjectAccessor::GetPlayer(*me, m_uiPlayerGUID); }
private:
bool AssistPlayerInCombat(Unit* who);
bool AssistPlayerInCombatAgainst(Unit* who);
bool IsPlayerOrGroupInRange();
void FillPointMovementListForCreature();

View File

@@ -63,7 +63,7 @@ void FollowerAI::AttackStart(Unit* who)
//This part provides assistance to a player that are attacked by who, even if out of normal aggro range
//It will cause me to attack who that are attacking _any_ player (which has been confirmed may happen also on offi)
//The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
bool FollowerAI::AssistPlayerInCombat(Unit* who)
bool FollowerAI::AssistPlayerInCombatAgainst(Unit* who)
{
if (!who || !who->GetVictim())
return false;
@@ -96,7 +96,7 @@ void FollowerAI::MoveInLineOfSight(Unit* who)
return;
if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack(true, me) && who->isInAccessiblePlaceFor(me))
if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(who))
if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombatAgainst(who))
return;
if (me->CanStartAttack(who))

View File

@@ -69,7 +69,7 @@ private:
void AddFollowState(uint32 uiFollowState) { m_uiFollowState |= uiFollowState; }
void RemoveFollowState(uint32 uiFollowState) { m_uiFollowState &= ~uiFollowState; }
bool AssistPlayerInCombat(Unit* who);
bool AssistPlayerInCombatAgainst(Unit* who);
ObjectGuid m_uiLeaderGUID;
uint32 m_uiUpdateFollowTimer;

View File

@@ -30,6 +30,7 @@
SmartAI::SmartAI(Creature* c) : CreatureAI(c)
{
mIsCharmed = false;
// copy script to local (protection for table reload)
mWayPoints = nullptr;
@@ -76,6 +77,11 @@ SmartAI::SmartAI(Creature* c) : CreatureAI(c)
conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry());
}
bool SmartAI::IsAIControlled() const
{
return !mIsCharmed;
}
void SmartAI::UpdateDespawn(const uint32 diff)
{
if (mDespawnState <= 1 || mDespawnState > 3)
@@ -347,7 +353,10 @@ void SmartAI::EndPath(bool fail)
mCurrentWPID = 0;
if (mCanRepeatPath)
StartPath(mRun, GetScript()->GetPathId(), mCanRepeatPath);
{
if (IsAIControlled())
StartPath(mRun, GetScript()->GetPathId(), true);
}
else
GetScript()->SetPathId(0);
@@ -370,6 +379,9 @@ void SmartAI::ResumePath()
void SmartAI::ReturnToLastOOCPos()
{
if (!IsAIControlled())
return;
me->SetWalk(false);
float x, y, z, o;
me->GetHomePosition(x, y, z, o);
@@ -511,6 +523,9 @@ void SmartAI::UpdateAI(uint32 diff)
mFollowArrivedTimer -= diff;
}
if (!IsAIControlled())
return;
if (!UpdateVictim())
return;
@@ -620,10 +635,6 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
{
// xinef: fixes strange jumps when charming SmartAI npc
if (!me->IsAlive() || me->IsInEvadeMode())
return;
if (mEvadeDisabled)
{
GetScript()->ProcessEventsFor(SMART_EVENT_EVADE);
@@ -636,12 +647,12 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
return;
}
me->RemoveEvadeAuras();
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
GetScript()->ProcessEventsFor(SMART_EVENT_EVADE); //must be after aura clear so we can cast spells from db
SetRun(mRun);
if (HasEscortState(SMART_ESCORT_ESCORTING))
@@ -675,10 +686,13 @@ void SmartAI::MoveInLineOfSight(Unit* who)
GetScript()->OnMoveInLineOfSight(who);
if (!IsAIControlled())
return;
if (me->GetVictim())
return;
if (me->HasReactState(REACT_PASSIVE) || AssistPlayerInCombat(who))
if (me->HasReactState(REACT_PASSIVE) || AssistPlayerInCombatAgainst(who))
return;
if (me->CanStartAttack(who))
@@ -694,13 +708,14 @@ void SmartAI::MoveInLineOfSight(Unit* who)
bool SmartAI::CanAIAttack(Unit const* /*who*/) const
{
if (me->GetReactState() == REACT_PASSIVE)
return false;
return true;
return !(me->GetReactState() == REACT_PASSIVE);
}
bool SmartAI::AssistPlayerInCombat(Unit* who)
bool SmartAI::AssistPlayerInCombatAgainst(Unit* who)
{
if (!IsAIControlled())
return false;
// Xinef: if unit has no victim, or victim is player controlled thing
if (!who->GetVictim() || who->GetCharmerOrOwnerOrOwnGUID().IsPlayer())
return false;
@@ -773,7 +788,8 @@ void SmartAI::JustReachedHome()
void SmartAI::EnterCombat(Unit* enemy)
{
// Xinef: Interrupt channeled spells
me->InterruptSpell(CURRENT_CHANNELED_SPELL, true, true);
if (IsAIControlled())
me->InterruptSpell(CURRENT_CHANNELED_SPELL, true, true);
GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy);
}
@@ -841,6 +857,9 @@ void SmartAI::DamageTaken(Unit* doneBy, uint32& damage, DamageEffectType damaget
if (doneBy)
GetScript()->ProcessEventsFor(SMART_EVENT_DAMAGED, doneBy, damage);
if (!IsAIControlled()) // don't allow players to use unkillable units
return;
// Xinef: skip nodamage type (eg. instakill effect)
if (damagetype != NODAMAGE && mInvincibilityHpLevel && (damage >= me->GetHealth() - mInvincibilityHpLevel))
damage = me->GetHealth() - mInvincibilityHpLevel; // damage should not be nullified, because of player damage req.
@@ -871,10 +890,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);
@@ -900,9 +915,29 @@ void SmartAI::InitializeAI()
}
}
void SmartAI::OnCharmed(bool apply)
void SmartAI::OnCharmed(bool /* apply */)
{
GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, nullptr, 0, 0, apply);
bool const charmed = me->IsCharmed();
if (charmed) // 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);
}
mIsCharmed = charmed;
if (!charmed && !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, charmed);
}
void SmartAI::DoAction(int32 param)
@@ -995,6 +1030,10 @@ void SmartAI::SetCombatMove(bool on)
return;
mCanCombatMove = on;
if (!IsAIControlled())
return;
if (!HasEscortState(SMART_ESCORT_ESCORTING))
{
if (on && me->GetVictim())
@@ -1024,7 +1063,6 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui
return;
}
SetRun(mRun);
mFollowGuid = target->GetGUID();
mFollowDist = dist;
mFollowAngle = angle;
@@ -1032,9 +1070,9 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui
mFollowCredit = credit;
mFollowArrivedEntry = end;
mFollowArrivedAlive = !aliveState; // negate - 0 is alive
me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle);
mFollowCreditType = creditType;
SetRun(mRun);
me->GetMotionMaster()->MoveFollow(target, mFollowDist, mFollowAngle);
}
void SmartAI::StopFollow(bool complete)

View File

@@ -47,6 +47,9 @@ public:
~SmartAI() override {};
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);
@@ -133,9 +136,6 @@ public:
// 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;
@@ -205,6 +205,7 @@ public:
void SetForcedCombatMove(float dist);
private:
bool mIsCharmed;
uint32 mFollowCreditType;
uint32 mFollowArrivedTimer;
uint32 mFollowCredit;
@@ -234,7 +235,7 @@ private:
bool mForcedPaused;
uint32 mInvincibilityHpLevel;
bool AssistPlayerInCombat(Unit* who);
bool AssistPlayerInCombatAgainst(Unit* who);
uint32 mDespawnTime;
uint32 mDespawnState;

View File

@@ -121,7 +121,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;
}
@@ -4031,6 +4031,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) && IsCharmedCreature(me))
return;
switch (e.GetEventType())
{
case SMART_EVENT_LINK://special handling
@@ -4180,12 +4183,17 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax, me->GetVictim());
break;
}
case SMART_EVENT_CHARMED:
{
if (bvar == (e.event.charm.onRemove != 1))
ProcessAction(e, unit, var0, var1, bvar, spell, gob);
break;
}
//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:
@@ -5127,6 +5135,37 @@ Unit* SmartScript::GetLastInvoker(Unit* invoker)
return nullptr;
}
bool SmartScript::IsUnit(WorldObject* obj)
{
return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
}
bool SmartScript::IsPlayer(WorldObject* obj)
{
return obj && obj->GetTypeId() == TYPEID_PLAYER;
}
bool SmartScript::IsCreature(WorldObject* obj)
{
return obj && obj->GetTypeId() == TYPEID_UNIT;
}
bool SmartScript::IsCharmedCreature(WorldObject* obj)
{
if (!obj)
return false;
if (Creature* creatureObj = obj->ToCreature())
return creatureObj->IsCharmed();
return false;
}
bool SmartScript::IsGameObject(WorldObject* obj)
{
return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
}
void SmartScript::IncPhase(uint32 p)
{
// protect phase from overflowing

View File

@@ -61,25 +61,11 @@ public:
return obj;
}
bool IsUnit(WorldObject* obj)
{
return obj && obj->IsInWorld() && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
}
bool IsPlayer(WorldObject* obj)
{
return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_PLAYER;
}
bool IsCreature(WorldObject* obj)
{
return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_UNIT;
}
bool IsGameObject(WorldObject* obj)
{
return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_GAMEOBJECT;
}
static bool IsUnit(WorldObject* obj);
static bool IsPlayer(WorldObject* obj);
static bool IsCreature(WorldObject* obj);
static bool IsCharmedCreature(WorldObject* obj);
static bool IsGameObject(WorldObject* obj);
void OnUpdate(const uint32 diff);
void OnMoveInLineOfSight(Unit* who);

View File

@@ -133,7 +133,7 @@ enum SMART_EVENT
SMART_EVENT_IC_LOS = 26, // HostilityMode, MaxRnage, CooldownMin, CooldownMax, PlayerOnly
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
@@ -312,6 +312,19 @@ struct SmartEvent
uint32 repeatMax;
} aura;
struct
{
uint32 onRemove;
} charm;
struct
{
uint32 spell;
uint32 count;
uint32 repeatMin;
uint32 repeatMax;
} targetAura;
struct
{
uint32 type;
@@ -1740,9 +1753,10 @@ 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