NWN 2da hex tutorial

Submitted by Rork on Mon, 02/01/2021 - 18:28

Let's have a look at hexadecimals and how they can be used for configurations.

When looking at Neverwinter Nights's 2da configuration several values have a hexadecimal format (0x##). Hexadecimals are a numeric system which use values from 0 to F normally written as 0x0 - 0xF, whereas 0 - 9 are the standard 0 - 9, 0xA = 10 and 0xF = 15. After 0xF it works like normal numerals so a one takes the 'ten place': 0x10 (= 16) up to 0xFF (= 255) and 0x100 (=256) etc.

One of the columns that use hexadecimals is AlignRestrict in classes.2da. In which 0x01 stands for neutral, 0x02 for lawful, 0x04 for chaotic. 0x08 for good and 0x10 for evil. The reason why these numbers jump can easily be seen if they are translated to binary, see the table below. So each 'jump' adds a position to the binary representation of the number.

hex value decimal binary
0x01 neutral 1 00001
0x02 lawful 2 00010
0x04 chaotic 4 00100
0x08 good 8 01000
0x10 evil 16 10000

For a computer it is easy to get the setting from the position in the binary. So the last position decides whether the character can be neutral on the given class or not, the second position whether it can be lawful etc. To set restrictions on multiple alignments simply add up the individual numbers and write them down in hexadecimal format.

For example, a paladin can only be lawful good. Therefore, neutral, chaotic and evil should be excluded. The setting is 0x01 + 0x04 + 0x10 = 0x15 which is indeed the setting in classes.2da. I haven't found the trick with adding hexadecimals yet so it might be hard to do more complicated additions. Luckily, an easy commandline script is available to do the calculation. Just write down the calculation in hexadecimals as the second part of the printf statement:

perl -e 'printf("0x%X\n", 0x01+0x04+0x10)'

Reading out the configuration
To read out such configuration binary AND operators can be used. Such a script for the AlignRestrict values would look like this:

#!/usr/bin/perl

use strict;
use warnings;

my $hex = 0x15;

if ($hex & 0x01) {
  print "non-neutral\n";
}
if ($hex & 0x02) {
  print "non-lawful\n";
}
if ($hex & 0x04) {
  print "non-chaotic\n";
}
if ($hex & 0x08) {
  print "non-good\n";
}
if ($hex & 0x10) {
  print "non-evil\n";
}

Which prints:

non-neutral
non-chaotic
non-evil

To avoid writing a lot of if statements or when the number of settings may vary an array and a loop testing all of the settings can be used:

#!/usr/bin/perl

use strict;
use warnings;

my $hex = 0x15;

my @settings = ("non-neutral", "non-lawful", "non-chaotic", "non-good", "non-evil");
my $i = 0x01;
foreach my $setting (@settings) {
  if ($hex & $i) {
    print $setting . "\n";
  }
  $i *= 2;
}