Skip to content

Commit

Permalink
AI bestweapon tweaks and more ammo reduction % spread
Browse files Browse the repository at this point in the history
  • Loading branch information
phobos2077 committed Jun 29, 2024
1 parent 8515056 commit 8c91912
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 12 deletions.
1 change: 1 addition & 0 deletions docs/todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
2 changes: 1 addition & 1 deletion proto_src/items/ammo/00000359.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sid: -1
type: ITEM_TYPE_AMMO
material: 1
size: 1
weight: 2
weight: 1
cost: 450
inventoryFid: 117440749
soundId: '0'
Expand Down
Binary file modified root/data/proto/items/00000359.pro
Binary file not shown.
8 changes: 7 additions & 1 deletion root/mods/ecco/combat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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: <min_percent>,<max_percent>
; 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
Expand Down
25 changes: 18 additions & 7 deletions scripts_src/_pbs_main/gl_pbs_ai.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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
Expand All @@ -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),
Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
12 changes: 9 additions & 3 deletions scripts_src/_pbs_main/gl_pbs_damage_mod.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 8c91912

Please sign in to comment.