HenchSpells.2da editor (standalone) for Neverwinter Nights 2

not ready yet.

just kidding!



Nice. Is there a chance you will create something similar for henchracial.2da and henchclasses.2da also? I don’t think this would be a tough task (compared to henchspells.2da).

I’d like to … tbh that was the original idea … 3 editors in one. Then i started on Henchspells …

( i believe it is now functionally accessing all bits - and can output a valid HenchSpells.2da ) But the issue is that a field in the 2da is not simply what it is labeled as … a few of the master-ints have been multi-purposed; “DamageInfo” for example can hold damage-info, dispel-info, or buff-info. The bit-places mean different things depending on how the DamageInfo master-int is accessed by the AI - in other words the bits overlap and so are should be considered as exclusive to the type/mode. And “SaveType” looks like it’s been quadruple-purposed …

So while the editor seems functional I still want to group things to make more sense. For example, show/hide bit-groupings according to what spelltype has been chosen on the SpellInfo page.

yeh, Racial and Classes should be a welcome breeze next to that. /shrug

Once i’m reasonably content w/ Spells – who knows when – would like to implement the other two as sub-modes of operation in the same executable. But if that’s troublesome i’ll do an executable for each, barring burn-out/unforeseen circumstances etc.

this is what i’m currently prodding at

See the beneficial-group on the right? Those values have nothing to do with saves. They are damage immunity/resistance info instead (ie, for a buff spell). But the bits for SaveType are of course valid if interpreted that way by the core scripts. not so valid otherwise …

Then, along the bottom, there’s WeaponType and AcBonusType. They make no sense for Cloudkill lol – but neither do they make sense for a spell such as Endure Elements. I have yet to figure out exactly when to show/hide different bit-groupings that are in fact the same master-int.


preview of the ReadMe

1 Like


An editor for HenchSpells.2da


it’s getting close …

(commit history)

HenchRacial and HenchClasses are in. One executable. But not released quite yet.

There’s still some twiddling to do with what’s called Info Version – apparently every entry in each 2da gets a “version” assigned. It seems to be useful for behind-the-scene debugging only. That is if you’re playing a module and make changes to an entry, the info-version of that entry can be bumped up (or down tbh) so that an updated version of the entry will be cached on the module-object (and used instead of the previous data).

The other thing I want to do concerns the fact that neither HenchRacial nor HenchClasses have a “label” column. So when they’re open in the editor all you get is an ID # for RacialSubtypes.2da or Classes.2da … not sure how to cope with that (or if i will even)

option 1 is to create a hardcoded manifest w/ labels for Races and Classes …
option 2 is to copy those two 2das to the editor’s folder and parse out labels from them …
option 3 is use a config-file
option 4 is procrastinate – look up the labels for the IDs in the 2das by opening the 2das.
option 5 is put in an Option that can hold the paths of RacialSubtypes.2da and Classes.2da (as long as they’re not still zipped in the NwN2 installation folder) and parse out labels from them …

NOTE: it’s the user’s responsibility to ensure that corresponding 2das actually remain in sync

after that there’s merely tidying and perhaps small refactors

/carry on

Maybe show a popup message (when the program starts for the first time) with the following text: “Would you like to display labels for classes/races? If so, please specify manually the pathes to the corresponding 2da files in the settings menu”? It fits to the option 5 from the list above. I believe it’s the best choice.

After all, it should be a completely optional feature.

For people like me who don’t know what those 2da files do, what does this do in game terms?

that’s what i’m thinking atm. but probly without the prompt. The thing to note, however, is that those paths won’t be saved (unless they’re written to a .ini/.cfg file – but I really don’t want to create any extra/settings files).

Ie, as long as the app is open the paths would be retained. Close the app and ~poof~

Anyway it’s not a pressing concern since option 4 is available.

The hench*.2da files store data about spells/races/classes. The CoreAI scripts will use that data to decide what NPCs/creatures are going to do in combat.

If a spell is flagged as having an “immunity to” … the AI is less likely to cast that spell against a creature that has that Immunity.

Or if a spell is flagged as a “long duration buff” and player has that option turned on their character sheet’s Behaviors tab – auto cast long duration buffs – then creatures which have that spell memorized will auto-cast it at the start of combat.

There are flags for DC-calculation of spells so that the AI can do a preliminary test against an opponent, to check if there’s any point in trying to stick a particular spell on said opponent.

(the AI does a lot of cheating … if it’s working correctly.)

Regarding Classes/Races: they tell the AI what feats are available (Barbarians get Rage eg.) and whether the NPC/creature is a caster and if so is it an arcane or divine caster and what bonuses it gets to DC etc. But i’m not as sure about how the AI uses Races/Classes data as spells-data.

I mean such data about race and class should be on the creature already … but perhaps the 2da-info is shorthand, go-to information.

tl;dr – this editor is for people who want to tweak the NwN2 ai on a global level BUT it edits only the 2das. The real work happens in the CoreAI scripts

That said, it allows custom (brand new and/or ill-defined) spells/feats/races/classes to at least get a foothold in the AI …

oh, something I should note … (there’s a billion things to note…)

The AI that i’m talking about is called by





Check a creature’s standard AI-scripts to see which one it’s using. I believe the stock scripts for Companions/Associates use the HenchDCR, while the stock scripts for NPCs/monsters ( nw_c2_default* ) call the old, nwn1 DCR routines.

That’s beyond my purview however, am just mentioning it,

@Aqvilinus - very basic atm


now it’s cookin w/ mustard  :)


how does the monster ai determine which spell to cast in a given situation? is there a congruent 2da to weight spells, and if so, will you include it within your editor?

btw really nice work you did there!

it seems to use the hardcoded tTalent functions, eg: GetCreatureTalentBest()

There’s a lot of scripted decision-making going on in ‘nw_i0_generic’ etc. before the talent calls tho. And it will sometimes straightforwardly script things out;

if (should I go invisible && can I go invisible) ActionCastSpell(invis)

tbh i’ve changed all calls from DCR to hDCR and don’t notice much difference. I mean i’m sure there’s a lot of difference, but gameplay-wise the Nwn1 ai that Nwn2 inherited is a good AI.

no. uh no

Perhaps you’ve heard of the “X2_L_BEH” variables, those are for weighting what creatures do in the Monster/NPC (nwn1) ai:


(they don’t work in the advanced AI however.)

i do know about the switches. afaik they only weight actions on a global level, like casting a spell without assessing which spell would be best. still, thanks for explaining, and your work on the editor of course.

really sure those ‘switches’ – they’re not actually switches even though constant variable labels are defined in ‘x2_inc_switches’ – they’re actually integer-values that modify base values which are defined in the nwn1 scripts. (a guy gets kinda familiar with this stuff after staring at it for hundreds of hours…) Anyway, really sure that they’re per creature, used by

CalculateTactics() // nwn1 core-ai funct.

you’ve reminded me that I should, since my copy of the game uses only the Nwn2 Ai, re-implement those ‘switches’ in some fashion … thanks.

And the extended editor should be up either today or tomorrow, depending on how many more holes to fix*


ver 1.2.12


2020 jul 14

- trim 2da rows before attempting to parse them (prevent throwing an exception on some loosely formatted 2da files)