Chel
Master Knight
This is the code and instructions for the battle morale system that I developed. I post it here to make it easier for anyone who might like to use it.
Currently a fifth version of the system is implemented in my mod and I find it adds a lot of variety to the battles as well as new tactical gameplay content.
You can read about how it works (and watch a video) here: http://forums.taleworlds.com/index.php/topic,36364.0.html
Paste this into module_scripts.py
And paste these triggers into mission_templates.py, into battle missions like field battle, castle siege, village raid.
For castle missions, use
(call_script, "(call_script, "script_rout_check"),
instead of
(call_script, "script_rout_check"),
Because the castle scenes are different, troops might not have a good place to retreat, so "script_rout_check" makes it harder to cause a rout of either side in a siege. This part needs some further refinement, but for now it basically means sieges are not affected by morale very much
The code isn't very commented, but most of it is pretty self-explanatory.
Any questions?
Currently a fifth version of the system is implemented in my mod and I find it adds a lot of variety to the battles as well as new tactical gameplay content.
You can read about how it works (and watch a video) here: http://forums.taleworlds.com/index.php/topic,36364.0.html
Paste this into module_scripts.py
Code:
############# BATTLE MORALE
#script_healthbars
("healthbars",
[
(try_for_agents,":agent"),
# (agent_is_alive,":agent"),
(agent_is_human,":agent"),
(agent_is_ally,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(agent_get_position,pos2,":agent"),
(position_move_z,pos2,204,0),
(try_begin),
(ge,":hitpoints",70),
(particle_system_burst, "psys_troop_fresh", pos2,1),
(else_try),
(ge,":hitpoints",30),
(particle_system_burst, "psys_troop_med", pos2,1),
(else_try),
# (ge,":hitpoints",1),
(particle_system_burst, "psys_troop_low", pos2,2),
(try_end),
(end_try),
(assign,reg1,"$allies_coh_base"),
(assign,reg2,"$enemies_coh"),
(assign,reg3,"$new_kills"),
(display_message,"@Your troops are at {reg1}% cohesion (+{reg3}% bonus), the enemy at {reg2}%!",0x6495ed),
]),
#script_morale_check
("morale_check",
[
(try_begin),
(lt,"$allies_coh",80),
(store_random_in_range,":routed",1,101),
(assign,":chance_ply",85),
(val_sub,":chance_ply","$allies_coh"),
(try_begin),
(le,":routed",":chance_ply"),
#(display_message,"@Morale of your troops wavers!",0xff4040),
(call_script, "script_flee_allies"),
(try_end),
(try_end),
(try_begin),
(lt,"$enemies_coh",80),
(store_random_in_range,":routed",1,101),
(assign,":chance_ply",85),
(val_sub,":chance_ply","$enemies_coh"),
(try_begin),
(le,":routed",":chance_ply"),
#(display_message,"@Morale of your enemies wavers!",0x7ccd7c),
(call_script, "script_flee_enemies"),
(try_end),
(try_end),
]),
#script_battle_cry
("battle_cry",
[
(store_skill_level,":leader","skl_leadership","trp_player"),
(try_for_agents,":agent"),
(agent_is_alive,":agent"),
(agent_is_human,":agent"),
(agent_is_ally,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(try_begin),
(le,":hitpoints",80),
(val_add,":hitpoints",":leader"),
(val_add,":hitpoints",10),
(agent_set_hit_points,":agent",":hitpoints"),
(try_end),
(end_try),
(try_for_agents,":agent"),
(agent_is_alive,":agent"),
(agent_is_human,":agent"),
(agent_is_ally,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(val_sub,":hitpoints",10),
(store_random_in_range,":routed",1,101),
(try_begin),
(le,":routed",":hitpoints"),
(agent_clear_scripted_mode,":agent"),
(try_end),
(end_try),
]),
("rally",
[
#(display_message,"@Your enemies rally to rejoin the battle!",0xff4040),
(try_for_agents,":agent"),
(agent_is_alive,":agent"),
(agent_is_human,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
#(val_sub,":hitpoints",10),
(store_random_in_range,":routed",1,101),
(try_begin),
(le,":routed",":hitpoints"),
(agent_clear_scripted_mode,":agent"),
(try_end),
(end_try),
]),
#script_rout_check
("rout_check",
[
(assign,":ally","$allies_coh"),
#(assign,reg2,"$allies_coh"),
#(display_message,"@allies {reg2}% cohesion!"),
(assign,":enemy","$enemies_coh"),
#(assign,reg2,"$enemies_coh"),
#(display_message,"@enemies {reg2}% cohesion!"),
(val_sub,":ally",":enemy"),
#(assign,reg2,":ally"),
#(display_message,"@difference {reg2}."),
(try_begin),
(ge,":ally",40),
#(display_message,"@Your enemies flee in terror!",0x7ccd7c),
(call_script, "script_rout_enemies"),
(try_end),
(try_begin),
(le,":ally",-40),
#(display_message,"@Your troops flee in terror!",0xff4040),
(call_script, "script_rout_allies"),
(try_end),
]),
#script_rout_check_castle
("rout_check_castle",
[
(assign,":ally","$allies_coh"),
#(assign,reg2,"$allies_coh"),
#(display_message,"@allies {reg2}% cohesion!"),
(assign,":enemy","$enemies_coh"),
#(assign,reg2,"$enemies_coh"),
#(display_message,"@enemies {reg2}% cohesion!"),
(val_sub,":ally",":enemy"),
#(assign,reg2,":ally"),
#(display_message,"@difference {reg2}."),
(try_begin),
(ge,":ally",60),
(display_message,"@Your enemies flee in terror!",0x7ccd7c),
(call_script, "script_rout_enemies"),
(try_end),
(try_begin),
(le,":ally",-60),
(display_message,"@Your troops flee in terror!",0xff4040),
(call_script, "script_rout_allies"),
(try_end),
]),
## script_flee
("flee_allies",
[
(get_scene_boundaries, pos3, pos4),
(position_get_x,":xmin",pos3),
(position_get_y,":ymin",pos3),
(position_get_x,":xmax",pos4),
(position_get_y,":ymax",pos4),
(val_div,":xmin",100),
(val_div,":xmax",100),
(store_random_in_range,":xrout_point3",":xmin",":xmax"),
(val_mul,":xrout_point3",100),
(store_random_in_range,":yrout_point3",":xmin",":xmax"),
(val_mul,":yrout_point3",100),
(store_random_in_range,":xrout_point4",":xmin",":xmax"),
(val_mul,":xrout_point4",100),
(store_random_in_range,":yrout_point4",":xmin",":xmax"),
(val_mul,":yrout_point4",100),
(val_mul,":xmin",100),
(val_mul,":xmax",100),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_div,":xrout_point3",4),
(position_set_x,pos3,":xrout_point3"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_div,":yrout_point3",4),
(position_set_y,pos3,":yrout_point3"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_div,":xrout_point4",4),
(position_set_x,pos4,":xrout_point4"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_div,":yrout_point4",4),
(position_set_y,pos4,":yrout_point4"),
(store_skill_level,":leader","skl_leadership","trp_player"),
(try_for_agents,":agent"),
(agent_is_alive,":agent"),
(agent_is_human,":agent"),
(agent_is_ally,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(agent_get_troop_id,":troop_type", ":agent"),
(store_character_level, ":troop_level", ":troop_type"),
(val_div,":troop_level",10),
(val_add,":hitpoints",":troop_level"),
(assign,":chance_ply",100),
(val_sub,":chance_ply",":hitpoints"),
(val_sub,":chance_ply",":leader"),
(val_div,":chance_ply",2),
(store_random_in_range,":routed",1,101),
(try_begin),
(le,":routed",":chance_ply"),
# (display_message,"@One ally runs!"),
(agent_get_position,pos2,":agent"),
(position_move_z,pos2,200,0),
(agent_clear_scripted_mode,":agent"),
(agent_set_scripted_destination,":agent",pos4,1),
(particle_system_burst, "psys_troop_flee", pos2,20),
(try_end),
(end_try),
]),
("flee_enemies",
[
(get_scene_boundaries, pos3, pos4),
(position_get_x,":xmin",pos3),
(position_get_y,":ymin",pos3),
(position_get_x,":xmax",pos4),
(position_get_y,":ymax",pos4),
(val_div,":xmin",100),
(val_div,":xmax",100),
(store_random_in_range,":xrout_point3",":xmin",":xmax"),
(val_mul,":xrout_point3",100),
(store_random_in_range,":yrout_point3",":xmin",":xmax"),
(val_mul,":yrout_point3",100),
(store_random_in_range,":xrout_point4",":xmin",":xmax"),
(val_mul,":xrout_point4",100),
(store_random_in_range,":yrout_point4",":xmin",":xmax"),
(val_mul,":yrout_point4",100),
(val_mul,":xmin",100),
(val_mul,":xmax",100),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_div,":xrout_point3",4),
(position_set_x,pos3,":xrout_point3"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_div,":yrout_point3",4),
(position_set_y,pos3,":yrout_point3"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_div,":xrout_point4",4),
(position_set_x,pos4,":xrout_point4"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_div,":yrout_point4",4),
(position_set_y,pos4,":yrout_point4"),
(try_for_agents,":agent"),
(agent_is_alive,":agent"),
(agent_is_human,":agent"),
(neg|agent_is_ally,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(agent_get_troop_id,":troop_type", ":agent"),
(store_character_level, ":troop_level", ":troop_type"),
(val_div,":troop_level",10),
(val_add,":hitpoints",":troop_level"),
(assign,":chance_ply",100),
(val_sub,":chance_ply",":hitpoints"),
(val_sub,":chance_ply",4),
(val_div,":chance_ply",2),
(store_random_in_range,":routed",1,101),
(try_begin),
(le,":routed",":chance_ply"),
# (display_message,"@One enemy runs!"),
(agent_get_position,pos2,":agent"),
(position_move_z,pos2,200,0),
(agent_clear_scripted_mode,":agent"),
(agent_set_scripted_destination,":agent",pos3,1),
(particle_system_burst, "psys_troop_flee", pos2,20),
(try_end),
(end_try),
]),
## script_rout
("rout_allies",
[
(get_scene_boundaries, pos3, pos4),
(position_get_x,":xmin",pos3),
(position_get_y,":ymin",pos3),
(position_get_x,":xmax",pos4),
(position_get_y,":ymax",pos4),
(val_div,":xmin",100),
(val_div,":xmax",100),
(store_random_in_range,":xrout_point3",":xmin",":xmax"),
(val_mul,":xrout_point3",100),
(store_random_in_range,":yrout_point3",":xmin",":xmax"),
(val_mul,":yrout_point3",100),
(store_random_in_range,":xrout_point4",":xmin",":xmax"),
(val_mul,":xrout_point4",100),
(store_random_in_range,":yrout_point4",":xmin",":xmax"),
(val_mul,":yrout_point4",100),
(val_mul,":xmin",100),
(val_mul,":xmax",100),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_div,":xrout_point3",4),
(position_set_x,pos3,":xrout_point3"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_div,":yrout_point3",4),
(position_set_y,pos3,":yrout_point3"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_div,":xrout_point4",4),
(position_set_x,pos4,":xrout_point4"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_div,":yrout_point4",4),
(position_set_y,pos4,":yrout_point4"),
(store_skill_level,":leader","skl_leadership","trp_player"),
(try_for_agents,":agent"),
(agent_is_alive,":agent"),
(agent_is_human,":agent"),
(agent_is_ally,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(agent_get_troop_id,":troop_type", ":agent"),
(store_character_level, ":troop_level", ":troop_type"),
(val_div,":troop_level",10),
(val_div,":hitpoints",3),
(assign,":chance_ply",100),
(val_sub,":chance_ply",":hitpoints"),
(val_sub,":chance_ply",":leader"),
(val_sub,":chance_ply",":troop_level"),
(store_random_in_range,":routed",1,101),
(try_begin),
(le,":routed",":chance_ply"),
# (display_message,"@One ally runs!"),
(agent_get_position,pos2,":agent"),
(position_move_z,pos2,200,0),
(agent_clear_scripted_mode,":agent"),
(agent_set_scripted_destination,":agent",pos4,1),
(particle_system_burst, "psys_troop_flee", pos2,20),
(try_end),
(end_try),
]),
("rout_enemies",
[
(get_scene_boundaries, pos3, pos4),
(position_get_x,":xmin",pos3),
(position_get_y,":ymin",pos3),
(position_get_x,":xmax",pos4),
(position_get_y,":ymax",pos4),
(val_div,":xmin",100),
(val_div,":xmax",100),
(store_random_in_range,":xrout_point3",":xmin",":xmax"),
(val_mul,":xrout_point3",100),
(store_random_in_range,":yrout_point3",":xmin",":xmax"),
(val_mul,":yrout_point3",100),
(store_random_in_range,":xrout_point4",":xmin",":xmax"),
(val_mul,":xrout_point4",100),
(store_random_in_range,":yrout_point4",":xmin",":xmax"),
(val_mul,":yrout_point4",100),
(val_mul,":xmin",100),
(val_mul,":xmax",100),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_add,":xrout_point3",":xmin"),
(val_div,":xrout_point3",4),
(position_set_x,pos3,":xrout_point3"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_add,":yrout_point3",":ymin"),
(val_div,":yrout_point3",4),
(position_set_y,pos3,":yrout_point3"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_add,":xrout_point4",":xmax"),
(val_div,":xrout_point4",4),
(position_set_x,pos4,":xrout_point4"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_add,":yrout_point4",":ymax"),
(val_div,":yrout_point4",4),
(position_set_y,pos4,":yrout_point4"),
(try_for_agents,":agent"),
(agent_is_alive,":agent"),
(agent_is_human,":agent"),
(neg|agent_is_ally,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(agent_get_troop_id,":troop_type", ":agent"),
(store_character_level, ":troop_level", ":troop_type"),
(val_div,":troop_level",10),
(val_div,":hitpoints",3),
(assign,":chance_ply",100),
(val_sub,":chance_ply",":hitpoints"),
(val_sub,":chance_ply",3), ## AI's Leadership bonus
(val_sub,":chance_ply",":troop_level"),
(store_random_in_range,":routed",1,101),
(try_begin),
(le,":routed",":chance_ply"),
# (display_message,"@One enemy runs!"),
(agent_get_position,pos2,":agent"),
(position_move_z,pos2,200,0),
(agent_clear_scripted_mode,":agent"),
(agent_set_scripted_destination,":agent",pos3,1),
(particle_system_burst, "psys_troop_flee", pos2,20),
(try_end),
(end_try),
]),
#script_coherence
("coherence",
[
(get_scene_boundaries, pos3, pos4),
(assign,":num_allies",0),
(assign,":coh_allies",0),
(assign,":num_enemies",0),
(assign,":coh_enemies",0),
(try_for_agents,":agent"),
(agent_is_ally,":agent"),
(agent_is_human,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(agent_get_troop_id,":troop_type", ":agent"),
(store_character_level, ":troop_level", ":troop_type"),
# (val_div,":troop_level",10),
(val_mul,":hitpoints",":troop_level"),
(val_add,":num_allies",":troop_level"),
(val_add,":coh_allies",":hitpoints"),
(else_try),
(agent_is_human,":agent"),
(store_agent_hit_points,":hitpoints",":agent",0),
(agent_get_troop_id,":troop_type", ":agent"),
(store_character_level, ":troop_level", ":troop_type"),
# (val_div,":troop_level",10),
(val_mul,":hitpoints",":troop_level"),
(val_add,":num_enemies",":troop_level"),
(val_add,":coh_enemies",":hitpoints"),
(end_try),
(val_div,":coh_allies",":num_allies"),
(assign,"$allies_coh_base",":coh_allies"),
(assign,"$allies_coh","$allies_coh_base"),
(val_add,"$allies_coh","$new_kills"),
(val_div,":coh_enemies",":num_enemies"),
(assign,"$enemies_coh",":coh_enemies"),
]),
######################## end morale
#script_hero_exp_penalty
("hero_exp_penalty",
[(store_character_level,":level","trp_player"),
(val_mul,":level",-20),
(add_xp_to_troop,":level","trp_player"),
(assign,reg1,":level"),
(display_message, "@You lost {reg1} experience points.",0x8fbc8f),
]),
And paste these triggers into mission_templates.py, into battle missions like field battle, castle siege, village raid.
For castle missions, use
(call_script, "(call_script, "script_rout_check"),
instead of
(call_script, "script_rout_check"),
Because the castle scenes are different, troops might not have a good place to retreat, so "script_rout_check" makes it harder to cause a rout of either side in a siege. This part needs some further refinement, but for now it basically means sieges are not affected by morale very much
Code:
### BATTLE MORALE
(1, 0, ti_once, [], [
(get_player_agent_kill_count,"$base_kills",0),
(assign,"$new_kills_a",0),
(assign,"$new_kills",0),
]),
(3, 0, 3, [], [
(get_player_agent_kill_count,":more_kills",0),
(val_sub,":more_kills","$base_kills"),
(try_begin),
(gt,":more_kills","$new_kills_a"),
(assign,"$new_kills_a",":more_kills"),
(assign,"$new_kills",":more_kills"),
(val_div,"$new_kills",2),
(assign,reg1,":more_kills"),
(display_message,"@You have killed {reg1} enemies in this battle!",0x6495ed),
(display_message,"@Your bravery inspires your troops!",0x6495ed),
(try_end),
]),
####
(0, 0, 2, [(key_clicked, key_t)], [
(call_script, "script_coherence"),
(call_script, "script_healthbars"),
]),
(0, 0, ti_once, [(key_clicked, key_y)], [
#(play_sound,"snd_battle_cry_n"),
(display_message,"@You rally your men!",0x7ccd7c),
(call_script, "script_battle_cry"),
(call_script, "script_hero_exp_penalty"),
]),
(10, 0, 20, [ ], [
(call_script, "script_rally"),
]),
(0, 10, 100, [(key_clicked, key_u),(display_message,"@You call for reinforcements!",0x6495ed) ], [
(display_message,"@Reinforcements arrive!",0x6495ed),
(add_reinforcements_to_entry,0,7),
(add_reinforcements_to_entry,3,7),
(call_script, "script_hero_exp_penalty"),
]),
(1, 0, ti_once, [ ], [
(call_script, "script_coherence"),
]),
(15, 0, 10, [ ], [
(call_script, "script_coherence"),
(call_script, "script_morale_check"),
]),
(5, 0, 3, [ ], [
(call_script, "script_coherence"),
(call_script, "script_rout_check"),
]),
################### BATTLE MORALE END
The code isn't very commented, but most of it is pretty self-explanatory.
Any questions?