OSP Code Combat Stone lobbing script

Users who are viewing this thread

A script that enables you to pick up scene props and throw them to ppl with lethal consequences.
Includes great deal of real physics (flight and bouncing). Does not include weight considerations yet, but can be easily programmed to include those. Just needs some constants definition for different scene props and their relative visual sizes.

So far it uses two scene props, spr_stoneball (Native one) and spr_throwing_stone (new one). Can be easily reprogrammed to use any scene prop - like picking up and throwing a stool in a bar brawl :smile: Or a castle, if you really feel like it...

Feel free to use and modify it however you like. Mention me in the credits afterwards.

This code goes to a mission in module_mission_templates.py, where you want to be able to lob stones
Code:
################## STONELOBBING BEGIN ########################################
################## uses spr_stoneball and spr_throwing_stone (new one) props #
################## pos49 is used globally for stone tracking! ################
(0, 0, ti_once, [], [
  (assign,"$stonelobbing_state",0),				###### 0 no stones, 1 stone picked, 2,3,4 stone flying & bouncing
  (assign,"$stone_initial_velocity",35),
  (assign,"$stone_horizontal_velocity",0),
  (assign,"$stone_vertical_velocity",0),
  (assign,"$stone_rotation_x",20),				###### stone rotation speed in flight
  (assign,"$stone_rotation_y",30),
  (assign,"$stone_rotation_z",30),	
]),

(0,0,1, [
  (key_clicked, key_e),										###### picking up a stone
  (eq,"$stonelobbing_state",0),
     (get_player_agent_no,":player_agent"),
     (agent_get_wielded_item,reg1,":player_agent",0),			###### should be emptyhanded to pick up a stone, duh
     (agent_get_wielded_item,reg2,":player_agent",1),
#   (display_message, "@DEBUG:STONE: Pick stone E, throw F, should be emptyhanded to pick"),
     (eq,reg1,-1),
     (eq,reg2,-1),
  ],[
   (get_player_agent_no,":player_agent"),
   (agent_get_position,pos1,":player_agent"),
   (position_move_z,pos1,50),
			
   (scene_prop_get_num_instances,":num_stones","spr_stone_ball"), ### pick stone ball prop
   (try_for_range,":count",0,":num_stones"),
      (scene_prop_get_instance,":stone_instance", "spr_stone_ball", ":count"),
      (prop_instance_get_position,pos2,":stone_instance"),
      (get_distance_between_positions,":distance",pos1,pos2),
      (lt,":distance",150),
         (assign,"$stonelobbing_state",1),
         (assign,"$stone_picked_instance",":stone_instance"),
         (agent_set_walk_forward_animation,":player_agent", "anim_reload_crossbow"),
         (play_sound, "snd_man_grunt"),
   (try_end),

   (scene_prop_get_num_instances,":num_stones","spr_throwing_stone"),# or pick throwing stone prop
   (try_for_range,":count",0,":num_stones"),
      (scene_prop_get_instance,":stone_instance", "spr_throwing_stone", ":count"),
      (prop_instance_get_position,pos2,":stone_instance"),
      (get_distance_between_positions,":distance",pos1,pos2),
      (lt,":distance",150),(eq,"$stonelobbing_state",0),
         (assign,"$stonelobbing_state",1),
         (assign,"$stone_picked_instance",":stone_instance"),
         (agent_set_animation,":player_agent", "anim_reload_crossbow"),
         (play_sound, "snd_man_grunt"),
   (try_end),
]),

(0,0,5, [
   (key_clicked, key_f),
   (eq,"$stonelobbing_state",1),			###### throwing a stone
 ],[
   (get_player_agent_no,":player_agent"),
   (agent_get_position,pos1,":player_agent"),
   (agent_get_look_position,pos2,":player_agent"),
   (copy_position,pos3,pos2),									####### get stone initial velocities
   (position_move_y,pos3,"$stone_initial_velocity"),
   (position_transform_position_to_local, pos4, pos1,pos3),
   (position_get_y,"$stone_horizontal_velocity",pos4),
   (position_get_z,"$stone_vertical_velocity",pos4),
   (agent_get_position,pos49,":player_agent"),					###### orient stone with horizontal y for easier flight later
   (position_move_z,pos49,170),	
   (position_move_x,pos49,25),
   (prop_instance_set_position,"$stone_picked_instance",pos49),
   (agent_set_animation,":player_agent","anim_release_overswing_twohanded"),
   (play_sound, "snd_man_grunt"),
   (assign,"$stonelobbing_state",2),
]),

(0,0,0, [
   (ge,"$stonelobbing_state",2),								###### stone flight
 ],[
   (prop_instance_get_position,pos1,"$stone_picked_instance"),
   (copy_position,pos2,pos49),
   (position_set_z_to_ground_level, pos2),
   (position_transform_position_to_local,pos4, pos49,pos2),
   (position_get_z,":z_missile",pos4),
   (try_begin),
      (this_or_next|lt,":z_missile",-20), 		###### when ground is far away or flying up, fly stone
      (gt,"$stone_vertical_velocity",0),
      (position_move_y,pos49,"$stone_horizontal_velocity"),
      (position_move_z,pos49,"$stone_vertical_velocity"),
      (val_sub,"$stone_vertical_velocity",1),				###### gravity
      (copy_position,pos2,pos49),						###### stone rotation
      (position_copy_rotation,pos2,pos1),
      (position_rotate_x,pos2,"$stone_rotation_x"),
      (position_rotate_y,pos2,"$stone_rotation_y"),
      (try_begin),									###### add spin when bounced
	 (gt,"$stonelobbing_state",2),
         (position_rotate_z,pos2,"$stone_rotation_z"),
      (try_end),
      (prop_instance_animate_to_position,"$stone_picked_instance",pos2,5),

      (get_player_agent_no,":player_agent"),					###### when stone close to the agent
      (try_for_agents,":agent"),
         (agent_is_alive, ":agent"),
         (neq,":agent",":player_agent"),
         (agent_get_position,pos3,":agent"),
         (position_move_z,pos3,70),
         (get_distance_between_positions,":stone_hit",pos2,pos3),
         (try_begin),
            (lt,":stone_hit",100),
            (agent_play_sound,":agent","snd_blunt_hit"),
            (store_mul,":v","$stone_vertical_velocity",  "$stone_vertical_velocity"  ),
            (store_mul,":h","$stone_horizontal_velocity","$stone_horizontal_velocity"),
            (val_add,":v",":h"),
            (store_sqrt,":velocity",":v"),
            (try_begin),								###### kill the agent if stone is fast
               (gt,":velocity",40),
               (agent_set_hit_points,":agent",0,0),
               (agent_deliver_damage_to_agent,":player_agent",":agent"),
               (agent_play_sound,":agent","snd_man_die"),
               (val_sub,"$stone_horizontal_velocity",5),	
            (else_try),									###### ko agent and deliver some damage if stone is slow
               (store_agent_hit_points,":hp",":agent",1),
               (val_div,":velocity",2),
               (val_sub,":hp",":velocity"),
	       (try_begin), 
                   (lt,":hp",0),
                   (assign,":hp",0),
               (try_end),
               (agent_set_hit_points,":agent",":hp",1),
               (agent_deliver_damage_to_agent,":player_agent",":agent"),
               (agent_set_animation,":agent","anim_strike_fall_back_rise"),
               (agent_play_sound,":agent","snd_man_grunt"),
               (val_sub,"$stone_horizontal_velocity",2),
           (try_end),
        (try_end),
      (try_end),
   (else_try),
      (play_sound,"snd_body_fall_small"),
      (prop_instance_get_position,pos1,"$stone_picked_instance"),
      (position_set_z_to_ground_level,pos1),
      (position_move_z,pos1,30),
      (prop_instance_set_position,"$stone_picked_instance",pos1),
      (try_begin),
          (lt,"$stonelobbing_state",4),						###### bouncing stone
          (val_div,"$stone_vertical_velocity",-2),
          (val_div,"$stone_horizontal_velocity",2),
          (val_add,"$stonelobbing_state",1),
      (else_try),										###### stone reached final rest
#       (display_message,"@DEBUG:STONE: missile hit final ground"),
         (assign,"$stonelobbing_state",0),
      (try_end),	
   (try_end),
]),
			
(0,0,0, [
   (eq,"$stonelobbing_state",1),					###### carrying stone sync
 ],[
   (get_player_agent_no,":player_agent"), 
   (agent_get_position,pos6,":player_agent"),
   (position_move_z,pos6,170),
   (position_move_x,pos6,25), 
   (prop_instance_animate_to_position,"$stone_picked_instance",pos6,3),
# (agent_set_walk_forward_animation,":player_agent","anim_ready_overswing_twohanded"),#    dont know how to assign upperbody animation yet :(
]),			
################## STONELOBBING END ########################################
You will need to add props with Edit mode to scenes, or you will have nothing to lob

And a new prop made of Native throwing stone model.
Code goes at the end of the module_scene_props.py.
Code:
  ("throwing_stone",0,"throwing_stone","0",[]),


Script limitations:
1) you can't pick up another stone while first one is flying. CBA to write more script to handle this :smile:
2) I yet to find a way to keep player's arms up when carrying a stone, and preserve mobility

Engine limitations:
1) stone can only bounce from ground or non-vertical collision meshes. It will fly through vertical walls, nothing can be done about it
2) also, bouncing from horizontal surfaces looks best. The more vertical the obstacle, the more unnatural is the bouncing
3) you can equip back weapon & shield when you picked up a stone. I yet to find a way to forbid equipping
 
No. I concentrated on getting as good physics as possible and ease of usage for the player.

AI needs a bunch of completely different things, like working on searching and positioning algorithm, aiming, multiple stones in the air... I don't have time for that  :smile:
 
Very very awesome.  I was planning on creating some boulder throwing troops for Revenge of the Berserk at some point.  I could possibly code in the ai bits myself.  I'm sorry if this has been asked but this does look at how large the thrown item's collision box is right?
 
There's an hack that we use in the next version of 1866 for the dynamite script to get AI to use it correctly. It's a throwing weapon, but the damage is 0 and the mesh is invisible. There is a ti_on_weapon_attack associated with the weapon that calls a script which animates a scene prop, just like you have here. We use the shoot_speed of the thrown weapon along with the agent's look position as inputs to the script to calculate the initial velocity. So we just let the internal game logic do the hard work of figuring out how to aim  :grin:
 
Berserker Pride said:
.. this does look at how large the thrown item's collision box is right?

Unfortunately, there is no way for MS to use collision mesh :sad: All calculations are done relative to position origin of the prop. Not that important since you aren't supposed physically be able to throw very large props anyway. In a pinch you can approximate collision mesh for a thrown prop with a small sphere.

dstemmer said:
There's an hack that we use in the next version of 1866 for the dynamite script to get AI to use it correctly. It's a throwing weapon, but the damage is 0 and the mesh is invisible. There is a ti_on_weapon_attack associated with the weapon that calls a script which animates a scene prop, just like you have here. We use the shoot_speed of the thrown weapon along with the agent's look position as inputs to the script to calculate the initial velocity. So we just let the internal game logic do the hard work of figuring out how to aim  :grin:

That's clever stuff, it would eliminate half of the problems with AI coding. What's left is searching for the prop to throw, that can supposedly be done with agent_set_scripted_destination. And making all the visual stuff correct - AFAIK there can be problems with assigning specific animations to this "throwing weapon" while keeping native small stone throwing as it is. Also I do not know of the way to unequip weapon and shield for the AI agent.
And of course there should be major rewriting of all the constants, positions and speeds into array form to simulate several flying stones simultaneously.

EDIT: also, it's a bit annoying that there seems to be no way to play sounds from certain positions w/o agent involvement. I planned to experiment with invisible spawned agents to get sounds for stone hitting ground right, but moved elsewhere with my coding. If anyone was working on the problem of attaching sounds to scene prop animations, I'd be very interested to hear about your results
 
Oh my, it just came into my mind that I could script a football match using the same technique, instead of that trivial siege-related stuff..  :mrgreen: So much time lost in vain...

Kicking the ball prop through key clicks, with ball flight direction derived from your position relative to the ball at the time of kick + your speed.
With hostile AI w/o weapons rushing randomly either to kick the ball or to kick your butt.
 
Archevious said:
Best Mod Ever! :lol: Hmm... how would points work out though? :neutral:
That should be the easiest mod, if made for Warband, since no need at all to program AI  :smile:
Just several triggers allowing ball kicking and one trigger catching ball coordinates and handling scoring, bouncing off field borders and players.
And KO-ed players are allowed to respawn in time, like a team has unlimited substitutions

With vanilla M&B it would be tricky to make AI a challenge. It would not be a 100% football, since I would certainly need to bend some rules against the player. But I'm going to give it a shot on weekend
 
GetAssista said:
That's clever stuff, it would eliminate half of the problems with AI coding. What's left is searching for the prop to throw, that can supposedly be done with agent_set_scripted_destination.

We just added a bunch of dynamite props to each scene (like 10 to each scene) and moved them underground. When we want to throw the scene prop, we get its number (from 1-10, or 0-9, I can't remember) and set the appropriate slot on a troop array to '1' to indicate that it's in the air. We make sure that if a dynamite scene prop is in the air it can't be accessed by another instance of the script. When the dynamite blows up, we move the scene prop back underground and flip its flag back to '0' to make sure another script can access it. It's a little more complicated than that but that's the gist of it. Don't you have access to the 1866 source code? If so I could show you where to look at it.

GetAssista said:
And making all the visual stuff correct - AFAIK there can be problems with assigning specific animations to this "throwing weapon" while keeping native small stone throwing as it is. Also I do not know of the way to unequip weapon and shield for the AI agent.

Can't you just make the a new weapon and give it whatever throwing animation you want and attach the script to it? Also, if it's a throwing weapon, they'll put away their weapon before using it. Since the mesh is invisible you won't see anything in their hand. They'll still have a shield, though. Maybe you could solve this by making it itp_two_handed?

GetAssista said:
Oh my, it just came into my mind that I could script a football match using the same technique, instead of that trivial siege-related stuff..  :mrgreen: So much time lost in vain...

Kicking the ball prop through key clicks, with ball flight direction derived from your position relative to the ball at the time of kick + your speed.
With hostile AI w/o weapons rushing randomly either to kick the ball or to kick your butt.

Without weapons? Why? This seems like a great engine for a Blood Bowl or Mutant League Football mod!

That would be American football though. :twisted:
 
dstemmer said:
We just added a bunch of dynamite props to each scene (like 10 to each scene) ...
Don't you have access to the 1866 source code? If so I could show you where to look at it.
The whole point of my script is that the stone is picked from the ground, literally. I do not want it to magically appear out of nowhere. Dynamite, as well as small stones, need not use this. But big stone should.

And, yup, I would've used same array flagging technique if scripting multiple stones, I've already mentioned it :smile:

dstemmer said:
Can't you just make the a new weapon and give it whatever throwing animation you want and attach the script to it?
Umm, you are talking about a completely new class of weapon here. Is it possible to add new class? So far I was under impression that we can't do it in MB.
 
Oh, I didn't know you were picking up preexisting scene props. That's a bit trickier. In that case you can't force them to switch to the weapon.

And yes, you're right about not being able to add weapon classes, I wasn't reading carefully enough. To get a different animation for a thrown weapon, you'd have to either override one of the existing throwing animations (spear, stone, axe etc.) or use agent_set_animation with a ti_on_weapon_attack trigger, but it wouldn't fix the wind-up animation. You might be able to do something with agent_get_combat_state to see if they were readying a throw, but it would be tricky.
 
Berserker Pride said:
Medieval Football!!! You should make a mod with that to replace tournaments!
footballmh.jpg

they kick the ball a bit erratically so far :mrgreen: but compensate with fists
 
This is the best thing ever.  I have a million uses for it.  Thanks GetAssista, I will be using this for certain!

I will credit you when the mod is released.
 
Back
Top Bottom