Author Topic: Weapon Ricochets  (Read 2921 times)

0 Members and 1 Guest are viewing this topic.

Offline Dragon

  • Citation needed
  • 212
  • The sky is the limit.
Some time ago, I asked m!m if he could try to incorporate weapon ricochet function into his particle script. He said that it wasn't possible, but perhaps could be done as an in-engine feature. Initially, I didn't want to bother you with that, but recently m!m told me that he looked into this and send me a patch for the feature.
The problem is, it doesn't really work. The weapon created by it is removed as soon as it hits something. Could you take a look at this?
The patch:
Code: [Select]
Index: code/object/collideshipweapon.cpp
===================================================================
--- code/object/collideshipweapon.cpp   (revision 7936)
+++ code/object/collideshipweapon.cpp   (working copy)
@@ -64,16 +64,61 @@
  * Deal with weapon-ship hit stuff. 
  * Separated from check_collision routine below because of multiplayer reasons.
  */
-void ship_weapon_do_hit_stuff(object *ship_obj, object *weapon_obj, vec3d *world_hitpos, vec3d *hitpos, int quadrant_num, int submodel_num, vec3d /*not a pointer intentionaly*/ hit_dir)
+bool ship_weapon_do_hit_stuff(object *ship_obj, object *weapon_obj, vec3d *world_hitpos, vec3d *hitpos, int quadrant_num, int submodel_num, vec3d /*not a pointer intentionaly*/ hit_dir)
 {
        weapon  *wp = &Weapons[weapon_obj->instance];
        weapon_info     *wip = &Weapon_info[wp->weapon_info_index];
        ship *shipp = &Ships[ship_obj->instance];       
        float damage;
-       vec3d force;           
+       vec3d force;
+       
+       bool ricochet_happened = false;
 
+       if (Armor_types[shipp->armor_type_idx].GetRicochetProbability(wip->damage_type_idx) > 0.0f)
+       {
+               ArmorType *type = &Armor_types[shipp->armor_type_idx];
+               vec3d vel = weapon_obj->phys_info.vel;
+
+               vm_vec_normalize(&vel);
+               vm_vec_scale(&vel, -1.0f); // Required to get a correct result from vm_vec_dot
+
+               // assume hit_dir is normalized
+               float dot = vm_vec_dot(&vel, &hit_dir);
+
+               float result = dot * type->GetRicochetProbability(wip->damage_type_idx);
+
+               ricochet_happened = result > ((float) myrand() / RAND_MAX);
+
+               if (ricochet_happened)
+               {
+                       float pct = get_hull_pct(ship_obj);
+                       if (pct > type->GetRicochetStartLevel(wip->damage_type_idx))
+                               ricochet_happened = false;
+
+                       if (pct < type->GetRicochetEndLevel(wip->damage_type_idx))
+                               ricochet_happened = false;
+               }
+
+               if (ricochet_happened)
+               {
+                       wp->damage_scale *= type->GetRicochetDamageFactor(wip->damage_type_idx) * dot;
+
+                       vec3d vec;
+                       float real_dot = vm_vec_dot(&weapon_obj->phys_info.vel, &hit_dir);
+
+                       vm_vec_scale2(&vec, real_dot, 2);
+
+                       vec3d out;
+
+                       vm_vec_sub(&out, &weapon_obj->phys_info.vel, &vec);
+
+                       weapon_obj->phys_info.vel = out;
+                       weapon_obj->phys_info.desired_vel = out;
+               }
+       }
+
        // Apply hit & damage & stuff to weapon
-       weapon_hit(weapon_obj, ship_obj,  world_hitpos, quadrant_num);
+       weapon_hit(weapon_obj, ship_obj,  world_hitpos, quadrant_num, ricochet_happened);
 
        damage = wip->damage;
 
@@ -109,6 +154,7 @@
                ship_apply_whack( &force, hitpos, ship_obj );
        }
 
+       return ricochet_happened;
 }
 
 extern int Framecount;
Index: code/ship/ship.cpp
===================================================================
--- code/ship/ship.cpp  (revision 7936)
+++ code/ship/ship.cpp  (working copy)
@@ -16461,6 +16461,46 @@
        return 0.0f;
 }
 
+float ArmorType::GetRicochetProbability(int damage_type_idx)
+{
+       ArmorDamageType *adtp = getDamageType(damage_type_idx);
+
+       if (adtp == NULL)
+               return 0.0f;
+
+       return adtp->ricochet_probability;
+}
+
+float ArmorType::GetRicochetDamageFactor(int damage_type_idx)
+{
+       ArmorDamageType *adtp = getDamageType(damage_type_idx);
+
+       if (adtp == NULL)
+               return 0.0f;
+
+       return adtp->ricochet_damage_factor;
+}
+
+float ArmorType::GetRicochetStartLevel(int damage_type_idx)
+{
+       ArmorDamageType *adtp = getDamageType(damage_type_idx);
+
+       if (adtp == NULL)
+               return 0.0f;
+
+       return adtp->ricochet_start_level;
+}
+
+float ArmorType::GetRicochetEndLevel(int damage_type_idx)
+{
+       ArmorDamageType *adtp = getDamageType(damage_type_idx);
+
+       if (adtp == NULL)
+               return 0.0f;
+
+       return adtp->ricochet_end_level;
+}
+
 //***********************************Member functions
 
 ArmorType::ArmorType(char* in_name)
@@ -16544,6 +16584,47 @@
                        no_content = false;
                }
 
+               adt.ricochet_probability = 0.0f;
+               adt.ricochet_damage_factor = 1.0f;
+               adt.ricochet_start_level = 1.0f;
+               adt.ricochet_end_level = 0.0f;
+
+               if (optional_string("+Weapon Ricochet Probability:"))
+               {
+                       stuff_float(&temp_float);
+                       CLAMP(temp_float, 0.0f, 1.0f);
+
+                       adt.ricochet_probability = temp_float;
+                       no_content = false;
+               }
+
+               if (optional_string("+Weapon Ricochet Damage Factor:"))
+               {
+                       stuff_float(&temp_float);
+                       CLAMP(temp_float, 0.0f, 1.0f);
+
+                       adt.ricochet_damage_factor = temp_float;
+                       no_content = false;
+               }
+
+               if (optional_string("+Weapon Ricochet Start Level:"))
+               {
+                       stuff_float(&temp_float);
+                       CLAMP(temp_float, 0.0f, 100.0f);
+
+                       adt.ricochet_start_level = temp_float / 100.0f;
+                       no_content = false;
+               }
+
+               if (optional_string("+Weapon Ricochet End Level:"))
+               {
+                       stuff_float(&temp_float);
+                       CLAMP(temp_float, 0.0f, 100.0f);
+
+                       adt.ricochet_end_level = temp_float / 100.0f;
+                       no_content = false;
+               }
+
                //If we have calculations in this damage type, add it
                if(!no_content)
                {
@@ -16556,6 +16637,26 @@
        } while(optional_string("$Damage Type:"));
 }
 
+ArmorDamageType *ArmorType::getDamageType(int damage_type_idx)
+{
+       if (damage_type_idx < 0)
+               return NULL;
+
+       ArmorDamageType *adtp = NULL;
+
+       //Find the entry in the weapon that corresponds to the given weapon damage type
+       for(int i = 0; i < (int) DamageTypes.size(); i++)
+       {
+               if(DamageTypes[i].DamageTypeIndex == damage_type_idx)
+               {
+                       adtp = &DamageTypes[i];
+                       break;
+               }
+       }
+
+       return adtp;
+}
+
 //********************************Global functions
 
 int armor_type_get_idx(char* name)
Index: code/ship/ship.h
===================================================================
--- code/ship/ship.h    (revision 7936)
+++ code/ship/ship.h    (working copy)
@@ -176,6 +176,11 @@
        float                           piercing_start_pct;
        int                                     piercing_type;
 
+       // ricochet data
+       float ricochet_probability;
+       float ricochet_damage_factor;
+       float ricochet_start_level;
+       float ricochet_end_level;
 public:
        void clear();
 };
@@ -186,6 +191,10 @@
        char Name[NAME_LENGTH];
 
        SCP_vector<ArmorDamageType> DamageTypes;
+
+protected:
+       ArmorDamageType *getDamageType(int damage_type_idx);
+
 public:
        ArmorType(char* in_name);
        int flags;
@@ -197,6 +206,12 @@
        float GetShieldPiercePCT(int damage_type_idx);
        int GetPiercingType(int damage_type_idx);
        float GetPiercingLimit(int damage_type_idx);
+
+       float GetRicochetProbability(int damage_type_idx);
+       float GetRicochetDamageFactor(int damage_type_idx);
+       float GetRicochetStartLevel(int damage_type_idx);
+       float GetRicochetEndLevel(int damage_type_idx);
+
       
        //Set
        void ParseData();
Index: code/weapon/weapon.h
===================================================================
--- code/weapon/weapon.h        (revision 7936)
+++ code/weapon/weapon.h        (working copy)
@@ -214,6 +214,7 @@
        float damage_ship[MAX_WEP_DAMAGE_SLOTS];    // damage applied from each player
        int   damage_ship_id[MAX_WEP_DAMAGE_SLOTS]; // signature of the damager (corresponds to each entry in damage_ship)
 
+       float damage_scale; // a factor to influence the damage dealt by this weapon
 } weapon;
 
 
@@ -599,7 +600,7 @@
 void weapon_maybe_spew_particle(object *obj);
 
 bool weapon_armed(weapon *wp, bool hit_target);
-void weapon_hit( object * weapon_obj, object * other_obj, vec3d * hitpos, int quadrant = -1 );
+void weapon_hit( object * weapon_obj, object * other_obj, vec3d * hitpos, int quadrant = -1, bool ricichet_happened = false );
 int cmeasure_name_lookup(char *name);
 void spawn_child_weapons( object *objp );
 
Index: code/weapon/weapons.cpp
===================================================================
--- code/weapon/weapons.cpp     (revision 7936)
+++ code/weapon/weapons.cpp     (working copy)
@@ -5375,6 +5375,8 @@
                wp->damage_ship_id[i] = -1;
        }
 
+       wp->damage_scale = 1.0f;
+
        return objnum;
 }
 //     Spawn child weapons from object *objp.
@@ -5928,7 +5930,7 @@
 // This function is called when a weapon hits something (or, in the case of
 // missiles explodes for any particular reason)
 //
-void weapon_hit( object * weapon_obj, object * other_obj, vec3d * hitpos, int quadrant )
+void weapon_hit( object * weapon_obj, object * other_obj, vec3d * hitpos, int quadrant, bool ricochet_happened )
 {
        Assert(weapon_obj != NULL);
        if(weapon_obj == NULL){
@@ -6056,7 +6058,8 @@
                }
        }
 
-       weapon_obj->flags |= OF_SHOULD_BE_DEAD;
+       if (!ricochet_happened)
+               weapon_obj->flags |= OF_SHOULD_BE_DEAD;
 
        //Set shockwaves flag
        int sw_flag = SW_WEAPON;
@@ -6843,5 +6846,5 @@
                }
        }
       
-       return total_scale;
+       return total_scale * wp->damage_scale;
 }
 

 

Offline Fury

  • The Curmudgeon
  • 213
In a principle this is probably same limitation that prevents FSO from having real projectile hull piercing effects, similar to what beams have. If this is something that could be adapted for hull piercing effects as well, you could well imagine the spectacle that'd happen when you see a railgun or something piercing a ship as if it was a beam.

 

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
if you could gain access to the normal of the polygon you hit, you could deflect the shot appropriately. for scripting this requires a hook into collision response, which i think we may actually have.

build matrix from normal.
use that matrix to rotate the weapon's world velocity into the polygon's frame of reference.
flip the velocity z coordinate
unrotate the velocity back to the world frame of reference
apply to weapon.
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN

 

Offline m!m

  • 211
The normal can be accessed through the weapon:getCollisionInformation() function which will give you information about the last collision of this weapon which also contains the normal of the polygon that got hit.

 

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
the game would likely remove the weapon from the game after the collision. so you would probably just copy the weapon object in the collision hook. and then apply the transform to the velocity. do we have script level object/weapon copy?
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN

 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Yeah, it's how I would do it. When a weapon gets destroyed in a collision, spawn a new weapon object with reduced lifetime/damage.
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline Valathil

  • ...And I would have had a custom title if it wasn't for you meddling kids!
  • 29
  • Custom Title? Wizards need no Custom Title!
you dont need matrix rotation magic just do dot(-incident,normal)*normal + cross(normal,cross(normal,-incident))
┏┓╋┏┓╋╋╋╋╋╋╋╋╋┏┓
┃┃╋┃┃╋╋╋╋╋╋╋╋╋┃┃
┃┃┏┫┃┏┳━━┓┏━━┓┃┗━┳━━┳━━┳━━┓
┃┃┣┫┗┛┫┃━┫┃┏┓┃┃┏┓┃┏┓┃━━┫━━┫
┃┗┫┃┏┓┫┃━┫┃┏┓┃┃┗┛┃┗┛┣━━┣━━┃
┗━┻┻┛┗┻━━┛┗┛┗┛┗━━┻━━┻━━┻━━┛

 

Offline Ace

  • Truth of Babel
  • 212
    • http://www.lordofrigel.com
It'd be nice to tie this to the armor.tbl

So things like reflective armor for lasers would be possible.

With subsystem armor this could enable some amazing things like a beam firing onto a mirror subsystem that reflects it out, etc.
Ace
Self-plagiarism is style.
-Alfred Hitchcock

 

Offline Valathil

  • ...And I would have had a custom title if it wasn't for you meddling kids!
  • 29
  • Custom Title? Wizards need no Custom Title!
and then two ships that both have that shield and fire perpendicular at each other. bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce bounce
┏┓╋┏┓╋╋╋╋╋╋╋╋╋┏┓
┃┃╋┃┃╋╋╋╋╋╋╋╋╋┃┃
┃┃┏┫┃┏┳━━┓┏━━┓┃┗━┳━━┳━━┳━━┓
┃┃┣┫┗┛┫┃━┫┃┏┓┃┃┏┓┃┏┓┃━━┫━━┫
┃┗┫┃┏┓┫┃━┫┃┏┓┃┃┗┛┃┗┛┣━━┣━━┃
┗━┻┻┛┗┻━━┛┗┛┗┛┗━━┻━━┻━━┻━━┛

 

Offline Mongoose

  • Rikki-Tikki-Tavi
  • Global Moderator
  • 212
  • This brain for rent.
    • Steam
    • Something
SpacePONG!

 

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
you dont need matrix rotation magic just do dot(-incident,normal)*normal + cross(normal,cross(normal,-incident))

thats good to know. i just remembered what i did back in my quake c days.
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN

  

Offline Aardwolf

  • 211
  • Posts: 16,384
you dont need matrix rotation magic just do dot(-incident,normal)*normal + cross(normal,cross(normal,-incident))

what

why not just do...

incident + normal * 2.0 * dot(incident, normal)

might be - instead of +, idk

 

Offline m!m

  • 211
I'm using incident - 2  * normal * dot(normal, incident) and it works as expected

 

Offline Valathil

  • ...And I would have had a custom title if it wasn't for you meddling kids!
  • 29
  • Custom Title? Wizards need no Custom Title!
even better
┏┓╋┏┓╋╋╋╋╋╋╋╋╋┏┓
┃┃╋┃┃╋╋╋╋╋╋╋╋╋┃┃
┃┃┏┫┃┏┳━━┓┏━━┓┃┗━┳━━┳━━┳━━┓
┃┃┣┫┗┛┫┃━┫┃┏┓┃┃┏┓┃┏┓┃━━┫━━┫
┃┗┫┃┏┓┫┃━┫┃┏┓┃┃┗┛┃┗┛┣━━┣━━┃
┗━┻┻┛┗┻━━┛┗┛┗┛┗━━┻━━┻━━┻━━┛

 

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
how are you computing the incident? i dont know how to do that without a matrix op.

is it the dot of velocity and normal times 2pi?
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN

 

Offline Valathil

  • ...And I would have had a custom title if it wasn't for you meddling kids!
  • 29
  • Custom Title? Wizards need no Custom Title!
the incident is the velocity normalized , maybe - depending on the signage of the formula your using
┏┓╋┏┓╋╋╋╋╋╋╋╋╋┏┓
┃┃╋┃┃╋╋╋╋╋╋╋╋╋┃┃
┃┃┏┫┃┏┳━━┓┏━━┓┃┗━┳━━┳━━┳━━┓
┃┃┣┫┗┛┫┃━┫┃┏┓┃┃┏┓┃┏┓┃━━┫━━┫
┃┗┫┃┏┓┫┃━┫┃┏┓┃┃┗┛┃┗┛┣━━┣━━┃
┗━┻┻┛┗┻━━┛┗┛┗┛┗━━┻━━┻━━┻━━┛

 

Offline Aardwolf

  • 211
  • Posts: 16,384
Well in my/m!m's formula, velocity doesn't need to be normalized. "Incident" is just "velocity before impact".