Our custom AOE scripts have workarounds for those issues - you set the needed info on the aoe at time of casting, and check it instead of calling on the buggy functions. Code is acaos'. You'll have to disregard references to Herald of Storms - it's one of our quasis. Likewise, the #pragma stuff is for Skywing's compiler, which won't allow includes to contain void mains otherwise. I'll post the include first, then the acid fog spell:
ac_aoeper_inc
#include "hg_inc"
#include "ac_spell_inc"
int GetIsHeraldAoE(object oAoE) {
string sTag = GetTag(oAoE);
if (sTag == "VFX_PER_FOGFREEZE" ||
sTag == "VFX_AOE_CONSECRATE_20" ||
sTag == "VFX_PER_FOGACID" ||
sTag == "VFX_PER_FOGKILL" ||
sTag == "VFX_PER_FOGMIND" ||
sTag == "VFX_PER_FOGSTINK")
return TRUE;
return FALSE;
}
struct SpellInfo GetPersistentAoESpellInfo ();
#pragma default_function(GetPersistentAoESpellInfo)
int GetPersistentAoELimit (struct SpellInfo si);
#pragma default_function(GetPersistentAoELimit)
int GetPersistentAoEEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEEffect)
string GetPersistentAoETag (struct SpellInfo si);
#pragma default_function(GetPersistentAoETag)
string GetPersistentAoEName (struct SpellInfo si);
#pragma default_function(GetPersistentAoEName)
int GetPersistentAoETargetMask (struct SpellInfo si);
#pragma default_function(GetPersistentAoETargetMask)
int GetPersistentAoETargetType (struct SpellInfo si);
#pragma default_function(GetPersistentAoETargetType)
float GetPersistentAoEDuration (struct SpellInfo si);
#pragma default_function(GetPersistentAoEDuration)
effect GetPersistentAoEImpactEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEImpactEffect)
effect GetPersistentAoEDurationEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEDurationEffect)
effect GetPersistentAoEVisualEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEVisualEffect)
void ApplyAoEEffect (struct SpellInfo si, object oAoE, object oTarget, effect eEff, effect eDur, effect eVis);
#pragma default_function(ApplyAoEEffect)
float GetPersistentAoERemaining (object oAoE) {
int nRemaining = GetLocalInt(oAoE, "AoEExpires") - GetLocalInt(GetModule(), "uptime");
return IntToFloat(nRemaining < 1 ? 1 : nRemaining);
}
void DoAoEHeartbeat (struct SpellInfo si, object oAoE, effect eEff, effect eDur, effect eVis) {
int bDestroy = FALSE, bAllPCs = FALSE;
if (!GetIsObjectValid(oAoE))
return;
/* Storm of Vengeance doesn't destroy properly sometimes */
if (GetPersistentAoEEffect(si) == AOE_PER_STORM) {
if (si.id == SPELL_STORM_OF_VENGEANCE && GetLocalInt(GetArea(oAoE), "Area_Underwater"))
bAllPCs = TRUE;
if (GetLocalInt(GetModule(), "uptime") > GetLocalInt(oAoE, "AoEExpires"))
bDestroy = TRUE;
}
if (bDestroy ||
!GetIsObjectValid(si.caster) ||
GetIsDead(si.caster) ||
GetArea(si.caster) != si.area) {
SetPlotFlag(oAoE, FALSE);
DestroyObject(oAoE);
return;
}
DelayCommand(6.0, DoAoEHeartbeat(si, oAoE, eEff, eDur, eVis));
AddLocalInt(oAoE, "AoERounds", 1);
if (!LineOfSightObject(oAoE, si.caster))//PAoEs have no effect when caster out of LoS
return;
si.target = oAoE;
int nMask = GetPersistentAoETargetMask(si);
int nType = GetPersistentAoETargetType(si);
for (si.target = GetFirstInPersistentObject(oAoE, nMask);
GetIsObjectValid(si.target);
si.target = GetNextInPersistentObject(oAoE, nMask)) {
if (GetIsSpellTarget(si, si.target, nType) || (bAllPCs && GetIsPC(si.target))) {
SignalEvent(si.target, EventSpellCastAt(si.caster, si.id));
AssignCommand(si.caster, DelayCommand(GetRandomDelay(0.5, 4.5), ApplyAoEEffect(si, oAoE, si.target, eEff, eDur, eVis)));
}
}
}
void StartAoEHeartbeat (struct SpellInfo si, string sTag, effect eEff, effect eDur, effect eVis, int nUntil) {
int nCount = 1;
object oLoc, oAoE;
do {
oLoc = GetNearestObjectToLocation(OBJECT_TYPE_ALL, si.loc, nCount++);
} while (GetTag(oLoc) == sTag);
nCount = 1;
oAoE = GetNearestObjectByTag(sTag, oLoc);
while (GetIsObjectValid(oAoE)) {
if (GetAreaOfEffectCreator(oAoE) == si.caster && !GetLocalInt(oAoE, "AoEHeartbeat")) {
SetLocalInt(oAoE, "AoEHeartbeat", 1);
SetLocalInt(oAoE, "AoEExpires", nUntil);
SetLocalInt(oAoE, "AoESP", si.sp);
DelayCommand(0.0, DoAoEHeartbeat(si, oAoE, eEff, eDur, eVis));
return;
}
oAoE = GetNearestObjectByTag(sTag, oLoc, ++nCount);
}
}
void main () {
struct SpellInfo si = GetPersistentAoESpellInfo();
if (si.id < 0)
return;
float fDur = GetPersistentAoEDuration(si);
string sTag = GetPersistentAoETag(si);
effect eAoE = EffectAreaOfEffect(GetPersistentAoEEffect(si),
(si.id == SPELL_GREASE ? "nw_s0_greasea" : "****"), "****", "****");
int nLimit = GetPersistentAoELimit(si);
if (nLimit > 0) {
int nFound = 0, nCount = 1;
object oOther, oCreator, oArea = GetArea(si.caster);
while (GetIsObjectValid(oOther = GetNearestObjectByTag(sTag, si.caster, nCount++))) {
oCreator = GetAreaOfEffectCreator(oOther);
if (oCreator == oArea ||
GetLocalInt(oOther, "NoAoEDispel"))
continue;
if (GetIsPC(si.caster) && GetIsPC(oCreator)) {
if (GetIsHeraldAoE(oOther)) {
if (!GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, oCreator))
nFound++;
} else
nFound++;
} else if (GetFactionEqual(si.caster, oCreator)) {
nFound++;
}
if (nFound >= nLimit) {
SetPlotFlag(oOther, FALSE);
DestroyObject(oOther);
if (nFound == nLimit)
FloatingTextStringOnCreature("To prevent lag, only " +
IntToString(nLimit) + " " + GetPersistentAoEName(si) +
" spell" + (nLimit == 1 ? "" : "s") + " may exist in an area at the same time.", si.caster);
}
}
} else if (nLimit == -1) {
object oAoE, oCreator, oArea = GetArea(si.caster);
for (oAoE = GetFirstObjectInArea(oArea); GetIsObjectValid(oAoE); oAoE = GetNextObjectInArea(oArea)) {
oCreator = GetAreaOfEffectCreator(oAoE);
if (GetObjectType(oAoE) != OBJECT_TYPE_AREA_OF_EFFECT ||
oCreator != si.caster)
continue;
if (GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, oCreator) && //heralds ignore herald spells in this check - that limit handled in -2
GetIsHeraldAoE(oAoE))
continue;
if (FindSubString(" VFX_PER_FOGACID VFX_PER_FOGFIRE VFX_PER_FOGFREEZE VFX_PER_STORM VFX_PER_RAINFIRE VFX_PER_RAINFREEZE VFX_AOE_CONSECRATE_20 ",
" " + GetTag(oAoE) + " ") >= 0) {
SetPlotFlag(oAoE, FALSE);
DestroyObject(oAoE);
FloatingTextStringOnCreature("Only one area of effect damage field may exist per caster in an area at the same time.", si.caster);
}
}
} else if (nLimit == -2) {
object oAoE, oArea = GetArea(si.caster);
int nFound;
for (oAoE = GetFirstObjectInArea(oArea); GetIsObjectValid(oAoE); oAoE = GetNextObjectInArea(oArea)) {
if (GetObjectType(oAoE) != OBJECT_TYPE_AREA_OF_EFFECT ||
!GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, GetAreaOfEffectCreator(oAoE)))
continue;
if (FindSubString(" VFX_PER_FOGACID VFX_PER_FOGSTINK VFX_PER_FOGKILL VFX_AOE_CONSECRATE_20 VFX_PER_FOGFREEZE VFX_PER_FOGMIND ",
" " + GetTag(oAoE) + " ") >= 0) {
nFound++;
if (nFound >= 2) {
SetPlotFlag(oAoE, FALSE);
DestroyObject(oAoE);
if (nFound == 2)
FloatingTextStringOnCreature("Only two herald of storms clouds may exist in an area at the same time.", si.caster);
}
}
}
}
effect eEff = GetPersistentAoEImpactEffect(si);
effect eDur = GetPersistentAoEDurationEffect(si);
effect eVis = GetPersistentAoEVisualEffect(si);
AssignCommand(si.area, DelayCommand(2.0, StartAoEHeartbeat(si, sTag, eEff, eDur, eVis,
GetLocalInt(GetModule(), "uptime") + FloatToInt(fDur))));
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAoE, si.loc, fDur);
}
nw_s0_acidfog
#include "ac_aoeper_inc"
struct SpellInfo GetPersistentAoESpellInfo () { return GetSpellInfo(); }
int GetPersistentAoELimit (struct SpellInfo si) {
if (GetIsQuasiSpell(si, QUASIclass_HERALD_OF_STORMS))
return -2;
return -1;
}
int GetPersistentAoEEffect (struct SpellInfo si) { return AOE_PER_FOGACID; }
string GetPersistentAoETag (struct SpellInfo si) { return "VFX_PER_FOGACID"; }
string GetPersistentAoEName (struct SpellInfo si) { return "Acid Fog"; }
int GetPersistentAoETargetMask (struct SpellInfo si) { return OBJECT_TYPE_CREATURE; }
int GetPersistentAoETargetType (struct SpellInfo si) { return TARGET_TYPE_DEFAULT; }
float GetPersistentAoEDuration (struct SpellInfo si) {
return MetaDuration(si, si.clevel / 2, DURATION_IN_ROUNDS);
}
effect GetPersistentAoEImpactEffect (struct SpellInfo si) {
effect eEff;
return eEff;
}
effect GetPersistentAoEDurationEffect (struct SpellInfo si) {
effect eDur;
if (GetIsQuasiSpell(si, QUASIclass_HERALD_OF_STORMS))
eDur = EffectDamageIncrease(1);
return eDur;
}
effect GetPersistentAoEVisualEffect (struct SpellInfo si) {
ApplyVisualAtLocation(VFX_FNF_GAS_EXPLOSION_ACID, si.loc);
return EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_ACID);
}
void ApplyAoEEffect (struct SpellInfo si, object oAoE, object oTarget, effect eEff, effect eDur, effect eVis) {
if (!GetSpellResisted(si, oTarget, 0.0, 2)) {
int nDamage, nDice = si.clevel, nEffType = GetEffectType(eDur);
int nDamType = DAMAGE_TYPE_ACID, nSaveType = SAVING_THROW_TYPE_ACID;
if (nDice < 1)
nDice = 1;
nDamage = MetaPower(si, nDice, 6);
nDamage = GetEvasionAdjustedDamage(nDamage, oTarget, si.dc, nSaveType|SAVING_THROW_FLAG_SPELL, si.caster);
if (nDamage > 0) {
if (nEffType == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE) {
if (!GetHasSpecificEffect(eDur, oTarget))
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDur, oTarget);
eEff = EffectDamage(nDamage / 2, nDamType);
DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget));
eEff = EffectDamage(nDamage / 2, DAMAGE_TYPE_MAGICAL);
DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget));
} else if (nEffType == EFFECT_TYPE_DAMAGE_INCREASE) {
if (GetTrueDamageImmunity(oTarget, nDamType) < 100) {
int nDecrease = 25 - GetTotalDamageImmunityDecrease(oTarget, nDamType);
if (nDecrease > 5)
nDecrease = 5;
if (nDecrease > 0) {
eEff = EffectDamageImmunityDecrease(nDamType, nDecrease);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oTarget);
}
}
eEff = EffectDamage(nDamage, nDamType);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget);
} else {
eEff = EffectDamage(nDamage, nDamType);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget);
}
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
}
}
}
Funky