( "kt_init_troop_slots", kt_python_init_troop_slots() ),
# kt0: new strength calculation
# this script makes use of new slots that are filled out at init time with
# script code that was generated at compile time. the range of the values
# coming out of this script are much larger (about 100x) than the original
# range. furthermore, we add a defense calculation and troop count to the
# returns.
# INPUT:
# arg1: party_id
# arg2: exclude leader
# arg3: is siege
# OUTPUT:
# reg0: offense value
# reg1: defense value (damage redux in percent)
# reg2: troop count
( "kt_party_calculate_strength",
[
# remember our params
(store_script_param_1, ":party"), # party id
(store_script_param_2, ":exclude_leader"), # also a party id apparently
(store_script_param, ":is_siege", 3), # so we don't count horses for sieges
# clear out our returns and temps
(assign, reg0, 0),
(assign, reg1, 0),
(assign, reg2, 0),
# figure out which stack to start with and how many we have
(party_get_num_companion_stacks, ":num_stacks", ":party"),
(assign, ":first_stack", 0),
(try_begin),
(neq, ":exclude_leader", 0),
(assign, ":first_stack", 1),
(try_end),
# for each stack that we care about, grab the offense, defense and count
# and stuff the values into our return registers.
(try_for_range, ":i_stack", ":first_stack", ":num_stacks"),
(party_stack_get_troop_id, ":stack_troop", ":party", ":i_stack"),
(party_stack_get_size, ":stack_size",":party",":i_stack"),
(party_stack_get_num_wounded, ":num_wounded",":party",":i_stack"),
(val_sub, ":stack_size", ":num_wounded"),
(gt, ":stack_size", 0),
(assign, "
_val", 0),
(assign, ":d_val", 0),
(assign, ":h_val", 0),
(assign, ":tr_type", 0),
(try_begin),
# if this is not a hero, just read slots
(neg|troop_is_hero, ":stack_troop"),
(troop_get_slot, "
_val", ":stack_troop", kt_slot_troop_o_val),
(troop_get_slot, ":d_val", ":stack_troop", kt_slot_troop_d_val),
(troop_get_slot, ":h_val", ":stack_troop", kt_slot_troop_h_val),
(troop_get_slot, ":tr_type", ":stack_troop", kt_slot_troop_type),
# zero out horse bonuses for mounted archers. they aren't
# supposed to be charging into the fray.
(try_begin),
(eq, ":tr_type", kt_troop_type_mtdarcher),
(assign, ":h_val", 0),
(try_end),
# mul by stack size
(val_mul, "
_val", ":stack_size"),
(val_mul, ":d_val", ":stack_size"),
(val_mul, ":h_val", ":stack_size"),
(else_try),
# todo: heroes have different rules since they don't have troop
# templates. for now, we'll use 50 + level*3 for o_val and
# 20 + level*2 for d_val. in the future, this should be replaced
# by a gear lookup.
(store_character_level, ":level", ":stack_troop"),
(store_mul, "
_val", ":level", 3),
(val_add, "
_val", 50),
(store_mul, ":d_val", ":level", 2),
(val_add, ":d_val", 20),
(try_end),
# siege checks
(try_begin),
# if not sieging, mounted guys get a bonus.
(eq, ":is_siege", 0),
(try_begin),
# mounted archers only get 50% more defense
(eq, ":tr_type", kt_troop_type_mtdarcher),
(val_mul, ":d_val", 3),
(val_div, ":d_val", 2),
(else_try),
# cavalry get 50% more attack and defense and add h_val to o_val
(eq, ":tr_type", kt_troop_type_cavalry),
(val_mul, "
_val", 3),
(val_div, "
_val", 2),
(val_add, "
_val", ":h_val"),
(val_mul, ":d_val", 3),
(val_div, ":d_val", 2),
(try_end),
(val_add, "
_val", ":h_val"),
(try_end),
# add stuff up
(val_add, reg0, "
_val"),
(val_add, reg1, ":d_val"),
(val_add, reg2, ":stack_size"),
(try_end),
# calculate damage redux from defense
(val_div, reg1, reg2), # avg defense
(val_clamp, reg1, 0, 90), # values outside this range don't work well
(store_sub, reg1, 100, reg1), # opponent offense should be multiplied by this %
]),
# kt0: this is a helper that basically calls kt_party_calculate_strength
# for each attachment to the given party.
# INPUT:
# arg1: party_id
# arg2: exclude leader of given stack (not attachments)
# arg3: is_siege
# OUTPUT:
# reg0: aggregate strength
# reg1: number of attached parties
( "kt_party_calculate_strength_with_attachments",
[
# remember our params and set some initial values
(store_script_param_1, ":root_party"),
(store_script_param_2, ":exclude_leader"),
(store_script_param, ":is_siege", 3),
# call the counting script for the given party
(call_script, "script_kt_party_calculate_strength", ":root_party", ":exclude_leader", ":is_siege"),
(assign, ":strength_so_far", reg0),
(assign, ":def_so_far", reg1),
(assign, ":count_so_far", reg2),
(val_mul, ":def_so_far", ":count_so_far"),
# for every attached party, do the same
(party_get_num_attached_parties, ":attached_count", ":root_party"),
(try_for_range, ":rank", 0, ":attached_count"),
(party_get_attached_party_with_rank, ":attached_party", ":root_party", ":rank"),
(call_script, "script_kt_party_calculate_strength", ":attached_party", 0, ":is_siege"),
(val_add, ":strength_so_far", reg0),
(store_mul, ":def_this_party", reg1, reg2),
(val_add, ":def_so_far", ":def_this_party"),
(val_add, ":count_so_far", reg2),
(try_end),
# fill out our returns
(assign, reg0, ":strength_so_far"),
(val_div, ":def_so_far", ":count_so_far"),
(assign, reg1, ":def_so_far"),
(assign, reg2, ":count_so_far"),
]),
# kt0: there seem to be multiple ways to calculate how many fit troops
# there are in an encounter and they all do something slightly different
# but seem to be used for the same things. this is a simple consolidation
# attempt that counts guys the same way that we calculate party strengths.
# INPUT:
# arg1: party_id
# arg2: exclude leader
# OUTPUT:
# reg0: viable troop count
( "kt_count_viable_troops",
[
# remember our params
(store_script_param_1, ":party"), # party id
(store_script_param_2, ":exclude_leader"), # also a party id apparently
# clear out our return
(assign, reg0, 0),
# figure out which stack to start with and how many we have
(party_get_num_companion_stacks, ":num_stacks", ":party"),
(assign, ":first_stack", 0),
(try_begin),
(neq, ":exclude_leader", 0),
(assign, ":first_stack", 1),
(try_end),
(try_for_range, ":i_stack", ":first_stack", ":num_stacks"),
(party_stack_get_troop_id, ":stack_troop", ":party", ":i_stack"),
(party_stack_get_size, ":stack_size",":party",":i_stack"),
(party_stack_get_num_wounded, ":num_wounded",":party",":i_stack"),
(val_sub, ":stack_size", ":num_wounded"),
(try_begin),
(gt, ":stack_size", 0),
(try_begin),
# if this stack is a hero, check health vs. the viable thresh.
(troop_is_hero, ":stack_troop"),
(neg|troop_is_wounded, ":stack_troop"),
(val_add, reg0, 1),
(else_try),
# otherwise just add
(val_add, reg0, ":stack_size"),
(try_end),
(try_end),
(try_end),
# reg0 should have the battle-ready count
]),
# kt0: this is a helper that basically calls kt_count_viable_troops for
# each attachment to the given party. if the party has no attachments,
# it just returns the given party's count.
# INPUT:
# arg1: party_id
# arg2: exclude leader of given stack (not attachments)
# OUTPUT:
# reg0: viable troop count
# reg1: number of attached parties
( "kt_count_viable_troops_with_attachments",
[
# remember our params and set some initial values
(store_script_param_1, ":root_party"),
(store_script_param_2, ":exclude_leader"),
# call the counting script for the given party
(call_script, "script_kt_count_viable_troops", ":root_party", ":exclude_leader"),
(assign, ":count_so_far", reg0),
# for every attached party, do the same
(party_get_num_attached_parties, ":attached_count", ":root_party"),
(try_for_range, ":rank", 0, ":attached_count"),
(party_get_attached_party_with_rank, ":attached_party", ":root_party", ":rank"),
(call_script, "script_kt_count_viable_troops", ":attached_party", 0),
(val_add, ":count_so_far", reg0),
(try_end),
# fill out our returns
(assign, reg0, ":count_so_far"),
(assign, reg1, ":attached_count"),
]),