OSP Code Combat Shield Bash (OSP)

Users who are viewing this thread

Okay, so I decided to script multiplayer shield bash. Would be awesome if xenoargh would add this to the OP (original post). If anything doesn't work, then feel free to tell me!

Explanations: most of the stuff is run client-side, so no strain goes on server. You must block and then press the attack button in order to bash. The scripts get the closest agent in front of you within 1.75metres.
It won't move the agent backwards if the distance between the ground and agent is higher than 25 (aka you can't bash them off ledges.. feel free to change this but I did it so there wouldn't be any glitchers, e.g glitching through invisible barriers).

Here are the scripts, with instructions.
Code:
## Shield bash begin.
#Initially developed by xenoargh for singleplayer,
#rewritten/revamped for multiplayer by Sinisterius.

#This goes into module_mission_templates.py, at the top.
#Then, you must add "mp_shield_bash," (without quotations)
#to the mission template where you want the shield bash to
#be allowed. For example, the multiplayer_bt template.
mp_shield_bash = (
    0, 0, 0,
	[
	    (game_key_is_down, gk_defend),
		(game_key_clicked, gk_attack),
		(game_is_in_multiplayer_mode),
	],
	[
	    #Get local player data.
	    (multiplayer_get_my_player, ":player"),
		(player_is_active, ":player"),
		(player_get_agent_id, ":agent", ":player"),
		(agent_is_active, ":agent"),
		
		#Check if we're in the right condition.
		(agent_get_wielded_item, ":shield", ":agent", 1), #Offhand item.
		(is_between, ":shield", "itm_wooden_shield", "itm_steel_shield_herald03"),
		(agent_get_defend_action, ":action", ":agent"),
		(eq, ":action", 2), #Blocking.
		(agent_get_animation, ":anim", ":agent", 0),
		(neq, ":anim", "anim_shield_bash"),
		(agent_get_horse, ":horse", ":agent"),
		(eq, ":horse", -1), #No horse.
		
		#If everything is correct, then set agent up for bash.
		(multiplayer_send_2_int_to_server, mp_agent_set_animation_human, ":agent", "anim_shield_bash"), #Set animation.
		(player_get_troop_id, ":troop", ":player"),
		(troop_get_type, ":type", ":troop"),
		(try_begin),
		    (eq, ":type", tf_male),
			(multiplayer_send_2_int_to_server, mp_agent_play_sound, ":agent", "snd_man_yell"), #Play sound.
		(else_try),
		    (eq, ":type", tf_female),
			(multiplayer_send_2_int_to_server, mp_agent_play_sound, ":agent", "snd_woman_yell"), #Play sound.
		(try_end),
		
		#Bash. Get the closest agent within 175cm~1.75m.
		(agent_get_position, pos1, ":agent"),
		(assign, ":minimum_distance", 400),
		(assign, ":victim", -1),
		(try_for_agents, ":suspect"),
		    (neq, ":suspect", ":agent"), #Suspect can't be our local agent.
		    (agent_is_active, ":suspect"),
		    (agent_is_alive, ":suspect"),
			(agent_is_human, ":suspect"),
			
			#Compare distances.
			(agent_get_position, pos2, ":suspect"),
			(neg|position_is_behind_position, pos2, pos1),
			(get_distance_between_positions, ":distance", pos1, pos2),
			(le, ":distance", ":minimum_distance"),
			
			#If distance is sufficient..
			(assign, ":minimum_distance", ":distance"),
			(assign, ":victim", ":suspect"),
		(try_end),
		
		#If we have the victim, aka the closest agent, then deal with him. Else, do nothing.
		(ge, ":victim", 0),
		(agent_get_horse, ":horse", ":victim"),
		(eq, ":horse", -1), #No horse.
		(multiplayer_send_2_int_to_server, mp_agent_play_sound, ":victim", "snd_wooden_hit_low_armor_high_damage"), #Play sound.
		(agent_get_position, pos2, ":victim"),
		(position_move_y, pos2, -25),
		(position_get_distance_to_ground_level, ":distance", pos2),
		(try_begin),
		    (le, ":distance", 25),
			(multiplayer_send_2_int_to_server, mp_agent_set_position, ":victim", pos2), #Set position.
			(multiplayer_send_2_int_to_server, mp_agent_set_animation_human, ":victim", "anim_shield_strike"),
		(else_try),
		    (gt, ":distance", 25),
			(multiplayer_send_2_int_to_server, mp_agent_set_animation_human, ":victim", "anim_shield_strike"),
		(try_end),
	])


#Server/client events.
#Copy-paste this stuff right after the store_script_params in game_receive_network_message.
(try_begin),
    (eq, ":event_type", mp_agent_set_animation_human),
	(store_script_param, ":agent", 3),
	(store_script_param, ":anim", 4),
	
	#Play anim.
	(agent_is_active, ":agent"),
	(agent_is_alive, ":agent"),
	(agent_is_human, ":agent"),
	(agent_set_animation, ":agent", ":anim"),
(else_try),
    (eq, ":event_type", mp_agent_play_sound),
	(store_script_param, ":agent", 3),
	(store_script_param, ":sound", 4),
	
	#Send sound data to players.
	(agent_is_active, ":agent"),
	(agent_is_alive, ":agent"),
	(get_max_players, ":max_players"),
	(try_for_range, ":player", 0, ":max_players"),
	    (player_is_active, ":player"),
		(multiplayer_send_2_int_to_player, ":player", mp_agent_play_sound_client, ":agent", ":sound"),
	(try_end),
(else_try),
    (eq, ":event_type", mp_agent_set_position),
	(store_script_param, ":agent", 3),
	(store_script_param, ":position", 4),
	
	#Set position.
	(agent_is_active, ":agent"),
	(agent_is_alive, ":agent"),
	(agent_set_position, ":agent", ":position"),
(else_try),
    (neq, multiplayer_is_server),
	(try_begin),
	    (eq, ":event_type", mp_agent_play_sound_client),
	    (store_script_param, ":agent", 3),
	    (store_script_param, ":sound", 4),
		
		#Play sound.
	    (agent_is_active, ":agent"),
	    (agent_is_alive, ":agent"),
		(agent_play_sound, ":agent", ":sound"),
	(try_end),
(try_end),


#These animations go into module_animations.py
#They MUST replace existing unused animations.
["shield_bash", 0, amf_play|amf_priority_defend|amf_use_defend_speed|amf_client_owner_prediction,
[0.75, "defend_shield_parry_all", 1, 50, blend_in_defense], #Adjust duration for balance.  Currently at 0.75 seconds, fixed.
[0.75, "defend_shield_right", 1, 50, blend_in_defense],
[0.75, "defend_shield_left", 1, 50, blend_in_defense],
[0.75, "defend_shield_right", 1, 50, blend_in_defense],   
],
 ["shield_strike", acf_enforce_all|acf_align_with_ground, amf_priority_striked|amf_play|amf_accurate_body|amf_restart,
   [1.0, "anim_human", blow+5000, blow+5010, arf_blend_in_3|arf_make_custom_sound], 
   [1.7, "anim_human", blow+5400, blow+5453, arf_blend_in_2|arf_make_custom_sound],
   [1.44, "anim_human", blow+5400, blow+5445, arf_blend_in_2|arf_make_custom_sound],   
   ],
## Shield bash end.
 
Sinsterius: nice work, but I disagree with how you have done it. By adding the "mp_agent_set_position" event (by the way you forgot to post the header_common constants) a client could keep sending messages to teleport other players (or themself) around as much as they wanted to, as well as setting any animation or playing any sound. In multiplayer gaming, you want to have the server only listen to input events from the client, then check to see if the preconditions are met, and only then to apply the effect; though it is helpful if the client runs at least some of the checks - so the server is not flooded with messages that will obviously fail the conditions. So I would suggest splitting the code up, maybe with a script to check if the shield bash is going to have any effect, and then another part to apply it; run the first part only on the client, then send a "shield bash" message to the server, which runs both scripts.
 
Hmm, yes, you're right. It could be exploited. I'll re-write it now. Thanks for the input.

EDIT.
I updated the codes. Enjoy. Now you can't exploit the system anymore.
You also need to add the header_common event definitions, I'm too lazy to add them myself.
Code:
mp_shield_bash = (
    0, 0, 0,
	[
	    (game_key_is_down, gk_defend),
		(game_key_clicked, gk_attack),
		(game_is_in_multiplayer_mode),
	],
	[		
		(multiplayer_send_message_to_server, mp_shield_bash_server),
	])

Code:
#Server/client events.
#Copy-paste this stuff right after the store_script_params in game_receive_network_message.
(try_begin),
    (eq, ":event_type", mp_shield_bash_server),
	
	#Get sender data & max players.
	(player_is_active, ":player_no"),
	(player_get_agent_id, ":agent_no", ":player_no"),
	(agent_is_active, ":agent_no"),
	(get_max_players, ":max_players"),
	
	#Check if the sender is in the correct condition.
	(agent_get_wielded_item, ":shield", ":agent_no", 1), #Offhand item.
	(is_between, ":shield", "itm_wooden_shield", "itm_steel_shield_herald03"),
	(agent_get_defend_action, ":action", ":agent_no"),
	(eq, ":action", 2), #Blocking.
	(agent_get_animation, ":anim", ":agent_no", 0),
	(neq, ":anim", "anim_shield_bash"),
	(agent_get_horse, ":horse", ":agent_no"),
	(eq, ":horse", -1), #No horse.
	
	#If everything is correct, then set the sender agent up for bash.
	(agent_set_animation, ":agent_no", "anim_shield_bash"),
	(player_get_troop_id, ":troop_no", ":player_no"),
	(troop_get_type, ":type_no", ":troop_no"),
	(try_begin),
	    (eq, ":type", tf_male),
		(try_for_range, ":player", 0, ":max_players"),
		    (player_is_active, ":player"),
			(multiplayer_send_2_int_to_player, ":player", mp_agent_play_sound_client, ":agent_no", "snd_man_yell"),
		(try_end),
	(else_try),
	    (eq, ":type", tf_female),
		(try_for_range, ":player", 0, ":max_players"),
		    (player_is_active, ":player"),
			(multiplayer_send_2_int_to_player, ":player", mp_agent_play_sound_client, ":agent_no", "snd_woman_yell"),
		(try_end),
	(try_end),
	
	#Bash. Get the closest agent within 175cm~1.75m.
	(agent_get_position, pos1, ":agent"),
	(assign, ":minimum_distance", 400),
	(assign, ":victim", -1),
	(try_for_agents, ":suspect"),
	    (neq, ":suspect", ":agent"), #Suspect can't be our local agent.
	    (agent_is_active, ":suspect"),
	    (agent_is_alive, ":suspect"),
		(agent_is_human, ":suspect"),
		
		#Compare distances.
		(agent_get_position, pos2, ":suspect"),
		(neg|position_is_behind_position, pos2, pos1),
		(get_distance_between_positions, ":distance", pos1, pos2),
		(le, ":distance", ":minimum_distance"),
		
		#If distance is sufficient..
		(assign, ":minimum_distance", ":distance"),
		(assign, ":victim", ":suspect"),
	(try_end),
	
	#If we have the victim, aka the closest agent, then deal with him. Else, do nothing.
	(ge, ":victim", 0),
	(agent_get_horse, ":horse", ":victim"),
	(eq, ":horse", -1), #No horse.
	(try_for_range, ":player", 0, ":max_players"),
	    (player_is_active, ":player"),
		(multiplayer_send_2_int_to_player, ":player", mp_agent_play_sound_client, ":victim", "snd_wooden_hit_low_armor_high_damage"),
	(try_end),
	(agent_get_position, pos2, ":victim"),
	(position_move_y, pos2, -25),
	(position_get_distance_to_ground_level, ":distance", pos2),
	(try_begin),
	    (le, ":distance", 25),
		(agent_set_position, ":victim", pos2),
		(agent_set_animation, ":victim", "anim_shield_strike"),
	(else_try),
	    (gt, ":distance", 25),
		(agent_set_animation, ":victim", "anim_shield_strike"),
	(try_end),
(else_try),
    (neq, multiplayer_is_server),
	(try_begin),
	    (eq, ":event_type", mp_agent_play_sound_client),
		(store_script_param, ":agent", 3),
		(store_script_param, ":sound", 4),
		(agent_play_sound, ":agent", ":sound"),
	(try_end),
(try_end),

Code:
#These animations go into module_animations.py
#They MUST replace existing unused animations.

##################
##Copyright: xenoargh. ##
##################
["shield_bash", 0, amf_play|amf_priority_defend|amf_use_defend_speed|amf_client_owner_prediction,
[0.75, "defend_shield_parry_all", 1, 50, blend_in_defense], #Adjust duration for balance.  Currently at 0.75 seconds, fixed.
[0.75, "defend_shield_right", 1, 50, blend_in_defense],
[0.75, "defend_shield_left", 1, 50, blend_in_defense],
[0.75, "defend_shield_right", 1, 50, blend_in_defense],   
],
 ["shield_strike", acf_enforce_all|acf_align_with_ground, amf_priority_striked|amf_play|amf_accurate_body|amf_restart,
   [1.0, "anim_human", blow+5000, blow+5010, arf_blend_in_3|arf_make_custom_sound], 
   [1.7, "anim_human", blow+5400, blow+5453, arf_blend_in_2|arf_make_custom_sound],
   [1.44, "anim_human", blow+5400, blow+5445, arf_blend_in_2|arf_make_custom_sound],   
   ],
 
wow MP bashing. that's sound great for epic fights  :smile:

for SP i try to change some bashing animations. and i would know if it s possible with anim flags to start an anim at the frame 20 (for example) of an other animation.

my problem is i have an bashing animation in 2 times : the player back his shield to himself then hardly push forward. So i need the shield_strike animation starts when agent is hit by shield.
Actually agents are bashed when i prepare bashing. yesterday night i ve made some test but i can't figure how to get it works.

any ideas are welome  :grin:

BTW, i ve a script error about bad agent ID. the shield bashing works but i ve these damned red scipt
lines in front of my eyes when playing. it's really annoying.

i don't know why, build module runs fine and  i ve read the code many, many times. i can't find my mistake :sad: :sad:

i ve just pasted-copied the code :mrgreen:

in other hand, is there a way to desactivate system warnings ?

thanks beforehand, guys.
i guess this little bull**** may bores you but your help will be very appreciated.


EDIT: if someone is interesting by this bashing animation, you ll find it in MP Kengeki 0.95 mod. there is three BRF animation files. but you need to download the whole mod


 
Aha, very nice, multiplayer shield bashing. I'm pretty sure I will add this to the Sultan's Successors at some point in the future. Though knocking people off of ledges would be very much to my liking. :razz:
 
Use Pull and Concussive Shot/Throw. Actually if the ledge is thin, you needn't use Pull.

Sorry, couldn't stop myself... :grin:
It would be nice to knock people off ledges, but wouldn't that be an easy way to get past the defenders in a siege? You emerge from the ladder, bash the guys there, and when they fall down you'll have a clear path. BTW, does this code include a bash "cooldown"? I mean, is there any time interval after bashing, during which you can't bash?
 
The code is pretty dirty.

An update for module_scripts (sinisterius MP codes):

Search in game_receive_network_message:
Code:
      (else_try),
        (eq, ":event_type", multiplayer_event_admin_set_disallow_ranged_weapons),
        (try_begin),
          (store_script_param, ":value", 3),
          #validity check
          (player_is_admin, ":player_no"),
          (is_between, ":value", 0, 2),
          #condition checks are done
          (assign, "$g_multiplayer_disallow_ranged_weapons", ":value"),
        (try_end),

And paste directly under that, this:
Code:
      (else_try),
        (eq, ":event_type", mp_shield_bash_server),


	#Get sender data & max players.
#	(player_is_active, ":player_no"),
	(player_get_agent_id, ":agent_no", ":player_no"),
#        (agent_is_active, ":agent_no"),
	(agent_is_alive, ":agent_no"),
#	(agent_is_human, ":agent_no"),
	

	#Check if the sender is in the correct condition.
	(agent_get_wielded_item, ":shield", ":agent_no", 1), #Offhand item.
	(is_between, ":shield", "itm_wooden_shield", "itm_darts"),

	(agent_get_horse, ":horse", ":agent_no"),
	(eq, ":horse", -1), #No horse.
	
	#If everything is correct, then set the sender agent up for bash.
        (get_max_players, ":max_players"),
        (try_for_range, ":player", 0, ":max_players"),
	    (player_is_active, ":player"),
(agent_set_animation, ":agent_no", "anim_shield_bash"),
(multiplayer_send_2_int_to_player, ":player", mp_agent_shield_bash, ":agent_no", "anim_shield_bash"),
	(try_end),
	
	#Bash. Get the closest agent within 175cm~1.75m.
	(agent_get_position, pos1, ":agent_no"),
	(assign, ":minimum_distance", 100), #1 meter
	(assign, ":victim", -1),
	(try_for_agents, ":suspect"),
	    (agent_is_active, ":suspect"),
	    (agent_is_alive, ":suspect"),
	    (neq, ":suspect", ":agent_no"), #Suspect can't be our local agent.
		(agent_is_human, ":suspect"),
		
		#Compare distances.
		(agent_get_position, pos2, ":suspect"),
		(neg|position_is_behind_position, pos2, pos1),
		(get_distance_between_positions, ":distance", pos1, pos2),
		(le, ":distance", ":minimum_distance"),
		
		#If distance is sufficient..
		(assign, ":minimum_distance", ":distance"),
		(assign, ":victim", ":suspect"),
	(try_end),
	
	#If we have the victim, aka the closest agent, then deal with him. Else, do nothing.
	(ge, ":victim", 0),

	(agent_get_horse, ":horse", ":victim"),
	(eq, ":horse", -1), #No horse.

        (try_for_range, ":player", 0, ":max_players"),
	    (player_is_active, ":player"),
	    (multiplayer_send_2_int_to_player, ":player", mp_agent_play_sound_client, ":victim", "snd_wooden_hit_low_armor_high_damage"),
	(try_end),
	(agent_get_position, pos2, ":victim"),
	(position_move_y, pos2, -25),
	(position_get_distance_to_ground_level, ":distance", pos2),
	(try_begin),
	    (le, ":distance", 25),
		(agent_set_position, ":victim", pos2),
		(agent_set_animation, ":victim", "anim_shield_strike"),
                (try_for_range, ":player", 0, ":max_players"),
    	          (player_is_active, ":player"),
                  (multiplayer_send_2_int_to_player, ":player", mp_agent_shield_bash, ":victim", "anim_shield_strike"),
	        (try_end),
	(else_try),
	    (gt, ":distance", 25),
	    (agent_set_animation, ":victim", "anim_shield_strike"),
            (try_for_range, ":player", 0, ":max_players"),
	        (player_is_active, ":player"),
                (multiplayer_send_2_int_to_player, ":player", mp_agent_shield_bash, ":victim", "anim_shield_strike"),
            	(try_end),
	(try_end),


	(player_get_troop_id, ":troop_no", ":player_no"),
	(troop_get_type, ":type_no", ":troop_no"),
	(try_begin),
	    (eq, ":type_no", tf_male),
	    (try_for_range, ":player", 0, ":max_players"),
	        (player_is_active, ":player"),
	    	(multiplayer_send_2_int_to_player, ":player", mp_agent_play_sound_client, ":agent_no", "snd_man_yell"),
	    (try_end),
	(else_try),
	    (eq, ":type_no", tf_female),
	    (try_for_range, ":player", 0, ":max_players"),
	        (player_is_active, ":player"),
	    	(multiplayer_send_2_int_to_player, ":player", mp_agent_play_sound_client, ":agent_no", "snd_woman_yell"),
	    (try_end),
	(try_end),

And search for:
Code:
      (else_try),
        ###############
        #CLIENT EVENTS#
        ###############
        (neq, multiplayer_is_server),
        (try_begin),      
          (eq, ":event_type", multiplayer_event_return_renaming_server_allowed),
          (store_script_param, ":value", 3),
          (assign, "$g_multiplayer_renaming_server_allowed", ":value"),

And paste under that:
Code:
         (else_try),
	  (eq, ":event_type", mp_agent_play_sound_client),
	  (store_script_param, ":value", 3),
          (store_script_param, ":value_2", 4),
	  (agent_play_sound, ":value", ":value_2"),
        (else_try),
	  (eq, ":event_type", mp_agent_shield_bash),
	  (store_script_param, ":value", 3),
          (store_script_param, ":value_2", 4),
	  (agent_set_animation, ":value", ":value_2"),

Add to header_common.py:
Under:
Code:
multiplayer_event_admin_set_disallow_ranged_weapons           = 47
This:
Code:
mp_agent_play_sound_client                                     = 48
mp_agent_shield_bash                                           = 49

And

Under:
Code:
multiplayer_event_return_disallow_ranged_weapons              = 112
This:
Code:
mp_shield_bash_server                                      = 113


Extra:

Code:
mp_shield_bash = (
    0, 0, 0,
	[
	    (game_key_is_down, gk_defend),
		(game_key_clicked, gk_attack),
#		(game_in_multiplayer_mode),
	],
	[		
              (multiplayer_get_my_player, ":my_player"),
              (player_get_agent_id, ":agent_no", ":my_player"),
              
	(agent_get_wielded_item, ":shield", ":agent_no", 1), #Offhand item.
	(is_between, ":shield", "itm_wooden_shield", "itm_darts"),
 #              (display_message, "@shield bash initiated."),
#              (agent_get_animation, ":agent_anim", ":agent_no", 1),
		(multiplayer_send_message_to_server, mp_shield_bash_server),
	])
as the (game_is_in_multiplayer_mode), is supposed to be (game_in_multiplayer_mode),
 
Sorry for triple post, just to bump so everyone knows I fixed it. It's quite spammable and overpowered so I will work on that later. Also the shield-bash animation doesn't show. I think something in module_animations is wrong as the knockdown DOES show.
 
Hello, back from my mute.

I have fixed the shield bash completely (animations etc work now) and made it non-spammable (it has a cooldown timer). I will upload the codes soon.
 
Welcome back, animations also worked for my code (except that the module_animations code of the shieldbash was basically the same as just static blocking), so I kinda fixed it all already :/ didn't make the cooldown timer yet. I hope you at least tested it this time?
 
The code below is tested and it should work. But again, if any issues should show up, just tell me and I will update the codes once again.

Anyway, now there's a cooldown for the bash, which is 5seconds. Aka you can't bash again in 5seconds after bashing.
Also, I made it so that when you bash and the enemy is blocking with a shield, he won't be knocked down but instead both of you will play the shield bash animation (only if he is facing you, of course...).

All of the codes have instructions on how to implement and how it works.
Enjoy.
Code:
################################################
## Shield Bash                                ##
## Developed by 'xenoargh' for singleplayer.  ##
## Revamped for multiplayer by 'Sinisterius'. ##
## Animations Copyright (C) 2010 'xenoargh'.  ##
################################################


#####
#Add the following block of code to module_scripts.py,
#game_receive_network_message, right under the store_script_param's.
#That's all you need to do.
	(try_begin),
        (eq, ":event_type", rpw_shield_bash_server),
   
        #Get sender data & max players.
        (player_is_active, ":player_no"),
        (player_get_agent_id, ":agent_no", ":player_no"),
        (agent_is_active, ":agent_no"),
        (get_max_players, ":max_players"),
   
        #Check if the sender is in the correct condition.
		(neg|player_slot_ge, ":player_no", rpw_shield_bash_timer, 1), #Less than.
        (agent_get_wielded_item, ":shield", ":agent_no", 1), #Offhand item.
        (this_or_next|is_between, ":shield", "itm_roman_shield_square", "itm_roman_shield_end"),
		(is_between, ":shield", "itm_gallic_shield_1", "itm_gallic_shield_end"),
        (agent_get_defend_action, ":action", ":agent_no"),
        (eq, ":action", 2), #Blocking.
        (agent_get_horse, ":horse", ":agent_no"),
        (eq, ":horse", -1), #No horse.
   
        #If everything is correct, then set the sender agent up for bash.
		(player_set_slot, ":player_no", rpw_shield_bash_timer, 2), #Actually is 2*2.5=5seconds.
        (agent_set_animation, ":agent_no", "anim_shield_bash"),
        (agent_get_troop_id, ":troop_no", ":agent_no"),
        (troop_get_type, ":type_no", ":troop_no"),
        (try_begin),
            (eq, ":type_no", tf_male),
            (try_for_range, ":player", 0, ":max_players"),
                (player_is_active, ":player"),
                (multiplayer_send_2_int_to_player, ":player", rpw_agent_play_sound_client, ":agent_no", "snd_man_yell"),
            (try_end),
        (else_try),
            (eq, ":type_no", tf_female),
            (try_for_range, ":player", 0, ":max_players"),
                (player_is_active, ":player"),
                (multiplayer_send_2_int_to_player, ":player", rpw_agent_play_sound_client, ":agent_no", "snd_woman_yell"),
            (try_end),
        (try_end),
   
        #Bash. Get the closest agent within 100cm~1m.
        (agent_get_position, pos1, ":agent_no"),
        (assign, ":minimum_distance", 150),
        (assign, ":victim", -1),
        (try_for_agents, ":suspect"),
            (neq, ":suspect", ":agent_no"), #Suspect can't be our local agent.
            (agent_is_active, ":suspect"),
            (agent_is_alive, ":suspect"),
            (agent_is_human, ":suspect"),
      
            #Compare distances.
            (agent_get_position, pos2, ":suspect"),
            (neg|position_is_behind_position, pos2, pos1), #Suspect can't be behind basher.
            (get_distance_between_positions, ":distance", pos1, pos2),
            (le, ":distance", ":minimum_distance"),
      
            #If distance is sufficient..
            (assign, ":minimum_distance", ":distance"),
            (assign, ":victim", ":suspect"),
        (try_end),
   
        #If we have the victim, aka the closest agent, then deal with him. Else, do nothing.
        (ge, ":victim", 0),
        (agent_get_horse, ":horse", ":victim"),
        (eq, ":horse", -1), #No horse.
        (try_for_range, ":player", 0, ":max_players"),
            (player_is_active, ":player"),
            (multiplayer_send_2_int_to_player, ":player", rpw_agent_play_sound_client, ":victim", "snd_wooden_hit_low_armor_high_damage"),
        (try_end),
		(agent_get_defend_action, ":action", ":victim"),
		(try_begin),
			(eq, ":action", 2), #Blocking.
			(neg|position_is_behind_position, pos1, pos2), #If basher isn't behind victim.
            (agent_get_wielded_item, ":shield", ":victim", 1), #Offhand item.
			(try_begin),
                (this_or_next|is_between, ":shield", "itm_roman_shield_square", "itm_roman_shield_end"),
	        	(is_between, ":shield", "itm_gallic_shield_1", "itm_gallic_shield_end"),
                (position_move_y, pos2, -50),
                (position_get_distance_to_ground_level, ":distance", pos2),
                (try_begin),
                    (le, ":distance", 25),
                    (agent_set_animation, ":victim", "anim_shield_bash"),
                    (agent_set_position, ":victim", pos2),
                (else_try),
                    (agent_set_animation, ":victim", "anim_shield_bash"),
                (try_end),
			(try_end),
		(else_try),
            (agent_get_position, pos2, ":victim"),
            (position_move_y, pos2, -75),
            (position_get_distance_to_ground_level, ":distance", pos2),
            (try_begin),
                (le, ":distance", 25),
                (agent_set_animation, ":victim", "anim_shield_strike"),
                (agent_set_position, ":victim", pos2),
            (else_try),
                (agent_set_animation, ":victim", "anim_shield_strike"),
            (try_end),
		(try_end),
	(else_try),
	    (neq, multiplayer_is_server),
		(try_begin),
		    (eq, ":event_type", rpw_agent_play_sound_client),
			(store_script_param, ":agent", 3),
			(store_script_param, ":sound", 4),
			(agent_play_sound, ":agent", ":sound"),
		(try_end),
	(try_end),
Code:
#####
#Add these following triggers to module_mission_templates.py,
#above all other code. Then simply add:
#mp_shield_bash_1,
#mp_shield_bash_2,
#To your mission templates to activate the triggers.
mp_shield_bash_1 = (
	0, 0, 0,
	[
	    #Get player input for shield bash.
        (game_key_is_down, gk_defend),
        (game_key_clicked, gk_attack),
    ],
    [
	    #If input is given, then initialize a bash.
        (multiplayer_send_message_to_server, rpw_shield_bash_server),
    ])
mp_shield_bash_2 = (
	2.5, 0, 0, [],
	[
	    #Update each players shield bash timer.
		#Do this every 2.5 seconds for optimization issues.
	    (multiplayer_is_server),
	    (get_max_players, ":max"),
		(try_for_range, ":player", 0, ":max"),
		    (player_is_active, ":player"),
			(player_get_slot, ":value", ":player", rpw_shield_bash_timer),
			(val_sub, ":value", 1),
			(val_max, ":value", 0),
			(player_set_slot, ":player", rpw_shield_bash_timer, ":value"),
		(try_end),
	])
Code:
#####
#The following animations go into module_animations.py.
#Simply replace two unused human animations with these animations.
#You can adjust the duration of the bash, simply modify the '0.50' to
#your liking. So '1.0' is 1second and '0.50' is half a second.
["shield_bash", acf_enforce_all|acf_align_with_ground, amf_priority_striked|amf_play|amf_accurate_body|amf_restart,
    [0.50, "defend_shield_parry_all", 1, 50, blend_in_defense], #Adjust duration for balance.  Currently at 0.50 seconds, fixed.
    [0.50, "defend_shield_right", 1, 50, blend_in_defense],
    [0.50, "defend_shield_left", 1, 50, blend_in_defense],
    [0.50, "defend_shield_right", 1, 50, blend_in_defense],   
],
["shield_strike", acf_enforce_all|acf_align_with_ground, amf_priority_striked|amf_play|amf_accurate_body|amf_restart,
    [1.0, "anim_human", blow+5000, blow+5010, arf_blend_in_3|arf_make_custom_sound],
    [1.7, "anim_human", blow+5400, blow+5453, arf_blend_in_2|arf_make_custom_sound],
    [1.44, "anim_human", blow+5400, blow+5445, arf_blend_in_2|arf_make_custom_sound],   
],
Code:
#####
#Add this to header_common.py, right before 'multiplayer message types' and
#after other multiplayer_event_x's.
rpw_shield_bash_server = 150
Code:
#####
#This goes into module_constants.py, player slots.
rpw_shield_bash_timer = 50
 
Headmaster said:
It's possible to add a stat to a shield that determines damage that can be done by the bash?
Very easy. Create a new item slot (e.g item_shield_bash_damage_modifier) and then assign each shield their own values for that slot. Then get the equiped items slot during the damage-dealing part of the shield bash script and deal damage.

For example..
Code:
#In module_scripts.py, game initialization script.
(try_for_range, ":shield", "itm_shield_begin, "itm_shield_end"),
    (item_set_slot, ":shield", item_shield_bash_damage_modifier, 0),
(try_end),
(item_set_slot, "itm_shield_3", item_shield_bash_damage_modifier, 15),
#-||- repeat for other shields...

#Then to get the basic damage to deal.
(item_get_slot, ":base_damage", ":equiped_item", item_shield_bash_damage_modifier), #Get base damage modifier.
(assign, ":dif_min", ":base_damage"), #Init minimum damage difference.
(assign, ":dif_max", ":base_damage"), #Init maximum damage difference.
(val_sub, ":dif_min", 5), #min damage = base_damage - 5
(val_max, ":dif_min", 0), #min damage can't go below zero.
(val_add, ":dif_max", 6), #max damage = base_damage + 5 (+6 in our case because store_random_in_range excludes 1)
(store_random_in_range, ":damage", ":dif_min", ":dif_max"), #gets random value between (base_damage - 5 to base_damage + 5)
[code]
 
Can you make the shield bash have a chance of just stun the target instead of knocking them over every time? If the attack can range from just a short reaction, (the normal "oh I got hit!" animation) to a dazed reaction, to a knockdown, then it won't be quite as overpowering. And I'm happy to see that you can define damage according to shield. Makes some of these Scottish spiked targes a little more exciting:
targe.jpg

Along those lines, can you limit the action altogether to certain shields? Or change the animations that each shield use? (ie. more of a shoving animation for a tower shield, versus a swinging motion for a buckler?
 
Back
Top Bottom