aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2023-10-22 18:39:59 +0200
committerShauren <shauren.trinity@gmail.com>2023-10-22 18:39:59 +0200
commitdc9361fcc2eb16a59b52dfd8b0d47dfc1bf639be (patch)
treeb25b12a693f3e60f940be7a78df72b7ba47f4718 /src/server/game/Spells
parentb2393d6adeca9a54b6ff1fb62a87da48c068f010 (diff)
Core/Spells: Named and implemented most of SpellAttr8
Diffstat (limited to 'src/server/game/Spells')
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp10
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp2
-rw-r--r--src/server/game/Spells/Spell.cpp157
-rw-r--r--src/server/game/Spells/Spell.h17
-rw-r--r--src/server/game/Spells/SpellInfo.cpp33
5 files changed, 183 insertions, 36 deletions
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 26bd7a0c0ba..f33d2313a63 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -768,6 +768,8 @@ float AuraEffect::CalculateEstimatedfTotalPeriodicAmount(Unit* caster, Unit* tar
caster->ModSpellDurationTime(spellInfo, period);
else if (spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
period = int32(period * caster->m_unitData->ModCastingSpeed);
+ else if (spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC))
+ period = int32(period * caster->m_unitData->ModHaste);
if (!period)
return 0.0f;
@@ -851,6 +853,8 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= tru
caster->ModSpellDurationTime(m_spellInfo, _period);
else if (m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
_period = int32(_period * caster->m_unitData->ModCastingSpeed);
+ else if (m_spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC))
+ _period = int32(_period * caster->m_unitData->ModHaste);
}
}
else // prevent infinite loop on Update
@@ -967,7 +971,7 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply,
HandleEffect(aurApp, handleMask, true, triggeredBy);
}
- if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT) || Aura::EffectTypeNeedsSendingAmount(GetAuraType()))
+ if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT) || Aura::EffectTypeNeedsSendingAmount(GetAuraType()))
GetBase()->SetNeedClientUpdateForTargets();
}
@@ -5905,6 +5909,8 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve
{
Unit* triggerCaster = aurApp->GetTarget();
Unit* triggerTarget = eventInfo.GetProcTarget();
+ if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_TARGET_PROCS_ON_CASTER) && eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
+ triggerTarget = eventInfo.GetActor();
uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell;
if (triggerSpellId == 0)
@@ -5926,6 +5932,8 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
{
Unit* triggerCaster = aurApp->GetTarget();
Unit* triggerTarget = eventInfo.GetProcTarget();
+ if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_TARGET_PROCS_ON_CASTER) && eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
+ triggerTarget = eventInfo.GetActor();
uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell;
if (triggerSpellId == 0)
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 8ca596c16a9..2fe302740aa 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -148,7 +148,7 @@ void AuraApplication::_InitFlags(Unit* caster, uint32 effMask)
return effect && (GetEffectsToApply() & (1 << effect->GetEffIndex())) && Aura::EffectTypeNeedsSendingAmount(effect->GetAuraType());
};
- if (GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)
+ if (GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT)
|| std::find_if(GetBase()->GetAuraEffects().begin(), GetBase()->GetAuraEffects().end(), std::cref(effectNeedsAmount)) != GetBase()->GetAuraEffects().end())
_flags |= AFLAG_SCALABLE;
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index c0bc954a8b2..fce17019d45 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -824,6 +824,22 @@ void Spell::SelectSpellTargets()
}
}
+ if (m_targets.HasDst())
+ {
+ if (m_spellInfo->HasAttribute(SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE))
+ {
+ ZLiquidStatus status = m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseShift(),
+ m_targets.GetDstPos()->GetPositionX(), m_targets.GetDstPos()->GetPositionY(), m_targets.GetDstPos()->GetPositionZ(),
+ map_liquidHeaderTypeFlags::AllLiquids);
+ if (!(status & (LIQUID_MAP_WATER_WALK | LIQUID_MAP_IN_WATER)))
+ {
+ SendCastResult(SPELL_FAILED_NO_LIQUID);
+ finish(SPELL_FAILED_NO_LIQUID);
+ return;
+ }
+ }
+ }
+
if (uint64 dstDelay = CalculateDelayMomentForDst(m_spellInfo->LaunchDelay))
m_delayMoment = dstDelay;
}
@@ -2740,7 +2756,7 @@ void Spell::TargetInfo::DoTargetSpellHit(Spell* spell, SpellEffectInfo const& sp
if (unit->IsAlive() != IsAlive)
return;
- if (spell->getState() == SPELL_STATE_DELAYED && !spell->IsPositive() && (GameTime::GetGameTimeMS() - TimeDelay) <= unit->m_lastSanctuaryTime)
+ if (!spell->m_spellInfo->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY) && spell->getState() == SPELL_STATE_DELAYED && !spell->IsPositive() && (GameTime::GetGameTimeMS() - TimeDelay) <= unit->m_lastSanctuaryTime)
return; // No missinfo in that case
if (_spellHitTarget)
@@ -4672,6 +4688,9 @@ void Spell::SendSpellStart()
if (HasPowerTypeCost(POWER_RUNES))
castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
+ if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION) && m_casttime && m_caster->IsUnit())
+ castFlags |= CAST_FLAG_HEAL_PREDICTION;
+
WorldPackets::Spells::SpellStart packet;
WorldPackets::Spells::SpellCastData& castData = packet.Cast;
@@ -4737,13 +4756,8 @@ void Spell::SendSpellStart()
castData.Immunities.Value = mechanicImmunityMask;
}
- /** @todo implement heal prediction packet data
if (castFlags & CAST_FLAG_HEAL_PREDICTION)
- {
- castData.Predict.BeconGUID = ??
- castData.Predict.Points = 0;
- castData.Predict.Type = 0;
- }**/
+ UpdateSpellHealPrediction(castData.Predict, false);
m_caster->SendMessageToSet(packet.Write(), true);
}
@@ -4948,6 +4962,84 @@ int32 Spell::GetSpellCastDataAmmo()
return ammoDisplayID;
}
+static std::pair<int32, SpellHealPredictionType> CalcPredictedHealing(SpellInfo const* spellInfo, Unit const* unitCaster, Unit* target, uint32 castItemEntry, int32 castItemLevel, Spell* spell, bool withPeriodic)
+{
+ int32 points = 0;
+ SpellHealPredictionType type = SPELL_HEAL_PREDICTION_TARGET;
+ for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
+ {
+ switch (spellEffectInfo.Effect)
+ {
+ case SPELL_EFFECT_HEAL:
+ case SPELL_EFFECT_HEAL_PCT:
+ points += unitCaster->SpellHealingBonusDone(target,
+ spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
+ DIRECT_DAMAGE, spellEffectInfo, 1, spell);
+
+ if (target != unitCaster && (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER || spellEffectInfo.TargetB.GetTarget() == TARGET_UNIT_CASTER))
+ type = SPELL_HEAL_PREDICTION_TARGET_AND_CASTER; // Binding Heal-like spells
+ else if (spellEffectInfo.TargetA.GetCheckType() == TARGET_CHECK_PARTY || spellEffectInfo.TargetB.GetCheckType() == TARGET_CHECK_PARTY)
+ type = SPELL_HEAL_PREDICTION_TARGET_PARTY; // Prayer of Healing (old party-wide targeting)
+ break;
+ default:
+ break;
+ }
+
+ if (withPeriodic)
+ {
+ switch (spellEffectInfo.ApplyAuraName)
+ {
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ points += unitCaster->SpellHealingBonusDone(target,
+ spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
+ DIRECT_DAMAGE, spellEffectInfo, 1, spell) * spellInfo->GetMaxTicks();
+ break;
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
+ if (SpellInfo const* triggered = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, spellInfo->Difficulty))
+ points += CalcPredictedHealing(triggered, unitCaster, target, castItemEntry, castItemLevel, nullptr, withPeriodic).first;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return { points, type };
+}
+
+void Spell::UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& healPrediction, bool withPeriodic)
+{
+ healPrediction.BeaconGUID = ObjectGuid::Empty;
+ healPrediction.Points = 0;
+ healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET;
+
+ Unit const* unitCaster = m_caster->ToUnit();
+
+ if (Unit* target = m_targets.GetUnitTarget())
+ {
+ auto [points, type] = CalcPredictedHealing(m_spellInfo, unitCaster, target, m_castItemEntry, m_castItemLevel, this, withPeriodic);
+ healPrediction.Points = points;
+ healPrediction.Type = type;
+ }
+
+ static constexpr uint32 beaconSpellId = 53651;
+
+ if (healPrediction.Type == SPELL_HEAL_PREDICTION_TARGET && unitCaster->HasAura(beaconSpellId, unitCaster->GetGUID()))
+ {
+ auto beacon = std::find_if(unitCaster->GetSingleCastAuras().begin(), unitCaster->GetSingleCastAuras().end(), [](Aura const* aura)
+ {
+ return aura->GetSpellInfo()->GetEffects().size() > EFFECT_1 && aura->GetSpellInfo()->GetEffect(EFFECT_1).TriggerSpell == beaconSpellId;
+ });
+
+ if (beacon != unitCaster->GetSingleCastAuras().end())
+ {
+ healPrediction.BeaconGUID = (*beacon)->GetOwner()->GetGUID();
+ healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET_AND_BEACON;
+ }
+ }
+}
+
void Spell::SendSpellExecuteLog()
{
if (_executeLogEffects.empty())
@@ -5112,23 +5204,6 @@ void Spell::SendChannelStart(uint32 duration)
if (!unitCaster)
return;
- WorldPackets::Spells::SpellChannelStart spellChannelStart;
- spellChannelStart.CasterGUID = unitCaster->GetGUID();
- spellChannelStart.SpellID = m_spellInfo->Id;
- spellChannelStart.Visual = m_SpellVisual;
- spellChannelStart.ChannelDuration = duration;
- unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
-
- uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
- uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
-
- if (schoolImmunityMask || mechanicImmunityMask)
- {
- spellChannelStart.InterruptImmunities.emplace();
- spellChannelStart.InterruptImmunities->SchoolImmunities = schoolImmunityMask;
- spellChannelStart.InterruptImmunities->Immunities = mechanicImmunityMask;
- }
-
m_timer = duration;
if (!m_targets.HasDst())
@@ -5176,6 +5251,33 @@ void Spell::SendChannelStart(uint32 duration)
unitCaster->SetChannelSpellId(m_spellInfo->Id);
unitCaster->SetChannelVisual(m_SpellVisual);
+
+ WorldPackets::Spells::SpellChannelStart spellChannelStart;
+ spellChannelStart.CasterGUID = unitCaster->GetGUID();
+ spellChannelStart.SpellID = m_spellInfo->Id;
+ spellChannelStart.Visual = m_SpellVisual;
+ spellChannelStart.ChannelDuration = duration;
+
+ uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
+ uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
+
+ if (schoolImmunityMask || mechanicImmunityMask)
+ {
+ spellChannelStart.InterruptImmunities.emplace();
+ spellChannelStart.InterruptImmunities->SchoolImmunities = schoolImmunityMask;
+ spellChannelStart.InterruptImmunities->Immunities = mechanicImmunityMask;
+ }
+
+ if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION) && m_casttime && m_caster->IsUnit())
+ {
+ WorldPackets::Spells::SpellTargetedHealPrediction& healPrediction = spellChannelStart.HealPrediction.emplace();
+ if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
+ healPrediction.TargetGUID = unitCaster->m_unitData->ChannelObjects[0];
+
+ UpdateSpellHealPrediction(healPrediction.Predict, true);
+ }
+
+ unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
}
void Spell::SendResurrectRequest(Player* target)
@@ -5594,6 +5696,9 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
return SPELL_FAILED_CUSTOM_ERROR;
}
+ if (m_spellInfo->HasAttribute(SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL) && !m_caster->IsPlayer())
+ return SPELL_FAILED_CASTER_AURASTATE;
+
// Check global cooldown
if (strict && !(_triggeredCastFlags & TRIGGERED_IGNORE_GCD) && HasGlobalCooldown())
return !m_spellInfo->HasAttribute(SPELL_ATTR0_COOLDOWN_ON_EVENT) ? SPELL_FAILED_NOT_READY : SPELL_FAILED_DONT_REPORT;
@@ -6920,7 +7025,7 @@ SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules()
return isArena ? SPELL_FAILED_NOT_IN_ARENA : SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND;
if (isArena && m_spellInfo->HasAttribute(SPELL_ATTR9_NOT_USABLE_IN_ARENA))
- return SPELL_FAILED_NOT_IN_ARENA;
+ return SPELL_FAILED_NOT_IN_ARENA;
// check cooldowns
uint32 spellCooldown = m_spellInfo->GetRecoveryTime();
@@ -8075,7 +8180,7 @@ bool Spell::IsPositive() const
bool Spell::IsNeedSendToClient() const
{
return m_SpellVisual.SpellXSpellVisualID || m_SpellVisual.ScriptVisualID || m_spellInfo->IsChanneled() ||
- (m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)) || m_spellInfo->HasHitDelay() || (!m_triggeredByAuraSpell && !IsTriggered()) ||
+ (m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT)) || m_spellInfo->HasHitDelay() || (!m_triggeredByAuraSpell && !IsTriggered()) ||
m_spellInfo->HasAttribute(SPELL_ATTR7_ALWAYS_CAST_LOG);
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 25f65e51759..b16bf1eb5e6 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -28,12 +28,10 @@
#include "SpellDefines.h"
#include <memory>
-namespace WorldPackets
+namespace WorldPackets::Spells
{
- namespace Spells
- {
- struct SpellCastData;
- }
+struct SpellCastData;
+struct SpellHealPrediction;
}
class Aura;
@@ -147,6 +145,14 @@ enum SpellCastSource : uint8
SPELL_CAST_SOURCE_SPELL = 16,
};
+enum SpellHealPredictionType : uint8
+{
+ SPELL_HEAL_PREDICTION_TARGET = 0,
+ SPELL_HEAL_PREDICTION_TARGET_AND_CASTER = 1,
+ SPELL_HEAL_PREDICTION_TARGET_AND_BEACON = 2,
+ SPELL_HEAL_PREDICTION_TARGET_PARTY = 3,
+};
+
enum SpellRangeFlag
{
SPELL_RANGE_DEFAULT = 0,
@@ -888,6 +894,7 @@ class TC_GAME_API Spell
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData& data);
int32 GetSpellCastDataAmmo();
+ void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& healPrediction, bool withPeriodic);
SpellCastResult CanOpenLock(SpellEffectInfo const& effect, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
// -------------------------------------------
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 541496075a1..9b4b12295e2 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -560,7 +560,7 @@ int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* targ
if (Scaling.Coefficient != 0.0f)
{
uint32 level = _spellInfo->SpellLevel;
- if (target && _spellInfo->IsPositiveEffect(EffectIndex) && (Effect == SPELL_EFFECT_APPLY_AURA))
+ if (target && _spellInfo->HasAttribute(SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING))
level = target->GetLevel();
else if (caster && caster->IsUnit())
level = caster->ToUnit()->GetLevel();
@@ -632,7 +632,12 @@ int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* targ
if (ContentTuningEntry const* contentTuning = sContentTuningStore.LookupEntry(contentTuningId))
expansion = contentTuning->ExpansionID;
- int32 level = caster && caster->IsUnit() ? int32(caster->ToUnit()->GetLevel()) : 1;
+ int32 level = 1;
+ if (target && _spellInfo->HasAttribute(SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING))
+ level = target->GetLevel();
+ else if (caster && caster->IsUnit())
+ level = caster->ToUnit()->GetLevel();
+
value = sDB2Manager.EvaluateExpectedStat(stat, level, expansion, 0, CLASS_NONE, 0) * BasePoints / 100.0f;
}
@@ -2034,6 +2039,20 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
return SPELL_FAILED_NOT_IN_RAID_INSTANCE;
}
+ if (HasAttribute(SPELL_ATTR8_REMOVE_OUTSIDE_DUNGEONS_AND_RAIDS))
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if (!mapEntry || !mapEntry->IsDungeon())
+ return SPELL_FAILED_TARGET_NOT_IN_INSTANCE;
+ }
+
+ if (HasAttribute(SPELL_ATTR8_NOT_IN_BATTLEGROUND))
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if (!mapEntry || mapEntry->IsBattleground())
+ return SPELL_FAILED_NOT_IN_BATTLEGROUND;
+ }
+
// DB base check (if non empty then must fit at least single for allow)
SpellAreaMapBounds saBounds = sSpellMgr->GetSpellAreaMapBounds(Id);
if (saBounds.first != saBounds.second)
@@ -2153,6 +2172,10 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
Unit const* unitTarget = target->ToUnit();
+ if (HasAttribute(SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR))
+ if (caster != target && caster->GetGUID() != target->GetOwnerGUID())
+ return SPELL_FAILED_BAD_TARGETS;
+
// creature/player specific target checks
if (unitTarget)
{
@@ -2203,6 +2226,10 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
}
}
}
+
+ if (HasAttribute(SPELL_ATTR8_ONLY_TARGET_OWN_SUMMONS))
+ if (!unitTarget->IsSummon() || unitTarget->ToTempSummon()->GetSummonerGUID() != caster->GetGUID())
+ return SPELL_FAILED_BAD_TARGETS;
}
// corpse specific target checks
else if (Corpse const* corpseTarget = target->ToCorpse())
@@ -2294,7 +2321,7 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT))
return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
- if (HasAttribute(SPELL_ATTR8_BATTLE_RESURRECTION))
+ if (HasAttribute(SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT))
if (Map* map = caster->GetMap())
if (InstanceMap* iMap = map->ToInstanceMap())
if (InstanceScript* instance = iMap->GetInstanceScript())