Okay, it looks like the main problems with the limited ammo script have been solved. There may be a bug remaining somewhere, but I can't find it. Please post here if you run into one.
[EDIT] Added the AI bows, which were missing from the script and were thereby rendering it inoperable. Goes to show how many people are using this script, eh? [/EDIT]
The script, with instructions:
# MODULE_ITEMS
#
# These arrows need to be near the beginning of the module_items list, as they use troop
# slots on trp_player which are equal to the arrows' entry number. There is a limited number
# of slots, so if the arrows are (for example) number 500+ in the items file, this script
# will cease to work.
#
# Make sure none of the slots used in this script conflict with slots you may have already
# used in your mod. You can see the numbers of each item entry in ID_items.py.
#
# If you haven't modded any of trp_player's slots, then you have nothing to worry about.
#
# Replace the Native arrow entries with the following block.
#
# After you have done this, replace all mention of
itm_arrows in module_troops with
#
itm_ai_arrows. By doing this, AI arrows will not run out after 1 shot, they will
# not be considered by the limited ammo script, and they will not be lootable or available
# at merchants.
["ai_arrows","arrows", [("arrow",0)], itp_type_arrows|itp_unique, 0, 0,weight(3)|abundance(160)|weapon_length(95)|thrust_damage(1,pierce)|max_ammo(24),imodbits_missile],
["arrows","arrows", [("arrow",0)], itp_type_arrows|itp_merchandise, 0, 36,weight(3)|abundance(160)|weapon_length(95)|thrust_damage(1,pierce)|max_ammo(1),imodbits_missile],
["barbed_arrows","barbed_arrows", [("barbed_arrow",0)], itp_type_arrows|itp_merchandise, 0, 68,weight(3)|abundance(70)|weapon_length(95)|thrust_damage(2,pierce)|max_ammo(1),imodbits_missile],
["bodkin_arrows","bodkin_arrows", [("piercing_arrow",0)], itp_type_arrows|itp_merchandise, 0, 124,weight(3)|abundance(50)|weapon_length(100)|thrust_damage(3,pierce)|max_ammo(1),imodbits_missile],
["bolts","bolts", [("bolt",0)], itp_type_bolts|itp_merchandise, 0, 32,weight(2.25)|abundance(90)|weapon_length(55)|thrust_damage(1,pierce)|max_ammo(2),imodbits_missile],
# Replace the Native bow and crossbow entries with the following block:
["hunting_bow", "hunting_bow", [("hunting_bow",0)], itp_type_bow |itp_merchandise|itp_primary|itp_two_handed,itcf_shoot_bow, 17 , weight( 1 )|difficulty( 0 )|spd_rtng( 94 ) | shoot_speed( 46 ) | thrust_damage( 15 , pierce ),imodbits_bow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_hunting_bow"),(assign,"$range_low","itm_arrows"),(assign,"$range_high","itm_bolts"),(call_script,"script_limited_ammo")])]],
["short_bow", "short_bow", [("short_bow",0)], itp_type_bow |itp_merchandise|itp_primary|itp_two_handed ,itcf_shoot_bow, 58 , weight(1)|difficulty(1)|spd_rtng(9
| shoot_speed(49) | thrust_damage(16 , pierce ),imodbits_bow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_short_bow"),(assign,"$range_low","itm_arrows"),(assign,"$range_high","itm_bolts"),(call_script,"script_limited_ammo")])]],
["nomad_bow", "nomad_bow", [("nomad_bow",0)], itp_type_bow |itp_merchandise|itp_primary|itp_two_handed ,itcf_shoot_bow, 154 , weight(1.25)|difficulty(2)|spd_rtng(96) | shoot_speed(51) | thrust_damage(18 , pierce),imodbits_bow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_nomad_bow"),(assign,"$range_low","itm_arrows"),(assign,"$range_high","itm_bolts"),(call_script,"script_limited_ammo")])]],
["long_bow", "long_bow", [("long_bow",0)], itp_type_bow |itp_merchandise|itp_primary|itp_two_handed ,itcf_shoot_bow, 67 , weight(1.75)|difficulty(3)|spd_rtng(82) | shoot_speed(51) | thrust_damage(19 , pierce),imodbits_bow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_long_bow"),(assign,"$range_low","itm_arrows"),(assign,"$range_high","itm_bolts"),(call_script,"script_limited_ammo")])]],
["khergit_bow", "khergit_bow", [("khergit_bow",0)], itp_type_bow |itp_merchandise|itp_primary|itp_two_handed,itcf_shoot_bow, 164 , weight(1.25)|difficulty(3)|spd_rtng(95) | shoot_speed(54) | thrust_damage(20 ,pierce),imodbits_bow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_khergit_bow"),(assign,"$range_low","itm_arrows"),(assign,"$range_high","itm_bolts"),(call_script,"script_limited_ammo")])]],
["strong_bow", "strong_bow", [("strong_bow",0)], itp_type_bow |itp_merchandise|itp_primary|itp_two_handed ,itcf_shoot_bow, 251 , weight(1.25)|difficulty(3)|spd_rtng(94) | shoot_speed(55) | thrust_damage(21 ,pierce),imodbits_bow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_strong_bow"),(assign,"$range_low","itm_arrows"),(assign,"$range_high","itm_bolts"),(call_script,"script_limited_ammo")])]],
["war_bow", "war_bow", [("war_bow",0)],itp_type_bow|itp_merchandise|itp_primary|itp_two_handed ,itcf_shoot_bow, 304 , weight(1.5)|difficulty(4)|spd_rtng(93) | shoot_speed(56) | thrust_damage(22 ,pierce),imodbits_bow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_war_bow"),(assign,"$range_low","itm_arrows"),(assign,"$range_high","itm_bolts"),(call_script,"script_limited_ammo")])]],
["hunting_crossbow", "hunting_crossbow", [("crossbow",0)], itp_type_crossbow |itp_merchandise|itp_primary|itp_two_handed ,itcf_shoot_crossbow, 3 , weight(2.25)|difficulty(0)|spd_rtng(44) | shoot_speed(50) | thrust_damage(24 , pierce)|max_ammo(1),imodbits_crossbow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_hunting_crossbow"),(assign,"$range_low","itm_bolts"),(assign,"$range_high","itm_cartridges"),(call_script,"script_limited_ammo")])]],
["light_crossbow", "light_crossbow", [("light_crossbow",0)], itp_type_crossbow |itp_merchandise|itp_primary|itp_two_handed ,itcf_shoot_crossbow, 32 , weight(2.5)|difficulty(
|spd_rtng(43) | shoot_speed(59) | thrust_damage(33 , pierce)|max_ammo(1),imodbits_crossbow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_light_crossbow"),(assign,"$range_low","itm_bolts"),(assign,"$range_high","itm_cartridges"),(call_script,"script_limited_ammo")])]],
["crossbow", "crossbow", [("crossbow",0)], itp_type_crossbow |itp_merchandise|itp_primary|itp_two_handed|itp_cant_use_on_horseback ,itcf_shoot_crossbow, 149 , weight(3)|difficulty(
|spd_rtng(42) | shoot_speed(6
| thrust_damage(42,pierce)|max_ammo(1),imodbits_crossbow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_crossbow"),(assign,"$range_low","itm_bolts"),(assign,"$range_high","itm_cartridges"),(call_script,"script_limited_ammo")])]],
["heavy_crossbow", "heavy_crossbow", [("heavy_crossbow",0)], itp_type_crossbow |itp_merchandise|itp_primary|itp_two_handed|itp_cant_use_on_horseback ,itcf_shoot_crossbow, 291 , weight(3.5)|difficulty(9)|spd_rtng(40) | shoot_speed(72) | thrust_damage(47 ,pierce)|max_ammo(1),imodbits_crossbow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_heavy_crossbow"),(assign,"$range_low","itm_bolts"),(assign,"$range_high","itm_cartridges"),(call_script,"script_limited_ammo")])]],
["sniper_crossbow", "sniper_crossbow", [("heavy_crossbow",0)], itp_type_crossbow |itp_merchandise|itp_primary|itp_two_handed|itp_cant_use_on_horseback ,itcf_shoot_crossbow, 450 , weight(3.75)|difficulty(10)|spd_rtng(3
| shoot_speed(74) | thrust_damage(52 ,pierce)|max_ammo(1),imodbits_crossbow,
[(ti_on_weapon_attack, [(assign,reg(3),0),(assign,"$pin_item","itm_sniper_crossbow"),(assign,"$range_low","itm_bolts"),(assign,"$range_high","itm_cartridges"),(call_script,"script_limited_ammo")])]],
# Place extra bows and crossbows before this point, and add an AI equivalent bow at the
# same location at the end of the AI bows list.
# The AI bows have no attached scripts so that they will not drain the player's ammo.
# AI weapons are automatically placed in the inventory of all non-player troops; you can
# give them the normal scripted bows, and everything will still function as normal.
["hunting_bow_ai", "hunting_bow", [("hunting_bow",0)], itp_type_bow |itp_unique|itp_primary|itp_two_handed,itcf_shoot_bow, 17 , weight(1)|abundance(0)|difficulty(0)|spd_rtng(100) | shoot_speed(46) | thrust_damage(14 , pierce),imodbits_bow ],
["short_bow_ai", "short_bow", [("short_bow",0)], itp_type_bow |itp_unique|itp_primary|itp_two_handed ,itcf_shoot_bow, 58 , weight(1)|abundance(0)|difficulty(1)|spd_rtng(9
| shoot_speed(49) | thrust_damage(16 , pierce ),imodbits_bow ],
["nomad_bow_ai", "nomad_bow", [("nomad_bow",0)], itp_type_bow |itp_unique|itp_primary|itp_two_handed ,itcf_shoot_bow, 154 , weight(1.25)|abundance(0)|difficulty(2)|spd_rtng(96) | shoot_speed(51) | thrust_damage(18 , pierce),imodbits_bow ],
["long_bow_ai", "long_bow", [("long_bow",0)], itp_type_bow |itp_unique|itp_primary|itp_two_handed ,itcf_shoot_bow, 67 , weight(1.75)|abundance(0)|difficulty(3)|spd_rtng(82) | shoot_speed(51) | thrust_damage(19 , pierce),imodbits_bow ],
["khergit_bow_ai", "khergit_bow", [("khergit_bow",0)], itp_type_bow |itp_unique|itp_primary|itp_two_handed,itcf_shoot_bow, 164 , weight(1.25)|abundance(0)|difficulty(3)|spd_rtng(95) | shoot_speed(54) | thrust_damage(20 ,pierce),imodbits_bow ],
["strong_bow_ai", "strong_bow", [("strong_bow",0)], itp_type_bow |itp_unique|itp_primary|itp_two_handed ,itcf_shoot_bow, 251 , weight(1.25)|abundance(0)|difficulty(3)|spd_rtng(94) | shoot_speed(55) | thrust_damage(21 ,pierce),imodbits_bow ],
["war_bow_ai", "war_bow", [("war_bow",0)],itp_type_bow|itp_unique|itp_primary|itp_two_handed ,itcf_shoot_bow, 304 , weight(1.5)|abundance(0)|difficulty(4)|spd_rtng(93) | shoot_speed(56) | thrust_damage(22 ,pierce),imodbits_bow ],
["hunting_crossbow_ai", "hunting_crossbow", [("crossbow",0)], itp_type_crossbow |itp_unique|itp_primary|itp_two_handed ,itcf_shoot_crossbow, 3 , weight(2.25)|abundance(0)|difficulty(0)|spd_rtng(44) | shoot_speed(50) | thrust_damage(24 , pierce)|max_ammo(1),imodbits_crossbow ],
["light_crossbow_ai", "light_crossbow", [("light_crossbow",0)], itp_type_crossbow |itp_unique|itp_primary|itp_two_handed ,itcf_shoot_crossbow, 32 , weight(2.5)|abundance(0)|difficulty(
|spd_rtng(43) | shoot_speed(59) | thrust_damage(33 , pierce)|max_ammo(1),imodbits_crossbow ],
["crossbow_ai", "crossbow", [("crossbow",0)], itp_type_crossbow |itp_unique|itp_primary|itp_two_handed|itp_cant_use_on_horseback ,itcf_shoot_crossbow, 149 , weight(3)|abundance(0)|difficulty(
|spd_rtng(42) | shoot_speed(6
| thrust_damage(42,pierce)|max_ammo(1),imodbits_crossbow ],
["heavy_crossbow_ai", "heavy_crossbow", [("heavy_crossbow",0)], itp_type_crossbow |itp_unique|itp_primary|itp_two_handed|itp_cant_use_on_horseback ,itcf_shoot_crossbow, 291 , weight(3.5)|abundance(0)|difficulty(9)|spd_rtng(40) | shoot_speed(72) | thrust_damage(47 ,pierce)|max_ammo(1),imodbits_crossbow ],
["sniper_crossbow_ai", "sniper_crossbow", [("heavy_crossbow",0)], itp_type_crossbow |itp_unique|itp_primary|itp_two_handed|itp_cant_use_on_horseback ,itcf_shoot_crossbow, 450 , weight(3.75)|abundance(0)|difficulty(10)|spd_rtng(3
| shoot_speed(74) | thrust_damage(52 ,pierce)|max_ammo(1),imodbits_crossbow ],
# MODULE_SCRIPTS
# Add the following scripts to the bottom of your module_scripts file:
("limited_ammo",
[
# This script subtracts the shot from the player's ammo, and removes ammo where appropriate.
(assign,reg(3),0),
(get_player_agent_no,reg(5)),
(troop_has_item_equipped,"trp_player","$pin_item"),
(try_for_range_backwards,reg(1),"$range_low","$range_high"),
(troop_has_item_equipped,"trp_player",reg(1)),
(try_begin),
(neq,reg(3),1),
(val_add,"$ammo_used",1),
(troop_get_slot,reg(2),"trp_player",reg(1)),
(val_add,reg(2),1),
(troop_set_slot,"trp_player",reg(1),reg(2)),
(str_store_item_name,1,reg(1)),
(call_script,"script_get_ammo_num"),
(assign,reg(4),"$ammo_num"),
(val_sub,reg(4),reg(2)),
(display_message,"str_arrow_fired"),
(assign,reg(3),1),
(try_begin),
(troop_get_slot,reg(2),"trp_player",reg(1)),
(ge,reg(2),"$ammo_num"),
(troop_set_slot,"trp_player",reg(1),0),
(troop_remove_items,"trp_player",reg(1),1),
(try_end),
(try_end),
(try_begin),
(troop_has_item_equipped,"trp_player",reg(1)),
(agent_refill_ammo,reg(5)),
(try_end),
(try_end),
]),
("get_ammo_num",
[
# This script sets the appropriate maximum ammo numbers for each type of ammo.
(try_begin),
(is_between,reg(1),"itm_arrows","itm_bolts"),
(assign,"$ammo_num",24),
(else_try),
(is_between,reg(1),"itm_bolts","itm_cartridges"),
(assign,"$ammo_num",20),
(try_end),
]),
("limited_ammo_before_combat_start",
[
# This script identifies the player's ammo and replaces all AI troops' bows with AI bows.
(assign,reg(2),0),
(try_for_range_backwards,reg(1),"itm_arrows","itm_cartridges"),
(troop_has_item_equipped,"trp_player",reg(1)),
(eq,reg(2),0),
(assign,"$ammo_type",reg(1)),
(assign,reg(2),1),
(try_end),
(try_for_range,reg(1),"trp_novice_fighter","trp_troops_end"),
(troop_set_slot,reg(1),10,0),
(troop_set_slot,reg(1),11,0),
(try_for_range,reg(2),"itm_arrows","itm_cartridges"),
(store_item_kind_count,reg(3),reg(2),reg(1)),
(gt,reg(3),0),
(troop_set_slot,reg(1),10,reg(2)),
(troop_set_slot,reg(1),11,reg(3)),
(troop_remove_items,reg(1),reg(2),reg(3)),
(troop_add_items,reg(1),"itm_ai_arrows",reg(3)),
(try_end),
(try_for_range,reg(2),"itm_hunting_bow","itm_hunting_bow_ai"),
(store_item_kind_count,reg(3),reg(2),reg(1)),
(gt,reg(3),0),
(assign,reg(4),reg(2)),
(assign,reg(5),"itm_hunting_bow"),
(assign,reg(6),"itm_hunting_bow_ai"),
(val_sub,reg(6),reg(5)),
(val_add,reg(4),reg(6)),
(troop_remove_items,reg(1),reg(2),reg(3)),
(troop_add_items,reg(1),reg(4),reg(3)),
(try_end),
(try_end),
]),
("limited_ammo_on_leave_area",
[
# This script handles arrow recovery and puts AI bows and arrows back to normal.
(assign,reg(5),0),
(try_for_range_backwards,reg(1),"itm_arrows","itm_pilgrim_disguise"),
(troop_has_item_equipped,"trp_player",reg(1)),
(try_begin),
(gt,"$ammo_used",0),
(eq,reg(5),0),
(store_random_in_range,reg(3),0,"$ammo_used"),
(store_random_in_range,reg(4),0,"$ammo_used"),
(val_sub,reg(3),reg(4)),
(call_script,"script_get_ammo_num"),
(val_sub,"$ammo_num",1),
(troop_get_slot,reg(2),"trp_player",reg(1)),
(try_begin),
(lt,reg(3),0),
(assign,reg(3),0),
(else_try),
(assign,reg(6),reg(3)),
(val_add,reg(6),reg(2)),
(gt,reg(6),"$ammo_num"),
(assign,reg(6),"$ammo_num"),
(val_sub,reg(6),reg(2)),
(assign,reg(3),reg(6)),
(try_end),
(val_add,reg(2),reg(3)),
(troop_set_slot,"trp_player",reg(1),reg(2)),
(str_store_item_name,1,reg(1)),
(display_message,"str_recover_arrows"),
(assign,reg(5),1),
(try_end),
(try_end),
(try_begin),
(neq,"$ammo_type",0),
(neg|troop_has_item_equipped,"trp_player","$ammo_type"),
(gt,"$ammo_used",0),
(store_random_in_range,reg(3),0,"$ammo_used"),
(store_random_in_range,reg(4),0,"$ammo_used"),
(val_sub,reg(3),reg(4)),
(assign,reg(1),"$ammo_type"),
(call_script,"script_get_ammo_num"),
(val_sub,"$ammo_num",1),
(try_begin),
(lt,reg(3),5),
(assign,reg(3),0),
(else_try),
(gt,reg(3),"$ammo_num"),
(assign,reg(3),"$ammo_num"),
(try_end),
(try_begin),
(ge,reg(3),5),
(troop_add_items,"trp_player","$ammo_type",1),
(troop_get_slot,reg(2),"trp_player",reg(1)),
(val_add,reg(2),reg(3)),
(troop_set_slot,"trp_player",reg(1),reg(2)),
(str_store_item_name,1,reg(1)),
(display_message,"str_recover_arrows"),
(try_end),
(try_end),
(assign,"$ammo_used",0),
(try_for_range,reg(1),"trp_novice_fighter","trp_troops_end"),
(troop_get_slot,reg(2),reg(1),10),
(troop_get_slot,reg(3),reg(1),11),
(try_begin),
(store_item_kind_count,reg(4),"itm_ai_arrows",reg(1)),
(gt,reg(4),0),
(troop_remove_items,reg(1),"itm_ai_arrows",reg(4)),
(troop_add_items,reg(1),reg(2),reg(3)),
(try_end),
(try_for_range,reg(4),"itm_hunting_bow_ai","itm_flintlock_pistol"),
(store_item_kind_count,reg(5),reg(4),reg(1)),
(gt,reg(5),0),
(assign,reg(6),reg(4)),
(assign,reg(7),"itm_hunting_bow"),
(assign,reg(
,"itm_hunting_bow_ai"),
(val_sub,reg(
,reg(7)),
(val_sub,reg(6),reg(
),
(troop_remove_items,reg(1),reg(4),reg(5)),
(troop_add_items,reg(1),reg(6),reg(5)),
(try_end),
(try_end),
]),
# MODULE_STRINGS
# Add the following strings to the bottom of your module_strings file:
("arrow_fired", "You have {reg4} {s1} left in this quiver!"),
("recover_arrows", "At the end of the battle, you manage to recover {reg3} {s1}."),
# MODULE_MISSION_TEMPLATES
# Append the following mission template triggers to any template where you wish to have
# recoverable player ammunition.
# Native templates that have combat in them:
# "lead_charge", "charge_with_allies", "castle_attack_walls", "sneak_caught_fight",
# "betrayed_by_lord".
(ti_before_mission_start, 0, 0, [], [
(assign,"$ammo_used",0),
(call_script,"script_limited_ammo_before_combat_start"),
]),
(ti_on_leave_area, 0, 0, [], [
(call_script,"script_limited_ammo_on_leave_area")
]),
# When done, add the following line to your chosen mission templates after every instance of (finish_mission,1)
(call_script,"script_limited_ammo_on_leave_area"),
This script is free for one and all to use, with credit. You do not need to ask for permission.
Generously,
Winter