diff --git a/docs/todo.txt b/docs/todo.txt index 4564145..6eea354 100644 --- a/docs/todo.txt +++ b/docs/todo.txt @@ -26,6 +26,7 @@ Considering: IDEAS: +- napalm/incendiary throwing grenade? (similar to 40mm IC but for throwing, higher tier alternative to Molotov) - leather hides from dead brahmin? - weapon destruction chance/% to depend on attack type/damage (bursts vs single, explosion vs punch, etc) - Demolition Expert to buff all "explosion" attacks, not just traps? diff --git a/proto_src/items/ammo/00000359.yml b/proto_src/items/ammo/00000359.yml index 23e0cc2..6387a28 100644 --- a/proto_src/items/ammo/00000359.yml +++ b/proto_src/items/ammo/00000359.yml @@ -11,7 +11,7 @@ sid: -1 type: ITEM_TYPE_AMMO material: 1 size: 1 -weight: 2 +weight: 1 cost: 450 inventoryFid: 117440749 soundId: '0' diff --git a/root/data/proto/items/00000359.pro b/root/data/proto/items/00000359.pro index e6e2d73..331e41b 100644 Binary files a/root/data/proto/items/00000359.pro and b/root/data/proto/items/00000359.pro differ diff --git a/root/mods/ecco/combat.ini b/root/mods/ecco/combat.ini index f41a3f6..b2dadf6 100644 --- a/root/mods/ecco/combat.ini +++ b/root/mods/ecco/combat.ini @@ -8,6 +8,12 @@ called_int_req=6,4,2 ; Global multiplier for called_freq of all AI packets (ai.txt). Useful to increase called shot frequency across the game without editing every packet. called_freq_mult=0.5 +; 1 to enable smarter best weapon selection based on damage calculation using formula from EcCo damage mod +bestweapon_tweaks=1 + +; Reference armor PID to use when estimating damage from a weapon when there's no current target (such as when pressing Best Weapon button in party Combat Control window) +bestweapon_ref_armor_pid=379 ; Leather mk2 + [DAMAGE] ; A fraction [0..1] of shots in a critical burst attack that will keep armor bypass and critical damage multiplier. @@ -115,7 +121,7 @@ destroy_weapon_list=5,6,8,9,10,11,12,13,15,16,18,22,23,24,28,94,115,116,118,122, ; set positive to reduce % of ammo (not including ammo loaded in guns) left in critters after death: , ; 100 means remove all, 50 mean roughly 50% of ammo will be deleted, etc. -reduce_ammo_percent=70,90 +reduce_ammo_percent=60,100 ; set positive to reduce % of drugs left in critters after death reduce_drugs_percent=50 diff --git a/scripts_src/_pbs_main/gl_pbs_ai.ssl b/scripts_src/_pbs_main/gl_pbs_ai.ssl index ee9d92f..690f1ff 100644 --- a/scripts_src/_pbs_main/gl_pbs_ai.ssl +++ b/scripts_src/_pbs_main/gl_pbs_ai.ssl @@ -20,11 +20,16 @@ #define SCRIPT_REALNAME "pbs_ai" +import procedure calc_effective_dtdr(variable targetDT, variable targetDR, variable ammoDR, variable ctdSource, variable bypass, + variable weaponPerk, variable attackType); + variable begin ini_called_int_req; ini_called_freq_mult; turn_critter; modified_hit_chance; + + ini_bestweapon_ref_armor_pid; end /** @@ -191,6 +196,7 @@ procedure combatturn_handler begin end end +#define ref_armor_dtdr(offset, dmgType) (get_proto_data(ini_bestweapon_ref_armor_pid, offset + dmgType * 4) if ini_bestweapon_ref_armor_pid > 0 else 0) procedure weapon_rank(variable critter, variable weapon, variable target) begin // TODO: vanilla uses combat_safety_invalidate_weapon to account for potential friendly fire, this code does not @@ -203,10 +209,11 @@ procedure weapon_rank(variable critter, variable weapon, variable target) begin ammoDmgMult := (1.0 * get_proto_data(ammoPid, PROTO_AM_DMG_MULT) / get_proto_data(ammoPid, PROTO_AM_DMG_DIV) if (ammoPid > 0) else 1), dmgType := get_proto_data(pid, PROTO_WP_DMG_TYPE), perk := get_proto_data(pid, PROTO_WP_PERK), - targetDT := get_critter_stat(target, STAT_dmg_thresh + dmgType) if target != 0 else 0, - targetDR := get_critter_stat(target, STAT_dmg_resist + dmgType) if target != 0 else 0, - effectiveDT := (targetDT * 20 / 100) if perk == PERK_weapon_penetrate else targetDT, - expectedDmgPerAttack := (ammoDmgMult * avgDmg * avgBurstSize - effectiveDT) * (100 - targetDR) / 100, + targetDT := get_critter_stat(target, STAT_dmg_thresh + dmgType) if target != 0 else ref_armor_dtdr(PROTO_AR_DT_NORMAL, dmgType), + targetDR := get_critter_stat(target, STAT_dmg_resist + dmgType) if target != 0 else ref_armor_dtdr(PROTO_AR_DR_NORMAL, dmgType), + ammoDR := get_proto_data(ammoPid, PROTO_AM_DR_MOD) if (ammoPid > 0) else 0, + finalDTDR := calc_effective_dtdr(targetDT, targetDR, ammoDR, critter, false, perk, ATKTYPE_LWEP1), + expectedDmgPerAttack := avgBurstSize * math_max((ammoDmgMult * avgDmg - finalDTDR[0]) * (100 - finalDTDR[1]) / 100, 0), attackAP := get_proto_data(pid, PROTO_WP_APCOST_2) if (weapon_attack_mode2(pid) == ATTACK_MODE_BURST) else get_proto_data(pid, PROTO_WP_APCOST_1), expectedDmgPerAP := expectedDmgPerAttack / attackAP, range := get_proto_data(pid, PROTO_WP_RANGE_1), @@ -223,7 +230,8 @@ procedure weapon_rank(variable critter, variable weapon, variable target) begin end else rangeFactor := range; - // TODO: get calculated damage from gl_pbs_damage_mod via exported proc? + //debug_log_fmt("%s DR dmg mult: %.2f, dr mod: %d | target DT %d, DR %d", proto_data(ammoPid, it_name), ammoDmgMult, ammoDR, targetDT, targetDR); + //debug_log_fmt("%s effective DT/DR %s, dmgPerAttack: %.2f", obj_name(weapon), debug_array_str(finalDTDR), expectedDmgPerAttack); return round(dmgFactor + rangeFactor); end @@ -275,7 +283,7 @@ procedure bestweapon_handler begin weapon1rank := weapon_rank(critter, weapon1, target), weapon2rank := weapon_rank(critter, weapon2, target); - debug_log_fmt("%s's bestweapon: %s (%d) vs %s (%d)", obj_name_safe(critter), obj_name_safe(weapon1), weapon1rank, obj_name_safe(weapon2), weapon2rank); + debug_log_fmt("%s's bestweapon against %s: %s (%d) vs %s (%d)", obj_name_safe(critter), obj_name_safe(target), obj_name_safe(weapon1), weapon1rank, obj_name_safe(weapon2), weapon2rank); set_sfall_return(weapon1 if weapon1rank > weapon2rank else weapon2); end @@ -306,5 +314,8 @@ procedure start begin register_hook_proc(HOOK_COMBATTURN, combatturn_handler); end - register_hook_proc(HOOK_BESTWEAPON, bestweapon_handler); + if (get_ini_value_def(INI_FILE, INI_SECTION, "bestweapon_tweaks", 0)) then begin + load_num_from_ini_unclamped(bestweapon_ref_armor_pid, 0); + register_hook_proc(HOOK_BESTWEAPON, bestweapon_handler); + end end diff --git a/scripts_src/_pbs_main/gl_pbs_damage_mod.ssl b/scripts_src/_pbs_main/gl_pbs_damage_mod.ssl index 53b49b5..6cee1b6 100644 --- a/scripts_src/_pbs_main/gl_pbs_damage_mod.ssl +++ b/scripts_src/_pbs_main/gl_pbs_damage_mod.ssl @@ -39,7 +39,7 @@ procedure check_damage_formula; procedure get_weapon_damage_type_override(variable weapon); procedure calc_damage(variable weapon, variable rounds, variable targetDT, variable targetDR, variable rangedBonus, variable criticalMult, variable difficulty, variable ctdSource, variable flags, variable dmgType, variable weaponPerk, variable attackType); -procedure calc_effective_dtdr(variable targetDT, variable targetDR, variable ammoDR, variable ctdSource, variable bypass, +export procedure calc_effective_dtdr(variable targetDT, variable targetDR, variable ammoDR, variable ctdSource, variable bypass, variable weaponPerk, variable attackType); procedure get_ammo_value(variable weapon, variable param); procedure map_enter_p_proc; @@ -73,7 +73,8 @@ variable ini_dr_adjust_by_attack_mode, ini_debug, living_anatomy_bonus, - pyromaniac_bonus; + pyromaniac_bonus, + last_dtdr; procedure start begin if game_loaded then begin @@ -449,7 +450,12 @@ procedure calc_dtdr_vanilla_plus(variable targetDT, variable targetDR, variable // No change to DR calculation. targetDR += ammoDR; - return [math_max(targetDT, 0), math_max(math_min(targetDR, 100), 0)]; + if (not last_dtdr) then + last_dtdr := create_array_list(2); + + last_dtdr[0] := math_max(targetDT, 0); + last_dtdr[1] := math_max(math_min(targetDR, 100), 0); + return last_dtdr; end procedure calc_effective_dtdr(variable targetDT, variable targetDR, variable ammoDR, variable ctdSource, variable bypassArmor,