OSP Code Combat Hardcore fighting AI - Blocking, better positioning, feinting...etc

Best answers
0

Aye Forge,

I decided to release the codes of some of the features I once released in Vyrn OSP about a year ago or so.




Vyrn AI was a project that I worked on for a month or so. I needed to have an actual fighting AI that is smart and flexible. Dangerous, too. Hardcore stuff, player-like. Anyway, it works in certain levels that you set in game_start. You can set levels for any kind of troop you want. The lower the number, better it will fight. AI can:

  • Block
  • Feint
  • Position himself a lot better
  • Kick (needs work)
  • Chamber
  • Random hit
  • Counter-attack
  • Avoid/dodge (need the animation from Vyrn OSP)
  • Special strike (needs work)
  • Roll forward (needs animation from Vyrn OSP)
  • Jump charge (needs work & animation from Vyrn OSP)

It was an attempt on hardcore fantasy RPG. Feel free to use or edit any part you want as long as you give credits. You might need to clean it a bit from Vyrn-related stuff. Be aware of that.

Having said that, I am no coder in IRL and code could use improvements. It is a WIP. Do whatever you want with it.

Happy modding!




1 - ) Firstly, add these mission triggers to anywhere in mission_templates.py and then to any mission you want.

vyrn_ai_continue - > This trigger handles the special moves like jump charge and special strike. Both needs work, so you might not want to use them.
vyrn_ai - > This trigger is where everything is. How it works is that, it makes the necessary checks for an agent in suitable conditions, gets it vyrn_ai level and starts working each segment in combat in relation to the level of the troop's AI and a bit of random dices. It needs to work every milisecond or so, maybe a second would do. I guess that would also change the difficulty of the AI dramatically.



Code:
vyrn_ai_continue = (	
 1, 0, 0, [(eq, "$vyrn_AI_open", 1),],
  [
		#(store_mission_timer_c, ":timerc"),
		
		(get_player_agent_no, ":play"),
		(agent_is_active, ":play"),
		(agent_is_alive, ":play"),
	  #player setup
   (try_for_agents, ":agse"),
		(neq, ":agse", ":play"), #Agent is not player
		(agent_is_active, ":agse"),
		(agent_is_alive, ":agse"), 
		(agent_is_human, ":agse"),
		(agent_slot_eq, ":agse", slot_agent_is_running_away, 0), #isnt fleeing
		
		(agent_get_troop_id, ":agstrpe",":agse"),
		(troop_get_slot, ":is_AIe", ":agstrpe", slot_agent_has_vyrn_AI), #if agent has vyrn AI
		(eq, ":is_AIe", 1), #yes
		(troop_get_slot, ":chance_AIe", ":agstrpe", slot_vyrn_AI_chance),
	 
		(agent_get_team, ":ags_teame", ":agse"), 
	 
		#(assign, ":max_distance", 300), #distance between agents
		
		(agent_ai_get_look_target,":possiblee",":agse"),
		(gt,":possiblee",0), #there is at least someone
		
		(agent_is_active, ":possiblee"),
		(agent_is_alive, ":possiblee"),
		(agent_is_human, ":possiblee"),
		
		(agent_get_team, ":possible_teame", ":possiblee"),
		(neq, ":possible_teame", ":ags_teame"), #unfriendly teams
		
		(agent_get_position, pos13, ":possiblee"),
	    (agent_get_position, pos14, ":agse"),
		(neg|position_is_behind_position, pos13, pos14), #agents are not behind each other
		(get_distance_between_positions, ":diste", pos13, pos14),
		
	   # (agent_get_defend_action, ":pos_defe", ":possiblee"), #attack action
		#(agent_get_action_dir, ":pos_atkdire", ":possiblee"),
	   # (agent_get_attack_action, ":pos_atke", ":possiblee"), #attack action
		(agent_get_animation, ":agse_anime", ":agse", 1),
		(agent_get_wielded_item, ":l_wielded_itema", ":agse", 0),
		#(agent_get_wielded_item, ":r_wielded_itema", ":agse", 1),
		#(agent_get_animation, ":pos_anime", ":possiblee", 1),
		(store_random_in_range, ":chance_strengthe", 1, ":chance_AIe"), #chance is based on troop
		(eq, ":chance_strengthe", 1),
			#Jump Charge
			(try_begin),
				(is_between, ":diste", 600, 800),
				(neq, ":agse_anime", "anim_jump_charge"),
				(agent_set_animation, ":agse", "anim_jump_charge"),
				(le, ":diste", 600),
				(agent_set_attack_action, ":agse", 3, 0),
				(agent_set_position, ":agse", pos13),
			(try_end),
				# #Brutal Strike
			# (try_begin),
				# (store_random_in_range, ":dice", 1, 200),
				# (eq, ":dice", 1),
				# (le, ":diste", 200),
				# (agent_set_animation, ":agse", "anim_brutal_strike"),
				# (agent_get_bone_position, pos9, ":agse", hb_hand_r, 1),
				# (get_distance_between_positions, ":dist_brutal", pos9, pos13),
				# (le, ":dist_brutal", 200),
				# (store_random_in_range, ":brutal_damage", 35, 70),
				# (agent_deliver_damage_to_agent, ":agse", ":possiblee", ":brutal_damage", ":l_wielded_itema"),
				# (agent_set_animation, ":possiblee", "anim_vyrn_AI_fall", 1),							
			# (try_end),
	(try_end),
    ])

vyrn_ai = (
  0, 0, 0, [(eq, "$vyrn_AI_open", 1),], [
    
		(get_player_agent_no, ":pla"),
		(agent_is_active, ":pla"),
		(agent_is_alive, ":pla"),
	  #player setup
   (try_for_agents, ":ags"),
		(neq, ":ags", ":pla"), #Agent is not player
		(agent_is_active, ":ags"),
		(agent_is_alive, ":ags"), 
		(agent_is_human, ":ags"),
		(agent_slot_eq, ":ags", slot_agent_is_running_away, 0), #isnt fleeing
		
		(agent_get_troop_id, ":agstrp",":ags"),
		(troop_get_slot, ":is_AI", ":agstrp", slot_agent_has_vyrn_AI), #if agent has vyrn AI
		(eq, ":is_AI", 1), #yes
		(troop_get_slot, ":chance_AI", ":agstrp", slot_vyrn_AI_chance),
	 
		(agent_get_team, ":ags_team", ":ags"), 
	 
		#(assign, ":max_distance", 300), #distance between agents
		
		(agent_ai_get_look_target,":possible",":ags"),
		(gt,":possible",0), #there is at least someone
		
		(agent_is_active, ":possible"),
		(agent_is_alive, ":possible"),
		(agent_is_human, ":possible"),
		
		(agent_get_team, ":possible_team", ":possible"),
		(neq, ":possible_team", ":ags_team"), #unfriendly teams
		
		(agent_get_position, pos11, ":possible"),
	    (agent_get_position, pos12, ":ags"),
		(neg|position_is_behind_position, pos11, pos12), #agents are not behind each other
		(get_distance_between_positions, ":dist", pos11, pos12),
		
	    (agent_get_defend_action, ":pos_def", ":possible"), #attack action
		(agent_get_action_dir, ":pos_atkdir", ":possible"),
	    (agent_get_attack_action, ":pos_atk", ":possible"), #attack action
		(agent_get_animation, ":ags_anim", ":ags", 1),
		(agent_get_animation, ":pos_anim", ":possible", 1),
		(store_random_in_range, ":chance_strength", 1, ":chance_AI"), #chance is based on troop
		(eq, ":chance_strength", 1),
		#Footwork
		(try_begin),
			(try_begin),
				(le, ":dist", 500),
				(agent_force_rethink, ":ags"),
				(agent_set_scripted_destination, ":ags", pos11, 0, 1),
			(else_try),
				(is_between, ":dist", 0, 300),
				(agent_force_rethink, ":ags"),
				(store_random_in_range, ":dice_for_footwork", 0, 5),
				(eq, ":dice_for_footwork", 1),
				(store_random_in_range, ":random", -60, 60),
				(position_move_x, pos11, ":random", 0),
				(position_move_y, pos11, ":random", 0),
				(position_rotate_x, pos11, ":random", 0),
				(position_rotate_y, pos11, ":random", 0),
				(agent_set_scripted_destination, ":ags", pos11, 0, 1),
			(try_end),
		(try_end),
		#Chambering
			(try_begin),
				(le, ":dist", 200),
				(store_random_in_range, ":extra_dice", 1, 80),
				(neq, ":pos_atk", 1),
				(eq, ":pos_atk", 2),
				(eq, ":extra_dice", 1),
				(try_begin),					
					(eq, ":pos_atkdir", 0),
					(agent_set_attack_action, ":ags", 0, 0),
				(else_try),
					(eq, ":pos_atkdir", 1),
					(agent_set_attack_action,":ags", 2, 0),
				(else_try),
					(eq, ":pos_atkdir", 2),
					(agent_set_attack_action, ":ags", 1, 0),
				(else_try),
					(eq, ":pos_atkdir", 3),
					(agent_set_attack_action, ":ags", 3, 0),
			(try_end),
			(try_end),
			#Chamber disarming
			(try_begin),
				(eq, ":pos_def", 1),
				(neq, ":pos_def", 2),
				(eq, ":pos_atkdir", 1),
				(eq, ":pos_atkdir", 2),
				(neq, ":pos_atk", 1),
				(eq, ":pos_atk", 2),
				(agent_is_in_parried_animation, ":possible"),
				(agent_get_wielded_item, ":weapon", ":ags", 0),
				(agent_unequip_item, ":ags", ":weapon"),
				(agent_get_bone_position, pos2, ":ags", hb_hand_r, 1),
				(store_random_in_range, ":z_rotation", 0, 360),
				(store_random_in_range, ":y_rotation", -60, 60),
				(store_random_in_range, ":x_pos", -90, 90),
				(store_random_in_range, ":y_pos", -90, 90),
				(position_rotate_z, pos2,":z_rotation"),
				(position_rotate_y, pos2,":y_rotation"),
				(position_move_x, pos2, ":x_pos"),
				(position_move_y, pos2, ":y_pos"),
				(position_set_z_to_ground_level, pos2),
				(position_move_z, pos2, 5),
				(set_spawn_position, pos2),
				(spawn_item, ":weapon"),
			(try_end),
			#Feinting
			(try_begin),
					(store_random_in_range, ":dice", 1, 60),
					(store_random_in_range, ":style", 1, 5),
					(store_random_in_range, ":random_dir", 0, 3),
					(store_random_in_range, ":random_action", 0, 1),
					(le, ":dist", 200),
					(eq, ":dice", 1),
					(eq, ":pos_def", 2),
					(assign, ":continue", 0),
					(eq, ":continue", 0),
				(try_begin),
					(eq, ":style", 1),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 1),
				(else_try),
					(eq, ":style", 2),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 1),
				(else_try),
					(eq, ":style", 3),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 1),
				(else_try),
					(eq, ":style", 4),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 0),
					(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
					(assign, ":continue", 1),
				(try_end),
			(try_end),
			#Counter-attack
			(try_begin),
				(le, ":dist", 200),
				(this_or_next|eq, ":pos_atk", 6),
				(eq, ":pos_atk", 3),
				(store_random_in_range, ":random_dir", 1, 3),
				(store_random_in_range, ":random_action", 0, 1),
				(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
			(try_end),
			#Attacking
			(try_begin),
			(try_begin),
				(le, ":dist", 300),
				(store_random_in_range, ":random_dir", 0, 3),
				(store_random_in_range, ":random_action", 0, 1),
				(eq, ":pos_def", 2),
				(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
			(else_try),
				(le, ":dist", 200),
				(store_random_in_range, ":random_dir", 1, 3),
				(store_random_in_range, ":random_action", 0, 1),
				(eq, ":pos_def", 2),
				(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
			(try_end),
			(try_end),
			#Blocking
		(try_begin),
		(neq, ":pos_atk", 1), #readying attack
		(eq, ":pos_atk", 2), #releasing attack	
		(le, ":dist", 200),
		#(store_random_in_range, ":random_chance", 1, 150),
		(try_begin),
			(eq, ":pos_atkdir", 0),
			(agent_set_defend_action, ":ags", 0, 0),
		(else_try),
			(eq, ":pos_atkdir", 1),
			(agent_set_defend_action, ":ags", 1, 0),
		(else_try),
			(eq, ":pos_atkdir", 2),
			(agent_set_defend_action, ":ags", 2, 0),
		(else_try),
			(eq, ":pos_atkdir", 3),
			(agent_set_defend_action, ":ags", 3, 0),
		(try_end),
		(try_end),
		#Avoid
		(try_begin),
			(le, ":dist", 200),
		    (neq, ":pos_atk", 1), #readying attack
			(eq, ":pos_atk", 2), #releasing attack
			(this_or_next|eq, ":pos_atkdir", 0),
			(eq, ":pos_atkdir", 3),
			(store_random_in_range, ":dice_for_avoid", 0, 15),
			(store_random_in_range, ":chance", 0, 2),
			(eq, ":dice_for_avoid", 1),
				(try_begin),
					(eq, ":chance", 1),
					(agent_set_defend_action, ":ags", -2, 0),
					(agent_set_animation, ":ags", "anim_avoid_right_start"),
				(else_try),
					(eq, ":chance", 2),
					(agent_set_defend_action, ":ags", -2, 0),
					(agent_set_animation, ":ags", "anim_avoid_left_start"),
				(try_end),
		(try_end),
		#AI kick
		(try_begin),
			(neq, ":ags_anim", "anim_brutal_strike"),
			(le, ":dist", 100),
			(store_random_in_range,":kickchance", 1, 360),	
			(eq,":kickchance",1), #5-ish% chance per check
			(agent_set_animation, ":ags", "anim_vyrn_AI_kick"),
			(agent_get_bone_position, pos5, ":ags", hb_foot_r, 1),
			(get_distance_between_positions, ":dist_to_leg", pos5, pos11),
			(le, ":dist_to_leg", 150),
			(store_random_in_range, ":rndm_damage", 0, 5),# anim_prepare_kick_0 exists as well
			(agent_deliver_damage_to_agent, ":ags", ":possible", ":rndm_damage"),#3 damage done atm.
			(agent_set_animation, ":possible", "anim_strike3_abdomen_front"),#Get Kicked
			(eq, ":pos_anim", "anim_strike3_abdomen_front"),
			(store_random_in_range, ":random_dir", 0, 3),
			(store_random_in_range, ":random_action", 0, 1),
			(agent_set_attack_action, ":ags", ":random_dir", ":random_action"),
	   (try_end),
   (try_end),
    ])
2 - ) Secondly, add these constants to anywhere in module_constants.py.

Code:
slot_agent_has_vyrn_AI = 29
slot_vyrn_AI_chance = 30
3 - ) Set the level of the AI in the beginning of the game like this:  I used it in game_start

P.S - The name of the constant can be confusing. I do not know what I was thinking when I named a constant with 'agent' when I used it for a 'troop'. It is a constant that is used for a troop that is later on used in mission trigger to adjust the agents of that troop.

Enables the AI for specific troop.


Code:
  (try_begin),	  
	   (troop_set_slot, "trp_blue_raven", slot_agent_has_vyrn_AI, 1),
	   (troop_set_slot, "trp_kingdom_2_lord", slot_agent_has_vyrn_AI, 1),
	   (troop_set_slot, "trp_kingdom_1_lord", slot_agent_has_vyrn_AI, 1),
	   (troop_set_slot, "trp_urulvin", slot_agent_has_vyrn_AI, 1),
	   (troop_set_slot, "trp_monvil", slot_agent_has_vyrn_AI, 1),
	   (troop_set_slot, "trp_vildon", slot_agent_has_vyrn_AI, 1),
	   (troop_set_slot, "trp_urulvin_cinematic", slot_agent_has_vyrn_AI, 1),
	   (troop_set_slot, "trp_vand", slot_agent_has_vyrn_AI, 1),
	  (try_end),
 
Level of the AI is handled below. Smaller the number is, better it will fight. Below 3 is really really hard to beat, just to warn you. Around 3-5 is quite a fun and challenging AI. In video, it was 2.

Code:
#AI - smaller, better blocking	  
 (try_begin),	  
	(troop_set_slot, "trp_blue_raven", slot_vyrn_AI_chance, 2),
	  
	(troop_set_slot, "trp_urulvin", slot_vyrn_AI_chance, 1),
	(troop_set_slot, "trp_monvil", slot_vyrn_AI_chance, 2),

	(troop_set_slot, "trp_vand", slot_vyrn_AI_chance, 5),
	(troop_set_slot, "trp_vildon", slot_vyrn_AI_chance, 3),
		
	(troop_set_slot, "trp_azulan", slot_vyrn_AI_chance, 3),
	(troop_set_slot, "trp_toras", slot_vyrn_AI_chance, 4),
	   
	(troop_set_slot, "trp_kingdom_1_lord", slot_vyrn_AI_chance, 2),
	(troop_set_slot, "trp_kingdom_2_lord", slot_vyrn_AI_chance, 1),
 (try_end),
And, finally put this somewhere in game_start, too. It just enables the trigger. You can use it to disable the AI.

Code:
(assign, "$vyrn_AI_open", 1),
Cheers! :party:

Credits to Barabas & Zarthas for the inspirational codes.
 

Bad Idea

Knight
M&BWBWF&SNW
Best answers
0
Awesome. Thanks for sharing!

I've got ideas to put this into invasion mode, with low blocking scores for slightly more dangerous enemies. Fencer type enemies for example

I gotta check out the full osp, for sure :O
 

kalarhan

Python Saint
Count
WBNWVCWF&S
Best answers
31
Barabashenko said:
How can I define the "hb_hand_r"?
file header_commons.py

if yours doesnt have it, then download a updated version of the modsys (like from Native), and copy it from there.
 

HarryPham123

Knight
Best answers
0
hi there i have a problem with the error

WARNING: Local variable never used: l_wielded_item, at: 0

how to fix this
 
Best answers
0
HarryPham123 said:
hi there i have a problem with the error

WARNING: Local variable never used: l_wielded_item, at: 0

how to fix this
This is just a warning. Feel free to ignore. Or uncomment it.
 

Razors

Recruit
Best answers
0
Thank you for sharing.

Is this designed for 1vs1's or will it also work in big battles? I'd like to try it out on a companion.
 
Best answers
0
Razors said:
Thank you for sharing.

Is this designed for 1vs1's or will it also work in big battles? I'd like to try it out on a companion.
Works for both, but designed for duels.

If you want a battle AI - I advise you check out Oliveran's AI.
 

Razors

Recruit
Best answers
0
Efe Karacar said:
Razors said:
Thank you for sharing.

Is this designed for 1vs1's or will it also work in big battles? I'd like to try it out on a companion.
Works for both, but designed for duels.

If you want a battle AI - I advise you check out Oliveran's AI.
Alright, I'll try it out, again thanks!

Do you perhaps have a link? Tried searching but couldn't find it

EDIT: Never mind found it :smile: