Skip to content

PSTEE Engine Quirks

AquadrizztAquadrizzt Member Posts: 1,068
edited April 2023 in PST:EE Mods
As I work on my various Planescape mods, I come across pieces of information about the functionality of the engine. Here are some interesting things I have discovered
  • Unused Opcodes That Work: Timestop, Use Any Item
  • Unused Opcodes That Don't Work: Find Traps, Improved Alacrity, Haste, Create Magical Weapon, Fist Thac0 Bonus, Fist Damage Bonus, Modify Visual Range
  • The engine does support the addition of new Mage and Priest spells as long as you remember to ADD_SPELL_EX them and update spells.2da.
  • The trigger condition for items in store files (offset 0x001c in the Items for Sale extended header) cannot contain an Or() statement.
  • The store interface will place conditionally available items above unconditionally available items. The order of these within the .sto file is respected within these two groups.

I'm curious to see what interesting engine behavior other people have found.
Post edited by Aquadrizzt on

Comments

  • argent77argent77 Member Posts: 3,448
    PST:EE does not support any weather effects, including fog.

    The SpellCast*() triggers don't seem to work in PST:EE, which includes
    0x0091 SpellCast(O:Object*,I:Spell*Spell)
    0x0091 SpellCastRES(S:Spell*,O:Object*)
    0x00a6 SpellCastPriest(O:Object*,I:Spell*Spell)
    0x00a6 SpellCastPriestRES(S:Spell*,O:Object*)
    0x00a7 SpellCastInnate(O:Object*,I:Spell*Spell)
    0x00a7 SpellCastInnateRES(S:Spell*,O:Object*)
    0x00a1 SpellCastOnMe(O:Caster*,I:Spell*Spell)
    0x00a1 SpellCastOnMeRES(S:Spell*,O:Caster*)
    
  • AquadrizztAquadrizzt Member Posts: 1,068
    edited November 2022
    The Blindness opcode (78) only applies the AC penalty. It has no discernible effect on THAC0 or visual range.
  • AquadrizztAquadrizzt Member Posts: 1,068
    edited November 2022
    A damage effect (Opcode 12) that permits a save will always be "save for half damage".

    You can avoid this by having the damage effect applied via a sub resource and having the save be placed on the 177/326 effect that applies the sub resource.
  • AquadrizztAquadrizzt Member Posts: 1,068
    Invisibility (opcode 20) does not care about the parameter1 value that determines whether it's normal or improved.

    All invisibility is removed upon attack.
  • AquadrizztAquadrizzt Member Posts: 1,068
    Stunning damage (which is described as "nonlethal" damage by the PSTEE engine) does not appear to have any non-lethal behavior. A creature whose current HP is brought to 0 by non-lethal damage will die.
  • AquadrizztAquadrizzt Member Posts: 1,068
    edited December 2022
    Turns out I was incorrect about projectiles in Planescape. If you scour the game resources for references to projectl.ids and update the .ids file to accommodate the slight changes to projectl.ids since the IESDP entry for it was written, you can successfully implement a fully customizable projectile.

    Many of the existing projectiles are hardcoded, although there are a few ones that can be modified. (Thanks to Bubb for getting the list of hardcoded projectiles indices.)

    An updated version of PROJECTL.ids is copied here.
    21  --         // unused, instant hit (hardcoded)
    23  --         // chromatic orb - used by spwi101.spl (hardcoded)
    24  --         // do not use - crash (hardcoded)
    25  --         // do not use - crash (hardcoded)
    38  --         // adder's kiss - special spell hit (spwi201.spl) (hardcoded)
    44  --          // unused, instant hit (hardcoded)
    59  ghost    // howl of pandemonium ghost - used by spwi603.spl 
    61  stormbld // blade storm blade - used by spwi702.spl <unsure about this one>
    65  --          // unused, instant hit (hardcoded)
    66  --          // unused, instant hit (hardcoded)
    67  --          // unused, instant hit (hardcoded)
    68  --          // unused, instant hit (x2) (hardcoded)
    69  --          // unused, instant hit (x3) (hardcoded) 
    70  --          // unused, instant hit (x4) (hardcoded)
    71  --          // unused, instant hit (x5) (hardcoded)     
    72  --          // unused, instant hit (x6) (hardcoded)
    73  --          // unused, instant hit (x7) (hardcoded)
    74  --          // unused, instant hit (x8) (hardcoded)
    75  --          // unused, instant hit (x9) (hardcoded)
    76  --          // unused, instant hit (x10) (hardcoded)
    77  --          // unused, instant hit (x11) (hardcoded)
    78  --          // invisible traveling projectile (explosion projectile of sppr105.pro, spwi108.pro) (hardcoded)
    80  --          // unused, instant hit, prevents save/rest (hardcoded)
    81  --          // unused, instant hit, prevents save/rest (hardcoded)
    82  --          // unused, instant hit, prevents save/rest (hardcoded)
    83  --          // unused, instant hit, prevents save/rest (hardcoded)
    84  --          // unused, instant hit, prevents save/rest (hardcoded)
    85  --          // unused, instant hit, prevents save/rest (hardcoded)
    86  --          // unused, instant hit, prevents save/rest (hardcoded)
    87  --          // unused, instant hit, prevents save/rest (hardcoded)
    88  --          // unused, instant hit, prevents save/rest (hardcoded)
    89  --          // unused, instant hit, prevents save/rest (hardcoded)
    90  --          // unused, instant hit, prevents save/rest (hardcoded)
    96  --          // unused, instant hit, medium radius around target (hardcoded)
    109 --          // unused, instant hit (hardcoded)
    118 --          // unused, instant hit (hardcoded)
    119 --          // unused, instant hit (hardcoded)
    120 --          // unused, instant hit (hardcoded)
    121 --          // unused, instant hit (hardcoded)
    122 --          // unused, instant hit (hardcoded)
    123 --          // unused, instant hit (hardcoded)
    124 --          // unused, instant hit (hardcoded)
    125 --          // unused, instant hit (hardcoded)
    126 --          // unused, instant hit (hardcoded)
    127 --          // unused, instant hit (hardcoded)
    128 --          // unused, instant hit (hardcoded)
    129 --          // unused, instant hit (hardcoded)
    130 --          // unused, instant hit (hardcoded)
    131 --          // unused, instant hit (hardcoded)
    132 --          // unused, instant hit (hardcoded) 
    133 --          // unused, instant hit (hardcoded)
    134 --          // unused, instant hit (hardcoded) 
    135 --          // unused, instant hit (hardcoded) 
    136 --          // unused, instant hit (hardcoded) 
    137 --          // unused, instant hit (hardcoded)  
    138 --          // unused, instant hit (hardcoded)  
    139 --          // unused, instant hit (hardcoded) 
    140 --          // unused, instant hit (hardcoded)  
    141 --          // unused, instant hit (hardcoded) 
    142 --          // unused, no ally/neutral hit, prevents save/rest (hardcoded)
    143 --          // unused, no ally/neutral hit, prevents save/rest (hardcoded)
    144 --          // unused, no ally/neutral hit, prevents save/rest (hardcoded)
    145 --          // unused, instant hit (hardcoded)  
    146 --          // unused, instant hit (hardcoded)
    147 --          // unused, instant hit (hardcoded)
    188 --          // delayed hit, then hits everyone in area (hardcoded)
    189 ntoken   // hold person - used by ntoken.itm 
    190 --          // do not use - crash (hardcoded)
    194 --          // unused, instant hit (hardcoded)
    195 --          // unused, instant hit (hardcoded)
    196 --          // unused, instant hit (hardcoded)
    197 --          // unused, instant hit (hardcoded)
    198 --          // unused, instant hit (hardcoded)
    199 --          // unused, instant hit (hardcoded)
    200 --          // unused, instant hit (hardcoded)
    201 --          // unused, instant hit (hardcoded)
    202 --          // unused, instant hit (hardcoded)
    203 --         // litany of curses - used by spin101.spl (hardcoded)
    204 --         // stories-bones-tell/speak with dead - used by spin103.spl, sppr304.spl (hardcoded)
    205 magicmis // magic missiles 1 - used by spwi107.spl
    206 spwi107  // magic missiles 2 - used by spwi107.spl
    207 spwi107  // magic missiles 3 - used by spwi107.spl
    208 spwi107  // magic missiles 4 - used by spwi107.spl
    209 spwi107  // magic missiles 5 - used by spwi107.spl
    210 spwi107  // magic missiles 6 - unused
    211 spwi107  // magic missiles 7 - unused
    212 spwi107  // magic missiles 8 - unused
    213 spwi107  // magic missiles 9 - unused
    214 spwi107  // magic missiles 10 - unused
    215 --         // skull mob - used by spin102.spl (hardcoded)
    216 --          // do not use - crash (hardcoded)
    217 --         // swarm curse (spwi212), 9' radius (hardcoded)
    218 --         // swarm curse arrow - used by swarm curse (hardcoded)
    219 --       // originally adder's kiss, unused
    220 --         // ice knife - used by spwi207.spl (hardcoded) 
    221 --         // pacify - used by spwi108.spl (hardcoded)
    222 --         // strength - used by spwi211.spl (hardcoded)
    223 --         // ball of lightning - used by spwi301 (hardcoded)
    224 --         // ball of lightning sphere - used by spwi301 (hardcoded)
    225 --         // blood bridge - used by spwi204.spl (hardcoded)
    226 --         // force missiles - used by spwi405.spl (hardcoded)
    227 --         // improved strength - used by spwi406.spl (hardcoded)
    228 --         // shroud of shadows - used by spwi408.spl (hardcoded)
    229 --         // cloudkill - used by spwi501.spl (hardcoded)
    230 --         // howl of pandemonium - used by spwi603.spl (hardcoded)
    231 --         // blade storm - used by spwi702.spl (hardcoded)
    232 --         // elysium's fires - used by spwi905.spl (hardcoded)
    233 --         // abyssal fury - used by spwi912.spl (hardcoded)
    234 --         // horror - used by spwi213.spl (hardcoded)
    235 --         // knock - used by spwi215.spl (hardcoded) 
    236 --         // hold undead - used by spwi307.spl (hardcoded)
    237 --         // missile of patience - used by spwi113.spl (hardcoded)
    238 --         // elysium's tears - used by spwi305.spl (hardcoded)
    239 --         // tasha's unbearable derisive laughter - used by spwi308.spl (hardcoded)
    240 --         // axe of torment - used by spwi310.spl (hardcoded)
    241 --         // blacksphere - unused, originally used by spwi401.spl (hardcoded)
    242 --         // cone of cold - used by spwi502.spl (hardcoded)
    243 --         // desert hell - used by spwi505.spl (hardcoded)
    244 --         // fire and ice - used by spwi506.spl (hardcoded)
    245 --         // chain lightning storm - used by spwi604.spl (hardcoded)
    246 --         // acid storm - used by spwi701.spl (hardcoded)
    247 --         // stygian ice storm - used by spwi705.spl (hardcoded) 
    248 --         // meteor storm bombardment - used by spwi802.spl (hardcoded)
    249 --         // deathbolt - used by spwi803.spl (hardcoded)
    250 --         // ignus' fury - used by spwi804.spl (hardcoded)
    251 --         // pw blind - used by spwi805.spl (hardcoded)
    252 --         // mechanus' cannon - used by spwi807.spl (hardcoded)
    253 --         // celestial host - used by spwi901.spl (hardcoded)
    254 --         // rune of torment - unused, originally used by spwi914.spl (hardcoded)
    255 --         // blessing - used by sppr101.spl, spwi118.spl (hardcoded)
    256 --         // curse - used by sppr103.spl, spwi117.spl (hardcoded)
    257 --       // originally detect evil, unused
    258 --         // halo of lesser revelation - used by sppr105.spl (hardcoded) 
    259 --         // spritual hammer - used by sppr204.spl (hardcoded)
    260 --         // call lightning - used by sppr301.spl (hardcoded)
    261 --       // originally soul exodus, unused 
    262 --         // vampiric touch - used by spwi309.spl (hardcoded)
    263 --         // confusion - used by spwi402.spl (hardcoded)
    264 --         // pw kill - used by spwi909.spl (hardcoded)
    265 --         // globe of invulnerability - used by spwi602.spl (hardcoded)
    266 bolt01   // nordom's crossbow bolts - used by bolt01.itm through bolt09.itm, nordbolt.itm
    267 --         // raise dead - used by sppr502.spl, spin108.spl (hardcoded)
    268 --         // aura of fear - used by spin106.spl (hardcoded)
    269 --         // conflagration - used by spwi902.spl (hardcoded)
    270 spwi001  // special trap - used by spwi001.spl 
    271 ignusfi  // ignus' fireball - used by ignusfi.itm
    272 imiss    // tongues of flame 1 - used by spwi116.spl
    273 spwi116  // tongues of flame 2 - used by spwi116.spl
    274 spwi116  // tongues of flame 3 - used by spwi116.spl
    275 spwi116  // tongues of flame 4 - used by spwi116.spl
    276 spwi116  // tongues of flame 5 - used by spwi116.spl
    277 --         // ignus' terror - used by spwi217.spl (hardcoded)
    278 --         // infernal orb - used by spwi218.spl (hardcoded)
    279 --         // fiery rain - used by spwi313.spl (hardcoded)
    280 --         // elemental strike - used by spwi410.spl (hardcoded)
    281 amiss    // reign of anger 1 - used by spwi121.spl
    282 spwi121  // reign of anger 2 - used by spwi121.spl
    283 spwi121  // reign of anger 3 - used by spwi121.spl
    284 spwi121  // reign of anger 4 - used by spwi121.spl
    285 spwi121  // reign of anger 5 - used by spwi121.spl
    286 --         // power of one - used by spwi219.spl (hardcoded)
    287 --         // kiss - used by spin107.spl (hardcoded)
    288 --         // embalming - used by spwi103.spl, spwi205.spl (hardcoded)
    289 spwi305b // elysium tears meteor - used by spwi305
    290 spwi002  // special trap - used by spwi002.spl
    291 spwi003  // special trap - used by spwi003.spl
    292 spwi004  // special trap - used by spwi004.spl
    293 spwi005  // special trap - used by spwi005.spl
    294 spwi006  // special trap - used by spwi006.spl
    295 spwi007  // special trap - used by spwi007.spl
    296 spwi008  // special trap - used by spwi008.spl
    297 spwi009  // special trap - used by spwi009.spl
    298 spwi010  // special trap - used by spwi010.spl
    299 --         // rune of torment - used by spwi914.spl (hardcoded) 
    300 --         // blacksphere - used by spwi401.spl (hardcoded)
    455 --         // prayer - used by sppr303.spl (via prayerg.spl)
    456 --         // prayer - used by sppr303.spl (via prayerb.spl)
    
    Post edited by Aquadrizzt on
  • AquadrizztAquadrizzt Member Posts: 1,068
    The triggers of HasItemEquiped and HasItemEquiped real do not appear to function at all (consistently evaluate to False).
  • AquadrizztAquadrizzt Member Posts: 1,068
    edited June 2023
    Despite not having any of the files present by default, PSTEE will apply the effects of appropriate CLAB files to members of that class (e.g. effects listed in a provided CLABFI01 will be applied to all Fighters as normal).

    EDIT: The CLAB files of interest are CLABFI01.2da (Fighter), CLABTH01.2da (Thief), CLABMA01.2da (Mage), and CLABPR01.2da (Priest).

    Note that Planescape's default special abilities menu does NOT allow for special abilities to be added to creatures it doesn't expect (e.g. you couldn't give Morte's Litany of Curses to TNO, or Sensory Touch to anyone but TNO or Grace). This can be fixed with the following code.
    COPY_EXISTING ~ui.menu~ ~override~ 
    	REPLACE_TEXTUALLY ~showContextMenu(const.ACTIONBAR_STATE_SPECIAL_ABILITES)~ ~showContextMenu(106)~
    	REPLACE_TEXTUALLY ~clickable lua "pst:SpecialAbilitiesContextClickable() and fullActionbarClickable()"~ ~clickable lua "fullActionbarClickable()"~
    

    Be aware that this will disable access to Thief abilities (Stealth, Thieving, Find Traps) without further hacking, such as the following, which has the dialog button on the default interface open up a Thief action bar.
    COPY_EXISTING ~ui.menu~ ~override~ 
    REPLACE_TEXTUALLY ~Infinity_PopMenu('WORLD_CONTEXT_BAR')[%TAB%%LNL%%MNL%%WNL%]+if(game:GetIconIndex() == 18 and game:GetState() == 2) then[%TAB%%LNL%%MNL%%WNL%]+game:SetState(0)[%TAB%%LNL%%MNL%%WNL%]+game:SetIconIndex(0)[%TAB%%LNL%%MNL%%WNL%]+else[%TAB%%LNL%%MNL%%WNL%]+game:SetState(2)[%TAB%%LNL%%MNL%%WNL%]+game:SetIconIndex(18)[%TAB%%LNL%%MNL%%WNL%]+end~ ~actionbarResetState()
    			showContextMenu(21)~
    
    Post edited by Aquadrizzt on
  • AquadrizztAquadrizzt Member Posts: 1,068
    If you modify HPCONBON.2da, TNO's starting hit points (before Constitution bonus from levels) will match the table for Constitution scores of 14 or lower, but will be set to whatever value is specified for a Constitution of 14 if the actual value is higher.
  • AquadrizztAquadrizzt Member Posts: 1,068
    edited June 2023
    PSTEE does not (as far as I can tell) support kits (even when adding the appropriate tables such as KITLIST.2da). However, it does allow the AddKit(...) action to apply mage schools. These appear to be entirely aesthetic, however, as items and spells do not seem to respect the exclusion flags associated with those schools at all (I tested every possible spell flag for Abjurer and none of them prevented an Abjurer from using the item or learning/casting the spell).
    Post edited by Aquadrizzt on
  • MephistoSatanDevilMephistoSatanDevil Member Posts: 13
    Aquadrizzt wrote: »
    Despite not having any of the files present by default, PSTEE will apply the effects of appropriate CLAB files to members of that class (e.g. effects listed in a provided CLABFI01 will be applied to all Fighters as normal).

    EDIT: The CLAB files of interest are CLABFI01.2da (Fighter), CLABTH01.2da (Thief), CLABMA01.2da (Mage), and CLABPR01.2da (Priest).

    Note that Planescape's default special abilities menu does NOT allow for special abilities to be added to creatures it doesn't expect (e.g. you couldn't give Morte's Litany of Curses to TNO, or Sensory Touch to anyone but TNO or Grace). This can be fixed with the following code.
    COPY_EXISTING ~ui.menu~ ~override~ 
    	REPLACE_TEXTUALLY ~showContextMenu(const.ACTIONBAR_STATE_SPECIAL_ABILITES)~ ~showContextMenu(106)~
    	REPLACE_TEXTUALLY ~clickable lua "pst:SpecialAbilitiesContextClickable() and fullActionbarClickable()"~ ~clickable lua "fullActionbarClickable()"~
    

    Be aware that this will disable access to Thief abilities (Stealth, Thieving, Find Traps) without further hacking, such as the following, which has the dialog button on the default interface open up a Thief action bar.
    COPY_EXISTING ~ui.menu~ ~override~ 
    REPLACE_TEXTUALLY ~Infinity_PopMenu('WORLD_CONTEXT_BAR')[%TAB%%LNL%%MNL%%WNL%]+if(game:GetIconIndex() == 18 and game:GetState() == 2) then[%TAB%%LNL%%MNL%%WNL%]+game:SetState(0)[%TAB%%LNL%%MNL%%WNL%]+game:SetIconIndex(0)[%TAB%%LNL%%MNL%%WNL%]+else[%TAB%%LNL%%MNL%%WNL%]+game:SetState(2)[%TAB%%LNL%%MNL%%WNL%]+game:SetIconIndex(18)[%TAB%%LNL%%MNL%%WNL%]+end~ ~actionbarResetState()
    			showContextMenu(21)~
    
    I used Near Infinity to change TNO to Multi-Class Fighter/Mage/Thief, but the special abilities menu doesn't show Thief abilities. is this related? If I want to use FMT Multi-Class as normal, how should I modify it?
  • AquadrizztAquadrizzt Member Posts: 1,068
    edited May 26
    I used Near Infinity to change TNO to Multi-Class Fighter/Mage/Thief, but the special abilities menu doesn't show Thief abilities. is this related? If I want to use FMT Multi-Class as normal, how should I modify it?

    Yes, what you're observing stems from the same engine behavior. Most resources are only defined for the default classes of TNO and the companions. Thus, Thieves (TNO) and Fighter/Thieves (Annah) have the correct access to thieving abilities in their Special bar, but a modded Mage/Thief or Fighter/Mage/Thief would not. You could use my ability menu workaround to fix this, but it isn't the cleanest implementation - I'm not good at UI modding.

    I believe you can (with the above hack to get access to Thief abilities), make Fighter/Mage/Thief work almost exactly as expected on an engine side with some fixes to clastext.2da, thiefscl.2da, and thiefskl.2da. The Mage spellbook appears to work fine, as does thief skill allocation upon level up.

    Most things you want to apply to TNO on game launch can be done by modifying CHARBASE.cre, but specifying the class occurs around line 13278 of the ui.menu (see below). The value in OnClassSelectButtonClick(#) defines the starting class based on the class id number from class.ids. 10 is the number for a F/M/T.
    --Set the class
    createCharScreen:SetCurrentStep(4)
    createCharScreen:OnClassSelectButtonClick(10)
    

    Note that if you want to get the right number of thief points to spend upon level up, you'll want to set your initial levels (in CHARBASE.cre) to 1/0/0. This would allow your character to instantly level up once loading in. Again, not the best implementation (there's probably a UI way to pick thief skills and then begin the game) but it will work.

    Cleric/Mage and F/M/C also appear to work properly (other than a missing "spellbook flip" button like from BG2).

    EDIT: One big thing that I'll make a note to investigate later is that item usability flags do not work for multiclasses. A F/M/T would be able to use an item that says "priests only", even though none of the constituent classes would be able to. NI doesn't list a usability flag that checks for F/M/T, but I'll play around.

    EDIT2: Yep, the Indep unusability flag also prevents use by F/M/T.
  • MephistoSatanDevilMephistoSatanDevil Member Posts: 13
    Aquadrizzt wrote: »
    I used Near Infinity to change TNO to Multi-Class Fighter/Mage/Thief, but the special abilities menu doesn't show Thief abilities. is this related? If I want to use FMT Multi-Class as normal, how should I modify it?

    Yes, what you're observing stems from the same engine behavior. Most resources are only defined for the default classes of TNO and the companions. Thus, Thieves (TNO) and Fighter/Thieves (Annah) have the correct access to thieving abilities in their Special bar, but a modded Mage/Thief or Fighter/Mage/Thief would not. You could use my ability menu workaround to fix this, but it isn't the cleanest implementation - I'm not good at UI modding.

    I believe you can (with the above hack to get access to Thief abilities), make Fighter/Mage/Thief work almost exactly as expected on an engine side with some fixes to clastext.2da, thiefscl.2da, and thiefskl.2da. The Mage spellbook appears to work fine, as does thief skill allocation upon level up.

    Most things you want to apply to TNO on game launch can be done by modifying CHARBASE.cre, but specifying the class occurs around line 13278 of the ui.menu (see below). The value in OnClassSelectButtonClick(#) defines the starting class based on the class id number from class.ids. 10 is the number for a F/M/T.
    --Set the class
    createCharScreen:SetCurrentStep(4)
    createCharScreen:OnClassSelectButtonClick(10)
    

    Note that if you want to get the right number of thief points to spend upon level up, you'll want to set your initial levels (in CHARBASE.cre) to 1/0/0. This would allow your character to instantly level up once loading in. Again, not the best implementation (there's probably a UI way to pick thief skills and then begin the game) but it will work.

    Cleric/Mage and F/M/C also appear to work properly (other than a missing "spellbook flip" button like from BG2).

    EDIT: One big thing that I'll make a note to investigate later is that item usability flags do not work for multiclasses. A F/M/T would be able to use an item that says "priests only", even though none of the constituent classes would be able to. NI doesn't list a usability flag that checks for F/M/T, but I'll play around.

    EDIT2: Yep, the Indep unusability flag also prevents use by F/M/T.

    It seems that using F/M/T normally is impossible. :(

    I try to modify the ui.menu to add the thief abilities in the special abilities bar, but it didn't work. :'(
    The attachment is the three 2da files that I have modified.
  • AquadrizztAquadrizzt Member Posts: 1,068
    edited June 11
    @MephistoSatanDevil let me play around with it a bit and see if I can make something stable for you. No promises on an ETA though... I'm in the depths of doctoral thesis hell.

    EDIT: Okay so I have the base line functionality of TNO as a FMT working. He can scribe and cast spells, use thief skills, and equip any weapon. The game properly splits his XP amongst the three classes. The game currently does not award attribute points or proficiency points on any level up, which I am working to address.

    There is still some minor jank here or there, but overall not bad for a few hours of effort. I am currently working on fixing the interactions with class specialization, the various NPC trainers, and the aforementioned ability score issue.

    EDIT2: Okay well that took substantially more effort than I expected but I am pretty sure I have it in as good as a state as it's going to be. I'll package it up and type up a readme tomorrow.
    Post edited by Aquadrizzt on
Sign In or Register to comment.