A script to reset armor bonuses for player & party members

NovaRain

Casual Modder
Modder
Moderator
DT/DR values from wearing armors are saved in bonus stats in the gamesave files, so if you change armor stats or use mods like F2WR, trying to unwield/change worn armors in existing saves will result in leftover or negative values.

For example, Sulik was wearing a leather armor with vanilla stats in an old save; he should have Laser DT 0 and DR 20% in his bonus stats (can be checked with F12se). If you installed F2WR, it changes Laser DT/DR of leather armor to 2/0%. When you load the save and tell him removing his armor, his naked Laser DT/DR bonus values will become -2/20%, making wearing other armors has less Laser DT and more Laser DR. The same goes to the player. Of course you can prevent this issue by firstly removing all armors you and party members are wearing in the save before installing mods, but that's kinda redundant IMO.

I've been working on my own weapon/armor mod that's similar to F2WR + canon tuning. Since I need to test different armor values, I made a script that can reset armor bonuses for player and party members to save me some trouble.
Code:
// gl_armorreset.int
procedure start;
procedure reset_pc_armor_stats(variable armor);
procedure reset_npc_armor_stats(variable critter, variable armor);
procedure set_npc_armor_bonus(variable critter, variable dtdr_arr);
procedure inventorymove_handler;
procedure invenwield_handler;

#include ".\HEADERS\DEFINE.H"
#include ".\HEADERS\define_extra.h"
#include ".\HEADERS\COMMAND.H"
#include ".\HEADERS\sfall.h"

#define party_equip_armor(critter)  (critter == Vic_Ptr) or (critter == Myron_Ptr) or (critter == MacRae_Ptr) or  \
                                    (critter == Sulik_Ptr) or (critter == Lenny_Ptr) or (critter == Davin_Ptr) or \
                                    (critter == Miria_Ptr) or (critter == Kitsune_Ptr) or (critter == Dex_Ptr) or \
                                    (critter == Cat_Jules_Ptr)

procedure start begin
   if game_loaded then begin
      register_hook_proc(HOOK_INVENTORYMOVE, inventorymove_handler);
      register_hook_proc(HOOK_INVENWIELD, invenwield_handler);
   end
end

procedure reset_pc_armor_stats(variable armor) begin
   variable i, j;
   if (armor > 0) then begin
      set_pc_extra_stat(STAT_ac, get_proto_data(armor, PROTO_AR_AC) + has_trait(TRAIT_PERK, dude_obj, PERK_dodger) * 5);
      // DT loop
      for (i := STAT_dmg_thresh; i <= STAT_dmg_thresh_explosion; i++) begin
         set_pc_extra_stat(i, get_proto_data(armor, (i * 4))); // PROTO_AR_DT_*
      end
      // DR loop
      for (i := STAT_dmg_resist; i <= STAT_dmg_resist_explosion; i++) begin
         set_pc_extra_stat(i, get_proto_data(armor, (i + 16 + j))); // PROTO_AR_DR_*
         j += 3;
      end
      set_pc_extra_stat(STAT_dmg_resist, get_proto_data(armor, PROTO_AR_DR_NORMAL) + has_trait(TRAIT_PERK, dude_obj, PERK_toughness) * 10 + dude_is_prizefighter * 5);
   end else begin
      set_pc_extra_stat(STAT_ac, has_trait(TRAIT_PERK, dude_obj, PERK_dodger) * 5);
      for (i := STAT_dmg_thresh; i <= STAT_dmg_resist_explosion; i++) begin
         set_pc_extra_stat(i, 0);
      end
      set_pc_extra_stat(STAT_dmg_resist, has_trait(TRAIT_PERK, dude_obj, PERK_toughness) * 10 + dude_is_prizefighter * 5);
   end
end

procedure reset_npc_armor_stats(variable critter, variable armor) begin
   variable i, j;
   if (armor > 0) then begin
      set_critter_extra_stat(critter, STAT_ac, get_proto_data(armor, PROTO_AR_AC));
      // DT loop
      for (i := STAT_dmg_thresh; i <= STAT_dmg_thresh_explosion; i++) begin
         set_critter_extra_stat(critter, i, get_proto_data(armor, (i * 4))); // PROTO_AR_DT_*
      end
      // DR loop
      for (i := STAT_dmg_resist; i <= STAT_dmg_resist_explosion; i++) begin
         set_critter_extra_stat(critter, i, get_proto_data(armor, (i + 16 + j))); // PROTO_AR_DR_*
         j += 3;
      end
      set_critter_extra_stat(critter, STAT_dmg_resist_emp, get_proto_data(armor, PROTO_AR_DR_EMP) + 500);
   end else begin
      set_critter_extra_stat(critter, STAT_ac, 0);
      for (i := STAT_dmg_thresh; i <= STAT_dmg_resist_explosion; i++) begin
         set_critter_extra_stat(critter, i, 0);
      end
      set_critter_extra_stat(critter, STAT_dmg_resist_emp, 500);
   end
end

procedure set_npc_armor_bonus(variable critter, variable dtdr_arr) begin
   variable i;
   for (i := STAT_dmg_thresh; i <= STAT_dmg_resist_explosion; i++) begin
      set_critter_extra_stat(critter, i, get_critter_extra_stat(critter, i) + dtdr_arr[i - STAT_dmg_thresh]);
   end
end

procedure inventorymove_handler begin
   variable
      slot := get_sfall_arg,
      item_moved := get_sfall_arg;

   if (obj_item_subtype(item_moved) == item_type_armor) and slot then begin
      if (obj_pid(critter_inven_obj(dude_obj, INVEN_TYPE_WORN)) > 0) then begin
         call reset_pc_armor_stats(obj_pid(critter_inven_obj(dude_obj, INVEN_TYPE_WORN)));
      end else begin
         call reset_pc_armor_stats(-1);
      end
   end
end

procedure invenwield_handler begin
   variable
      critter := get_sfall_arg,
      item := get_sfall_arg,
      slot := get_sfall_arg,
      wielding := get_sfall_arg,
      level, dtdr_arr;

   if party_equip_armor(critter) and (slot == INVEN_TYPE_WORN) then begin
      if wielding then begin
         call reset_npc_armor_stats(critter, obj_pid(critter_inven_obj(critter, INVEN_TYPE_WORN)));
      end else begin
         call reset_npc_armor_stats(critter, obj_pid(item));
      end

      if (critter == Myron_Ptr) then begin
         set_critter_extra_stat(critter, STAT_ac, get_critter_extra_stat(critter, STAT_ac) + 5);
      end
      if (critter == Lenny_Ptr) then begin
         level := get_npc_level(mstr_scrname(239));
         // Do not set EMP DR bonus
         switch level begin
            case 1: dtdr_arr := [1, 2, 2, 1, 1, 0, 2, 10, 15, 15, 10, 10, 0, 15];
            case 2: dtdr_arr := [1, 2, 2, 1, 1, 0, 2, 10, 20, 20, 10, 10, 0, 15];
            case 3: dtdr_arr := [2, 2, 2, 2, 1, 0, 2, 15, 25, 25, 15, 10, 0, 15];
            default: dtdr_arr := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
         end
         fix_array(dtdr_arr);
         call set_npc_armor_bonus(critter, dtdr_arr);
      end
   end
end
The script will make sure there won't be leftover or negative values in bonus stats when you take off or replace armors for party members. For the player, you can "click" (pick up & put down without dragging) your current worn armor in the inventory to update your armor stats. Due to scripting limits, your DT/DR values won't be reset if you move your worn armor directly back to the inventory list, but the values will be corrected when wearing a new armor.

It's probably not the most elegant one and definitely not versatile enough, as you can see it only works on limited party members and requires additional definitions for Myron (who has AC bonus equaling to Dodger perk) and Lenny (who has natural armor once he levels up). It could be rewritten into loading armor bonus stats from party member protos with an INI containing a list of their base/stages PIDs, so it would be more versatile for other TCs with new party members. But I'm not good at scripting/programming stuff. :oops:
 
Last edited:
I had hell with this in first versions of inventory filter. Stalin's sorted it out later.
 
Last edited:
I had hell with this in first versions of inventory filter.
Там была проблема другая, у брони слетала характеристика защиты, а тут у Криттеров. :)
 
Back
Top