This simple code replacement improves the belfry mechanics during sieges. It increases the amount of siege attackers pushing the tower and makes some changes to the mechanic by which the siege progresses. In addition, the player can also contribute to pushing (as long as the character is not standing on top of the siege tower, as in multiplayer), an effect which is increased with the troop's strength. The selection now also attempts to pick soldiers with some sort of shield instead of the first available agent, and allows archers to push as well when their ammunition is consumed. When the grunts pushing the siege tower are injured, they gradually retreat occurs towards their original entry point and fresher troops are selected instead.
Comment out common_siege_rotate_belfry, common_siege_attacker_do_not_stall from usage in native siege templates as they are redundant.
Instead of the fixed number of 6 bots pushing the siege ladder, up to 12 are allocated - two in the first row, one in the middle, and three in the back.
Comment out common_siege_rotate_belfry, common_siege_attacker_do_not_stall from usage in native siege templates as they are redundant.
Code:
common_siege_init_ai_and_belfry = (
0, 0, ti_once,
[
(call_script, "script_siege_init_ai_and_belfry"),
], [])
#run every frame for smooth wheel rotation
common_siege_move_belfry = (
0, 0, ti_once,
[
(call_script, "script_cf_siege_move_belfry"),
], [ #modified from native
(call_script, "script_siege_rot_belfry_platform")
])
# #this is run when the tower is in the final position
# #(eq, "$belfry_positioned", 1),
# common_siege_rotate_belfry = (
# 3, 2, ti_once,
# [(call_script, "script_cf_siege_rotate_belfry_platform")],
# [(assign, "$belfry_positioned", 3)])
# #native belfry has two stages at most - (assign, "$belfry_positioned", 2), is called from cf script
#the belfry siege mechanism allows 20 seconds after mission start before archer are also allowed to push
#the middle agent loop allows for infantry or cavalry to contribute
#identical destinations allow for a tighter formation of 12, 2 at front, 1 mid, and 3 back
#the player is also allowed to push (higher strenght = faster), although standing on any of the belfry props will cause this to fail
common_siege_assign_men_to_belfry = (
4, 0, ti_once,
[(call_script, "script_cf_siege_assign_men_to_belfry")],
[
(try_for_agents, ":cur_agent"),
(agent_is_active, ":cur_agent"),
(agent_is_alive, ":cur_agent"),
(agent_is_human, ":cur_agent"),
(agent_clear_scripted_mode, ":cur_agent"),
#turns out the stall script really doesn't do anything
(agent_ai_set_always_attack_in_melee, ":cur_agent", 0),
(agent_set_speed_limit, ":cur_agent", 100),
(try_end),
(set_show_messages, 0),
#clears out stand ground order
(team_give_order, "$attacker_team", grc_everyone, mordr_charge),
#makes sure they do not stall on ladder
(team_give_order, "$attacker_team", grc_everyone, mordr_use_melee_weapons),
(set_show_messages, 1),
])
Instead of the fixed number of 6 bots pushing the siege ladder, up to 12 are allocated - two in the first row, one in the middle, and three in the back.
Code:
# script_cf_siege_move_belfry
# Input: none
# Output: none (required for siege mission templates)
("cf_siege_move_belfry",
[(neq, "$last_belfry_object_pos", slot_scene_belfry_props_begin),
(entry_point_get_position,pos1,50),
(entry_point_get_position,pos4,55),
(get_distance_between_positions, ":total_distance", pos4, pos1),
(store_current_scene, ":cur_scene"),
(scene_get_slot, ":first_belfry_object", ":cur_scene", slot_scene_belfry_props_begin),
(prop_instance_get_position, pos2, ":first_belfry_object"),
(entry_point_get_position,pos1,"$cur_belfry_pos"),
(position_transform_position_to_parent, pos3, pos1, pos_belfry_begin),
(position_transform_position_to_parent, pos5, pos4, pos_belfry_begin),
(get_distance_between_positions, ":cur_distance", pos2, pos3),
(get_distance_between_positions, ":distance_left", pos2, pos5),
(try_begin),
(le, ":cur_distance", 10),
(val_add, "$cur_belfry_pos", 1),
(entry_point_get_position,pos1,"$cur_belfry_pos"),
(position_transform_position_to_parent, pos3, pos1, pos_belfry_begin),
(get_distance_between_positions, ":cur_distance", pos2, pos3),
(try_end),
(neq, "$cur_belfry_pos", 50),
(assign, ":base_speed", 20),
(store_div, ":slow_range", ":total_distance", 60),
(store_sub, ":distance_moved", ":total_distance", ":distance_left"),
(try_begin),
(lt, ":distance_moved", ":slow_range"),
(store_mul, ":base_speed", ":distance_moved", -60),
(val_div, ":base_speed", ":slow_range"),
(val_add, ":base_speed", 80),
(else_try),
(lt, ":distance_left", ":slow_range"),
(store_mul, ":base_speed", ":distance_left", -60),
(val_div, ":base_speed", ":slow_range"),
(val_add, ":base_speed", 80),
(try_end),
(store_mul, ":belfry_speed", ":cur_distance", ":base_speed"),
(try_begin),
(eq, "$belfry_num_men_pushing", 0),
(assign, ":belfry_speed", 1000000),
(else_try),
(val_mul, ":belfry_speed", 15), #assuming an average strength per man
(val_div, ":belfry_speed", "$belfry_num_men_pushing"),
(try_end),
(try_begin),
(le, "$cur_belfry_pos", 55),
(init_position, pos3),
(position_rotate_x, pos3, ":distance_moved"),
(scene_get_slot, ":base_belfry_object", ":cur_scene", slot_scene_belfry_props_begin),
(prop_instance_get_position, pos4, ":base_belfry_object"),
(entry_point_get_position,pos1,"$cur_belfry_pos"),
(try_for_range, ":i_belfry_object_pos", slot_scene_belfry_props_begin, "$last_belfry_object_pos"),
(scene_get_slot, ":cur_belfry_object", ":cur_scene", ":i_belfry_object_pos"),
(try_begin),
(ge, ":i_belfry_object_pos", "$belfry_rotating_objects_begin"),
(prop_instance_get_starting_position, pos5, ":base_belfry_object"),
(prop_instance_get_starting_position, pos6, ":cur_belfry_object"),
(position_transform_position_to_local, pos7, pos5, pos6),
(position_transform_position_to_parent, pos5, pos4, pos7),
(position_transform_position_to_parent, pos6, pos5, pos3),
(prop_instance_set_position, ":cur_belfry_object", pos6),
(else_try),
(assign, ":pos_no", pos_belfry_begin),
(val_add, ":pos_no", ":i_belfry_object_pos"),
(val_sub, ":pos_no", slot_scene_belfry_props_begin),
(position_transform_position_to_parent, pos2, pos1, ":pos_no"),
(prop_instance_animate_to_position, ":cur_belfry_object", pos2, ":belfry_speed"),
(try_end),
(try_end),
(try_end),
(gt, "$cur_belfry_pos", 55),
(assign, "$belfry_positioned", 1),
]),
# script_cf_siege_rotate_belfry_platform
# Input: none
# Output: none (required for siege mission templates)
("cf_siege_rotate_belfry_platform",
[(eq, "$belfry_positioned", 1),
(scene_prop_get_instance, ":belfry_object", "spr_belfry_platform_a", 0),
(prop_instance_get_position, pos1, ":belfry_object"),
(position_rotate_x, pos1, -90),
(prop_instance_animate_to_position, ":belfry_object", pos1, 400),
(assign, "$belfry_positioned", 2),
]),
# script_siege_rotate_belfry_platform
# Input: none
# Output: none ($belfry_positioned assigned)
("siege_rot_belfry_platform",
[
(try_begin),
(scene_prop_get_instance, ":belfry_object", "spr_belfry_platform_a", 0),
(prop_instance_get_position, pos1, ":belfry_object"),
(position_rotate_x, pos1, -90),
(prop_instance_animate_to_position, ":belfry_object", pos1, 400),
(assign, "$belfry_positioned", 3),
(try_end),
]),
# script_cf_siege_assign_men_to_belfry
# Input: none
# Output: none (required for siege mission templates)
("cf_siege_assign_men_to_belfry",
[
(neq, "$last_belfry_object_pos", slot_scene_belfry_props_begin),
(assign, ":end_trigger", 0),
(try_begin),
(lt, "$belfry_positioned", 3),
(get_player_agent_no, ":player_agent"),
(store_current_scene, ":cur_scene"),
(scene_get_slot, ":first_belfry_object", ":cur_scene", slot_scene_belfry_props_begin),
(prop_instance_get_position, pos2, ":first_belfry_object"),
(assign, ":slot_1_positioned", 0),
(assign, ":slot_2_positioned", 0),
(assign, ":slot_3_positioned", 0),
(assign, ":slot_4_positioned", 0),
(assign, ":slot_5_positioned", 0),
(assign, ":slot_6_positioned", 0),
(assign, "$belfry_num_slots_positioned", 0),
#this has been modified to allow the player to help push
(try_begin), #the player can try to help
(get_player_agent_no, ":player_agent"),
(agent_is_alive, ":player_agent"), #while still alive
#can't push from inside/on top - makes no physical sense
(assign, ":belfry_pos", "$last_belfry_object_pos"),
(try_for_range, ":i_belfry_object_pos", slot_scene_belfry_props_begin, ":belfry_pos"),
(scene_get_slot, ":belfry_object", ":cur_scene", ":i_belfry_object_pos"),
(scene_prop_has_agent_on_it, ":belfry_object", ":player_agent"),
(assign, ":belfry_pos", -1),
(try_end), #if the player is stepping on top, loop is broken
(eq, ":belfry_pos", "$last_belfry_object_pos"),
#although bots tend to get stuck and exert force, ignoring this physical impossiblity
(agent_get_team, ":agent_team", ":player_agent"),
(this_or_next|eq, ":agent_team", "$attacker_team"),
(eq, ":agent_team", "$attacker_team_2"),
(init_position, pos3),
(position_move_y, pos3, -600),
(position_transform_position_to_parent, pos5, pos2, pos3),
(agent_get_position, pos3, ":player_agent"),
(get_distance_between_positions, ":target_distance", pos5, pos3),
(lt, ":target_distance", 600), #same as other distance
(agent_get_troop_id, ":player_troop", ":player_agent"),
(store_attribute_level, "$belfry_num_men_pushing", ":player_troop", ca_strength),
# (assign, reg1, ":target_distance"),
# (display_message, "@player is pushing from {reg1} cm away"),
(else_try),
(assign, "$belfry_num_men_pushing", 0),
(try_end),
#this is a maintenance loop - it will be triggered most often and repositions pushing agents
(try_for_agents, ":cur_agent"),
(agent_is_active, ":cur_agent"),
(agent_is_alive, ":cur_agent"),
(agent_is_human, ":cur_agent"),
(try_begin),
(agent_get_slot, ":x_pos", ":cur_agent", slot_agent_target_x_pos),
(try_begin), #remove wounded agents from the belfry pusher list
(this_or_next|eq, ":x_pos", 600),
(eq, ":x_pos", -600),
(store_agent_hit_points, ":health", ":cur_agent", 0),
(le, ":health", 33), #wounded
(agent_clear_scripted_mode, ":cur_agent"),
(agent_force_rethink, ":cur_agent"),
(agent_get_entry_no, ":entry", ":cur_agent"),
(entry_point_get_position, pos1, ":entry"), #spawn point
# (str_store_agent_name, s1, ":cur_agent"),
# (assign, reg1, ":entry"),
# (display_message, "@{s1} to be replaced at {reg1}", 0xff0000),
#do not bother re-raising speed limit - pretend they are limping
(agent_set_scripted_destination, ":cur_agent", pos1),
(agent_set_slot, ":cur_agent", slot_agent_target_x_pos, 0),
(agent_set_slot, ":cur_agent", slot_agent_target_y_pos, 0),
(assign, ":x_pos", 0),
(try_end),
(neq, ":x_pos", 0), #do some level-sorting here as opposed to agent id selector?
(agent_get_slot, ":y_pos", ":cur_agent", slot_agent_target_y_pos),
(try_begin),
(eq, ":x_pos", -600),
(try_begin),
(eq, ":y_pos", 0),
(val_add, ":slot_1_positioned", 1),
(else_try),
(eq, ":y_pos", -200),
(val_add, ":slot_2_positioned", 1),
(else_try),
(val_add, ":slot_3_positioned", 1),
(try_end),
(else_try),
(try_begin),
(eq, ":y_pos", 0),
(val_add, ":slot_4_positioned", 1),
(else_try),
(eq, ":y_pos", -200),
(val_add, ":slot_5_positioned", 1),
(else_try),
(val_add, ":slot_6_positioned", 1),
(try_end),
(try_end),
(val_add, "$belfry_num_slots_positioned", 1),
(init_position, pos1),
(position_move_x, pos1, ":x_pos"),
(position_move_y, pos1, ":y_pos"),
(init_position, pos3),
(position_move_x, pos3, ":x_pos"),
(position_move_y, pos3, -1000),
(position_transform_position_to_parent, pos4, pos2, pos1),
(position_transform_position_to_parent, pos5, pos2, pos3),
(agent_get_position, pos6, ":cur_agent"),
(get_distance_between_positions, ":target_distance", pos6, pos4),
(get_distance_between_positions, ":waypoint_distance", pos6, pos5),
(try_begin),
(this_or_next|lt, ":target_distance", ":waypoint_distance"),
(lt, ":waypoint_distance", 600),
(agent_set_scripted_destination, ":cur_agent", pos4, 1),
(else_try),
(agent_set_scripted_destination, ":cur_agent", pos5, 1),
(try_end),
(try_begin),
(le, ":target_distance", 300),
(agent_get_troop_id, ":cur_troop", ":cur_agent"),
(store_attribute_level, ":strength", ":cur_troop", ca_strength),
(store_agent_hit_points, ":health", ":cur_agent", 0),
(val_mul, ":strength", ":health"),
(val_div, ":strength", 100),
(val_add, "$belfry_num_men_pushing", ":strength"),
# (str_store_agent_name, s1, ":cur_agent"),
# (assign, reg1, ":x_pos"),
# (assign, reg2, ":y_pos"),
# (assign, reg3, ":health"),
# (assign, reg4, "$belfry_num_slots_positioned"),
# (assign, reg0, "$belfry_num_men_pushing"),
# (display_message, "@loop {reg0}/{reg4}: {s1} pushing at {reg1},{reg2} with {reg3} health",0xffffff),
(try_end),
(try_end),
(try_end),
(try_begin), #assigns non-pushing agents?
#2 front, 1 mid, 3 back
(lt, "$belfry_num_slots_positioned", 12),
(try_for_agents, ":cur_agent"),
(lt, "$belfry_num_slots_positioned", 12),
(agent_is_alive, ":cur_agent"),
(agent_get_team, ":cur_agent_team", ":cur_agent"),
(this_or_next|eq, "$attacker_team", ":cur_agent_team"),
(eq, "$attacker_team_2", ":cur_agent_team"),
(neq, ":player_agent", ":cur_agent"),
(agent_get_class, ":agent_class", ":cur_agent"),
(try_begin), #allow archers to push
(eq, ":agent_class", grc_archers),
(agent_get_ammo, ":ammo", ":cur_agent"),
(le, ":ammo", 0),
(assign, ":agent_class", grc_everyone),
(try_end),
(neq, ":agent_class", grc_archers),
# (this_or_next|eq, ":agent_class", grc_infantry),
# (eq, ":agent_class", grc_cavalry),
# (agent_get_wielded_item, ":shield", ":cur_agent", 1),
(assign, ":shield", -1),
(try_for_range, ":slots", ek_item_0, ek_head),
(agent_get_item_slot, ":item", ":cur_agent", ":slots"),
(gt, ":item", 0),
(item_get_type, ":type", ":item"),
(eq, ":type", itp_type_shield),
(assign, ":shield", ":item"),
(try_end),
#we want there to be a greater chance of tower pushers having shields in use
(this_or_next|gt, ":shield", 0),
(lt, "$belfry_num_slots_positioned", 6), #this is for troops without shields, ranged units without ammo as seen above, etc.
(store_agent_hit_points, ":health", ":cur_agent", 0),
(eq, ":health", 100), #healthy
(agent_get_slot, ":x_pos", ":cur_agent", 1),
(eq, ":x_pos", 0),
(assign, ":y_pos", 0),
#restructured - symmetry and increased quantity
(try_begin),
(eq, ":slot_5_positioned", 0),
(assign, ":x_pos", 600),
(assign, ":y_pos", -200),
(val_add, ":slot_5_positioned", 1),
(else_try),
(eq, ":slot_2_positioned", 0),
(assign, ":x_pos", -600),
(assign, ":y_pos", -200),
(val_add, ":slot_2_positioned", 1),
(else_try),
(lt, ":slot_1_positioned", 2),
(assign, ":x_pos", -600),
(assign, ":y_pos", 0),
(val_add, ":slot_1_positioned", 1),
(else_try),
(lt, ":slot_4_positioned", 2),
(assign, ":x_pos", 600),
(assign, ":y_pos", 0),
(val_add, ":slot_4_positioned", 1),
(else_try),
(lt, ":slot_3_positioned", 3),
(assign, ":x_pos", -600),
(assign, ":y_pos", -400),
(val_add, ":slot_3_positioned", 1),
(else_try),
(lt, ":slot_6_positioned", 3),
(assign, ":x_pos", 600),
(assign, ":y_pos", -400),
(val_add, ":slot_6_positioned", 1),
(try_end),
(val_add, "$belfry_num_slots_positioned", 1),
(agent_set_slot, ":cur_agent", slot_agent_target_x_pos, ":x_pos"),
(agent_set_slot, ":cur_agent", slot_agent_target_y_pos, ":y_pos"),
# (str_store_agent_name, s1, ":cur_agent"),
# (try_begin),
# (gt, ":shield", 0),
# (str_store_item_name, s2, ":shield"),
# (else_try),
# (str_store_string, s2, "@beefy arms"),
# (try_end),
# (assign, reg1, ":x_pos"),
# (assign, reg2, ":y_pos"),
# (assign, reg0, "$belfry_num_slots_positioned"),
# (display_message, "@middle loop {reg0}: {s1} pushing wiith {s2} at {reg1},{reg2}", 0xffff00),
#this really doesn't seem to work
(agent_ai_set_always_attack_in_melee, ":cur_agent", 1),
(try_begin),
(gt, ":shield", 0),
(agent_get_wielded_item, ":item", ":cur_agent", 1),
(neq, ":shield", ":item"),
(agent_set_wielded_item, ":cur_agent", ":shield"),
(try_end),
(agent_set_speed_limit, ":cur_agent", 3),
(try_end),
(try_end),
(else_try),
(assign, ":end_trigger", 1),
(try_end),
(eq, ":end_trigger", 1),
]),