The vfx_persistent.2da controls the default scripts and the size, shape and VFX of area of effect objects you can create.

AOE Inner Workings

EffectAreaOfEffect is used to generate area of effects in game. These have two different applications - to a location (non-moving) or to a creature object (moving).

They are special objects - you can't create them any other way. They're not quite effects and not quite full objects - they're instead a weird mix of both.

In most cases you do need to have a valid AOE creator for these to function correctly. In some cases the creator can be destroyed or logged out but it usually causes Weird Things(TM) to happen, usually regarding effects created from the AOE's themselves.

The below hasn't been fully tested but should be assumed - in NWN:EE some fixes were put in place for AOE objects. There may be other fixes also needed.

Both Types Properties

  • Exist as an OBJECT_TYPE_AREA_OF_EFFECT and searchable specifically with GetFirstObjectInShape and GetNearestObject (yes both movable and non-movable ones)
  • Has a tag matching the "LABEL" column and findable using GetObjectByTag and GetNearestObjectByTag
    • This is also - without further interaction - the only way to get the bounding sizes and other properties
  • Has special properties set on it regarding:
    • The creator (the object the script applying the effect was called from) returned by GetAreaOfEffectCreator(OBJECT_SELF)
    • The event scripts: On Enter, On Exit and Heartbeat - done from the script command or the 2da line - there is also a User Defined Event apparently available, but cannot be set at inception but later can with SetEventScript (needs testing!)
    • The size and shape of it from the 2da entry
    • The duration remaining (not sure this can be retrieved unless it's a mobile one)
    • The spell ID which is used when applying effects (so they can be accurately removed later) - however GetSpellId() fails, instead use GetEffectSpellId(EffectDazed()) as a workaround
    • The spell save DC - should set to the right amount when GetSpellSaveDC is called, and should in later versions of NWN:EE correctly save
    • The caster level - should be set to the right amount when using ResistSpell
      • GetCasterLevel() (any variant) does not work properly and changes as new spells are cast even in NWN:EE
      • Effects applied by an AOE in has no caster level set (making them always dispellable). Note that effects caused by an AOE usually should only be removed when the AOE itself is - if coded well this will always be the case - so could be made extraordinary instead.
  • If the AOE calls EventSpellCastAt it will use the creator, not itself, as the caster
  • If the AOE applies an effect apparently (needs fully testing - in the case of now-invalid casters also!) it gets created with the correct spell ID and that the creator is GetAreaOfEffectCreator.

Moving Object Properties

  • Applied as an effect that is searchable by GetFirst/NextEffect and can be removed with RemoveEffect and DispelMagic functions. The duration is tracked here instead and is retrievable.
  • Will be moving with the object it is applied to - although is known to "Lag behind" meaning the creature moves outside of the AOE area and the OnExit event removes it. This is especially true if the creature is moving fast or there are just a lot of things going on and the AOE just...doesn't update it's location.
    • Think of it as a check that does JumpToLocation(GetLocation(GetAreaOfEffectCreator(OBJECT_SELF))) done...intermittently

Static Location Properties

  • An orientation is properly set (especially relevant for square and rectangular areas)

Scripts

There are actually 4 event scripts, 3 defined in vfx_persistent.2da and apparently an On User Defined one.

  • OnEnter - fired when a object enters
  • OnExit - fired when an object leaves, or when the AOE is destroyed/expires and the objects all "leave" it
  • OnHeartbeat - fired roughly every round (6 seconds) to apply continual effects for those with in
  • OnUserDefined - when SignalEvent is used on the object and it is of type UserDefinedEvent.

Hardcoded Aspects

Line 7 VFX_PER_WALLBLADE is the only persistent VFX that enables environmental mapping on the model. Sadly we can't bypass this with progfx.2da unhardcoding.

It doesn't appear any other line is hardcoded.

Cut Persistent VFX

Like how Law/Chaos variants of Protection from Good/Evil were removed, it appears Circle of Law and Circle of Chaos was planned (lines 14 and 15).

Mobile AOEs and "The target exiting their own AOE"

Mobile AOEs (usually cast on self) if they don't get their position updated can mean the person moving around can move out of them - especially if at high speed in a small AOE object or on a laggy server.

Since removing all effects from the spell removes the AOE itself this is a fun time when a bard manages to stop singing because they ran outside of their own singing AOE!

A workaround is to never remove effects from the AOE OnExit event unless the effect has been removed from the caster (ie it has dispelled or expired) since the order goes:  Effect removed → Fire on Exit of AOE → Destroy AOE object.

Scripts and overlapping AOEs and dispel magic/RemoveEffect notes

There are some oddities when AOEs overlap. This needs more thorough testing and there are now also a fair chunk of different ways to identify a specific AOE's effects, eg; by tagging effects.

2da Columns

Column NameExampleValid ValuesDescription and Notes
LABELVFX_PER_FOGACIDText that matches a tag format

For once a LABEL column that is actually used by the game! This column is used to set the tag of the created AOE object.

Tags are usually upper case, with no spaces.

Bioware signifies "VFX_PER_" as "persistent", applied to the ground, and VFX_MOB_ as "mobile" - ie applied to a creature.

SHAPEC

C - Circular

R - Retangular

There doesn't appear to be any other options, but C and R cover most use cases.
RADIUS5Float value

Radius in meters if SHAPE is C.

This is used both for the edge where On Enter is triggered/objects are considered inside the AOE, but also for the VFX limits if MODEL01/MODEL02/MODEL03 is used.

WIDTH10Float value

Width in meters if SHAPE is R

This is used both for the edge where On Enter is triggered/objects are considered inside the AOE, but also for the VFX limits if MODEL01/MODEL02/MODEL03 is used.

LENGTH2Float value

Length in meters if SHAPE is R

This is used both for the edge where On Enter is triggered/objects are considered inside the AOE, but also for the VFX limits if MODEL01/MODEL02/MODEL03 is used.

ONENTERNW_S0_AcidFogAResref of script NSS fileOn Enter script that fires when an object enters the area. Bioware ones are signified by "A"
ONEXITNW_S0_AcidFogBResref of script NSS fileOn Exit script that fires when an object leaves the area (also happens if the AOE duration runs out or it is destroyed). Bioware ones are signified by "B"
HEARTBEATNW_S0_AcidFogCResref of script NSS fileOn Heartbeat script that fires when 6 seconds has elapsed (so "once per round") if the AOE object gets proper updates mind you (See: issues above). Bioware ones are signified by "C".
OrientWithGround00 or 1Presumably causes the VFX to be orientated with the ground, so on slopes it'd be flat against the slope. No default AOE Bioware uses has this turned on, probably because it'd look weird.
DurationVFX230visualeffects.2da line referenceA large, single VFX that is applied to the position of the VFX when the AOE is in place. Many that use this option do not use the other options in this list.
MODEL01vps_fogacidResref of VFX modelIf MODEL01 is defined then NUMACT01 amounts are spawned for DURATION01 milliseconds randomly in the area with EDGEWGHT01 affecting how close to the edge they are.
MODEL02vps_fogacidResref of VFX modelIf MODEL02 is defined then NUMACT02 amounts are spawned for DURATION02 milliseconds randomly in the area with EDGEWGHT02 affecting how close to the edge they are.
MODEL03vps_fogacidResref of VFX modelIf MODEL03 is defined then NUMACT03 amounts are spawned for DURATION03 milliseconds randomly in the area with EDGEWGHT03 affecting how close to the edge they are.
NUMACT015Integer amountAmount of MODEL01 VFX models to spawn
NUMACT0210Integer amountAmount of MODEL02 VFX models to spawn
NUMACT035Integer amountAmount of MODEL03 VFX models to spawn
DURATION013400Integer millisecondsAmount of time MODEL01 VFX models stay for
DURATION021100Integer millisecondsAmount of time MODEL02 VFX models stay for
DURATION031900Integer millisecondsAmount of time MODEL03 VFX models stay for
EDGEWGHT0100.0 - 1.0 floatEdge weight of MODEL01 VFX inside the AOE shape
EDGEWGHT020.250.0 - 1.0 floatEdge weight of MODEL02 VFX inside the AOE shape
EDGEWGHT030.250.0 - 1.0 floatEdge weight of MODEL03 VFX inside the AOE shape
SoundImpactsps_darknessResref of sound fileA one time single shot sound effect played at the location of where the AOE is spawned
SoundDurationsps_fog_loopResref of sound fileA repeating constantly playing sound effect centered on the location where the AOE is
SoundCessation****Resref of sound fileA one time single shot sound effect played at the location of where the AOE is when it is removed from the game (end of duration/DestroyObject)
SoundOneShotsps_fogResref of sound fileA sound that apparently repeatedly randomly plays each round
SoundOneShotPercentage0.30.0 - 1.0 floatPercentage chance (per round?) to play the SoundOneShot VFX
MODELMIN01vps_fogacid_LResref of VFX modelReplaces MODEL01 if present and is on Low Quality Graphics mode
MODELMIN02vps_fogacid_LResref of VFX modelReplaces MODEL02 if present and is on Low Quality Graphics mode
MODELMIN03vps_fogacid_LResref of VFX modelReplaces MODEL03 if present and is on Low Quality Graphics mode
  • No labels