Dexterity damage for bows and Weapon Finesse

Hello

Did someone managed to make NWN add dexterity bonus to bow’s damage? And what about Weapon finesse? It would be cool to add dexterity bonus to damage.

Would it be very difficult to make?

Thanks!

Pretty sure that stuff is hard-coded. Might be able to do it with NWNX. Dunno…not an NWNX user but maybe someone else will chime in.

Oh that’s bad news. Thanks for answering.

It’s possible to add it via scripting to the on-equip player script (as long as the module has it slotted).

It might not exactly be like the bonus damage from strength (in terms of all calculations involving crits ecc), but you can add it via effect damage.

This is how it works more or less:
First you take the Module OnEquip and OnUnequip scripts and you add the following line (the added part is the second one, the line above should already be in the scripts).
I am going to assume you will use “x2_mod_def_equ” and “x2_mod_def_unequ” as module scripts for player equip events. (beware that the original campaign did not use these scripts last time I checked)

For the Onequip script:

object oPC   = GetPCItemLastEquippedBy();
DelayCommand(0.0f, ExecuteScript("equip_dexdamage", oPC));

For the OnUnequip script:

object oPC   = GetPCItemLastUnequippedBy();
DelayCommand(0.0f, ExecuteScript("equip_dexdamage", oPC));

Now, the actual script, I called it “equip_dexdamage” as you can see on the two lines above.

const string FX_DEXDAMAGE = "dex_damage";

int GetIsFinessable(int nWEAPON)
{
    switch(nWEAPON)
    {
        case BASE_ITEM_DAGGER:
        case BASE_ITEM_HANDAXE:
        case BASE_ITEM_KAMA:
        case BASE_ITEM_KUKRI:
        case BASE_ITEM_LIGHTHAMMER:
        case BASE_ITEM_LIGHTMACE:
        case BASE_ITEM_RAPIER:
        case BASE_ITEM_SHORTSWORD:
        case BASE_ITEM_SICKLE:
        case BASE_ITEM_WHIP:
        case BASE_ITEM_INVALID:
        case BASE_ITEM_LARGESHIELD:
        case BASE_ITEM_SMALLSHIELD:
        case BASE_ITEM_TOWERSHIELD:
            return TRUE;
    }
    return FALSE;
}

void ApplyDexDamage(object oPC, int nBONUS, int nTYPE)
{
    //Conversion to proper DAMAGE_BONUS variable for values higher than 5. Capped at 20 effective bonus (30 as var value).
    if (nBONUS > 5) nBONUS = nBONUS + 10;
    if (nBONUS > 30) nBONUS = 30;
    effect eDMG = EffectDamageIncrease(nBONUS, nTYPE);
    eDMG = SupernaturalEffect(eDMG);
    eDMG = TagEffect(eDMG, FX_DEXDAMAGE);
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDMG, oPC);
}

void main()
{
    object oPC = OBJECT_SELF;
    effect eFX = GetFirstEffect(oPC);
    while (GetIsEffectValid(eFX) == TRUE)
    {
        if (GetEffectTag(eFX) == FX_DEXDAMAGE) RemoveEffect(oPC, eFX);
        eFX = GetNextEffect(oPC);
    }

    int nBONUS = GetAbilityModifier(ABILITY_DEXTERITY, oPC);
    if (nBONUS < 1) return;

    int nTYPE = DAMAGE_TYPE_PIERCING;

    object oRIGHT = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
    if (GetWeaponRanged(oRIGHT) == TRUE)
    {
        DelayCommand(0.0f, ApplyDexDamage(oPC, nBONUS, nTYPE));
        return;
    }

    nBONUS = nBONUS - GetAbilityModifier(ABILITY_STRENGTH, oPC);
    if (nBONUS < 1) return;
    if (GetHasFeat(FEAT_WEAPON_FINESSE, oPC) == FALSE) return;

    int nRIGHT = GetBaseItemType(oRIGHT);
    if (GetIsFinessable(nRIGHT) == FALSE) return;

    object oLEFT = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
    int nLEFT = GetBaseItemType(oLEFT);
    if (GetIsFinessable(nLEFT) == FALSE) return;
    DelayCommand(0.0f, ApplyDexDamage(oPC, nBONUS, nTYPE));
}

This should set you to go, keep in mind that it’s disabled for shields for now (because I don’t remember if weapon finesse is supposed to work with shields equipped or not, with tower shields it would certainly make little sense).

If, By any chance, you play a module that does not have those two scripts as their player equip events, you can set them on the fly.
First you need to make a new script, I call it “tag_scripts”

#include "x2_inc_switches"

void main()
{
    SetModuleSwitch(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS, TRUE);
    object oMODULE = GetModule();
    SetEventScript(oMODULE, EVENT_SCRIPT_MODULE_ON_EQUIP_ITEM, "x2_mod_def_equ");
    SetEventScript(oMODULE, EVENT_SCRIPT_MODULE_ON_UNEQUIP_ITEM, "x2_mod_def_unequ");
    FloatingTextStringOnCreature("Tag based scripts enabled for Equip and Unequip Events.", OBJECT_SELF, FALSE);
}

Then, when you are playing, call up the Cheat Console, turn ON the Debug Mode and then run the command to call the “tag_script” here, if you have done everything right you will get the message telling you that tag based scripts are enabled for Equip and Unequip events.

You can find the guide to the NWN Cheat Console here:

Thank you very much, I will see if I can make it work. By the way, weapon finesse does work with small and large shields. Don’t know with tower shield though.

I managed to make it work. My character is a Ranger with Str 14 and Dex 17, and the longbow apears +3 piercing damage, and the short sword +1 piercing damage, probably because of the +2 of the Str modifier.

But there is a problem: for example, when I have the longbow equipped I have + 3 bonus, but when I equip directly after the short swords, it won’t go to +1, it still keeps +3 piercing and +2 of Str. To fix I have to unequip and equip the short swords.

Is it a problem with equip/ unequip scritpt? Is there a workaround or I will have to make a 10 Str character?

Thank you very much for spending your time teaching me.

@Malfatto I edited the post above to fix your issue, the problem was in the lack of a delay on the execution on the script (the frist two callbacks from x2_mod_def_equ and unequ).

I also modified the equip_dexdamage script to solve two more issues:

  1. shields now allow for weapon finesse
  2. bonuses with values higher than 5 would provide incorrect amounts of damage (random dices) due to how the damage variables are coded into the engine.

Now, it should do, more or less what you asked for. Keep in mind that when something is hardcoded, the various workarounds can almost never truly achieve a full 100% replica, however, a 99% is better than a 0% in my book.

1 Like

Thank you Clangeddin, it feels much better to play a Ranger now, I feel much less wimpy. The adjustments you made worked. There are just two things that could change:

  1. Sometimes, when I load a game I do alot of damage. Like, 30-40 with a common longbow or shortsword with a level 3 character. If I save I break the game. The workaround I do is everytime I reload a save I unequip an reequip my weapon. Is there a fix for this?

  2. This one is just a polish. Is there a way that if my dexterity go down, because of poison for example, the damage goes down without need do unequip equip?

Even is there is no solution it’s much better now. Thank you very much!

I think that the only way to “solve” both issues with one stone is to run a heartbeat script on the module that executes “equip_dexdamage” on the player every 6 seconds or so.
You still would need to wait for the 6 seconds interval at worst for the fix to kick in (it could take less as well).

void main()
{
    object oPC = GetFirstPC();
    object oCOMP;
    int nCOMP;
    int nTYPE;
    while (oPC != OBJECT_INVALID)
    {
        DelayCommand(0.1, ExecuteScript("equip_dexdamage", oPC));
        nTYPE = 1;
        while (nTYPE < ASSOCIATE_TYPE_DOMINATED)
        {
            nCOMP = 1;
            oCOMP = GetAssociate(nTYPE, oPC, nCOMP);
            while (oCOMP != OBJECT_INVALID)
            {
                DelayCommand(0.2, ExecuteScript("equip_dexdamage", oCOMP));
                nCOMP = nCOMP + 1;
                oCOMP = GetAssociate(nTYPE, oPC, nCOMP);
            }
            nTYPE = nTYPE + 1;
        }
        oPC = GetNextPC();
    }
}

OnHeartbeat is a module event like the Player on Equip or onUnequip
You can set it up by adding the line

SetEventScript(oMODULE, EVENT_SCRIPT_MODULE_ON_HEARTBEAT, "heart_finesse");

(I called the heartbeat script “heart_finesse”)

To the script called up by the Cheat Console that enables the tag based scripts like I showed you before.
Or you can slot it directly via the toolset.

Hello
Everything is working wonders, thank you very much you’re a hero.
One last question: Is it possible to run your script for everybody or at least the henchmen?

Thank you and happy new year!

I edited the heartbeat scrpt to make it work with all associates of all types (henchmen, familiars, animal companions, summoned and dominated creatures).

Hopefully it won’t make your game stutter too much.
Happy new year!

2 Likes

Hello

I’ve been having a blast running your script in many modules, and it didn’t stutter my game… until now. It only stutters with the error “too many instructions” when I dominate a creature with the Animal Empathy. When I release the animal the stutter and error stops.

So could you do me a big favor? Keep the script affecting everyone as it is but remove from dominated creatures.

Thank you very much.

Ok, done. I edited the script above.

Thank you very much.

That’s odd though. It looks like it would have to be getting stuck in the inner loop. Maybe GetAssociate(DOMINATED) is not working correctly with respect to nNth?

Hello

I don’t know, what you said is greek to me. I just noticed now because I made a new ranger and this one has Animal Empathy. What I find odd is that the animal I dominated was a dire wolf, and as far as I know they don’t have Weapon Finesse.