You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Current »

A special option for visual effects in NWN (does not need to be EE) is to align them with the head model, allowing the user to create eye, hair, hat, and horn accessories.

This feature was first used in v1.64 of the original game for unit aligned flags (lines 303 to 306 of visualeffects.2da) and was later expanded to head-aligned eye effects for all races (lines 324 to 336 in visualeffects.2da)

The important parts of the visualeffects.2da entry are the columns "Imp_HeadCon_Node" and "OrientWithObject".

A modern use of head-aligned vfx is to produce equipment-driven head accessories such as hats, hair, or horns, though there are many other options.

Getting Started

Before you get started, you'll need to have a model to work with. It can be effectively any model, like an eyepatch, horns, or even just a basic visual effect. This tutorial will not cover making such things, but you can find ample content on the Vault, or pull something useful out of the original content.

The files you'll need to edit include:

  • VISUALEFFECTS.2DA

If you need a copy of those files for your override or development folder, you can extract them using NWN Explorer for EE. ** Which may require special setup **

As of the time of this writing, the 2DA files are located under NWN Main Data > data\base_2da\ > Game Data. Find those two files and export them to your preferred location for development.

Building the Visual Effects Line

The next thing you want to do is open VISUALEFFECTS.2DA in your text editor or 2DA reader.

Copy the line below and append it to the bottom of your spreadsheet:

324 <new_vfx_label_here> D 0 <new_vfx_filename_here> **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** 1


Note the ID number given here is 324. Replace that with whatever your new line ID would be. (tip: in Notepad++ usually equals line number minus 4)

Modify the following parts above:

  • <new_vfx_label_here>: this is just a label, though it may also equate to a NwScript constant you create for later use.
  • <new_vfx_filename_here>: the filename of your head-aligned model

Getting It In the Game

If you did everything correctly, and your new files are either in Override or Development folder, you should be able to make use of your new visual effect gear.

You'll now need to apply a new visual effect. There are many options, including tag-based on-equip scripts, or on-use item unique properties.

Tag-Based On-Equip Scripts

Within the NWN Toolset, on your module properties panel, you'll see a tab called "Events". In the list of events, you'll see two events: OnPlayerEquipItem and OnPlayerUnEquipItem.

These events use some expansion 2 scripts by default: "x2_mod_def_equ" and "x2_mod_def_unequ" respectively.

They rely on the module flag MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS being set to TRUE.

That switch can be enabled by setting a module INT of name "X2_SWITCH_ENABLE_TAGBASED_SCRIPTS" to 1, or by calling one of the following on module load:

  • SetLocalInt (GetModule(), "X2_SWITCH_ENABLE_TAGBASED_SCRIPTS", 1);
  • SetLocalInt (GetModule(), MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS, 1);
  • SetModuleSwitch("X2_SWITCH_ENABLE_TAGBASED_SCRIPTS", TRUE);
  • SetModuleSwitch(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS, TRUE);

If you are using the default module OnModuleLoad script "x2_mod_def_load", you'll notice that on line 89, tag-based scripts are already enabled by default, so none of the above would be needed.

To use this power, simply set the item TAG equal to the name of the script to call. For example if you have an item called Hat01 that applies a special hat appearance, then you might want to make a script named "it_hat01" and set the tag on the hat to the same.

On-Use Unique Item Properties

As another option, you can give the host item the property "Cast Spell > Unique Power Self Only". When cast, this item power will call the event X2_ITEM_EVENT_ACTIVATE which can also be handled in your tag-based script.

The X2_IT_EXAMPLE Script

The toolset already comes with an example script showing all the events that will run to the tag-based script. You can open "X2_IT_EXAMPLE" in the toolset script editor.

The most important events here are:

  • X2_ITEM_EVENT_ACTIVATE: called when the Unique Power spell is cast
  • X2_ITEM_EVENT_EQUIP: called when the item is equipped
  • X2_ITEM_EVENT_UNEQUIP: called when the item is unequipped

Managing the Current Effect With Local Variables

Because a player could activate multiple head-based effects at once, it is important to manage the current visual effect by storing it in a local variable on the player.

Already applied effects for any particular "Fashion" slot will need to be removed before any new one is added, or effects will stack visually, becoming messy, or too strong.

In your event-handling tag-based script, you might use a script like this, which stores an effect tag on the effect and in a "slot" variable on the PC.


#include "x2_inc_switches"

// This script runs when a pc activates an item with the tag IT_HAT01
// The script toggles the visual effect IT_HAT01 on the activator

//Applies the specified Fashion VFX to oTarget in slot sEffectSlotName, and tags the effect with sEffectTag
void ApplyFashionEffectToObject(object oTarget, int nEffectID, string sEffectSlotName, string sEffectTag);
void ApplyFashionEffectToObject(object oTarget, int nEffectID, string sEffectSlotName, string sEffectTag)
{
    effect eEffect = EffectVisualEffect(nEffectID);
    eEffect = SupernaturalEffect(eEffect);
eEffect = TagEffect(eEffect, sEffectTag);
   ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEffect, oTarget);
    SetLocalString(oTarget, sEffectSlotName, sEffectTag);
}

//Removes all visual effects from oTarget having tag equal to sEffectTag
void RemoveFashionEffectFromObjectByTag(object oTarget, string sEffectTag);
void RemoveFashionEffectFromObjectByTag(object oTarget, string sEffectTag)
{
if (sEffectTag != "")
{
effect eLoop = GetFirstEffect(oTarget);
while (GetIsEffectValid(eLoop)) {
if (GetEffectType(eLoop) == EFFECT_TYPE_VISUALEFFECT)
if (GetEffectTag(eLoop) == sEffectTag)
RemoveEffect(oTarget, eLoop);
eLoop = GetNextEffect(oTarget);
}
}
}

//Removes all visual effects from oTarget having the tag associated with the
//Fashion VFX applied in slot sEffectSlotName on oTarget
void RemoveFashionEffectFromObjectBySlot(object oTarget, string sEffectSlotName);
void RemoveFashionEffectFromObjectBySlot(object oTarget, string sEffectSlotName)
{
string sEffectTag = GetLocalString(oTarget, sEffectSlotName);
RemoveFashionEffectFromObjectByTag(oTarget, sEffectTag);
}

//Removes all visual effects from oTarget having the specified tag sEffectTag,
//or the tag associated with the Fashion VFX applied in slot sEffectSlotName on oTarget,
//then applies the specified Fashion VFX nEffectID to oTarget in slot sEffectSlotName,
//and tags the effect with sEffectTag
void SafeApplyFashionEffectToObject(object oTarget, int nEffectID, string sEffectSlotName, string sEffectTag);
void SafeApplyFashionEffectToObject(object oTarget, int nEffectID, string sEffectSlotName, string sEffectTag)
{
    RemoveFashionEffectFromObjectBySlot(oTarget, sEffectSlotName);
    RemoveFashionEffectFromObjectByTag(oTarget, sEffectTag);
ApplyFashionEffectToObject(oTarget, nEffectID, sEffectSlotName, sEffectTag);
}


void main()
{
    int nEvent = GetUserDefinedItemEventNumber();
    object oPC;
object oItem;

    if (nEvent == X2_ITEM_EVENT_ACTIVATE) {
oPC = GetItemActivator();
oItem = GetItemActivated();

string sTag = GetTag(oItem);
int nEffectID = 324; //modify this to reflect your new visualeffect line number
string sEffectSlotName = "FASHION_SLOT_HEAD"; //customize this to fit your needs

SafeApplyFashionEffectToObject(oPC, nEffectID, sEffectSlotName, sTag);
}
}

Conclusion

A script like this could be used to designate many Fashion VFX slots, such as eyes, horns, or even beard.

If combined with ProgFX Type 12 Fashion Accessories, additional slots could be made for any number of new Dummy nodes added to the phenotype base model (ie. "pmh0.mdl"),

In the script above, the top portion of functions can be placed into an include-able file, such as "inc_fashionvfx" and called from every item handling script.

Items can also store variables, so the nEffectID and sEffectSlotName might also be stored in the item variables list and could be customizeable through crafting.

A more powerful effect application script could be produced allowing any one item to apply multiple effects. A builder would simply need to store a variable on the item "vfxCount", and then cycle through all the local variables to find "vfx<X>" where <X> would be replaced with values 1 to vfxCount. SafeApplyFashionEffectToObject or ApplyFashionEffectToObject could then be looped for each VFX being applied.

  • No labels