OSP Code Combat Overhauled Morale and Routing (Also Reduces Stuttering)

Redleg

Sergeant Knight at Arms
Best answers
0
Jacobhinds,
Any news on the updating for this code?  I would like to try it in my mod, Calradia 1050 A.D.
 

Kentucky James VII

BioAfrikaner
Duke
Best answers
1
I'm still tweaking it. It's been a long process and there's now a ton more code, so if more people show interest I'll focus my efforts on releasing it.
 

Nikephoros

Section Moderator
M&BWB
Best answers
0
To fix the horse issue, i added a line with agent_is_human in module_scripts, is it the right way to fix it?

Code:
 #script_all_enemies_routed
    # This script checks that all enemies are routed or killed.
    # INPUT: none
    # OUTPUT: reg0 = enemies routed 0 or 1
    ("all_enemies_routed", [
      (try_for_agents, ":agent"),
		(neg|agent_is_ally, ":agent"),
		(agent_is_alive, ":agent"),
                (agent_is_human, ":agent"),
		(agent_get_slot, ":routing", ":agent", slot_agent_is_running_away),
		(eq, ":routing", 0),
		(val_add, reg0, 1),
      (try_end),
	]),
 

Kentucky James VII

BioAfrikaner
Duke
Best answers
1
Here's the new version. Before I replace the one in the OP, it would be great if somebody could test this out on their own module to see if I've missed anything out.

Code:
#jacobhinds Morale Code BEGIN

#script_cf_calculate_battle_ratio
#assigns battle size difference
#Inputs = none
#Outputs = none
	("cf_calculate_battle_ratio",
		[
			#bugfix; prevents earlier scripts from enforcing
			#fixed_point_* operations
			#(set_fixed_point_multiplier, 1),

			(assign, "$battle_ratio", 0),

			(assign, "$j_num_us_ready", 0),
			(assign, "$j_num_us_wounded", 0),
			(assign, "$j_num_us_routed", 0),
			(assign, "$j_num_us_dead", 0),

			(assign, "$j_num_allies_ready", 0),
			(assign, "$j_num_allies_wounded", 0),
			(assign, "$j_num_allies_routed", 0),
			(assign, "$j_num_allies_dead", 0),

			(assign, "$j_num_enemies_ready", 0),
			(assign, "$j_num_enemies_wounded", 0),
			(assign, "$j_num_enemies_routed", 0),
			(assign, "$j_num_enemies_dead", 0),

			#count and categorize agents (me, ally, enemy/wounded, dead, routed, alive)
			(try_for_agents, ":cur_agent"),
			  (agent_is_human, ":cur_agent"),
			  (agent_get_party_id, ":agent_party", ":cur_agent"),
			  (try_begin),
				(eq, ":agent_party", "p_main_party"),
				(try_begin),
				  (agent_is_alive, ":cur_agent"),
				  (val_add, "$j_num_us_ready", 1),
				(else_try),
				  (agent_is_wounded, ":cur_agent"),
				  (val_add, "$j_num_us_wounded", 1),
				(else_try),
				  (agent_is_routed, ":cur_agent"),
				  (val_add, "$j_num_us_routed", 1),
				(else_try),
				  (val_add, "$j_num_us_dead", 1),
				(try_end),
			  (else_try),
				(agent_is_ally, ":cur_agent"),
				(try_begin),
				  (agent_is_alive, ":cur_agent"),
				  (val_add, "$j_num_allies_ready", 1),
				(else_try),
				  (agent_is_wounded, ":cur_agent"),
				  (val_add, "$j_num_allies_wounded", 1),
				(else_try),
				  (agent_is_routed, ":cur_agent"),
				  (val_add, "$j_num_allies_routed", 1),
				(else_try),
				  (val_add, "$j_num_allies_dead", 1),
				(try_end),
			  (else_try),
				(try_begin),
				  (agent_is_alive, ":cur_agent"),
				  (val_add, "$j_num_enemies_ready", 1),
				(else_try),
				  (agent_is_wounded, ":cur_agent"),
				  (val_add, "$j_num_enemies_wounded", 1),
				(else_try),
				  (agent_is_routed, ":cur_agent"),
				  (val_add, "$j_num_enemies_routed", 1),
				(else_try),
				  (val_add, "$j_num_enemies_dead", 1),
				(try_end),
			  (try_end),
			(try_end),

			#don't think I need these
			# (assign, ":ratio", 0),
			# (assign, ":ratio_3", 0),
			# (assign, ":difference", 0),
			# (assign, ":enemy_sqrt", 0),
			# (assign, ":ally_sqrt", 0),

			# ALLY STRENGTH
			(assign, ":ally_strength", 1),
			(val_add, ":ally_strength", "$j_num_enemies_routed"),
			(val_add, ":ally_strength", "$j_num_enemies_dead"),
			(val_add, ":ally_strength", "$j_num_enemies_wounded"),
			#ready is counted three times
			(val_add, ":ally_strength", "$j_num_us_ready"),
			(val_add, ":ally_strength", "$j_num_us_ready"),
			(val_add, ":ally_strength", "$j_num_us_ready"),
			(val_add, ":ally_strength", "$j_num_allies_ready"),	
			(val_add, ":ally_strength", "$j_num_allies_ready"),	
			(val_add, ":ally_strength", "$j_num_allies_ready"),	
	
			# ENEMY STRENGTH
			(assign, ":enemy_strength", 1),
			(val_add, ":enemy_strength", "$j_num_us_dead"),
			(val_add, ":enemy_strength", "$j_num_us_wounded"),
			(val_add, ":enemy_strength", "$j_num_us_routed"),
			(val_add, ":enemy_strength", "$j_num_allies_dead"),
			(val_add, ":enemy_strength", "$j_num_allies_wounded"),
			(val_add, ":enemy_strength", "$j_num_allies_routed"),
			#ready is counted three times
			(val_add, ":enemy_strength", "$j_num_enemies_ready"),
			(val_add, ":enemy_strength", "$j_num_enemies_ready"),
			(val_add, ":enemy_strength", "$j_num_enemies_ready"),

			#(A*10/E)
			#10/1 ratio = 10,000 morale penalty
			(store_mul, ":enemy_value", ":enemy_strength", battle_ratio_multiple),
			(val_div, ":enemy_value", ":ally_strength"), 

			#(E*10/A)
			(store_mul, ":ally_value", ":ally_strength", battle_ratio_multiple),
			(val_div, ":ally_value", ":enemy_strength"),

			#if enemy value is greater, use negative of that. 
			(try_begin),
				(gt, ":enemy_value", ":ally_value"),
				(val_sub, ":enemy_value", battle_ratio_multiple),
				(store_sub, ":enemy_value", 0, ":enemy_value"),
				(assign, "$battle_ratio", ":enemy_value"),
			(else_try),
				(val_sub, ":ally_value", battle_ratio_multiple),
				(assign, "$battle_ratio", ":ally_value"),
			(try_end),

			 #(val_clamp, "$battle_ratio", -max_ratio, max_ratio),

			# (assign, reg2, ":enemy_value"),
			# (assign, reg1, ":ally_value"),

			 #(assign, reg0, "$battle_ratio"),
			 #(display_message, "@Battle Ratio:{reg0}"),


			#(sqrt A - sqrt E)^3 + (A-E) (unused)

				#(sqrt A - sqrt E)^3
				# (store_sqrt, ":enemy_sqrt", ":enemy_strength"),
				# (store_sqrt, ":ally_sqrt", ":ally_strength"),
				# (store_sub, ":ratio", ":ally_sqrt", ":enemy_sqrt"),
				# #I get the feeling store_pow doesn't work or is deprecated in some way; keep getting weird results
				# #perhaps use cumbersome approach instead:
				# (store_pow, ":ratio_3", ":ratio", 3),
				# # (store_mul, ":ratio_3", ":ratio", ":ratio"), #squared
				# # (val_mul, ":ratio_3", ":ratio"), #cubed

				# #(A-E)
				# (store_sub, ":difference", ":ally_strength", ":enemy_strength"),

			# (store_add, "$battle_ratio", ":difference", ":ratio_3"),
			# (val_mul, "$battle_ratio", 10),
			# (val_mul, "$battle_ratio", 10),

		#housekeeping BEGIN
			# (assign, reg2, "$battle_ratio"),
			# (assign, reg3, ":ally_strength"),
			# (assign, reg4, ":enemy_strength"),
			# (display_message, "@{reg3}/{reg4}={reg2}"),

			 #find average morale for each side
			 # (assign, ":enemy_morale", 1),
			 # (assign, ":ally_morale", 1),
			 # (assign, ":ally_amount", 1),
			
			#store morale for all troops
			 # (try_for_agents,":cur_agent"),
				 # (agent_is_human, ":cur_agent"),
				 # (agent_is_alive, ":cur_agent"),
				 # (agent_get_slot, ":agent_courage_score", ":cur_agent", slot_agent_courage_score),
				 # (try_begin),
					 # (agent_is_ally, ":cur_agent"),
					 # (val_add, ":ally_morale", ":agent_courage_score"),
				 # (else_try),
					 # (val_add, ":enemy_morale", ":agent_courage_score"),
				 # (try_end),
			 # (try_end),

			 # (store_add, ":ally_amount", "$j_num_us_ready", "$j_num_allies_ready"),

			 # (store_div, reg6, ":ally_morale", ":ally_amount"),
			 # (store_div, reg7, ":enemy_morale", "$j_num_enemies_ready"),
			 # (display_message, "@Morale: {reg6}/{reg7}"),

			#check that fixed_point_whatever or something else isn't screwing me over
			#answer: it is, and tends to fluctuate
			# (store_sqrt, ":four", 16),
			# (assign, reg5, ":four"),
			# (display_message, "@the square root of sixteen is {reg5}"),
		#housekeeping END

			#100-10	= ~400
			#100-30	= ~150
			#100-50	= ~75

			#50-10	= ~100
			#50-30	= ~25
			#50-40	= ~10
		]
	),

#scipt_cf_agent_can_rout
#determines whether a troop can rout or not (more than 10% casualties)
#input: cur_agent
("cf_agent_can_rout", [
	(store_script_param, ":agent", 1),

	(try_begin),
		(agent_is_ally, ":agent"),
		#count ready allies
		(assign, ":ready", "$j_num_us_ready"),
		(val_add, ":ready", "$j_num_allies_ready"),

		#count deady allies
		(store_add, ":deady", "$j_num_us_wounded", "$j_num_us_routed"),
		(val_add, ":deady", "$j_num_us_dead"),
		(val_add, ":deady", "$j_num_allies_wounded"),
		(val_add, ":deady", "$j_num_allies_routed"),
		(val_add, ":deady", "$j_num_allies_dead"),
		(val_mul, ":deady", 10),
	(else_try),
		#count ready enemies
		(assign, ":ready", "$j_num_enemies_ready"),

		#count deady enemies
		(store_add, ":deady", "$j_num_enemies_wounded", "$j_num_enemies_routed"),
		(val_add, ":deady", "$j_num_enemies_dead"),
		(val_mul, ":deady", 10),
	(try_end),
	# (display_message, "@agents cannot rout"),
	(gt, ":deady", ":ready"),
	# (display_message, "@agents can rout"),
]),
#jacobhinds Morale Code END

Replace the following scripts in module_scripts.py:

script_apply_death_effect_on_courage_scores,
script_decide_run_away_or_not*
(choose correct script depending on whether you have FormAI or not. Also, if you don't have my Form Musket Square script installed, delete or comment out any lines with instances of script_agent_remove_from_square).

Code:
#jacobhinds Morale Code BEGIN

  # script_apply_death_effect_on_courage_scores
  # Input: dead agent id, killer agent id
  # Output: none
  ("apply_death_effect_on_courage_scores",
    [
      (store_script_param, ":dead_agent_no", 1),
      (store_script_param, ":killer_agent_no", 2),



      (try_begin),
        (agent_is_human, ":dead_agent_no"),

        (try_begin),
          (agent_is_ally, ":dead_agent_no"),
          (assign, ":is_dead_agent_ally", 1),
        (else_try),
          (assign, ":is_dead_agent_ally", 0),
        (try_end),

        #(agent_get_position, pos0, ":dead_agent_no"),
        #(assign, ":number_of_near_allies_to_dead_agent", 0),

        # (try_for_agents, ":agent_no"),
          # (agent_is_human, ":agent_no"),
          # (agent_is_alive, ":agent_no"),

          # (agent_get_position, pos1, ":agent_no"),
          # (get_distance_between_positions, ":dist", pos0, pos1),

          # (le, ":dist", 1300), # to count number of allies within 13 meters to dead agent.

          # (try_begin),
            # (agent_is_ally, ":agent_no"),
            # (assign, ":is_agent_ally", 1),
          # (else_try),
            # (assign, ":is_agent_ally", 0),
          # (try_end),

          # (try_begin),
            # (eq, ":is_dead_agent_ally", ":is_agent_ally"),
            # (val_add, ":number_of_near_allies_to_dead_agent", 1), #was 1
																	# # (number_of_near_allies_to_dead_agent) is counted because if there are
          # (try_end),                                              # many allies of dead agent around him, negative courage effect become less.

			# # jacobhinds edit: wait a second, this doesn't really make sense. 
			# # If a soldier in a blob of soldiers gets slaughtered, nobody routs, 
			# # but if they're outside, they cause more routing. Halve this effect:
			# # distance should play the biggest role.
          # (val_div, ":number_of_near_allies_to_dead_agent", 2),

        # (try_end),

        (try_for_agents, ":agent_no"),
          (agent_is_human, ":agent_no"),
          (agent_is_alive, ":agent_no"),

          (try_begin),
            (agent_is_ally, ":agent_no"),
            (assign, ":is_agent_ally", 1),
          (else_try),
            (assign, ":is_agent_ally", 0),
          (try_end),

          (try_begin), # each agent is effected by a killed agent positively if he is rival or negatively if he is ally.
            (neq, ":is_dead_agent_ally", ":is_agent_ally"),
            (assign, ":agent_delta_courage_score", 0),  # if killed agent is agent of rival side, add points to fear score #was 10 #after that, was 1
          (else_try),
            (assign, ":agent_delta_courage_score", -4), # if killed agent is agent of our side, decrease points from fear score #jacobhinds was -15, was -4 before battle_ratio overhaul, FEAR SCORE
            #(val_add, ":agent_delta_courage_score", ":number_of_near_allies_to_dead_agent"), # ":number_of_near_allies_to_dead_agent" is added because if there are many # allies of dead agent around him, negative courage effect become less.
            # (try_begin),                                                                    
              # (lt, ":agent_delta_courage_score", -4), #was -5 #was -2 before battle_ratio overhaul #was gt
              # (assign, ":agent_delta_courage_score", -4), #was -5
            # (try_end),

            (agent_get_slot, ":dead_agent_was_running_away_or_not", ":dead_agent_no",  slot_agent_is_running_away), #look dead agent was running away or not.
            (try_begin),
              (eq, ":dead_agent_was_running_away_or_not", 1),
              (val_div, ":agent_delta_courage_score", 3), #was 3 # if killed agent was running away his negative effect on ally courage scores become very less. This added because
            (try_end),                                     # running away agents are easily killed and courage scores become very in a running away group after a time, and
          (try_end),                                       # they do not stop running away although they pass near a new powerful ally party.
          (agent_get_position, pos1, ":agent_no"),
          (get_distance_between_positions, ":dist", pos0, pos1),

          (try_begin), #if agent is the killer, give him x20 more courage than usual
            (eq, ":killer_agent_no", ":agent_no"),
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 20),
            (val_add, ":agent_courage_score", ":agent_delta_courage_score"),
            (agent_set_slot, ":agent_no", slot_agent_courage_score, ":agent_courage_score"),
          (try_end),

			#jacobhinds edit: prevent morale from getting too high
          (try_begin),
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
			(ge, ":agent_courage_score", max_morale),
            (agent_set_slot, ":agent_no", slot_agent_courage_score, max_morale),
          (try_end),

			
          (try_begin),
            (lt, ":dist", 100), #0-1 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 100), #was 150
          (else_try),
            (lt, ":dist", 200), #2 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 100), #was 120
          (else_try),
            (lt, ":dist", 300), #3 meter
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 100),
          (else_try),
            (lt, ":dist", 400), #4 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 90),
          (else_try),
            (lt, ":dist", 600), #5-6 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 80),
          (else_try),
            (lt, ":dist", 800), #7-8 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 70),
          (else_try),
            (lt, ":dist", 1000), #9-10 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 60),
          (else_try),
            (lt, ":dist", 1500), #11-15 meter
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 50),
          (else_try),
            (lt, ":dist", 2500), #16-25 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 40),
          (else_try),
            (lt, ":dist", 4000), #26-40 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 30),
          (else_try),
            (lt, ":dist", 6500), #41-65 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 20),
          (else_try),
            (lt, ":dist", 10000), #61-100 meters
            (agent_get_slot, ":agent_courage_score", ":agent_no", slot_agent_courage_score),
            (val_mul, ":agent_delta_courage_score", 10),
          (try_end),
        (try_end),
      (try_end),

			#housekeeping
			# (store_random_in_range, ":rand", 0, 10),
			# (try_begin),
				# (eq, ":rand", 1),
				# (assign, reg4, ":agent_delta_courage_score"),
				# (display_message, "@{reg4}"),
			# (try_end),
			#housekeeping

      ]), #ozan

#jacobhinds Morale Code END
Code:
#jacobhinds Morale Code BEGIN
#(FormAI version)

# # Line added to clear scripted mode right before each (agent_start_running_away, ":cur_agent")
  # script_decide_run_away_or_not
  # Input: none
  # Output: none
  ("decide_run_away_or_not",
    [
      (store_script_param, ":cur_agent", 1),
      (store_script_param, ":mission_time", 2),
      


      (assign, ":force_retreat", 0),
      (agent_get_team, ":agent_team", ":cur_agent"),
      (agent_get_division, ":agent_division", ":cur_agent"),
      (try_begin),
        (lt, ":agent_division", 9), #static classes
        (team_get_movement_order, ":agent_movement_order", ":agent_team", ":agent_division"),
        (eq, ":agent_movement_order", mordr_retreat),
        (assign, ":force_retreat", 1),
      (try_end),

      (agent_get_slot, ":is_cur_agent_running_away", ":cur_agent", slot_agent_is_running_away),
      (try_begin),
		#(neg|agent_slot_eq, ":cur_agent", slot_agent_courage_score_bonus, -1),
        (eq, ":is_cur_agent_running_away", 0),
        (try_begin),
          (eq, ":force_retreat", 1),
          (agent_clear_scripted_mode, ":cur_agent"),	#handle scripted mode troops - motomataru
          (agent_start_running_away, ":cur_agent"),
		  (call_script, "script_agent_remove_from_square", ":cur_agent"), #jacobhinds infantry square script (remove if you don't have the infantry square script)
          (agent_set_slot, ":cur_agent",  slot_agent_is_running_away, 1),
		  #(agent_set_speed_limit, ":cur_agent", 60),
        (else_try),
          (ge, ":mission_time", 4), #first 4 seconds anyone does not run away whatever happens.
          (agent_get_slot, ":agent_courage_score", ":cur_agent",  slot_agent_courage_score),
          (store_agent_hit_points, ":agent_hit_points", ":cur_agent"),
          (val_mul, ":agent_hit_points", 10), #was 4
         # (try_begin),
          #  (agent_is_ally, ":cur_agent"),
           # (val_sub, ":agent_hit_points", 100), #ally agents will be more tend to run away, to make game more funnier/harder
         # (try_end),

#	IGNORE THIS, just rambling from several workarounds ago BEGIN

#	ratio
#	assume major battle 100(enemy) vs 100(ally)
#	20/100 = 0.2 = nigh unbreakable (for now give no negative effects)
#	100/20 = 5	 = rout
#	battle ratio * 100
#	potential swing from 0-1000 courage score malus before rout
#	perhaps link to battle ai....? or unbalanced?

#	IGNORE THIS, just rambling from several workarounds ago END

		  (try_begin),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(agent_is_ally, ":cur_agent"),
			(val_add, ":agent_hit_points", "$battle_ratio"),
		  (else_try),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(val_sub, ":agent_hit_points", "$battle_ratio"),
		  (try_end),

          #(val_mul, ":agent_hit_points", 10),
          (store_sub, ":start_running_away_courage_score_limit", 300, ":agent_hit_points"), #was 3500
          (lt, ":agent_courage_score", ":start_running_away_courage_score_limit"), #if (courage score < 3500 - (agent hit points * 40)) and (agent is not running away) then start running away, average hit points : 50, average running away limit = 1500

          (agent_get_troop_id, ":troop_id", ":cur_agent"), #for now do not let heroes to run away from battle
          (neg|troop_is_hero, ":troop_id"),

		  (try_begin), #this block is optional, delete if you don't have diplomacy or if you don't want retreating voices. 
			  (call_script, "script_dplmc_store_troop_is_female", ":troop_id"), #shout "retreat" if male
			  (neq, reg0, 1),
			  #(agent_play_sound, ":cur_agent", "snd_man_retreat"), #uncomment if you want retreating voices 
		  (try_end),
                                
          (agent_clear_scripted_mode, ":cur_agent"),	#handle scripted mode troops - motomataru
          (agent_start_running_away, ":cur_agent"),
		  (call_script, "script_agent_remove_from_square", ":cur_agent"), #jacobhinds infantry square script (remove if you don't have the infantry square script)
		  #(agent_set_speed_limit, ":cur_agent", 60),
          (agent_set_slot, ":cur_agent",  slot_agent_is_running_away, 1),
        (try_end),


      (else_try),
		#(neg|agent_slot_eq, ":cur_agent", slot_agent_courage_score_bonus, -1),
        (neq, ":force_retreat", 1),
        (agent_get_slot, ":agent_courage_score", ":cur_agent",  slot_agent_courage_score),
        (store_agent_hit_points, ":agent_hit_points", ":cur_agent"),      
        (val_mul, ":agent_hit_points", 10), #was 4
   #     (try_begin),
    #      (agent_is_ally, ":cur_agent"),
     #     (val_sub, ":agent_hit_points", 100), #ally agents will be more tend to run away, to make game more funnier/harder
      #  (try_end),

		  (try_begin),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(agent_is_ally, ":cur_agent"),
			(val_add, ":agent_hit_points", "$battle_ratio"),
		  (else_try),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(val_sub, ":agent_hit_points", "$battle_ratio"),
		  (try_end),

        #(val_mul, ":agent_hit_points", 10),
        (store_sub, ":stop_running_away_courage_score_limit", 0, ":agent_hit_points"), 
        (ge, ":agent_courage_score", ":stop_running_away_courage_score_limit"), #if (courage score > 3700 - agent hit points) and (agent is running away) then stop running away, average hit points : 50, average running away limit = 1700
        (agent_stop_running_away, ":cur_agent"),
        (agent_set_slot, ":cur_agent",  slot_agent_is_running_away, 0),
      (try_end),      
  ]), #ozan


#jacobhinds Morale Code END
#(FormAI version)
Code:
#jacobhinds Morale Code BEGIN
#(Native version)

  # script_decide_run_away_or_not
  # Input: none
  # Output: none
  ("decide_run_away_or_not",
    [
      (store_script_param, ":cur_agent", 1),
      (store_script_param, ":mission_time", 2),
      


      (assign, ":force_retreat", 0),
      (agent_get_team, ":agent_team", ":cur_agent"),
      (agent_get_division, ":agent_division", ":cur_agent"),
      (try_begin),
        (lt, ":agent_division", 9), #static classes
        (team_get_movement_order, ":agent_movement_order", ":agent_team", ":agent_division"),
        (eq, ":agent_movement_order", mordr_retreat),
        (assign, ":force_retreat", 1),
      (try_end),

      (agent_get_slot, ":is_cur_agent_running_away", ":cur_agent", slot_agent_is_running_away),
      (try_begin),
		#(neg|agent_slot_eq, ":cur_agent", slot_agent_courage_score_bonus, -1),
        (eq, ":is_cur_agent_running_away", 0),
        (try_begin),
          (eq, ":force_retreat", 1),
          (agent_start_running_away, ":cur_agent"),
		  (call_script, "script_agent_remove_from_square", ":cur_agent"), #jacobhinds infantry square script (remove if you don't have the infantry square script)
          (agent_set_slot, ":cur_agent",  slot_agent_is_running_away, 1),
		  #(agent_set_speed_limit, ":cur_agent", 60),
        (else_try),
          (ge, ":mission_time", 4), #first 4 seconds anyone does not run away whatever happens.
          (agent_get_slot, ":agent_courage_score", ":cur_agent",  slot_agent_courage_score),
          (store_agent_hit_points, ":agent_hit_points", ":cur_agent"),
          (val_mul, ":agent_hit_points", 10), #was 4
         # (try_begin),
          #  (agent_is_ally, ":cur_agent"),
           # (val_sub, ":agent_hit_points", 100), #ally agents will be more tend to run away, to make game more funnier/harder
         # (try_end),

#	IGNORE THIS, just rambling from several workarounds ago BEGIN

#	ratio
#	assume major battle 100(enemy) vs 100(ally)
#	20/100 = 0.2 = nigh unbreakable (for now give no negative effects)
#	100/20 = 5	 = rout
#	battle ratio * 100
#	potential swing from 0-1000 courage score malus before rout
#	perhaps link to battle ai....? or unbalanced?

#	IGNORE THIS, just rambling from several workarounds ago END

		  (try_begin),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(agent_is_ally, ":cur_agent"),
			(val_add, ":agent_hit_points", "$battle_ratio"),
		  (else_try),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(val_sub, ":agent_hit_points", "$battle_ratio"),
		  (try_end),

          #(val_mul, ":agent_hit_points", 10),
          (store_sub, ":start_running_away_courage_score_limit", 300, ":agent_hit_points"), #was 3500
          (lt, ":agent_courage_score", ":start_running_away_courage_score_limit"), #if (courage score < 3500 - (agent hit points * 40)) and (agent is not running away) then start running away, average hit points : 50, average running away limit = 1500

          (agent_get_troop_id, ":troop_id", ":cur_agent"), #for now do not let heroes to run away from battle
          (neg|troop_is_hero, ":troop_id"),

		  (try_begin), #this block is optional, delete if you don't have diplomacy or if you don't want retreating voices. 
			  (call_script, "script_dplmc_store_troop_is_female", ":troop_id"), #shout "retreat" if male
			  (neq, reg0, 1),
			  #(agent_play_sound, ":cur_agent", "snd_man_retreat"), #uncomment if you want retreating voices
		  (try_end),
                                
          (agent_clear_scripted_mode, ":cur_agent"),	#handle scripted mode troops - motomataru
          (agent_start_running_away, ":cur_agent"),
		  (call_script, "script_agent_remove_from_square", ":cur_agent"), #jacobhinds infantry square script (remove if you don't have the infantry square script)
		  #(agent_set_speed_limit, ":cur_agent", 60),
          (agent_set_slot, ":cur_agent",  slot_agent_is_running_away, 1),
        (try_end),


      (else_try),
		#(neg|agent_slot_eq, ":cur_agent", slot_agent_courage_score_bonus, -1),
        (neq, ":force_retreat", 1),
        (agent_get_slot, ":agent_courage_score", ":cur_agent",  slot_agent_courage_score),
        (store_agent_hit_points, ":agent_hit_points", ":cur_agent"),      
        (val_mul, ":agent_hit_points", 10), #was 4
   #     (try_begin),
    #      (agent_is_ally, ":cur_agent"),
     #     (val_sub, ":agent_hit_points", 100), #ally agents will be more tend to run away, to make game more funnier/harder
      #  (try_end),

		  (try_begin),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(agent_is_ally, ":cur_agent"),
			(val_add, ":agent_hit_points", "$battle_ratio"),
		  (else_try),
			(call_script, "script_cf_agent_can_rout", ":cur_agent"),
			(val_sub, ":agent_hit_points", "$battle_ratio"),
		  (try_end),

        #(val_mul, ":agent_hit_points", 10),
        (store_sub, ":stop_running_away_courage_score_limit", 0, ":agent_hit_points"), 
        (ge, ":agent_courage_score", ":stop_running_away_courage_score_limit"), #if (courage score > 3700 - agent hit points) and (agent is running away) then stop running away, average hit points : 50, average running away limit = 1700
        (agent_stop_running_away, ":cur_agent"),
        (agent_set_slot, ":cur_agent",  slot_agent_is_running_away, 0),
      (try_end),      
  ]), #ozan


#jacobhinds Morale Code END
#(Native version)

Add these to the the top of the file, then add each trigger to the lead_charge template (plus quick_battle_battle if you want them in custom battles)
#jacobhinds Morale Code BEGIN


jacobhinds_battle_ratio_init = (
#proportionalises battle ratio by adding ABS of ratio to both sides when they spawn
0, 0, ti_once, [],
[
(call_script, "script_cf_calculate_battle_ratio"),
],
)

jacobhinds_battle_ratio_spawn_bonus = (
#proportionalises battle ratio by adding ABS of ratio to both sides when they spawn
ti_on_agent_spawn, 0.1, 0, [],
[
(store_trigger_param_1, ":agent"),

(agent_get_slot, ":courage", ":agent", slot_agent_courage_score),
(try_begin),
(ge, "$battle_ratio", 0),
(val_add, ":courage", "$battle_ratio"),
(else_try),
(val_sub, ":courage", "$battle_ratio"),
(try_end),
(agent_set_slot, ":agent", slot_agent_courage_score, ":courage"),
],
)

jacobhinds_battle_ratio_calculate = (
10, 0, 0, [],
[
(call_script, "script_cf_calculate_battle_ratio"),
],
)
#jacobhinds Morale Code END

Go through module_mission_templates.py and comment out any examples of this.
Code:
(3, 0, 0, [
           (call_script, "script_apply_effect_of_other_people_on_courage_scores"),
              ], []), #calculating and applying effect of people on others courage scores

Also in module module_mission_templates.py, replace any instances of this:
(val_mul, ":troop_level", 35),
with this:
(val_mul, ":troop_level", 100),


Code:
max_morale = 35000
battle_ratio_multiple = 200
 

Kentucky James VII

BioAfrikaner
Duke
Best answers
1
1. It's been completely overhauled. There are some bugs in the old version due to me not understanding the code in some places. Now it's more straightforward:
- Both armies start out with similar amounts of morale.
- The weight of numbers affects how likely each troop is to rout.
- No army can rout until more than 10% of their army is dead/wounded/routed.
- Morale is replenished every few seconds by a factor of the number of remaining allies. If there's nobody left on the field, nobody will come back.

2. Since they basically do the same thing, they might clash a bit. Even then, Chel's code uses workarounds from before routing was even a feature in warband (I think taleworlds actually used his idea). Unless you're stuck on pre-2010 mount and blade, use my code.
 

Lord of Shadows

Sergeant Knight
WBNWVCWF&SM&B
Best answers
0
Thanks for the answer. :smile:
I remember having both codes in my mod at some point but I'm not really sure if they conflicted... Thanks anyway.
 

Giggityninja

Sergeant
Best answers
0
For some reason, the script that allows you to leave a battle if all enemy troops are routing, is sometimes causing a victory message to pop up seconds after a battle has begun. I am using Form Ai by the way, but I did put the main script under FormAi_scripts.py's native replacements section as it said to do.
 

Giggityninja

Sergeant
Best answers
0
jacobhinds said:
The script in the OP is outdated. A few posts above is the new code. It should be working.
Wow, very fast response! After an attempt to install the new version, it seems like routing doesn't even happen.
Is this how I'm supposed to add the triggers into lead_charge?

      jacobhinds_battle_ratio_init,
      jacobhinds_battle_ratio_spawn_bonus,
      jacobhinds_battle_ratio_calculate,
 

Kentucky James VII

BioAfrikaner
Duke
Best answers
1
They go in the "consequences" segment of the mission template. Mission templates follow this general structur:

("lead_charge", mtf_whatever|mtf_somegarbage, other garbage,
"Your men charge the enemy"
[
(1, Spawn point info),
(34, Spawn point info),
(35, Spawn point info),
],
[
Consequences
] + trigger_triggers

Look particularly at the placement of the square brackets since those are what delineate the different segments of the mission template.
 

Giggityninja

Sergeant
Best answers
0
jacobhinds said:
They go in the "consequences" segment of the mission template. Mission templates follow this general structur:

("lead_charge", mtf_whatever|mtf_somegarbage, other garbage,
"Your men charge the enemy"
[
(1, Spawn point info),
(34, Spawn point info),
(35, Spawn point info),
],
[
Consequences
] + trigger_triggers

Look particularly at the placement of the square brackets since those are what delineate the different segments of the mission template.
This is what I put, replacing the comma in the last bracket:

    ] + jacobhinds_battle_ratio_init,
  ),


  (
    "village_attack_bandits",mtf_battle_mode|mtf_synch_inventory,charge,

And I get this error:
TypeError: 'tuple' object is not callable
 

Lord of Shadows

Sergeant Knight
WBNWVCWF&SM&B
Best answers
0
This is where you put it:

Code:
      common_battle_order_panel,
      common_battle_order_panel_tick,
#Battle Morale Begin
      jacobhinds_battle_ratio_init,
      jacobhinds_battle_ratio_spawn_bonus,
      jacobhinds_battle_ratio_calculate,
#Battle Morale End
    ]),
 

BrandonM

Regular
WBVC
Best answers
0
Not sure if this will prevent it from working right - but trying to add this to silverstag I ran into a few issues:

1> (call_script, "script_agent_remove_from_square", ":cur_agent"), #jacobhinds infantry square script - I had to comment out references to these because I don't think Silverstag uses your infantry formations - these lines are in both the Native and FormAI versions you posted.

2> # (try_begin),
#  (call_script, "script_dplmc_store_troop_is_female", ":troop_id"), #shout "retreat" if male
#  (neq, reg0, 1),
  #(agent_play_sound, ":cur_agent", "snd_man_retreat"), #uncomment if you want retreating voices
# (try_end),

Again - I didn't find this script: dplmc_store_troop_is_female anywhere in the Silverstag source.  It looks like you're just using it to make a shout so I'm hoping the rest of your script will work without that.

Just to make sure it wasn't just me :smile: I also checked the untouched original Module System files to see if either of those functions exists and they don't.  I'm guessing the formation one comes from your musket square script - and the second from some diplomacy scripts(?)


Thanks,
Brandon
 

Kentucky James VII

BioAfrikaner
Duke
Best answers
1
Yep, those two scripts are completely optional. I'm pretty sure I removed them from the post after Produno told me they weren't compatible with his scripts, but I'll give it another look.
 

HarryPham123

Knight
Best answers
0
i have a problem in a new version that i have a invalid syntax error this invalid syntax is jacobhinds_battle_ratio_init = (

#jacobhinds Morale Code BEGIN


jacobhinds_battle_ratio_init = (
#proportionalises battle ratio by adding ABS of ratio to both sides when they spawn
  0, 0, ti_once, [],
  [
      (call_script, "script_cf_calculate_battle_ratio"),
  ]),
                 

jacobhinds_battle_ratio_spawn_bonus = (
#proportionalises battle ratio by adding ABS of ratio to both sides when they spawn
  ti_on_agent_spawn, 0.1, 0, [],
  [
      (store_trigger_param_1, ":agent"),

      (agent_get_slot, ":courage", ":agent", slot_agent_courage_score),
      (try_begin),
        (ge, "$battle_ratio", 0),
        (val_add, ":courage", "$battle_ratio"),
      (else_try),
        (val_sub, ":courage", "$battle_ratio"),
      (try_end),
      (agent_set_slot, ":agent", slot_agent_courage_score, ":courage"),
  ]),
                 

jacobhinds_battle_ratio_calculate = (
  10, 0, 0, [],
  [
      (call_script, "script_cf_calculate_battle_ratio"),
  ]),
           
#jacobhinds Morale Code END