Hard Light Productions Forums
Modding, Mission Design, and Coding => FS2 Open Coding - The Source Code Project (SCP) => Topic started by: Dragon on November 01, 2011, 06:32:58 am
-
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:
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;
}
-
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.
-
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.
-
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.
-
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?
-
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.
-
you dont need matrix rotation magic just do dot(-incident,normal)*normal + cross(normal,cross(normal,-incident))
-
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.
-
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
-
SpacePONG!
-
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.
-
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
-
I'm using incident - 2 * normal * dot(normal, incident) and it works as expected
-
even better
-
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?
-
the incident is the velocity normalized , maybe - depending on the signage of the formula your using
-
Well in my/m!m's formula, velocity doesn't need to be normalized. "Incident" is just "velocity before impact".