ShadowM wrote...
Ok is there a way to find the vfx persistent ID?
vfx_persistent.2da, the LABEL column:
LABEL SHAPE RADIUS WIDTH
LENGTH ONENTER ONEXIT HEARTBEAT
OrientWithGround DurationVFX MODEL01 MODEL02
MODEL03 NUMACT01 NUMACT02 NUMACT03 DURATION01
DURATION02 DURATION03 EDGEWGHT01 EDGEWGHT02 EDGEWGHT03
SoundImpact SoundDuration SoundCessation SoundOneShot
SoundOneShotPercentage MODELMIN01 MODELMIN02
MODELMIN03
0 VFX_PER_FOGACID C 5 ****
**** NW_S0_AcidFogA NW_S0_AcidFogB NW_S0_AcidFogC
0 **** vps_fogacid vps_fogacid
vps_fogacid 5 10 5 3400
1100 1900 0 0.25 0.25
**** sps_fog_loop **** sps_fog
0.3 vps_fogacid_L vps_fogacid_L
vps_fogacid_L
1 VFX_PER_FOGFIRE C 5 ****
**** NW_S0_IncCloudA NW_S0_IncCloudB NW_S0_IncCloudC
0 **** vps_fogfire vps_fogfire
vps_fogfire 5 5 5 3400
1100 1900 0 0 0.25
**** sps_fog_loop **** sps_fogfire
0.3 vps_fogfire_L vps_fogfire_L
vps_fogfire_L
2 VFX_PER_FOGSTINK C 6.7 ****
**** NW_S0_StinkCldA **** NW_S0_StinkCldC
0 **** vps_fogstink vps_fogstink
vps_fogstink 5 5 5 3400
1100 1900 0 0 0.25
**** sps_fog_loop **** sps_fog
0.3 vps_fogstink_L vps_fogstink_L
vps_fogstink_L
3 VFX_PER_FOGKILL
*snip*
Occasionally more than one spell will use the same paoe object tag, so you'll want to set spell id on them after they're cast, searching for the nearest aoe of the proper tag without a set spell id.
Is it possible to run all the heartbeat, enter, exit scripts through say with only three scripts? One for each type.
Just trying to save on resources of having the edited scripts.
Yes, though you're likely going to be better off with a more nuanced approach, depending on your needs. Here's our centralized paoe include, which at least keeps script sizes down, and eliminates duplicative code. Unlike most include scripts you'll see on these boards, the main() function is in the include, and the spell scripts contain plug-in functions - I'll show you a sample one. Also, I should note that this approach makes the aoe scripts unnecessary, because everything is handled in the pseudoheartbeat. First, the include:
#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 ();
int GetPersistentAoELimit (struct SpellInfo si);
int GetPersistentAoEEffect (struct SpellInfo si);
string GetPersistentAoETag (struct SpellInfo si);
string GetPersistentAoEName (struct SpellInfo si);
int GetPersistentAoETargetMask (struct SpellInfo si);
int GetPersistentAoETargetType (struct SpellInfo si);
float GetPersistentAoEDuration (struct SpellInfo si);
effect GetPersistentAoEImpactEffect (struct SpellInfo si);
effect GetPersistentAoEDurationEffect (struct SpellInfo si);
effect GetPersistentAoEVisualEffect (struct SpellInfo si);
void ApplyAoEEffect (struct SpellInfo si, object oAoE, object oTarget, effect eEff, effect eDur, effect eVis);
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);
}
And now, a sample aoe spellscript (acid fog, but with our custom edits):
#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 = GetReflexAdjustedDamage(nDamage, oTarget, si.dc, nSaveType, 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);
}
}
}
Now, you could obviously do the same, but just set all the paoe's to use the same scripts in the 2da, putting a switch in the script, but this way tends to be neater. LMK if you have any questions.
Funky
Modifié par FunkySwerve, 16 juin 2011 - 06:38 .