Skip to content

Commit 2666ab6

Browse files
committed
NPC ammo quantity overhaul
- ensure_npcs_ammo: count individual bullets instead of whole packs and calculate needed qty based on number of shots or bursts - critter_loot: add chance to have 0 ammo instead of the given range (to avoid constantly having to unload like 3 bullets) - critter_loot: reduce loot in deathanim2 instead of ondeath to account for some deaths dropping all loot on ground before it can be reduced!
1 parent 7171873 commit 2666ab6

File tree

7 files changed

+141
-54
lines changed

7 files changed

+141
-54
lines changed

docs/todo.txt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
for 1.0.0:
22
- finish Big Guns run
33
- add warning message if wrong sfall version is used (save version to ini, if it changed and still wrong, show message again)
4-
5-
for 0.9.7:
6-
- playtest
4+
- add tie-ins to barter "demand" feature, have some trader explain it in dialog (and maybe also boost your barter skill)
5+
- review usages of WEAPON_ACCURATE perk
6+
- recheck economy of all craft involving ammo after pack size changes
77

88

99
for "future":
10+
- investigate "damage_mod: Expected attacker and weapon differs", seems to be rare
1011
- custom craft schematic art
1112
- cavern encounters need rebalance!!
12-
- take a look at 4/5 AP cost for pistols
13-
- add tie-ins to barter "demand" feature, have some trader explain it in dialog (and maybe also boost your barter skill)
1413

1514

1615
Considering:
16+
- 4 AP cost for 14mm Pistol?
17+
- add special sounds for Bozar AMR (& M2?)
1718
- craft Combat Armor mk2 (what component? fuel is overused)
1819
- hard to choose specific craft component when several are available: don't auto-search trunk? or provide UI to select component?
1920
- installer switch to disable barter formula
@@ -27,10 +28,10 @@ Considering:
2728

2829
IDEAS:
2930
- some way to lure more enemy types into traps than just Geckos and Rats (Scorpions, Deathclaws, Humans...)
30-
- napalm/incendiary throwing grenade? (similar to 40mm IC but for throwing, higher tier alternative to Molotov)
3131
- leather hides from dead brahmin?
3232
- weapon destruction chance/% to depend on attack type/damage (bursts vs single, explosion vs punch, etc)
3333
- Demolition Expert to buff all "explosion" attacks, not just traps?
34+
- napalm/incendiary throwing grenade? (similar to 40mm IC but for throwing, higher tier alternative to Molotov)
3435
- more powerful crafted grenade (3 home-made grenades bundled together?)
3536
- NEW PERK: +1 to carry over AP
3637
- NEW PERK: subsequent shots to the same target cost less AP (except bursts)

root/mods/ecco/combat.ini

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ bestweapon_ref_armor_pid=379 ; Leather mk2
1919
; A fraction [0..1] of shots in a critical burst attack that will keep armor bypass and critical damage multiplier.
2020
; 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.
2121
; NOTE: first bullet always retains bypass and multiplier.
22-
; To disable, set to 1.
22+
; For vanilla behavior, set to 1.
2323
burst_critical_fraction=0.5
2424

2525
; DT affected by ammo DR Adjust value. Set separate modes for positive (JHP) and negative (AP) values. Available modes:
@@ -45,7 +45,7 @@ knockback_div=14
4545
knockback_perk_div=6
4646

4747
; Print detailed log of every damage calculation to debug log.
48-
debug=1
48+
debug=0
4949

5050

5151
[ATTACK_MODES]
@@ -120,11 +120,14 @@ destroy_weapon_spawn_junk_chance_mult=5
120120
destroy_weapon_list=5,6,8,9,10,11,12,13,15,16,18,22,23,24,28,94,115,116,118,122,143,160,233,235,242,268,283,287,296,299,300,313,332,350,351,352,353,354,355,385,387,388,389,391,392,394,395,396,397,398,399,400,401,402,403,404,405,406,407,500,522,617,629,630,634,638,639,640,643,644,646,647,648
121121

122122
; set positive to reduce % of ammo (not including ammo loaded in guns) left in critters after death: <min_percent>,<max_percent>
123-
; 100 means remove all, 50 mean roughly 50% of ammo will be deleted, etc.
124-
reduce_ammo_percent=60,100
123+
; 100 means remove all, 50 mean roughly 50% of ammo will be deleted, etc. Range: [0, 100].
124+
reduce_ammo_percent=50,70
125+
126+
; if >0, a chance to skip reduce_ammo_percent and just remove ammo stack/magazine entirely
127+
reduce_ammo_to_zero_chance=40
125128

126129
; set positive to reduce % of drugs left in critters after death
127-
reduce_drugs_percent=50
130+
reduce_drugs_percent=70
128131

129132
; comma-separated list of drug pids to be subject of reduce
130133
; Currently: Stimpak, Radaway, Antidote, Mentats, Buffout, Rad-X, Psycho, Super Stimpak, Healing powder

root/mods/ecco/misc.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ unload_weapons=1
172172
[ENCOUNTERS]
173173
; Restore Sneak state after map change
174174
remember_sneak=1
175-
; Make sure all ranged NPC's have spare ammo
175+
; Make sure all ranged NPC's have some spare ammo to remain in the fight for longer
176176
ensure_npcs_ammo=1
177177

178178

scripts_src/_pbs_headers/loot_utils.h

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,38 @@ procedure reduce_item_count(variable invenObj, variable item, variable newCount)
1717
destroy_object(item);
1818
end
1919

20-
#define calc_reduced_ammo_range(count, percentRange) math_round_chance(count * (100 - random(percentRange[0], percentRange[1])) / 100.0)
20+
procedure calc_reduced_ammo_range(variable count, variable percentRange, variable emptyChance := 0) begin
21+
if (emptyChance > 0 and random(0, 99) < emptyChance) then
22+
return 0;
23+
24+
/* variable
25+
rnd := random(percentRange[0], percentRange[1]),
26+
clamped := math_max(100 - rnd, 0),
27+
multed := count * clamped / 100.0,
28+
rounded := math_round_chance(multed),
29+
allInOne := */
30+
31+
//debug_log_fmt("calc range from %d: rnd = %d, clamped = %d, multed = %.2f, rounded = %d, allInOne = %d", count, rnd, clamped, multed, rounded, allInOne);
32+
return math_round_chance(count * math_max(100 - random(percentRange[0], percentRange[1]), 0) / 100.0);
33+
end
2134

2235
/**
2336
* Reduces number of individual bullets in an ammo stack by a percentage range.
2437
* @arg {ObjectPtr} invenObj - Container or critter
2538
* @arg {ObjectPtr} item - item stack object
2639
* @arg {list} percentRange - [min, max] range of % to remove
40+
* @arg {int} emptyChance - probabiltiy to remove all ammo
2741
* @ret {string}
2842
*/
29-
procedure reduce_ammo_in_stack(variable invenObj, variable item, variable percentRange) begin
43+
procedure reduce_ammo_in_stack(variable invenObj, variable item, variable percentRange, variable emptyChance := 0) begin
3044
if (percentRange[1] <= 0) then return "";
3145

3246
variable
3347
pid := obj_pid(item),
3448
packSize := get_proto_data(pid, PROTO_AM_PACK_SIZE),
3549
count := (obj_is_carrying_obj(invenObj, item) - 1) * packSize + get_weapon_ammo_count(item),
36-
newCount := calc_reduced_ammo_range(count, percentRange);
50+
newCount := calc_reduced_ammo_range(count, percentRange, emptyChance),
51+
itemName := obj_name(item);
3752

3853
//display_msg("count: "+count+", pack: "+packSize+", new: "+newCount+" ("+ceil(1.0*newCount / packSize)+")");
3954
call reduce_item_count(invenObj, item, ceil(1.0 * newCount / packSize));
@@ -42,17 +57,18 @@ procedure reduce_ammo_in_stack(variable invenObj, variable item, variable percen
4257
if (item and newCount % packSize > 0) then
4358
set_weapon_ammo_count(item, newCount % packSize);
4459

45-
return obj_name(item)+" ("+count+" -> "+newCount+")";
60+
return itemName+" ("+count+" -> "+newCount+"), ";
4661
end
4762

4863

4964
/**
5065
* Reduces number of individual bullets in an ammo stack by a percentage range.
5166
* @arg {ObjectPtr} item - Weapon item
5267
* @arg {list} percentRange - [min, max] range of % to remove
68+
* @arg {int} emptyChance - probabiltiy to remove all ammo
5369
* @ret {string}
5470
*/
55-
procedure reduce_ammo_in_weapon(variable item, variable percentRange) begin
71+
procedure reduce_ammo_in_weapon(variable item, variable percentRange, variable emptyChance := 0) begin
5672
if (percentRange[1] <= 0) then return "";
5773

5874
variable
@@ -61,9 +77,9 @@ procedure reduce_ammo_in_weapon(variable item, variable percentRange) begin
6177

6278
if (count <= 0) then return "";
6379

64-
newCount := calc_reduced_ammo_range(count, percentRange);
80+
newCount := calc_reduced_ammo_range(count, percentRange, emptyChance);
6581
set_weapon_ammo_count(item, newCount);
66-
return string_format("%s mag ammo (%d -> %d)", obj_name(item), count, newCount);
82+
return string_format("%s mag ammo (%d -> %d), ", obj_name(item), count, newCount);
6783
end
6884

6985
/**
@@ -83,7 +99,7 @@ procedure reduce_ammo_on_ground(variable item, variable percentRange) begin
8399
else
84100
destroy_object(item);
85101

86-
return string_format("%s (%d -> %d)", obj_name(item), count, newCount);
102+
return string_format("%s (%d -> %d), ", obj_name(item), count, newCount);
87103
end
88104

89105

@@ -110,7 +126,7 @@ procedure reduce_item_in_stack(variable invenObj, variable item, variable pidLis
110126
if (newCount == count) then return "";
111127

112128
call reduce_item_count(invenObj, item, newCount);
113-
return obj_name(item)+" ("+count+" -> "+newCount+")";
129+
return obj_name(item)+" ("+count+" -> "+newCount+"), ";
114130
end
115131

116132
/**

scripts_src/_pbs_main/gl_ammocost_mod.ssl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ variable
1515

1616
procedure start;
1717

18+
export procedure ammocost_mod_get_cost(variable weaponPid);
19+
20+
procedure ammocost_mod_get_cost(variable weaponPid) begin
21+
return ini_ammocost[weaponPid] or 1;
22+
end
23+
1824
/*
1925
HOOK_AMMOCOST
2026
Runs when calculating ammo cost for a weapon. Doesn't affect damage, only how much ammo is spent. By default, weapons can make attacks when at least 1 ammo is left, regardless of ammo cost calculations. To add proper check for ammo before attacking and proper calculation of the number of burst rounds (hook type 1 and 2 in arg3), set CheckWeaponAmmoCost=1 in Misc section of ddraw.ini.

scripts_src/_pbs_main/gl_pbs_critter_loot.ssl

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ procedure start;
1111

1212
#define SCRIPT_REALNAME "gl_pbs_critter_loot"
1313

14+
#include "../headers/animcomd.h"
1415
#include "../headers/scenepid.h"
16+
1517
#include "../sfall/define_lite.h"
1618
#include "../sfall/command_lite.h"
1719
#include "../sfall/lib.strings.h"
@@ -34,15 +36,16 @@ variable
3436
ini_weapon_drop_dist,
3537
ini_weapon_drop_dir,
3638
ini_reduce_ammo_percent,
39+
ini_reduce_ammo_to_zero_chance,
3740
ini_reduce_drugs_percent,
3841
ini_reduce_drugs_pids;
3942

4043

4144
variable destroyed_stats;
4245

4346
procedure destroy_critter_weapon(variable critter);
44-
procedure drop_weapons(variable critter);
45-
procedure reduce_loot(variable critter);
47+
procedure try_drop_weapons(variable critter);
48+
procedure try_reduce_loot(variable critter);
4649

4750
#define INI_FILE INI_COMBAT
4851
#define INI_SECTION "CRITTER_LOOT"
@@ -52,6 +55,25 @@ procedure reduce_loot(variable critter);
5255
//#define load_ini_int_clamped(name, min, max) int_from_ini_file_clamped(name, INI_COMBAT, INI_SECTION, min, max)
5356
//#define load_ini_int_list(name) int_list_from_ini_file(name, INI_COMBAT, INI_SECTION)
5457

58+
59+
procedure deathanim2_handler begin
60+
variable
61+
critter := get_sfall_arg_at(2),
62+
animId := get_sfall_arg_at(4);
63+
64+
// Reduce loot before all items drop to the ground due to violent death.
65+
/*if (( animId == ANIM_electrified_to_nothing
66+
or animId == ANIM_exploded_to_nothing
67+
)
68+
and is_critter(critter)
69+
and not critter_proto_has_flag(obj_pid(critter), CFLG_NODROP)
70+
and not critter_proto_has_flag(obj_pid(critter), CFLG_SPECIAL))
71+
then begin
72+
call try_reduce_loot(critter);
73+
end*/
74+
call try_reduce_loot(critter);
75+
end
76+
5577
/*
5678
HOOK_ONDEATH
5779
Runs immediately after a critter dies for any reason. No return values; this is just a convenience for when you need to do something after death for a large number of different critters and don't want to have to script each and every one of them.
@@ -68,15 +90,11 @@ procedure ondeath_handler begin
6890
if (not critter or obj_type(critter) != OBJ_TYPE_CRITTER) then
6991
return;
7092

71-
if (not obj_in_party(critter)
72-
and (ini_reduce_ammo_percent[1] > 0 or ini_reduce_drugs_percent > 0 or ini_destroy_weapon_percent > 0)) then begin
73-
call reduce_loot(critter);
74-
end
75-
if (ini_weapon_drop_chance > 0 and random(1, 100) <= ini_weapon_drop_chance) then begin
76-
call drop_weapons(critter);
77-
end
93+
//call try_reduce_loot(critter);
94+
call try_drop_weapons(critter);
7895
end
7996

97+
8098
procedure start begin
8199
if (game_loaded) then begin
82100

@@ -89,9 +107,11 @@ procedure start begin
89107
load_num_from_ini(weapon_drop_dir, 0, 0, 5);
90108

91109
load_range_from_ini(reduce_ammo_percent, 0, 0, 0, 100);
110+
load_num_from_ini(reduce_ammo_to_zero_chance, 0, 0, 100);
92111
load_num_from_ini(reduce_drugs_percent, 0, 0, 100);
93112
load_int_list_from_ini(reduce_drugs_pids);
94113

114+
register_hook_proc(HOOK_DEATHANIM2, deathanim2_handler);
95115
register_hook_proc(HOOK_ONDEATH, ondeath_handler);
96116
end
97117
end
@@ -152,7 +172,7 @@ end
152172

153173
#define is_unarmed_weapon_pid(pid) (weapon_attack_mode1(pid) == ATTACK_MODE_PUNCH)
154174

155-
procedure drop_weapons(variable critter) begin
175+
procedure try_drop_weapons(variable critter) begin
156176
variable
157177
dist,
158178
dir,
@@ -161,7 +181,9 @@ procedure drop_weapons(variable critter) begin
161181
critter_flags,
162182
i;
163183

164-
if (critter_proto_has_flag(obj_pid(critter), CFLG_NODROP)) then return;
184+
if (ini_weapon_drop_chance <= 0
185+
or critter_proto_has_flag(obj_pid(critter), CFLG_NODROP)
186+
or random(1, 100) > ini_weapon_drop_chance) then return;
165187

166188
for (i := 1; i <= 2; i++) begin
167189
weapon := critter_inven_obj(critter, i);
@@ -192,13 +214,15 @@ procedure drop_weapons(variable critter) begin
192214
move_to(weapon, dropped_hex, elevation(critter));
193215
end
194216

195-
procedure reduce_loot(variable critter) begin
217+
procedure try_reduce_loot(variable critter) begin
196218
variable
197219
item,
198220
list,
199221
removeStats;
200222

201-
if (critter_proto_has_flag(obj_pid(critter), CFLG_NOSTEAL)) then return;
223+
if ((ini_reduce_ammo_percent[1] <= 0 and ini_reduce_drugs_percent <= 0 and ini_destroy_weapon_percent <= 0)
224+
or obj_in_party(critter)
225+
or critter_proto_has_flag(obj_pid(critter), CFLG_NOSTEAL)) then return;
202226

203227
list := inven_as_array(critter);
204228
removeStats := "";
@@ -207,7 +231,7 @@ procedure reduce_loot(variable critter) begin
207231
continue;
208232

209233
if (obj_item_subtype(item) == item_type_ammo) then begin
210-
removeStats += reduce_ammo_in_stack(critter, item, ini_reduce_ammo_percent);
234+
removeStats += reduce_ammo_in_stack(critter, item, ini_reduce_ammo_percent, ini_reduce_ammo_to_zero_chance);
211235
end
212236
else if (obj_item_subtype(item) == item_type_drug) then begin
213237
removeStats += reduce_item_in_stack(critter, item, ini_reduce_drugs_pids, ini_reduce_drugs_percent);
@@ -218,7 +242,7 @@ procedure reduce_loot(variable critter) begin
218242
and try_destroy_weapon(critter, item)) then
219243
removeStats += obj_name(item)+", ";
220244
else
221-
removeStats += reduce_ammo_in_weapon(item, ini_reduce_ammo_percent);
245+
removeStats += reduce_ammo_in_weapon(item, ini_reduce_ammo_percent, ini_reduce_ammo_to_zero_chance);
222246
end
223247
end
224248
if (removeStats != "") then

0 commit comments

Comments
 (0)