FS2_Open
Open source remastering of the Freespace 2 engine
collidedebrisship.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "asteroid/asteroid.h"
13 #include "debris/debris.h"
14 #include "hud/hud.h"
15 #include "io/timer.h"
16 #include "object/objcollide.h"
17 #include "object/object.h"
18 #include "parse/scripting.h"
19 #include "playerman/player.h"
20 #include "ship/ship.h"
21 #include "ship/shiphit.h"
22 
23 
25 
32 {
33  float dist;
34  object *pdebris = pair->a;
35  object *pship = pair->b;
36 
37  // Don't check collisions for warping out player
38  if ( Player->control_mode != PCM_NORMAL ) {
39  if ( pship == Player_obj )
40  return 0;
41  }
42 
43  Assert( pdebris->type == OBJ_DEBRIS );
44  Assert( pship->type == OBJ_SHIP );
45 
46  // don't check collision if it's our own debris and we are dying
47  if ( (pdebris->parent == OBJ_INDEX(pship)) && (Ships[pship->instance].flags & SF_DYING) )
48  return 0;
49 
50  dist = vm_vec_dist( &pdebris->pos, &pship->pos );
51  if ( dist < pdebris->radius + pship->radius ) {
52  int hit;
53  vec3d hitpos;
54  // create and initialize ship_ship_hit_info struct
55  collision_info_struct debris_hit_info;
56  init_collision_info_struct(&debris_hit_info);
57 
58  if ( pdebris->phys_info.mass > pship->phys_info.mass ) {
59  debris_hit_info.heavy = pdebris;
60  debris_hit_info.light = pship;
61  } else {
62  debris_hit_info.heavy = pship;
63  debris_hit_info.light = pdebris;
64  }
65 
66  hit = debris_check_collision(pdebris, pship, &hitpos, &debris_hit_info );
67  if ( hit )
68  {
69  Script_system.SetHookObjects(4, "Ship", pship, "Debris", pdebris, "Self", pship, "Object", pdebris);
70  bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEDEBRIS, pship);
71 
72  Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship);
73  bool debris_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, pdebris);
74  if(!ship_override && !debris_override)
75  {
76  float ship_damage;
77  float debris_damage;
78 
79  // do collision physics
80  calculate_ship_ship_collision_physics( &debris_hit_info );
81 
82  if ( debris_hit_info.impulse < 0.5f )
83  return 0;
84 
85  // calculate ship damage
86  ship_damage = 0.005f * debris_hit_info.impulse; // Cut collision-based damage in half.
87  // Decrease heavy damage by 2x.
88  if (ship_damage > 5.0f)
89  ship_damage = 5.0f + (ship_damage - 5.0f)/2.0f;
90 
91  // calculate debris damage and set debris damage to greater or debris and ship
92  // debris damage is needed since we can really whack some small debris with afterburner and not do
93  // significant damage to ship but the debris goes off faster than afterburner speed.
94  debris_damage = debris_hit_info.impulse/pdebris->phys_info.mass; // ie, delta velocity of debris
95  debris_damage = (debris_damage > ship_damage) ? debris_damage : ship_damage;
96 
97  // modify ship damage by debris damage multiplier
98  ship_damage *= Debris[pdebris->instance].damage_mult;
99 
100  // supercaps cap damage at 10-20% max hull ship damage
101  if (Ship_info[Ships[pship->instance].ship_info_index].flags & SIF_SUPERCAP) {
102  float cap_percent_damage = frand_range(0.1f, 0.2f);
103  ship_damage = MIN(ship_damage, cap_percent_damage * Ships[pship->instance].ship_max_hull_strength);
104  }
105 
106  // apply damage to debris
107  debris_hit( pdebris, pship, &hitpos, debris_damage); // speed => damage
108  int quadrant_num, apply_ship_damage;
109 
110  // apply damage to ship unless 1) debris is from ship
111  apply_ship_damage = !(pship->signature == pdebris->parent_sig);
112 
113  if ( debris_hit_info.heavy == pship ) {
114  quadrant_num = get_ship_quadrant_from_global(&hitpos, pship);
115  if ((pship->flags & OF_NO_SHIELDS) || !ship_is_shield_up(pship, quadrant_num) ) {
116  quadrant_num = -1;
117  }
118  if (apply_ship_damage) {
119  ship_apply_local_damage(debris_hit_info.heavy, debris_hit_info.light, &hitpos, ship_damage, quadrant_num, CREATE_SPARKS, debris_hit_info.submodel_num);
120  }
121  } else {
122  // don't draw sparks using sphere hit position
123  if (apply_ship_damage) {
124  ship_apply_local_damage(debris_hit_info.light, debris_hit_info.heavy, &hitpos, ship_damage, MISS_SHIELDS, NO_SPARKS);
125  }
126  }
127 
128  // maybe print Collision on HUD
129  if ( pship == Player_obj ) {
130  hud_start_text_flash(XSTR("Collision", 1431), 2000);
131  }
132 
133  collide_ship_ship_do_sound(&hitpos, pship, pdebris, pship==Player_obj);
134  }
135 
136  Script_system.SetHookObjects(2, "Self",pship, "Object", pdebris);
137  if(!(debris_override && !ship_override))
138  Script_system.RunCondition(CHA_COLLIDEDEBRIS, '\0', NULL, pship);
139 
140  Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship);
141  if((debris_override && !ship_override) || (!debris_override && !ship_override))
142  Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, pdebris);
143 
144  Script_system.RemHookVars(4, "Ship", "Debris", "Self", "Object");
145 
146  return 0;
147  }
148  } else { // Bounding spheres don't intersect, set timestamp for next collision check.
149  float ship_max_speed, debris_speed;
150  float time;
151  ship *shipp;
152 
153  shipp = &Ships[pship->instance];
154 
156  ship_max_speed = MAX(ship_get_max_speed(shipp), ship_get_warpout_speed(pship));
157  } else {
158  ship_max_speed = ship_get_max_speed(shipp);
159  }
160  ship_max_speed = MAX(ship_max_speed, 10.0f);
161  ship_max_speed = MAX(ship_max_speed, pship->phys_info.vel.xyz.z);
162 
163  debris_speed = pdebris->phys_info.speed;
164 
165  time = 1000.0f * (dist - pship->radius - pdebris->radius - 10.0f) / (ship_max_speed + debris_speed); // 10.0f is a safety factor
166  time -= 200.0f; // allow one frame slow frame at ~5 fps
167 
168  if (time > 100) {
169  pair->next_check_time = timestamp( fl2i(time) );
170  } else {
171  pair->next_check_time = timestamp(0); // check next time
172  }
173  }
174 
175  return 0;
176 }
177 
184 {
185  if (!Asteroids_enabled)
186  return 0;
187 
188  float dist;
189  object *pasteroid = pair->a;
190  object *pship = pair->b;
191 
192  // Don't check collisions for warping out player
193  if ( Player->control_mode != PCM_NORMAL ) {
194  if ( pship == Player_obj ) return 0;
195  }
196 
197  if (pasteroid->hull_strength < 0.0f)
198  return 0;
199 
200  Assert( pasteroid->type == OBJ_ASTEROID );
201  Assert( pship->type == OBJ_SHIP );
202 
203  dist = vm_vec_dist( &pasteroid->pos, &pship->pos );
204 
205  if ( dist < pasteroid->radius + pship->radius ) {
206  int hit;
207  vec3d hitpos;
208  // create and initialize ship_ship_hit_info struct
209  collision_info_struct asteroid_hit_info;
210  init_collision_info_struct(&asteroid_hit_info);
211 
212  if ( pasteroid->phys_info.mass > pship->phys_info.mass ) {
213  asteroid_hit_info.heavy = pasteroid;
214  asteroid_hit_info.light = pship;
215  } else {
216  asteroid_hit_info.heavy = pship;
217  asteroid_hit_info.light = pasteroid;
218  }
219 
220  hit = asteroid_check_collision(pasteroid, pship, &hitpos, &asteroid_hit_info );
221  if ( hit )
222  {
223  //Scripting support (WMC)
224  Script_system.SetHookObjects(4, "Ship", pship, "Asteroid", pasteroid, "Self",pship, "Object", pasteroid);
225  bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEASTEROID, pship);
226 
227  Script_system.SetHookObjects(2, "Self",pasteroid, "Object", pship);
228  bool asteroid_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, pasteroid);
229 
230  if(!ship_override && !asteroid_override)
231  {
232  float ship_damage;
233  float asteroid_damage;
234 
235  vec3d asteroid_vel = pasteroid->phys_info.vel;
236 
237  // do collision physics
238  calculate_ship_ship_collision_physics( &asteroid_hit_info );
239 
240  if ( asteroid_hit_info.impulse < 0.5f )
241  return 0;
242 
243  // limit damage from impulse by making max impulse (for damage) 2*m*v_max_relative
244  float max_ship_impulse = (2.0f*pship->phys_info.max_vel.xyz.z+vm_vec_mag_quick(&asteroid_vel)) *
245  (pship->phys_info.mass*pasteroid->phys_info.mass) / (pship->phys_info.mass + pasteroid->phys_info.mass);
246 
247  if (asteroid_hit_info.impulse > max_ship_impulse) {
248  ship_damage = 0.001f * max_ship_impulse;
249  } else {
250  ship_damage = 0.001f * asteroid_hit_info.impulse; // Cut collision-based damage in half.
251  }
252 
253  // Decrease heavy damage by 2x.
254  if (ship_damage > 5.0f)
255  ship_damage = 5.0f + (ship_damage - 5.0f)/2.0f;
256 
257  if ((ship_damage > 500.0f) && (ship_damage > Ships[pship->instance].ship_max_hull_strength/8.0f)) {
258  ship_damage = Ships[pship->instance].ship_max_hull_strength/8.0f;
259  nprintf(("AI", "Pinning damage to %s from asteroid at %7.3f (%7.3f percent)\n", Ships[pship->instance].ship_name, ship_damage, 100.0f * ship_damage/Ships[pship->instance].ship_max_hull_strength));
260  }
261 
262  // Decrease damage during warp out because it's annoying when your escoree dies during warp out.
264  ship_damage /= 3.0f;
265 
266  // calculate asteroid damage and set asteroid damage to greater or asteroid and ship
267  // asteroid damage is needed since we can really whack some small asteroid with afterburner and not do
268  // significant damage to ship but the asteroid goes off faster than afterburner speed.
269  asteroid_damage = asteroid_hit_info.impulse/pasteroid->phys_info.mass; // ie, delta velocity of asteroid
270  asteroid_damage = (asteroid_damage > ship_damage) ? asteroid_damage : ship_damage;
271 
272  // apply damage to asteroid
273  asteroid_hit( pasteroid, pship, &hitpos, asteroid_damage); // speed => damage
274 
275  //extern fix Missiontime;
276 
277  int quadrant_num;
278  if ( asteroid_hit_info.heavy == pship ) {
279  quadrant_num = get_ship_quadrant_from_global(&hitpos, pship);
280  if ((pship->flags & OF_NO_SHIELDS) || !ship_is_shield_up(pship, quadrant_num) ) {
281  quadrant_num = -1;
282  }
283  ship_apply_local_damage(asteroid_hit_info.heavy, asteroid_hit_info.light, &hitpos, ship_damage, quadrant_num, CREATE_SPARKS, asteroid_hit_info.submodel_num);
284  } else {
285  // don't draw sparks (using sphere hitpos)
286  ship_apply_local_damage(asteroid_hit_info.light, asteroid_hit_info.heavy, &hitpos, ship_damage, MISS_SHIELDS, NO_SPARKS);
287  }
288 
289  // maybe print Collision on HUD
290  if ( pship == Player_obj ) {
291  hud_start_text_flash(XSTR("Collision", 1431), 2000);
292  }
293 
294  collide_ship_ship_do_sound(&hitpos, pship, pasteroid, pship==Player_obj);
295  }
296 
297  Script_system.SetHookObjects(2, "Self",pship, "Object", pasteroid);
298  if(!(asteroid_override && !ship_override))
299  Script_system.RunCondition(CHA_COLLIDEASTEROID, '\0', NULL, pship);
300 
301  Script_system.SetHookObjects(2, "Self",pasteroid, "Object", pship);
302  if((asteroid_override && !ship_override) || (!asteroid_override && !ship_override))
303  Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, pasteroid);
304 
305  Script_system.RemHookVars(4, "Ship", "Asteroid", "Self", "Object");
306 
307  return 0;
308  }
309 
310  return 0;
311  } else {
312  // estimate earliest time at which pair can hit
313  float asteroid_max_speed, ship_max_speed, time;
314  ship *shipp = &Ships[pship->instance];
315 
316  asteroid_max_speed = vm_vec_mag(&pasteroid->phys_info.vel); // Asteroid... vel gets reset, not max vel.z
317  asteroid_max_speed = MAX(asteroid_max_speed, 10.0f);
318 
320  ship_max_speed = MAX(ship_get_max_speed(shipp), ship_get_warpout_speed(pship));
321  } else {
322  ship_max_speed = ship_get_max_speed(shipp);
323  }
324  ship_max_speed = MAX(ship_max_speed, 10.0f);
325  ship_max_speed = MAX(ship_max_speed, pship->phys_info.vel.xyz.z);
326 
327 
328  time = 1000.0f * (dist - pship->radius - pasteroid->radius - 10.0f) / (asteroid_max_speed + ship_max_speed); // 10.0f is a safety factor
329  time -= 200.0f; // allow one frame slow frame at ~5 fps
330 
331  if (time > 100) {
332  pair->next_check_time = timestamp( fl2i(time) );
333  } else {
334  pair->next_check_time = timestamp(0); // check next time
335  }
336  return 0;
337  }
338 }
int timestamp(int delta_ms)
Definition: timer.cpp:226
#define MIN(a, b)
Definition: pstypes.h:296
float vm_vec_mag_quick(const vec3d *v)
Definition: vecmat.cpp:371
float ship_get_max_speed(ship *shipp)
Definition: ship.cpp:17279
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
#define SIF_SUPERCAP
Definition: ship.h:901
int collide_asteroid_ship(obj_pair *pair)
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
float ship_get_warpout_speed(object *objp)
Definition: ship.cpp:17306
physics_info phys_info
Definition: object.h:157
int ship_is_beginning_warpout_speedup(object *objp)
Definition: ship.cpp:17334
int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos, collision_info_struct *asteroid_hit_info)
Definition: asteroid.cpp:918
#define PCM_NORMAL
Definition: player.h:58
Assert(pm!=NULL)
Definition: pstypes.h:88
int ai_index
Definition: ship.h:538
#define OBJ_ASTEROID
Definition: object.h:44
struct vec3d::@225::@227 xyz
vec3d max_vel
Definition: physics.h:49
GLclampf f
Definition: Glext.h:7097
#define OF_NO_SHIELDS
Definition: object.h:110
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
uint flags
Definition: ship.h:644
int collide_debris_ship(obj_pair *pair)
void calculate_ship_ship_collision_physics(collision_info_struct *ship_ship_hit_info)
int next_check_time
Definition: objcollide.h:58
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
script_state Script_system("FS2_Open Scripting")
int signature
Definition: object.h:145
void debris_hit(object *debris_obj, object *other_obj, vec3d *hitpos, float damage)
Definition: debris.cpp:751
int instance
Definition: object.h:150
object * a
Definition: objcollide.h:55
void collide_ship_ship_do_sound(vec3d *world_hit_pos, object *A, object *B, int player_involved)
float ship_max_hull_strength
Definition: ship.h:597
#define nprintf(args)
Definition: pstypes.h:239
#define CHA_COLLIDEDEBRIS
Definition: scripting.h:49
float damage_mult
Definition: debris.h:48
float speed
Definition: physics.h:79
int mode
Definition: ai.h:336
float hull_strength
Definition: object.h:160
#define OBJ_DEBRIS
Definition: object.h:37
int parent
Definition: object.h:147
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
#define AIM_WARP_OUT
Definition: ai.h:186
#define NO_SPARKS
Definition: shiphit.h:20
Definition: ship.h:534
int Asteroids_enabled
Definition: asteroid.cpp:57
debris Debris[MAX_DEBRIS_PIECES]
Definition: debris.cpp:41
#define CHA_COLLIDEASTEROID
Definition: scripting.h:50
#define MISS_SHIELDS
Definition: shiphit.h:23
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
#define OBJ_INDEX(objp)
Definition: object.h:235
#define OBJ_SHIP
Definition: object.h:32
int control_mode
Definition: player.h:134
int RunCondition(int condition, char format='\0', void *data=NULL, class object *objp=NULL, int more_data=0)
Definition: scripting.cpp:924
void SetHookObjects(int num,...)
Definition: scripting.cpp:556
vec3d vel
Definition: physics.h:77
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
#define fl2i(fl)
Definition: floating.h:33
player * Player
void hud_start_text_flash(char *txt, int t, int interval)
int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, collision_info_struct *debris_hit_info)
Definition: debris.cpp:808
#define CREATE_SPARKS
Definition: shiphit.h:21
void RemHookVars(unsigned int num,...)
Definition: scripting.cpp:754
int ship_info_index
Definition: ship.h:539
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
void ship_apply_local_damage(object *ship_objp, object *other_obj, vec3d *hitpos, float damage, int quadrant, bool create_spark, int submodel_num, vec3d *hit_normal)
Definition: shiphit.cpp:2359
object * b
Definition: objcollide.h:56
void asteroid_hit(object *pasteroid_obj, object *other_obj, vec3d *hitpos, float damage)
Definition: asteroid.cpp:1368
void init_collision_info_struct(collision_info_struct *cis)
object * Player_obj
Definition: object.cpp:56
#define SF_DYING
Definition: ship.h:447
#define MAX(a, b)
Definition: pstypes.h:299
float mass
Definition: physics.h:39
#define CHA_COLLIDESHIP
Definition: scripting.h:47
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
char type
Definition: object.h:146
bool IsConditionOverride(int action, object *objp=NULL)
Definition: scripting.cpp:938
int parent_sig
Definition: object.h:148
char ship_name[NAME_LENGTH]
Definition: ship.h:604
int ship_is_shield_up(object *obj, int quadrant)
Definition: shield.cpp:964
int get_ship_quadrant_from_global(vec3d *global_pos, object *objp)