fix(Core/Creatures): Implemented `SUMMON_PROP_FLAG_ONLY_VISIBLE_TO_SU… (#14054)

* fix(Core/Creatures): Implemented `SUMMON_PROP_FLAG_ONLY_VISIBLE_TO_SUMMONER` summon flag.

Fixes #6674

* Update.
This commit is contained in:
UltraNix
2023-01-06 00:52:05 +01:00
committed by GitHub
parent 0e1e8f27de
commit 14f3b444ae
12 changed files with 96 additions and 44 deletions

View File

@@ -1267,10 +1267,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
case SMART_ACTION_SUMMON_CREATURE:
{
WorldObject* summoner = GetBaseObject() ? GetBaseObject() : unit;
EnumFlag<SmartActionSummonCreatureFlags> flags(static_cast<SmartActionSummonCreatureFlags>(e.action.summonCreature.flags));
bool preferUnit = flags.HasFlag(SmartActionSummonCreatureFlags::PreferUnit);
WorldObject* summoner = preferUnit ? unit : Coalesce<WorldObject>(GetBaseObject(), unit);
if (!summoner)
break;
bool personalSpawn = flags.HasFlag(SmartActionSummonCreatureFlags::PersonalSpawn);
if (e.GetTargetType() == SMART_TARGET_RANDOM_POINT)
{
float range = (float)e.target.randomPoint.range;
@@ -1282,7 +1286,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
randomPoint = me->GetRandomPoint(me->GetPosition(), range);
else
randomPoint = me->GetRandomPoint(srcPos, range);
if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, randomPoint, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration))
if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, randomPoint, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration, 0, nullptr, personalSpawn))
{
if (unit && e.action.summonCreature.attackInvoker)
summon->AI()->AttackStart(unit);
@@ -1301,7 +1305,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
y += e.target.y;
z += e.target.z;
o += e.target.o;
if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration))
if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration, nullptr, personalSpawn))
{
if (e.action.summonCreature.attackInvoker == 2) // pussywizard: proper attackInvoker implementation
summon->AI()->AttackStart(unit);

View File

@@ -534,7 +534,7 @@ enum SMART_ACTION
SMART_ACTION_ACTIVATE_GOBJECT = 9, //
SMART_ACTION_RANDOM_EMOTE = 10, // EmoteId1, EmoteId2, EmoteId3...
SMART_ACTION_CAST = 11, // SpellId, CastFlags, LimitTargets
SMART_ACTION_SUMMON_CREATURE = 12, // CreatureID, summonType, duration in ms, attackInvoker, attackScriptOwner
SMART_ACTION_SUMMON_CREATURE = 12, // CreatureID, summonType, duration in ms, attackInvoker, attackScriptOwner, flags(SmartActionSummonCreatureFlags)
SMART_ACTION_THREAT_SINGLE_PCT = 13, // Threat%
SMART_ACTION_THREAT_ALL_PCT = 14, // Threat%
SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS = 15, // QuestID
@@ -696,6 +696,17 @@ enum SMART_ACTION
SMART_ACTION_AC_END = 225, // placeholder
};
enum class SmartActionSummonCreatureFlags
{
None = 0,
PersonalSpawn = 1,
PreferUnit = 2,
All = PersonalSpawn | PreferUnit
};
DEFINE_ENUM_FLAG(SmartActionSummonCreatureFlags);
struct SmartAction
{
SMART_ACTION type;
@@ -820,6 +831,7 @@ struct SmartAction
uint32 duration;
SAIBool attackInvoker;
uint32 attackScriptOwner;
uint32 flags; // SmartActionSummonCreatureFlags
} summonCreature;
struct

View File

@@ -454,11 +454,27 @@ void ThreatMgr::AddThreat(Unit* victim, float threat, SpellSchoolMask schoolMask
void ThreatMgr::DoAddThreat(Unit* victim, float threat)
{
uint32 redirectThreadPct = victim->GetRedirectThreatPercent();
Unit* redirectTarget = victim->GetRedirectThreatTarget();
// Personal Spawns from same summoner can aggro each other
if (TempSummon* tempSummonVictim = victim->ToTempSummon())
{
if (tempSummonVictim->IsVisibleBySummonerOnly())
{
if (!GetOwner()->ToTempSummon() ||
!GetOwner()->ToTempSummon()->IsVisibleBySummonerOnly() ||
tempSummonVictim->GetSummonerGUID() != GetOwner()->ToTempSummon()->GetSummonerGUID())
{
redirectThreadPct = 100;
redirectTarget = tempSummonVictim->GetSummonerUnit();
}
}
}
// must check > 0.0f, otherwise dead loop
if (threat > 0.0f && redirectThreadPct)
{
if (Unit* redirectTarget = victim->GetRedirectThreatTarget())
if (redirectTarget)
{
float redirectThreat = CalculatePct(threat, redirectThreadPct);
threat -= redirectThreat;

View File

@@ -25,7 +25,7 @@
TempSummon::TempSummon(SummonPropertiesEntry const* properties, ObjectGuid owner, bool isWorldObject) :
Creature(isWorldObject), m_Properties(properties), m_type(TEMPSUMMON_MANUAL_DESPAWN),
m_timer(0), m_lifetime(0)
m_timer(0), m_lifetime(0), _visibleBySummonerOnly(false)
{
if (owner)
{

View File

@@ -57,14 +57,19 @@ public:
uint32 GetTimer() { return m_timer; }
void SetTimer(uint32 t) { m_timer = t; }
void SetVisibleBySummonerOnly(bool visibleBySummonerOnly) { _visibleBySummonerOnly = visibleBySummonerOnly; }
[[nodiscard]] bool IsVisibleBySummonerOnly() const { return _visibleBySummonerOnly; }
const SummonPropertiesEntry* const m_Properties;
std::string GetDebugInfo() const override;
private:
TempSummonType m_type;
uint32 m_timer;
uint32 m_lifetime;
ObjectGuid m_summonerGUID;
bool _visibleBySummonerOnly;
};
class Minion : public TempSummon

View File

@@ -1773,6 +1773,17 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
WorldObject const* viewpoint = this;
if (Player const* thisPlayer = ToPlayer())
{
if (Creature const* creature = obj->ToCreature())
{
if (TempSummon const* tempSummon = creature->ToTempSummon())
{
if (tempSummon->IsVisibleBySummonerOnly() && GetGUID() != tempSummon->GetSummonerGUID())
{
return false;
}
}
}
if (thisPlayer->isDead() && thisPlayer->GetHealth() > 0 && // Cheap way to check for ghost state
!(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & GHOST_VISIBILITY_GHOST))
{
@@ -2115,7 +2126,7 @@ void WorldObject::AddObjectToRemoveList()
map->AddObjectToRemoveList(this);
}
TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= nullptr*/, uint32 duration /*= 0*/, WorldObject* summoner /*= nullptr*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/)
TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties /*= nullptr*/, uint32 duration /*= 0*/, WorldObject* summoner /*= nullptr*/, uint32 spellId /*= 0*/, uint32 vehId /*= 0*/, bool visibleBySummonerOnly /*= false*/)
{
uint32 mask = UNIT_MASK_SUMMON;
if (properties)
@@ -2204,6 +2215,9 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert
summon->SetHomePosition(pos);
summon->InitStats(duration);
summon->SetVisibleBySummonerOnly(visibleBySummonerOnly);
if (!AddToMap(summon->ToCreature(), summon->GetOwnerGUID().IsPlayer() || (summoner && summoner->GetTransport())))
{
delete summon;
@@ -2236,7 +2250,7 @@ void Map::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= null
list->push_back(summon);
}
TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang, TempSummonType spwtype, uint32 despwtime, SummonPropertiesEntry const* properties)
TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang, TempSummonType spwtype, uint32 despwtime, SummonPropertiesEntry const* properties, bool visibleBySummonerOnly)
{
if (!x && !y && !z)
{
@@ -2245,7 +2259,7 @@ TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, fl
}
Position pos;
pos.Relocate(x, y, z, ang);
return SummonCreature(id, pos, spwtype, despwtime, 0, properties);
return SummonCreature(id, pos, spwtype, despwtime, 0, properties, visibleBySummonerOnly);
}
GameObject* Map::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime, bool checkTransport)
@@ -2301,11 +2315,11 @@ void WorldObject::ClearZoneScript()
m_zoneScript = nullptr;
}
TempSummon* WorldObject::SummonCreature(uint32 entry, const Position& pos, TempSummonType spwtype, uint32 duration, uint32 /*vehId*/, SummonPropertiesEntry const* properties) const
TempSummon* WorldObject::SummonCreature(uint32 entry, const Position& pos, TempSummonType spwtype, uint32 duration, uint32 /*vehId*/, SummonPropertiesEntry const* properties, bool visibleBySummonerOnly /*= false*/) const
{
if (Map* map = FindMap())
{
if (TempSummon* summon = map->SummonCreature(entry, pos, properties, duration, (WorldObject*) this))
if (TempSummon* summon = map->SummonCreature(entry, pos, properties, duration, (WorldObject*)this, 0, 0, visibleBySummonerOnly))
{
summon->SetTempSummonType(spwtype);
return summon;

View File

@@ -522,8 +522,8 @@ public:
void ClearZoneScript();
[[nodiscard]] ZoneScript* GetZoneScript() const { return m_zoneScript; }
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);
TempSummon* SummonCreature(uint32 id, const Position& pos, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, uint32 vehId = 0, SummonPropertiesEntry const* properties = nullptr, bool visibleBySummonerOnly = false) 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, bool visibleBySummonerOnly = false);
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);

View File

@@ -597,7 +597,7 @@ namespace Acore
void Visit(PlayerMapType& m)
{
for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr)
if (itr->GetSource()->InSamePhase(i_searcher) && itr->GetSource()->IsWithinDist(i_searcher, i_dist))
if (itr->GetSource()->HaveAtClient(i_searcher) && itr->GetSource()->IsWithinDist(i_searcher, i_dist))
i_do(itr->GetSource());
}

View File

@@ -500,7 +500,7 @@ public:
void UpdateIteratorBack(Player* player);
TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = nullptr, uint32 duration = 0, WorldObject* summoner = nullptr, uint32 spellId = 0, uint32 vehId = 0);
TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = nullptr, uint32 duration = 0, WorldObject* summoner = nullptr, uint32 spellId = 0, uint32 vehId = 0, bool visibleBySummonerOnly = false);
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, Position const& pos, float rotation0 = 0.0f, float rotation1 = 0.0f, float rotation2 = 0.0f, float rotation3 = 0.0f, uint32 respawnTime = 100, bool checkTransport = true);
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = nullptr);

View File

@@ -753,7 +753,7 @@ public:
HitTriggerSpellList m_hitTriggerSpells;
// effect helpers
void SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* properties, uint32 numSummons);
void SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* properties, uint32 numSummons, bool personalSpawn);
void CalculateJumpSpeeds(uint8 i, float dist, float& speedxy, float& speedz);
SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);

View File

@@ -2354,6 +2354,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
if (!m_originalCaster)
return;
bool personalSpawn = (properties->Flags & SUMMON_PROP_FLAG_ONLY_VISIBLE_TO_SUMMONER) != 0;
int32 duration = m_spellInfo->GetDuration();
if (Player* modOwner = m_originalCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
@@ -2398,7 +2399,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
case SUMMON_CATEGORY_UNK:
if (properties->Flags & 512)
{
SummonGuardian(effIndex, entry, properties, numSummons);
SummonGuardian(effIndex, entry, properties, numSummons, personalSpawn);
break;
}
switch (properties->Type)
@@ -2407,18 +2408,18 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
case SUMMON_TYPE_GUARDIAN:
case SUMMON_TYPE_GUARDIAN2:
case SUMMON_TYPE_MINION:
SummonGuardian(effIndex, entry, properties, numSummons);
SummonGuardian(effIndex, entry, properties, numSummons, personalSpawn);
break;
// Summons a vehicle, but doesn't force anyone to enter it (see SUMMON_CATEGORY_VEHICLE)
case SUMMON_TYPE_VEHICLE:
case SUMMON_TYPE_VEHICLE2:
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id, 0, personalSpawn);
break;
case SUMMON_TYPE_LIGHTWELL:
case SUMMON_TYPE_TOTEM:
{
// protection code
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id, 0, personalSpawn);
if (!summon || !summon->IsTotem())
return;
@@ -2436,7 +2437,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
case SUMMON_TYPE_JEEVES:
case SUMMON_TYPE_MINIPET:
{
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id, 0, personalSpawn);
if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION))
return;
@@ -2470,7 +2471,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
// randomize position for multiple summons
pos = m_caster->GetRandomPoint(*destTarget, radius);
summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration);
summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration, 0, nullptr, personalSpawn);
if (!summon)
continue;
@@ -2492,10 +2493,10 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
// Xinef: SummonGuardian function can summon a few npcs of same type, remove old summons with same entry here
if (m_originalCaster)
m_originalCaster->RemoveAllMinionsByEntry(entry);
SummonGuardian(effIndex, entry, properties, numSummons);
SummonGuardian(effIndex, entry, properties, numSummons, personalSpawn);
break;
case SUMMON_CATEGORY_PUPPET:
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id, 0, personalSpawn);
break;
case SUMMON_CATEGORY_VEHICLE:
// Summoning spells (usually triggered by npc_spellclick) that spawn a vehicle and that cause the clicker
@@ -2506,7 +2507,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
if (std::fabs(m_caster->GetPositionZ() - destTarget->GetPositionZ()) > 6.0f)
destTarget->m_positionZ = m_caster->GetPositionZ();
summon = m_originalCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_caster, m_spellInfo->Id);
summon = m_originalCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_caster, m_spellInfo->Id, 0, personalSpawn);
if (!summon || !summon->IsVehicle())
return;
@@ -3176,7 +3177,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex)
// Xinef: unsummon old guardian
if (Guardian* oldPet = m_originalCaster->GetGuardianPet())
oldPet->UnSummon();
SummonGuardian(effIndex, petentry, properties, 1);
SummonGuardian(effIndex, petentry, properties, 1, false);
}
return;
}
@@ -6005,7 +6006,7 @@ void Spell::EffectGameObjectSetDestructionState(SpellEffIndex effIndex)
gameObjTarget->SetDestructibleState(GameObjectDestructibleState(m_spellInfo->Effects[effIndex].MiscValue), player, true);
}
void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* properties, uint32 numGuardians)
void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* properties, uint32 numGuardians, bool personalSpawn)
{
Unit* caster = m_originalCaster;
if (!caster)
@@ -6105,7 +6106,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
pos = m_caster->GetRandomPoint(*destTarget, radius);
}
summon = map->SummonCreature(entry, pos, properties, duration, caster, m_spellInfo->Id);
summon = map->SummonCreature(entry, pos, properties, duration, caster, m_spellInfo->Id, 0, personalSpawn);
if (!summon)
return;

View File

@@ -426,22 +426,22 @@ enum SummonPropGroup
enum SummonPropFlags
{
SUMMON_PROP_FLAG_NONE = 0x00000000, // 1342 spells in 3.0.3
SUMMON_PROP_FLAG_ATTACK_SUMMONER = 0x00000001, // 75 spells in 3.0.3, something unfriendly TODO: Needs implementation
SUMMON_PROP_FLAG_ASSIST_COMBAT_SUMMON = 0x00000002, // 616 spells in 3.0.3, something friendly TODO: Needs implementation
SUMMON_PROP_FLAG_USE_LEVEL_OFFSET = 0x00000004, // 22 spells in 3.0.3, no idea... TODO: Needs implementation
SUMMON_PROP_FLAG_DESPAWN_ON_SUMMONER_DEATH = 0x00000008, // 49 spells in 3.0.3, some mounts TODO: Needs implementation
SUMMON_PROP_FLAG_ONLY_VISIBLE_TO_SUMMONER = 0x00000010, // 25 spells in 3.0.3, quest related? TODO: Needs implementation
SUMMON_PROP_FLAG_CANNOT_DISMISS_PET = 0x00000020, // 0 spells in 3.3.5, unused TODO: Needs implementation
SUMMON_PROP_FLAG_USE_DEMON_TIMEOUT = 0x00000040, // 12 spells in 3.0.3, no idea TODO: Needs implementation
SUMMON_PROP_FLAG_UNLIMITED_SUMMONS = 0x00000080, // 4 spells in 3.0.3, no idea TODO: Needs implementation
SUMMON_PROP_FLAG_USE_CREATURE_LEVEL = 0x00000100, // 51 spells in 3.0.3, no idea, many quest related TODO: Needs implementation
SUMMON_PROP_FLAG_JOIN_SUMMONER_SPAWN_GROUP = 0x00000200, // 51 spells in 3.0.3, something defensive TODO: Needs implementation
SUMMON_PROP_FLAG_DO_NOT_TOGGLE = 0x00000400, // 3 spells, requires something near? TODO: Needs implementation
SUMMON_PROP_FLAG_DESPAWN_WHEN_EXPIRED = 0x00000800, // 30 spells in 3.0.3, no idea TODO: Needs implementation
SUMMON_PROP_FLAG_USE_SUMMONER_FACTION = 0x00001000, // Lightwell, Jeeves, Gnomish Alarm-o-bot, Build vehicles(wintergrasp) TODO: Needs implementation
SUMMON_PROP_FLAG_DO_NOT_FOLLOW_MOUNTED_SUMMONER = 0x00002000, // Guides, player follows TODO: Needs implementation
SUMMON_PROP_FLAG_SAVE_PET_AUTOCAST = 0x00004000, // Force of Nature, Shadowfiend, Feral Spirit, Summon Water Elemental TODO: Needs implementation
SUMMON_PROP_FLAG_IGNORE_SUMMONER_PHASE = 0x00008000, // Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related? TODO: Needs implementation
SUMMON_PROP_FLAG_ATTACK_SUMMONER = 0x00000001, // NYI 75 spells in 3.0.3, something unfriendly
SUMMON_PROP_FLAG_ASSIST_COMBAT_SUMMON = 0x00000002, // NYI 616 spells in 3.0.3, something friendly
SUMMON_PROP_FLAG_USE_LEVEL_OFFSET = 0x00000004, // NYI 22 spells in 3.0.3, no idea...
SUMMON_PROP_FLAG_DESPAWN_ON_SUMMONER_DEATH = 0x00000008, // NYI 49 spells in 3.0.3, some mounts
SUMMON_PROP_FLAG_ONLY_VISIBLE_TO_SUMMONER = 0x00000010, // 25 spells in 3.0.3, quest related?
SUMMON_PROP_FLAG_CANNOT_DISMISS_PET = 0x00000020, // NYI 0 spells in 3.3.5, unused
SUMMON_PROP_FLAG_USE_DEMON_TIMEOUT = 0x00000040, // NYI 12 spells in 3.0.3, no idea
SUMMON_PROP_FLAG_UNLIMITED_SUMMONS = 0x00000080, // NYI 4 spells in 3.0.3, no idea
SUMMON_PROP_FLAG_USE_CREATURE_LEVEL = 0x00000100, // NYI 51 spells in 3.0.3, no idea, many quest related
SUMMON_PROP_FLAG_JOIN_SUMMONER_SPAWN_GROUP = 0x00000200, // NYI 51 spells in 3.0.3, something defensive
SUMMON_PROP_FLAG_DO_NOT_TOGGLE = 0x00000400, // NYI 3 spells, requires something near?
SUMMON_PROP_FLAG_DESPAWN_WHEN_EXPIRED = 0x00000800, // NYI 30 spells in 3.0.3, no idea
SUMMON_PROP_FLAG_USE_SUMMONER_FACTION = 0x00001000, // NYI Lightwell, Jeeves, Gnomish Alarm-o-bot, Build vehicles(wintergrasp)
SUMMON_PROP_FLAG_DO_NOT_FOLLOW_MOUNTED_SUMMONER = 0x00002000, // NYI Guides, player follows
SUMMON_PROP_FLAG_SAVE_PET_AUTOCAST = 0x00004000, // NYI Force of Nature, Shadowfiend, Feral Spirit, Summon Water Elemental
SUMMON_PROP_FLAG_IGNORE_SUMMONER_PHASE = 0x00008000, // NYI Light/Dark Bullet, Soul/Fiery Consumption, Twisted Visage, Twilight Whelp. Phase related?
};
enum VehicleSeatFlags