FANDOM


Dual Wielding NPC's

What it does

This is an addition to the function EquipAppropriateWeapons in the nw_i0_generic file. This enables any NPC who has the Two Weapon FIghting feat and has two weapons in their inventory to equip these weapons for combat. Once combat is over and there are no enemies near they unequip the weapons.

Should the NPC lack a second weapon or not have the Two Weapon Fighting feat but they do have the Shield Proficiency feat they will equip a shield if there is one in their inventory.

You don't have to worry about the weapon or shield tags. When the NPC's spawn they look at their inventory and determine what weapons and/or shields they will equip if it comes to combat. All you need to worry about is the NPC's having the proper feats and having the items in inventory.

Notes

There are a few ways to include this into your module. You will need to modify every file that is attached to the NPC's. You can rename the files so that only the NPC's you want will have this ability. You can save them with their existing names so that every creature in that module will have the ability as long as they have the appropriate feats. If you save them in your module they will not overwrite your existing files. These changes only apply to the module they are saved in. Should you choose later to go back to your original files all you need to do is delete them from this module.

The scripts we need to modify are nw_i0_generic, nw_c2_default1-9, a, b, d, and e.

Close to the bottom of the file nw_i0_generic we will add two functions called BaseItemWeapons and BaseItemShields. Inside is a check on specific bonuses applied to the weapons or shields. You can make these properties more valuable to the NPC when they spawn if you wish.

Right now the properties only add 1 to the NPC's value of the item. Weapons are determined by damage die (d6, d8, etc) and shields are determined by AC.

If you use the Build Module from the toolbar the script nw_i0_generic (or what you name it) will have a compile error. This is normal. It is an include script and include scripts always generate a compile error on Build Module. If you get an error on other scripts which include the script nw_i0_generic (or what you name it) then that means there is probably a problem in it. Check the line number the compiler gives you in both scripts to get close to the problem.


Editing the scripts

First we'll edit nw_i0_generic. This way we can see if there is an error in the script when we compile the rest of the scripts.

At the top of the file right under the comments by Bioware add this:

void BaseItemWeapons(object oItem = OBJECT_INVALID);
void BaseItemShields(object oItem = OBJECT_INVALID);
void SetPrimaryWeapon(object oTarget = OBJECT_SELF);
void SetSecondaryWeapon(object oTarget = OBJECT_SELF);
void SetShield(object oTarget = OBJECT_SELF);
void SheathWeapons(object oTarget = OBJECT_SELF);
void SetWeapons(object oTarget = OBJECT_SELF);

Now search for EquipAppropriateWeapons(object oTarget). We want to change that function to match ours. Replace that with this:

void EquipAppropriateWeapons(object oTarget)
{
    object oPrimary = GetLocalObject(OBJECT_SELF, "PRIMARY");
    object oSecondary = GetLocalObject(OBJECT_SELF, "SECONDARY");
    if(GetIsObjectValid(GetMaster()))
    {
        if(GetAssociateState(NW_ASC_USE_RANGED_WEAPON))
        {
            MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Associate Equiping Ranged Weapon");
            ActionEquipMostDamagingRanged(oTarget);
        }
        else
        {
            MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Associate Equiping Melee Weapon");
            ActionEquipMostDamagingMelee(oTarget);
        }
    }
    else if(GetIsObjectValid(oPrimary))
    {
        if(GetDistanceToObject(oTarget) > 5.0)
        {
            ActionEquipMostDamagingRanged(oTarget);
        }
        else
        {
            ActionEquipItem(oPrimary, INVENTORY_SLOT_RIGHTHAND);
            ActionEquipItem(oSecondary, INVENTORY_SLOT_LEFTHAND);
        }
    }
    else
    {
        if(GetDistanceToObject(oTarget) > 5.0)
        {
            ActionEquipMostDamagingRanged(oTarget);
        }
        else
        {
            ActionEquipMostDamagingMelee(oTarget);
        }
    }
}

Now at the very end of the file add this:

// Check the base item type of the weapon and set the value to the damage
void BaseItemWeapons(object oItem)
{
    int nValue = 0;
    if(GetBaseItemType(oItem) == BASE_ITEM_BASTARDSWORD) nValue = 10;
    if(GetBaseItemType(oItem) == BASE_ITEM_BATTLEAXE) nValue = 8;
    if(GetBaseItemType(oItem) == BASE_ITEM_LONGSWORD) nValue = 8;
    if(GetBaseItemType(oItem) == BASE_ITEM_WARHAMMER) nValue = 8;
    if(GetBaseItemType(oItem) == BASE_ITEM_CLUB) nValue = 6;
    if(GetBaseItemType(oItem) == BASE_ITEM_HANDAXE) nValue = 6;
    if(GetBaseItemType(oItem) == BASE_ITEM_KAMA) nValue = 6;
    if(GetBaseItemType(oItem) == BASE_ITEM_RAPIER) nValue = 6;
    if(GetBaseItemType(oItem) == BASE_ITEM_SCIMITAR) nValue = 6;
    if(GetBaseItemType(oItem) == BASE_ITEM_SHORTSWORD) nValue = 6;
    if(GetBaseItemType(oItem) == BASE_ITEM_SICKLE) nValue = 6;
    if(GetBaseItemType(oItem) ==BASE_ITEM_DAGGER) nValue = 4;
    if(GetBaseItemType(oItem) == BASE_ITEM_KUKRI) nValue = 4;
    if(GetBaseItemType(oItem) == BASE_ITEM_LIGHTHAMMER) nValue = 4;
    // Customize the values to your tastes for each of these item properties.
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_BONUS_FEAT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_FREEDOM_OF_MOVEMENT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_HASTE)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_HOLY_AVENGER)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMPROVED_EVASION)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_KEEN)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_MASSIVE_CRITICALS)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ON_HIT_PROPERTIES)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_ON_MONSTER_HIT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_POISON)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_REGENERATION)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_REGENERATION_VAMPIRIC)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_TRUE_SEEING)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_VORPAL)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_WOUNDING)) nValue++;
    SetLocalInt(OBJECT_SELF, "VALUE", nValue);
}
// Check the shields for best AC
void BaseItemShields(object oItem)
{
    int nValue = 0;
    if(GetBaseItemType(oItem) == BASE_ITEM_TOWERSHIELD) nValue = GetItemACValue(oItem);
    if(GetBaseItemType(oItem) == BASE_ITEM_LARGESHIELD) nValue = GetItemACValue(oItem);
    if(GetBaseItemType(oItem) == BASE_ITEM_SMALLSHIELD) nValue = GetItemACValue(oItem);
    // Customize the values to your tastes for each of these item properties.
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_ALIGNMENT_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_DAMAGE_TYPE)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_RACIAL_GROUP)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_AC_BONUS_VS_SPECIFIC_ALIGNMENT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_BONUS_FEAT)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_REDUCTION)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_DAMAGE_RESISTANCE)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_MISCELLANEOUS)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPELL_SCHOOL)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_IMPROVED_EVASION)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_NO_DAMAGE)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_REGENERATION)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SAVING_THROW_BONUS)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC)) nValue++;
    if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SPELL_RESISTANCE)) nValue++;
    SetLocalInt(OBJECT_SELF, "VALUE", nValue);
}
// Set the primary weapon to be equiped
void SetPrimaryWeapon(object oTarget)
{
    object oItem = GetFirstItemInInventory(oTarget);
    while(GetIsObjectValid(oItem))
    {
        BaseItemWeapons(oItem);
        if(GetLocalInt(oTarget, "VALUE") > 0 && GetLocalInt(oTarget, "VALUE") > GetLocalInt(oTarget, "PRIMARY"))
        {
            SetLocalObject(oTarget, "PRIMARY", oItem);
            SetLocalInt(oTarget, "PRIMARY", GetLocalInt(oTarget, "VALUE"));
            DeleteLocalInt(oTarget, "VALUE");
        }
        oItem = GetNextItemInInventory(oTarget);
    }
}
// Set the secondary weapon to be equiped
void SetSecondaryWeapon(object oTarget)
{
    object oItem = GetFirstItemInInventory(oTarget);
    object oPrimary = GetLocalObject(oTarget, "PRIMARY");
    int nPrimary = GetLocalInt(oTarget, "PRIMARY");
    if(GetHasFeat(FEAT_TWO_WEAPON_FIGHTING, oTarget))
    {
        while(GetIsObjectValid(oItem))
        {
            BaseItemWeapons(oItem);
            if(GetLocalInt(oTarget, "VALUE") > 0 && GetLocalInt(oTarget, "VALUE") >= GetLocalInt(oTarget, "SECONDARY") && oItem != oPrimary)
            {
                SetLocalObject(oTarget, "SECONDARY", oItem);
                SetLocalInt(oTarget, "SECONDARY", GetLocalInt(oTarget, "VALUE"));
                DeleteLocalInt(oTarget, "VALUE");
            }
            oItem = GetNextItemInInventory(oTarget);
        }
    }
}
// Sheath Weapons when not in use, including shields
void SheathWeapons(object oTarget)
{
    ActionUnequipItem(GetLocalObject(oTarget, "PRIMARY"));
    ActionUnequipItem(GetLocalObject(oTarget, "SECONDARY"));
}
// Used in the OnSpawn script to call the functions to set the weapons
void SetWeapons(object oTarget)
{
    SetPrimaryWeapon(oTarget);
    SetSecondaryWeapon(oTarget);
    SetShield(oTarget);
}
// Set the shield to be equipped if they cannot use two weapons or if they don't
// have two weapons
void SetShield(object oTarget)
{
    object oItem = GetFirstItemInInventory(oTarget);
    object oSecondary = GetLocalObject(oTarget, "SECONDARY");
    if(GetHasFeat(FEAT_SHIELD_PROFICIENCY, oTarget) && (!GetIsObjectValid(oSecondary)))
    {
        while(GetIsObjectValid(oItem))
        {
            BaseItemShields(oItem);
            if(GetLocalInt(oTarget, "VALUE") > 0 && GetLocalInt(oTarget, "VALUE") > GetLocalInt(oTarget, "SECONDARY"))
            {
                SetLocalObject(oTarget, "SECONDARY", oItem);
                SetLocalInt(oTarget, "SECONDARY", GetLocalInt(oTarget, "VALUE"));
                DeleteLocalInt(oTarget, "VALUE");
            }
            oItem = GetNextItemInInventory(oTarget);
        }
    }
}

Now we need to search through all of the files attached to the NPC so we can be sure our function is called including the nw_i0_generic. When you get to nw_c2_default2 or nw_c2_default9 we'll add more changes so look farther down for them. If you have not alread saved these files into your module now is a good time.

Use Find in files in the script edit to find DetermineCombatRound. Be sure to check the box for searching all files in the module. Also, if you decided to rename the files instead of using the default names be sure to change the #include "NW_I0_GENERIC" to what you named that file as you go.

Now search out all DetermineCombatRound in files nw_i0_generic, nw_c2_default1-9, a, b, d and e. Right above it add this:

EquipAppropriateWeapons(OBJECT_SELF);

When you get to nw_c2_default2 (OnPerceived) we need to add this right below the first {

    if(GetNumberOfMeleeAttackers() < 1 && GetNumberOfRangedAttackers() < 1)
    {
        SheathWeapons(OBJECT_SELF);
    }

When you get to nw_c2_default9 (OnSpawn) we need to add this right below GenerateNPCTreasure


SetWeapons(OBJECT_SELF);

That's it. Now your NPC's will be dual wielding upon combat and sheathing their weapons once combat is over. Enjoy.

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.