Skip to content

Commit

Permalink
AI called shot tweaks now a proper sub-mod
Browse files Browse the repository at this point in the history
- Load settings from ini
- Option in installer to disable
  • Loading branch information
phobos2077 committed May 26, 2024
1 parent 84249a5 commit a0c472f
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 28 deletions.
2 changes: 1 addition & 1 deletion docs/ddraw_ini_settings.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[Misc]

VersionString=FALLOUT II 1.02d RPU v29 + map_update + EcCo v0.9.4
VersionString=FALLOUT II 1.02d RPU v29 + map_update + EcCo v0.9.*

DamageFormula=0

Expand Down
4 changes: 4 additions & 0 deletions docs/ecco_changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
-=== CHANGELOG ===-

v0.9.6:
> AI:
- increased called (aimed) shot frequency of all enemies
- reduced minimum INT requirements for AI called shots to include many Gun-weilding NPC's in FO2

> Healing:
- replaced default FirstAid/Doctor/Repair skill usage with fully-featured scripted implementation
- added critical healing success: restores more HP than normal
Expand Down
6 changes: 4 additions & 2 deletions extra/installer.iss
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ en.InstallCustom=Custom install
en.InstallNull=Uncheck all

en.CMain=EcCo Gameplay Overhaul mod
;en.CCombatFreeMove=Bonus move points for high AG characters
en.CAICalledShots=More frequent called shots by NPC's
en.CCarryUnspentAP=Carry up to 2 unspent AP to next round
en.CRemoveBonusRoF=Removal of Bonus Rate of Fire perk
en.CThrowingMeleeDmg=Apply Melee Damage stat to Throwing weapons
Expand All @@ -88,7 +88,7 @@ ru.InstallCustom=Выборочная установка
ru.InstallNull=Ничего не выбирать

ru.CMain=EcCo - переработка геймплея
;ru.CCombatFreeMove=Бонусные ОД всем персонажам с высокой Ловкостью
ru.CAICalledShots=Более частые прицельные атаки ИИ
ru.CCarryUnspentAP=Перенос части непотраченных ОД на следующих ход
ru.CRemoveBonusRoF=Удаление перка "Бонус скорострельности"
ru.CThrowingMeleeDmg=Применять урон ближнего боя к метательному оружию
Expand All @@ -115,6 +115,7 @@ Name: "custom"; Description: "{cm:InstallCustom}"; Flags: iscustom
[Components]
Name: "main"; Description: "{cm:CMain}"; Types: full custom; Flags: fixed
;Name: "option"; Description: "{cm:COptions}"; Types: full
Name: "ai_called_shots"; Description: "{cm:CAICalledShots}"; Types: full
Name: "carry_unspent_ap"; Description: "{cm:CCarryUnspentAP}"; Types: full
Name: "remove_bonus_rof"; Description: "{cm:CRemoveBonusRoF}"; Types: full
Name: "throwing_melee_dmg"; Description: "{cm:CThrowingMeleeDmg}"; Types: full
Expand Down Expand Up @@ -165,6 +166,7 @@ Filename: "{app}\ddraw.ini"; Section: "Misc"; Key: "MovieTimer_artimer4"; String

;Filename: "{app}\ddraw.ini"; Section: "Misc"; Key: "CheckWeaponAmmoCost"; String: "1"; Components: combat

Filename: "{app}\mods\ecco\combat.ini"; Section: "AI"; Key: "called_tweaks"; String: "0"; Components: not ai_called_shots
Filename: "{app}\mods\ecco\combat.ini"; Section: "APCOST"; Key: "carry_unspent_ap"; String: "0"; Components: not carry_unspent_ap
Filename: "{app}\mods\ecco\combat.ini"; Section: "THROWING"; Key: "apply_melee_dmg"; String: "0"; Components: not throwing_melee_dmg
Filename: "{app}\mods\ecco\combat.ini"; Section: "MONSTER_PARTS"; Key: "enable"; String: "0"; Components: not monster_parts
Expand Down
8 changes: 4 additions & 4 deletions root/data/data/ai.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ area_attack_mode=be_sure
attack_end=2552
attack_start=2540
body_type=Tough Person
called_freq=25
called_freq=10
chance=25
color=58
font=101
Expand Down Expand Up @@ -1690,7 +1690,7 @@ attack_start=3140
attack_who=closest
best_weapon=ranged_over_melee
body_type=Ghoul
called_freq=20
called_freq=10
chance=25
color=58
distance=stay
Expand Down Expand Up @@ -1812,7 +1812,7 @@ attack_end=50140
attack_start=50140
attack_who=closest
body_type=None
called_freq=10
called_freq=20
chance=0
color=58
disposition=-1
Expand Down Expand Up @@ -8163,7 +8163,7 @@ aggression=90
attack_end=2552
attack_start=2540
body_type=Tough Person
called_freq=40
called_freq=10
chance=16
color=58
font=101
Expand Down
11 changes: 11 additions & 0 deletions root/mods/ecco/combat.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
[AI]
; 1 to enable smart body part selection and all other tweaks related to called shots, 0 to disable
called_tweaks=1

; Intelligence required to attempt called shots for each difficulty level Easy,Medium,Hard. Vanilla: 7,5,3.
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.2


[DAMAGE]
; A fraction [0..1] of shots in a critical burst attack that will keep armor bypass and critical damage multiplier.
; For example, if set to 0.5, 10 bullets hit target and attack was a critical, first 5 bullets will retain the full damage and bypass (if any) of the attack. 5 remaining bullets will deal normal damage as if there was no critical.
Expand Down
5 changes: 3 additions & 2 deletions scripts_src/_pbs_headers/ecco_ini.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
#define get_int_from_ini(file, section, setting) get_ini_setting(file + "|" + section + "|" + setting)
#define get_str_from_ini(file, section, setting) get_ini_string(file + "|" + section + "|" + setting)
#define get_float_from_ini(file, section, setting) atof(get_str_from_ini(file, section, setting))
#define get_list_from_ini(file, section, setting, func) array_transform(array_filter(string_split(get_str_from_ini(file, section, setting), ","), @string_null_or_empty), func)
#define get_int_list_from_ini(file, section, setting) get_list_from_ini(file, section, setting, @string_to_int)
#define get_list_from_ini(file, section, setting, func) array_transform(array_filter(string_split(get_str_from_ini(file, section, setting), ","), @string_null_or_empty, true), func)
#define get_int_list_from_ini(file, section, setting) string_split_ints(get_str_from_ini(file, section, setting), ",")

procedure get_ini_value_def(variable file, variable section, variable setting, variable defValue) begin
variable
Expand Down Expand Up @@ -71,6 +71,7 @@ end
//#define load_int_from_ini(name, def) ini_##name := get_int_from_ini_def(INI_FILE, INI_SECTION, #name, def)
#define load_bool_from_ini(name, def) ini_##name := (get_ini_value_def(INI_FILE, INI_SECTION, #name, def) != 0)
#define load_num_from_ini(name, def, min, max) ini_##name := math_clamp(get_ini_value_def(INI_FILE, INI_SECTION, #name, def), min, max)
#define load_int_list_from_ini(name) ini_##name := array_fixed(get_int_list_from_ini(INI_FILE, INI_SECTION, #name))
#define load_range_from_ini(name, defMin, defMax, min, max) ini_##name := array_fixed(ini_parse_range_clamped(get_str_from_ini(INI_FILE, INI_SECTION, #name), defMin, defMax, min, max))

#endif
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
#include "../../sfall/sfall.h"
#include "../../sfall/define_lite.h"
#include "../../sfall/define_extra.h"
#include "../../sfall/command_lite.h"
#include "../sfall/sfall.h"
#include "../sfall/define_lite.h"
#include "../sfall/define_extra.h"
#include "../sfall/command_lite.h"

#include "../../_pbs_headers/engine_funcs.h"
#include "../../_pbs_headers/ecco_log.h"
#include "../sfall/lib.arrays.h"

#include "../_pbs_headers/engine_funcs.h"
#include "../_pbs_headers/ecco_ini.h"
#include "../_pbs_headers/ecco_log.h"

#define SCRIPT_REALNAME "pbs_ai"

variable begin
ini_called_int_req;
ini_called_freq_mult;
turn_critter;
modified_hit_chance;
end


procedure get_min_iq_for_called begin
switch (combat_difficulty) begin
case DIFFICULTY_EASY: return 6;
case DIFFICULTY_MEDIUM: return 4; // many gun-user critters have IQ of 4, but in vanilla this was 5
case DIFFICULTY_HARD: return 2;
end
end

/**
* Similar to item_w_called_shot
*/
Expand Down Expand Up @@ -68,15 +64,20 @@ end*/
* @ret {int}
*/
procedure ai_choose_bodypart(variable attacker, variable attackType, variable hitChanceRaw, variable oldBodyPart) begin
variable
weapon := item_hit_with(attacker, attackType);
variable weapon := item_hit_with(attacker, attackType);

// TODO: check AP cost for called shot
if (not item_w_called_shot_my(attacker, weapon, attackType)) then return BODY_UNCALLED;

// Roll against called_freq.
variable calledFreq := ceil(get_object_ai_data(attacker, AI_CAP_CALLED_FREQ) * ini_called_freq_mult);
if (random(1, calledFreq) != 1) then return BODY_UNCALLED;

// Minimum INT check.
variable attackerIq := get_critter_stat(attacker, STAT_iq);
if (attackerIq < get_min_iq_for_called) then return BODY_UNCALLED;
if (attackerIq < ini_called_int_req[combat_difficulty]) then return BODY_UNCALLED;

// Choose random body part that satisfies check against min_to_hit.
variable bodyPart, resultPart, hitChance,
isRanged := item_w_subtype(weapon, attackType) == WEAPON_TYPE_RANGED,
oldModifier := calc_bodypart_hit_modifier(oldBodyPart, isRanged),
Expand Down Expand Up @@ -155,7 +156,7 @@ procedure tohit_handler begin
if (newBodyPart != bodyPart) then begin
set_object_data(ctd, C_ATTACK_BODY_PART, newBodyPart);
set_sfall_return(modified_hit_chance);
set_sfall_arg(0, hitChance);
set_sfall_arg(0, modified_hit_chance);
end
end
end
Expand All @@ -180,8 +181,30 @@ procedure combatturn_handler begin
end
end

#define INI_FILE INI_COMBAT
#define INI_SECTION "AI"

procedure load_called_shot_settings begin
load_int_list_from_ini(called_int_req);
load_num_from_ini(called_freq_mult, 1.0, 0.0, 10.0);

// Default INT requirements.
variable len := len_array(ini_called_int_req);
if (len < DIFFICULTY_HARD + 1) then begin
resize_array(ini_called_int_req, DIFFICULTY_HARD + 1);
ini_called_int_req[DIFFICULTY_HARD] := 3;
end
if (len < 2) then ini_called_int_req[DIFFICULTY_NORMAL] := 5;
if (len < 1) then ini_called_int_req[DIFFICULTY_EASY] := 7;

debug_log_fmt("Called Shot tweaks enabled. called_freq mult: %.2f, INT req: %s", ini_called_freq_mult, debug_array_str(ini_called_int_req));
end

procedure start begin
if not game_loaded then return;
if (get_ini_value_def(INI_FILE, INI_SECTION, "called_tweaks", 0) == 0) then return;

call load_called_shot_settings;

register_hook_proc(HOOK_TOHIT, tohit_handler);
register_hook_proc(HOOK_COMBATTURN, combatturn_handler);
Expand Down
5 changes: 5 additions & 0 deletions scripts_src/_pbs_main/tests/gl_cheat_enemyspawner.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "..\..\sfall\lib.inven.h"
#include "..\..\headers\animcomd.h"
#include "..\..\headers\critrpid.h"
#include "..\..\headers\scenepid.h"
#include "..\..\headers\itempid.h"
#include "..\..\headers\scripts.h"
#include "..\..\_pbs_headers\ecco_ids.h"
Expand All @@ -30,6 +31,10 @@ variable enemy_types;

#define is_throwing_weapon_pid(pid) (weapon_attack_mode1(pid) == ATTACK_MODE_THROW)

procedure spawn_obj(variable pid, variable tile := 0) begin
return create_object_sid(pid, tile or tile_under_cursor, dude_elevation, -1);
end

procedure spawn_enemy(variable type, variable tile := 0) begin
variable critter, pid, sid, weaponPid, weapon, ammoPid, stimpaks, female;
switch (type) begin
Expand Down

0 comments on commit a0c472f

Please sign in to comment.