Dual wielding npc

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.

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.