FS2_Open
Open source remastering of the Freespace 2 engine
collideshipship.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 "debugconsole/console.h"
15 #include "freespace2/freespace.h"
17 #include "gamesnd/gamesnd.h"
18 #include "hud/hudmessage.h"
19 #include "hud/hudshield.h"
20 #include "io/joy_ff.h"
21 #include "io/timer.h"
22 #include "object/objcollide.h"
23 #include "object/object.h"
24 #include "object/objectdock.h"
25 #include "object/objectshield.h"
26 #include "parse/scripting.h"
27 #include "playerman/player.h"
28 #include "render/3d.h" // needed for View_position, which is used when playing 3d sound
29 #include "ship/ship.h"
30 #include "ship/shiphit.h"
31 
32 
33 #define COLLIDE_DEBUG
34 #undef COLLIDE_DEBUG
35 
36 // GENERAL COLLISIONS FUNCTIONS
37 // calculates the inverse moment of inertia matrix in world coordinates
38 void get_I_inv (matrix* I_inv, matrix* I_inv_body, matrix* orient);
39 
40 // calculate the physics of extended two body collisions
42 
43 int ship_hit_shield(object *obj, mc_info *mc, collision_info_struct *sshs);
44 void collect_ship_ship_physics_info(object *heavier_obj, object *lighter_obj, mc_info *mc_info_obj, collision_info_struct *ship_ship_hit_info);
45 
46 #ifndef NDEBUG
47 static int Collide_friendly = 1;
48 DCF_BOOL( collide_friendly, Collide_friendly )
49 #endif
50 
51 static int Player_collide_sound, AI_collide_sound;
52 static int Player_collide_shield_sound, AI_collide_shield_sound;
53 
57 int ships_are_docking(object *objp1, object *objp2)
58 {
59  ai_info *aip1, *aip2;
60  ship *shipp1, *shipp2;
61 
62  shipp1 = &Ships[objp1->instance];
63  shipp2 = &Ships[objp2->instance];
64 
65  aip1 = &Ai_info[shipp1->ai_index];
66  aip2 = &Ai_info[shipp2->ai_index];
67 
68  if (dock_check_find_direct_docked_object(objp1, objp2)) {
69  return 1;
70  }
71 
72  if (aip1->mode == AIM_DOCK) {
73  if (aip1->goal_objnum == OBJ_INDEX(objp2)){
74  return 1;
75  }
76  }
77 
78  if (aip2->mode == AIM_DOCK) {
79  if (aip2->goal_objnum == OBJ_INDEX(objp1)){
80  return 1;
81  }
82  }
83 
84  return 0;
85 
86 }
87 
91 int bay_emerge_or_depart(object *heavy_objp, object *light_objp)
92 {
93  if (light_objp->type != OBJ_SHIP)
94  return 0;
95 
96  ai_info *aip = &Ai_info[Ships[light_objp->instance].ai_index];
97 
98  // the player shouldn't be allowed to fly through the ship just cause the rest of their wing can
99  if ((Player_obj == light_objp) && !Player_use_ai){
100  return 0;
101  }
102 
103  if ((aip->mode == AIM_BAY_EMERGE) || (aip->mode == AIM_BAY_DEPART)) {
104  if (aip->goal_objnum == OBJ_INDEX(heavy_objp))
105  return 1;
106  }
107 
108  return 0;
109 }
110 
111 int ship_ship_check_collision(collision_info_struct *ship_ship_hit_info, vec3d *hitpos)
112 {
113  object *heavy_obj = ship_ship_hit_info->heavy;
114  object *light_obj = ship_ship_hit_info->light;
115  int player_involved; // flag to indicate that A or B is the Player_obj
116 
117  Assert( heavy_obj->type == OBJ_SHIP );
118  Assert( light_obj->type == OBJ_SHIP );
119 
120  ship *heavy_shipp = &Ships[heavy_obj->instance];
121  ship *light_shipp = &Ships[light_obj->instance];
122 
123  ship_info *heavy_sip = &Ship_info[heavy_shipp->ship_info_index];
124  ship_info *light_sip = &Ship_info[light_shipp->ship_info_index];
125 
126  // AL 12-4-97: we use the player_involved flag to ensure collisions are always
127  // done with the player, regardless of team.
128  if ( heavy_obj == Player_obj || light_obj == Player_obj ) {
129  player_involved = 1;
130  } else {
131  player_involved = 0;
132  }
133 
134  // Make ships that are warping in not get collision detection done
135  if ( heavy_shipp->flags & SF_ARRIVING_STAGE_1 ) {
136  return 0;
137  }
138 
139  // Don't do collision detection for docking ships, since they will always collide while trying to dock
140  if ( ships_are_docking(heavy_obj, light_obj) ) {
141  return 0;
142  }
143 
144  // If light_obj emerging from or departing to dock bay in heavy_obj, no collision detection.
145  if (bay_emerge_or_depart(heavy_obj, light_obj)) {
146  return 0;
147  }
148 
149  // Ships which are dying should not do collision detection.
150  // Also, this is the only clean way I could figure to get ships to not do damage to each other for one frame
151  // when they are docked and departing. Due to sequencing, they would not show up as docked, yet they
152  // would still come through here, so they would harm each other, if on opposing teams. -- MK, 2/2/98
153  if ((heavy_obj->flags & OF_SHOULD_BE_DEAD) || (light_obj->flags & OF_SHOULD_BE_DEAD)) {
154  return 0;
155  }
156 
157 #ifndef NDEBUG
158  // Don't do collision detection on a pair of ships on the same team.
159  // Change this someday, but for now, it's a problem.
160  if ( !Collide_friendly ) { // Collide_friendly is a global value changed via debug console
161  if ( (!player_involved) && (heavy_shipp->team == light_shipp->team) ) {
162  return 0;
163  }
164  }
165 #endif
166 
167  // Apparently we're doing same team collisions.
168  // But, if both are offscreen, ignore the collision
169  if (heavy_shipp->team == light_shipp->team) {
170  if ( (!(heavy_obj->flags & OF_WAS_RENDERED) && !(light_obj->flags & OF_WAS_RENDERED)) ) {
171  return 0;
172  }
173  }
174 
175  // Set up model_collide info
176  mc_info mc;
177  mc_info_init(&mc);
178 
179  // Do in heavy object RF
180  mc.model_num = heavy_sip->model_num; // Fill in the model to check
181  mc.model_instance_num = heavy_shipp->model_instance_num;
182  mc.orient = &heavy_obj->orient; // The object's orient
183 
184  vec3d zero, p0, p1;
185  vm_vec_zero(&zero); // we need the physical vector and can not set its value to zero
186  vm_vec_sub(&p0, &light_obj->last_pos, &heavy_obj->last_pos);
187  vm_vec_sub(&p1, &light_obj->pos, &heavy_obj->pos);
188 
189  // find the light object's position in the heavy object's reference frame at last frame and also in this frame.
190  vec3d p0_temp, p0_rotated;
191 
192  // Collision detection from rotation enabled if at max rotaional velocity and 5fps, rotation is less than PI/2
193  // This should account for all ships
194  if ( (vm_vec_mag_squared( &heavy_obj->phys_info.max_rotvel ) * .04) < (PI*PI/4) ) {
195  // collide_rotate calculate (1) start position and (2) relative velocity
196  ship_ship_hit_info->collide_rotate = 1;
197  vm_vec_rotate(&p0_temp, &p0, &heavy_obj->last_orient);
198  vm_vec_unrotate(&p0_rotated, &p0_temp, &heavy_obj->orient);
199  mc.p0 = &p0_rotated; // Point 1 of ray to check
200  vm_vec_sub(&ship_ship_hit_info->light_rel_vel, &p1, &p0_rotated);
201  vm_vec_scale(&ship_ship_hit_info->light_rel_vel, 1/flFrametime);
202  }
203  // should be no ships that can rotate this fast
204  else {
205 #ifndef NDEBUG
206  static bool Warned_about_fast_rotational_collisions = false;
207  if (!Warned_about_fast_rotational_collisions) {
208  Warning(LOCATION, "Ship '%s' rotates too quickly! Rotational collision detection has been skipped.", heavy_sip->name);
209  Warned_about_fast_rotational_collisions = true;
210  }
211 #endif
212  ship_ship_hit_info->collide_rotate = 0;
213  mc.p0 = &p0; // Point 1 of ray to check
214  vm_vec_sub(&ship_ship_hit_info->light_rel_vel, &light_obj->phys_info.vel, &heavy_obj->phys_info.vel);
215  }
216 
217  // Set up collision info
218  mc.pos = &zero; // The object's position
219  mc.p1 = &p1; // Point 2 of ray to check
220  mc.radius = model_get_core_radius(light_sip->model_num);
221  mc.flags = (MC_CHECK_MODEL | MC_CHECK_SPHERELINE); // flags
222 
223  // Only check invisible face polygons for ship:ship of different teams.
224  if ( !(heavy_shipp->flags2 & SF2_DONT_COLLIDE_INVIS) ) {
225  if ((heavy_obj->flags & OF_PLAYER_SHIP) || (light_obj->flags & OF_PLAYER_SHIP) || (heavy_shipp->team != light_shipp->team) ) {
227  }
228  }
229 
230  // copy important data
231  int copy_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
232  vec3d copy_p0, copy_p1;
233  copy_p0 = *mc.p0;
234  copy_p1 = *mc.p1;
235 
236  // first test against the sphere - if this fails then don't do any submodel tests
238 
239  SCP_vector<int> submodel_vector;
240  int valid_hit_occured = 0;
241  polymodel *pm_light;
242  polymodel_instance *pmi;
243 
244  pm_light = model_get(Ship_info[light_shipp->ship_info_index].model_num);
245 
246  if(pm_light->submodel[pm_light->detail[0]].no_collisions) {
247  return 0;
248  }
249 
250  if (model_collide(&mc)) {
251 
252  // Set earliest hit time
253  ship_ship_hit_info->hit_time = FLT_MAX;
254 
255  // Do collision the cool new way
256  if ( ship_ship_hit_info->collide_rotate ) {
258 
259  model_get_rotating_submodel_list(&submodel_vector, heavy_obj);
260 
261  pmi = model_get_instance(heavy_shipp->model_instance_num);
262 
263  // turn off all rotating submodels and test for collision
264  for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
265  pmi->submodel[*smv].collision_checked = true;
266  }
267 
268  // reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
269  mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
270 
271  if (heavy_sip->collision_lod > -1) {
272  mc.lod = heavy_sip->collision_lod;
273  }
274 
275  // check each submodel in turn
276  for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
277  // turn on submodel for collision test
278  pmi->submodel[*smv].collision_checked = false;
279 
280  if (pmi->submodel[*smv].blown_off)
281  {
282  pmi->submodel[*smv].collision_checked = true;
283  continue;
284  }
285 
286  // set angles for last frame
287  angles copy_angles = pmi->submodel[*smv].angs;
288 
289  // find the start and end positions of the sphere in submodel RF
290  pmi->submodel[*smv].angs = pmi->submodel[*smv].prev_angs;
291  world_find_model_instance_point(&p0, &light_obj->last_pos, pmi, *smv, &heavy_obj->last_orient, &heavy_obj->last_pos);
292 
293  pmi->submodel[*smv].angs = copy_angles;
294  world_find_model_instance_point(&p1, &light_obj->pos, pmi, *smv, &heavy_obj->orient, &heavy_obj->pos);
295 
296  mc.p0 = &p0;
297  mc.p1 = &p1;
298 
300  mc.submodel_num = *smv;
301 
302  if ( model_collide(&mc) ) {
303  if (mc.hit_dist < ship_ship_hit_info->hit_time ) {
304  valid_hit_occured = 1;
305 
306  // set up ship_ship_hit_info common
307  set_hit_struct_info(ship_ship_hit_info, &mc, SUBMODEL_ROT_HIT);
308  model_instance_find_world_point(&ship_ship_hit_info->hit_pos, &mc.hit_point, mc.model_instance_num, mc.hit_submodel, &heavy_obj->orient, &zero);
309 
310  // set up ship_ship_hit_info for rotating submodel
311  if (ship_ship_hit_info->edge_hit == 0) {
312  model_instance_find_obj_dir(&ship_ship_hit_info->collision_normal, &mc.hit_normal, mc.model_instance_num, mc.hit_submodel, &heavy_obj->orient);
313  }
314 
315  // find position in submodel RF of light object at collison
316  vec3d int_light_pos, diff;
317  vm_vec_sub(&diff, mc.p1, mc.p0);
318  vm_vec_scale_add(&int_light_pos, mc.p0, &diff, mc.hit_dist);
319  model_instance_find_world_point(&ship_ship_hit_info->light_collision_cm_pos, &int_light_pos, mc.model_instance_num, mc.hit_submodel, &heavy_obj->orient, &zero);
320  }
321  }
322  }
323 
324  }
325 
326  // Recover and do usual ship_ship collision, but without rotating submodels
327  mc.flags = copy_flags;
328  *mc.p0 = copy_p0;
329  *mc.p1 = copy_p1;
330  mc.orient = &heavy_obj->orient;
331 
332  // usual ship_ship collision test
333  if ( model_collide(&mc) ) {
334  // check if this is the earliest hit
335  if (mc.hit_dist < ship_ship_hit_info->hit_time) {
336  valid_hit_occured = 1;
337 
338  set_hit_struct_info(ship_ship_hit_info, &mc, SUBMODEL_NO_ROT_HIT);
339 
340  // get collision normal if not edge hit
341  if (ship_ship_hit_info->edge_hit == 0) {
342  model_instance_find_obj_dir(&ship_ship_hit_info->collision_normal, &mc.hit_normal, mc.model_instance_num, mc.hit_submodel, &heavy_obj->orient);
343  }
344 
345  // find position in submodel RF of light object at collison
346  vec3d diff;
347  vm_vec_sub(&diff, mc.p1, mc.p0);
348  vm_vec_scale_add(&ship_ship_hit_info->light_collision_cm_pos, mc.p0, &diff, mc.hit_dist);
349  }
350  }
351  }
352 
353  if (valid_hit_occured) {
354 
355  // Collision debug stuff
356 #ifndef NDEBUG
357  object *collide_obj = NULL;
358  if (heavy_obj == Player_obj) {
359  collide_obj = light_obj;
360  } else if (light_obj == Player_obj) {
361  collide_obj = heavy_obj;
362  }
363  if ((collide_obj != NULL) && (Ship_info[Ships[collide_obj->instance].ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER))) {
364  char *submode_string = "";
365  ai_info *aip;
366 
367  extern char *Mode_text[];
368  aip = &Ai_info[Ships[collide_obj->instance].ai_index];
369 
370  if (aip->mode == AIM_CHASE)
371  submode_string = Submode_text[aip->submode];
372 
373  nprintf(("AI", "Player collided with ship %s, AI mode = %s, submode = %s\n", Ships[collide_obj->instance].ship_name, Mode_text[aip->mode], submode_string));
374  }
375 #endif
376 
377  // Update ai to deal with collisions
378  if (heavy_obj-Objects == Ai_info[light_shipp->ai_index].target_objnum) {
380  }
381  if (light_obj-Objects == Ai_info[heavy_shipp->ai_index].target_objnum) {
383  }
384 
385  // SET PHYSICS PARAMETERS
386  // already have (hitpos - heavy) and light_cm_pos
387  // get heavy cm pos - already have light_cm_pos
388  ship_ship_hit_info->heavy_collision_cm_pos = zero;
389 
390  // get r_heavy and r_light
391  ship_ship_hit_info->r_heavy = ship_ship_hit_info->hit_pos;
392  vm_vec_sub(&ship_ship_hit_info->r_light, &ship_ship_hit_info->hit_pos, &ship_ship_hit_info->light_collision_cm_pos);
393 
394  // set normal for edge hit
395  if ( ship_ship_hit_info->edge_hit ) {
396  vm_vec_copy_normalize(&ship_ship_hit_info->collision_normal, &ship_ship_hit_info->r_light);
397  vm_vec_negate(&ship_ship_hit_info->collision_normal);
398  }
399 
400  // get world hitpos
401  vm_vec_add(hitpos, &ship_ship_hit_info->heavy->pos, &ship_ship_hit_info->r_heavy);
402 
403  // do physics
404  calculate_ship_ship_collision_physics(ship_ship_hit_info);
405 
406  // Provide some separation for the case of same team
407  if (heavy_shipp->team == light_shipp->team) {
408  // If a couple of small ships, just move them apart.
409 
410  if ((heavy_sip->flags & SIF_SMALL_SHIP) && (light_sip->flags & SIF_SMALL_SHIP)) {
411  if ((heavy_obj->flags & OF_PLAYER_SHIP) || (light_obj->flags & OF_PLAYER_SHIP)) {
412  vec3d h_to_l_vec;
413  vec3d rel_vel_h;
414  vec3d perp_rel_vel;
415 
416  vm_vec_sub(&h_to_l_vec, &heavy_obj->pos, &light_obj->pos);
417  vm_vec_sub(&rel_vel_h, &heavy_obj->phys_info.vel, &light_obj->phys_info.vel);
418  float mass_sum = light_obj->phys_info.mass + heavy_obj->phys_info.mass;
419 
420  // get comp of rel_vel perp to h_to_l_vec;
421  float mag = vm_vec_dot(&h_to_l_vec, &rel_vel_h) / vm_vec_mag_squared(&h_to_l_vec);
422  vm_vec_scale_add(&perp_rel_vel, &rel_vel_h, &h_to_l_vec, -mag);
423  vm_vec_normalize(&perp_rel_vel);
424 
425  vm_vec_scale_add2(&heavy_obj->phys_info.vel, &perp_rel_vel,
426  heavy_sip->collision_physics.both_small_bounce * light_obj->phys_info.mass / mass_sum);
427  vm_vec_scale_add2(&light_obj->phys_info.vel, &perp_rel_vel,
428  -(light_sip->collision_physics.both_small_bounce) * heavy_obj->phys_info.mass / mass_sum);
429 
430  vm_vec_rotate( &heavy_obj->phys_info.prev_ramp_vel, &heavy_obj->phys_info.vel, &heavy_obj->orient );
431  vm_vec_rotate( &light_obj->phys_info.prev_ramp_vel, &light_obj->phys_info.vel, &light_obj->orient );
432  }
433  } else {
434  // add extra velocity to separate the two objects, backing up the direction we came in.
435  // TODO: add effect of velocity from rotating submodel
436  float rel_vel = vm_vec_mag_quick( &ship_ship_hit_info->light_rel_vel);
437  if (rel_vel < 1) {
438  rel_vel = 1.0f;
439  }
440  float mass_sum = heavy_obj->phys_info.mass + light_obj->phys_info.mass;
441  vm_vec_scale_add2( &heavy_obj->phys_info.vel, &ship_ship_hit_info->light_rel_vel,
442  heavy_sip->collision_physics.bounce*light_obj->phys_info.mass/(mass_sum*rel_vel) );
443  vm_vec_rotate( &heavy_obj->phys_info.prev_ramp_vel, &heavy_obj->phys_info.vel, &heavy_obj->orient );
444  vm_vec_scale_add2( &light_obj->phys_info.vel, &ship_ship_hit_info->light_rel_vel,
445  -(light_sip->collision_physics.bounce)*heavy_obj->phys_info.mass/(mass_sum*rel_vel) );
446  vm_vec_rotate( &light_obj->phys_info.prev_ramp_vel, &light_obj->phys_info.vel, &light_obj->orient );
447  }
448  }
449  }
450 
451 
452  return valid_hit_occured;
453 }
454 
460 int check_special_cruiser_asteroid_collision(object *heavy, object *lighter, float *cruiser_mass, int *cruiser_light)
461 {
462  int asteroid_type;
463 
464  if (heavy->type == OBJ_ASTEROID) {
465  Assert(lighter->type == OBJ_SHIP);
466  if (Ship_info[Ships[lighter->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) {
467 
468  asteroid_type = Asteroids[heavy->instance].asteroid_type;
469  if (asteroid_type == 0) {
470  *cruiser_mass = 10.0f * heavy->phys_info.mass;
471  } else if (asteroid_type == 1) {
472  *cruiser_mass = 4.0f * heavy->phys_info.mass;
473  } else {
474  *cruiser_mass = 2.0f * heavy->phys_info.mass;
475  }
476 
477  if (*cruiser_mass > lighter->phys_info.mass) {
478  *cruiser_light = 1;
479  return 1;
480  }
481  }
482  } else if (lighter->type == OBJ_ASTEROID) {
483  Assert(heavy->type == OBJ_SHIP);
484  if (Ship_info[Ships[heavy->instance].ship_info_index].flags & SIF_BIG_SHIP) {
485 
486  asteroid_type = Asteroids[lighter->instance].asteroid_type;
487  if (asteroid_type == 0) {
488  *cruiser_mass = 10.0f * lighter->phys_info.mass;
489  } else if (asteroid_type == 1) {
490  *cruiser_mass = 4.0f * lighter->phys_info.mass;
491  } else {
492  *cruiser_mass = 2.0f * lighter->phys_info.mass;
493  }
494 
495  if (*cruiser_mass > heavy->phys_info.mass) {
496  *cruiser_light = 0;
497  return 1;
498  }
499  }
500  }
501  return 0;
502 }
503 
507 bool check_subsystem_landing_allowed(ship_info *heavy_sip, collision_info_struct *ship_ship_hit_info) {
508  if (!(heavy_sip->flags2 & SIF2_ALLOW_LANDINGS))
509  return false;
510 
511  for (int i = 0; i < heavy_sip->n_subsystems; i++) {
512  if (heavy_sip->subsystems[i].flags & MSS_FLAG_ALLOW_LANDING &&
513  heavy_sip->subsystems[i].subobj_num == ship_ship_hit_info->submodel_num)
514  {
515  return true;
516  }
517  }
518  return false;
519 }
520 
521 // ------------------------------------------------------------------------------------------------
522 // input: ship_ship_hit => structure containing ship_ship hit info
523 // (includes) A, B => objects colliding
524 // r_A, r_B => position to collision from center of mass
525 // collision_normal => collision_normal (outward from B)
526 //
527 // output: velocity, angular velocity, impulse
528 //
529 // ------------------------------------------------------------------------------------------------
530 //
531 // calculates correct physics response to collision between two objects given
532 // masses, moments of inertia, velocities, angular velocities,
533 // relative collision positions, and the impulse direction
534 //
536 {
537  // important parameters passed thru ship_ship_or_debris_hit
538  // calculate the whack applied to each ship from collision
539 
540  // make local copies of hit_struct parameters
541  object *heavy = ship_ship_hit_info->heavy;
542  object *lighter = ship_ship_hit_info->light;
543 
544  // gurgh... this includes asteroids and debris too
545  Assert(heavy->type == OBJ_SHIP || heavy->type == OBJ_ASTEROID || heavy->type == OBJ_DEBRIS);
546  Assert(lighter->type == OBJ_SHIP || lighter->type == OBJ_ASTEROID || lighter->type == OBJ_DEBRIS);
547 
548  ship_info *light_sip = (lighter->type == OBJ_SHIP) ? &Ship_info[Ships[lighter->instance].ship_info_index] : NULL;
549  ship_info *heavy_sip = (heavy->type == OBJ_SHIP) ? &Ship_info[Ships[heavy->instance].ship_info_index] : NULL;
550 
551  // make cruiser/asteroid collision softer on cruisers.
552  int special_cruiser_asteroid_collision;
553  int cruiser_light = 0;
554  float cruiser_mass = 0.0f, copy_mass = 0.0f;
555  special_cruiser_asteroid_collision = check_special_cruiser_asteroid_collision(heavy, lighter, &cruiser_mass, &cruiser_light);
556 
557  if (special_cruiser_asteroid_collision) {
558  if (cruiser_light) {
559  Assert(lighter->phys_info.mass < cruiser_mass);
560  copy_mass = lighter->phys_info.mass;
561  lighter->phys_info.mass = cruiser_mass;
562  } else {
563  Assert(heavy->phys_info.mass < cruiser_mass);
564  copy_mass = heavy->phys_info.mass;
565  heavy->phys_info.mass = cruiser_mass;
566  }
567  }
568 
569  float coeff_restitution; // parameter controls amount of bounce
570  float v_rel_normal_m; // relative collision velocity in the direction of the collision normal
571  vec3d v_rel_parallel_m; // normalized v_rel (Va-Vb) projected onto collision surface
572  vec3d world_rotvel_heavy_m, world_rotvel_light_m, vel_from_rotvel_heavy_m, vel_from_rotvel_light_m, v_rel_m, vel_heavy_m, vel_light_m;
573 
574  coeff_restitution = 0.1f; // relative velocity wrt normal is zero after the collision ( range 0-1 )
575 
576  // find velocity of each obj at collision point
577 
578  // heavy object is in cm reference frame so we don't get a v_heavy term.
579  if ( ship_ship_hit_info->collide_rotate ) {
580  // if we have collisions from rotation, the effective velocity from rotation of the large body is alreay taken account
581  vm_vec_zero( &vel_heavy_m );
582  } else {
583  // take account the effective velocity from rotation
584  vm_vec_unrotate(&world_rotvel_heavy_m, &heavy->phys_info.rotvel, &heavy->orient); // heavy's world rotvel before collision
585  vm_vec_cross(&vel_from_rotvel_heavy_m, &world_rotvel_heavy_m, &ship_ship_hit_info->r_heavy); // heavy's velocity from rotvel before collision
586  vel_heavy_m = vel_from_rotvel_heavy_m;
587  }
588 
589  // if collision from rotating submodel of heavy obj, add in vel from rotvel of submodel
590  vec3d local_vel_from_submodel;
591 
592  if (ship_ship_hit_info->submodel_rot_hit == 1) {
593  polymodel *pm;
594  polymodel_instance *pmi = NULL;
595  int model_instance_num = -1;
596 
597  if (heavy->type == OBJ_SHIP) {
598  pm = model_get(heavy_sip->model_num);
599  model_instance_num = Ships[heavy->instance].model_instance_num;
600  pmi = model_get_instance(model_instance_num);
601  } else if (heavy->type == OBJ_ASTEROID) {
603  model_instance_num = Asteroids[heavy->instance].model_instance_num;
604  pmi = model_get_instance(model_instance_num);
605  } else if (heavy->type == OBJ_DEBRIS) {
606  pm = model_get(Debris[heavy->instance].model_num);
607  } else {
608  // we should have caught this already
609  Int3();
610  pm = NULL;
611  }
612 
613  if ( pmi != NULL && pmi->submodel[ship_ship_hit_info->submodel_num].sii != NULL ) {
614  // set point on axis of rotating submodel if not already set.
615  if ( !pmi->submodel[ship_ship_hit_info->submodel_num].sii->axis_set ) {
616  model_init_submodel_axis_pt(pmi->submodel[ship_ship_hit_info->submodel_num].sii, pm->id, ship_ship_hit_info->submodel_num);
617  }
618 
619  vec3d omega, axis, r_rot;
620  if ( pm->submodel[ship_ship_hit_info->submodel_num].movement_axis == MOVEMENT_AXIS_X ) {
621  axis = vmd_x_vector;
622  } else if ( pm->submodel[ship_ship_hit_info->submodel_num].movement_axis == MOVEMENT_AXIS_Y ) {
623  axis = vmd_y_vector;
624  } else if ( pm->submodel[ship_ship_hit_info->submodel_num].movement_axis == MOVEMENT_AXIS_Z ) {
625  axis = vmd_z_vector;
626  } else {
627  // must be one of these axes or submodel_rot_hit is incorrectly set
628  Int3();
629  }
630 
631  // get world rotational velocity of rotating submodel
632  model_instance_find_obj_dir(&omega, &axis, model_instance_num, ship_ship_hit_info->submodel_num, &heavy->orient);
633 
634  vm_vec_scale(&omega, pmi->submodel[ship_ship_hit_info->submodel_num].sii->cur_turn_rate);
635 
636  // world coords for r_rot
637  vec3d temp;
638  vm_vec_unrotate(&temp, &pmi->submodel[ship_ship_hit_info->submodel_num].sii->pt_on_axis, &heavy->orient);
639  vm_vec_sub(&r_rot, &ship_ship_hit_info->hit_pos, &temp);
640 
641  vm_vec_cross(&local_vel_from_submodel, &omega, &r_rot);
642  } else {
643  vm_vec_zero(&local_vel_from_submodel);
644  }
645  } else {
646  // didn't collide with submodel
647  vm_vec_zero(&local_vel_from_submodel);
648  }
649 
650  vm_vec_unrotate(&world_rotvel_light_m, &lighter->phys_info.rotvel, &lighter->orient); // light's world rotvel before collision
651  vm_vec_cross(&vel_from_rotvel_light_m, &world_rotvel_light_m, &ship_ship_hit_info->r_light); // light's velocity from rotvel before collision
652  vm_vec_add(&vel_light_m, &vel_from_rotvel_light_m, &ship_ship_hit_info->light_rel_vel);
653  vm_vec_sub(&v_rel_m, &vel_light_m, &vel_heavy_m);
654 
655  // Add in effect of rotating submodel
656  vm_vec_sub2(&v_rel_m, &local_vel_from_submodel);
657 
658  v_rel_normal_m = vm_vec_dot(&v_rel_m, &ship_ship_hit_info->collision_normal);// if less than zero, colliding contact taking place
659  // (v_slow - v_fast) dot (n_fast)
660 
661  if (v_rel_normal_m > 0) {
662  // This can happen in 2 situations.
663  // (1) The rotational velocity is large enough to cause ships to miss. In this case, there would most likely
664  // have been a collision, but at a later time, so reset v_rel_normal_m
665 
666  // (2) We could also have just gotten a slightly incorrect hitpos, where r dot v_rel is nearly zero.
667  // In this case, we know there was a collision, but slight collision and the normal is correct, so reset v_rel_normal_m
668  // need a normal direction. We can just take the -v_light normalized. v_rel_normal_m = -v_rel_normal_m;
669 
670  nprintf(("Physics", "Frame %i reset v_rel_normal_m %f Edge %i\n", Framecount, v_rel_normal_m, ship_ship_hit_info->edge_hit));
671  v_rel_normal_m = -v_rel_normal_m;
672  }
673 
674  //Maybe treat the current collision as a landing
675  //Init values just to be safe
676  vec3d light_local_vel(ship_ship_hit_info->light_rel_vel);
677  float light_uvec_dot_norm = 0.0f;
678  float light_fvec_dot_norm = 0.0f;
679  float light_rvec_dot_norm = 0.0f;
680  bool subsys_landing_allowed = lighter->type == OBJ_SHIP && heavy->type == OBJ_SHIP && check_subsystem_landing_allowed(heavy_sip, ship_ship_hit_info);
681  if (subsys_landing_allowed) {
682  vm_vec_rotate(&light_local_vel, &ship_ship_hit_info->light_rel_vel, &lighter->orient);
683  light_uvec_dot_norm = vm_vec_dot(&ship_ship_hit_info->collision_normal, &lighter->orient.vec.uvec);
684  light_fvec_dot_norm = vm_vec_dot(&ship_ship_hit_info->collision_normal, &lighter->orient.vec.fvec);
685  light_rvec_dot_norm = vm_vec_dot(&ship_ship_hit_info->collision_normal, &lighter->orient.vec.rvec);
686  }
687  if (subsys_landing_allowed &&
688  light_local_vel.xyz.z < light_sip->collision_physics.landing_max_z &&
689  light_local_vel.xyz.z > light_sip->collision_physics.landing_min_z &&
690  light_local_vel.xyz.y > light_sip->collision_physics.landing_min_y &&
691  fl_abs(light_local_vel.xyz.x) < light_sip->collision_physics.landing_max_x &&
692  light_uvec_dot_norm > 0 &&
693  light_fvec_dot_norm < light_sip->collision_physics.landing_max_angle &&
694  light_fvec_dot_norm > light_sip->collision_physics.landing_min_angle &&
695  fl_abs(light_rvec_dot_norm) < light_sip->collision_physics.landing_max_rot_angle)
696  {
697  ship_ship_hit_info->is_landing = true;
698  }
699 
700  vec3d rotational_impulse_heavy, rotational_impulse_light, delta_rotvel_heavy, delta_rotvel_light;
701  vec3d delta_vel_from_delta_rotvel_heavy, delta_vel_from_delta_rotvel_light, impulse;
702  float impulse_mag, heavy_denom, light_denom;
703  matrix heavy_I_inv, light_I_inv;
704 
705  // include a frictional collision impulse F parallel to the collision plane
706  // F = I * sin (collision_normal, normalized v_rel_m) [sin is ratio of v_rel_parallel_m to v_rel_m]
707  // note: (-) sign is needed to account for the direction of the v_rel_parallel_m
708  float collision_speed_parallel;
709  float parallel_mag;
710  impulse = ship_ship_hit_info->collision_normal;
711  vm_vec_projection_onto_plane(&v_rel_parallel_m, &v_rel_m, &ship_ship_hit_info->collision_normal);
712  collision_speed_parallel = vm_vec_normalize_safe(&v_rel_parallel_m);
713  float friction = (lighter->type == OBJ_SHIP) ? light_sip->collision_physics.friction : COLLISION_FRICTION_FACTOR;
714  parallel_mag = float(-friction) * collision_speed_parallel / vm_vec_mag(&v_rel_m);
715  vm_vec_scale_add2(&impulse, &v_rel_parallel_m, parallel_mag);
716 
717  // calculate the effect on the velocity of the collison point per unit impulse
718  // first find the effect thru change in rotvel
719  // then find the change in the cm vel
720  if (heavy == Player_obj) {
721  vm_vec_zero( &delta_rotvel_heavy );
722  heavy_denom = 1.0f / heavy->phys_info.mass;
723  } else {
724  vm_vec_cross(&rotational_impulse_heavy, &ship_ship_hit_info->r_heavy, &impulse);
725  get_I_inv(&heavy_I_inv, &heavy->phys_info.I_body_inv, &heavy->orient);
726  vm_vec_rotate(&delta_rotvel_heavy, &rotational_impulse_heavy, &heavy_I_inv);
727  float rotation_factor = (heavy->type == OBJ_SHIP) ? heavy_sip->collision_physics.rotation_factor : COLLISION_ROTATION_FACTOR;
728  vm_vec_scale(&delta_rotvel_heavy, rotation_factor); // hack decrease rotation (delta_rotvel)
729  vm_vec_cross(&delta_vel_from_delta_rotvel_heavy, &delta_rotvel_heavy , &ship_ship_hit_info->r_heavy);
730  heavy_denom = vm_vec_dot(&delta_vel_from_delta_rotvel_heavy, &ship_ship_hit_info->collision_normal);
731  if (heavy_denom < 0) {
732  // sanity check
733  heavy_denom = 0.0f;
734  }
735  heavy_denom += 1.0f / heavy->phys_info.mass;
736  }
737 
738  // calculate the effect on the velocity of the collison point per unit impulse
739  // first find the effect thru change in rotvel
740  // then find the change in the cm vel
741  // SUSHI: If on a landing surface, use the same shortcut the player gets
742  // This is a bit of a hack, but gets around some nasty unpredictable collision behavior
743  // when trying to do AI landings for certain ships
744  if (lighter == Player_obj || subsys_landing_allowed) {
745  vm_vec_zero( &delta_rotvel_light );
746  light_denom = 1.0f / lighter->phys_info.mass;
747  } else {
748  vm_vec_cross(&rotational_impulse_light, &ship_ship_hit_info->r_light, &impulse);
749  get_I_inv(&light_I_inv, &lighter->phys_info.I_body_inv, &lighter->orient);
750  vm_vec_rotate(&delta_rotvel_light, &rotational_impulse_light, &light_I_inv);
751  float rotation_factor = (lighter->type == OBJ_SHIP) ? light_sip->collision_physics.rotation_factor : COLLISION_ROTATION_FACTOR;
752  vm_vec_scale(&delta_rotvel_light, rotation_factor); // hack decrease rotation (delta_rotvel)
753  vm_vec_cross(&delta_vel_from_delta_rotvel_light, &delta_rotvel_light, &ship_ship_hit_info->r_light);
754  light_denom = vm_vec_dot(&delta_vel_from_delta_rotvel_light, &ship_ship_hit_info->collision_normal);
755  if (light_denom < 0) {
756  // sanity check
757  light_denom = 0.0f;
758  }
759  light_denom += 1.0f / lighter->phys_info.mass;
760  }
761 
762  // calculate the necessary impulse to achieved the desired relative velocity after the collision
763  // update damage info in mc
764  impulse_mag = -(1.0f + coeff_restitution)*v_rel_normal_m / (heavy_denom + light_denom);
765  ship_ship_hit_info->impulse = impulse_mag;
766  if (impulse_mag < 0) {
767  nprintf(("Physics", "negative impulse mag -- Get Dave A if not Descent Physics\n"));
768  impulse_mag = -impulse_mag;
769  }
770 
771  // update the physics info structs for heavy and light objects
772  // since we have already calculated delta rotvel for heavy and light in world coords
773  // physics should not have to recalculate this, just change into body coords (done in collide_whack)
774  vm_vec_scale(&impulse, impulse_mag);
775  vm_vec_scale(&delta_rotvel_light, impulse_mag);
776  physics_collide_whack(&impulse, &delta_rotvel_light, &lighter->phys_info, &lighter->orient, ship_ship_hit_info->is_landing);
777  vm_vec_negate(&impulse);
778  vm_vec_scale(&delta_rotvel_heavy, -impulse_mag);
779  physics_collide_whack(&impulse, &delta_rotvel_heavy, &heavy->phys_info, &heavy->orient, true);
780 
781  // If within certain bounds, we want to add some more rotation towards the "resting orientation" of the ship
782  // These bounds are defined separately from normal "landing" bounds so that they can be more generous:
783  // we can have crash landings that still re-orient the ship.
784  if (subsys_landing_allowed &&
785  light_local_vel.xyz.z < light_sip->collision_physics.reorient_max_z &&
786  light_local_vel.xyz.z > light_sip->collision_physics.reorient_min_z &&
787  light_local_vel.xyz.y > light_sip->collision_physics.reorient_min_y &&
788  fl_abs(light_local_vel.xyz.x) < light_sip->collision_physics.reorient_max_x &&
789  light_uvec_dot_norm > 0 &&
790  light_fvec_dot_norm < light_sip->collision_physics.reorient_max_angle &&
791  light_fvec_dot_norm > light_sip->collision_physics.reorient_min_angle &&
792  fl_abs(light_rvec_dot_norm) < light_sip->collision_physics.reorient_max_rot_angle)
793  {
794  vec3d landing_delta_rotvel;
795  landing_delta_rotvel.xyz.x = (light_fvec_dot_norm * light_sip->collision_physics.reorient_mult)
797  // For yaw, use the dot product between vel vector (normalized) and orientation on the xz plane
798  // This reduces to the following math
799  // We also clamp to reduce huge nose swings at low speeds
800  float xzVelMag = sqrt(light_local_vel.xyz.x * light_local_vel.xyz.x + light_local_vel.xyz.z * light_local_vel.xyz.z);
801  float xzVelDotOrient = MIN(MAX((xzVelMag > 0 ? (light_local_vel.xyz.x / xzVelMag) : 0), -0.5f), 0.5f);
802  landing_delta_rotvel.xyz.y = (xzVelMag > 2) ? (xzVelDotOrient * light_sip->collision_physics.reorient_mult) : 0;
803  landing_delta_rotvel.xyz.z = light_rvec_dot_norm * light_sip->collision_physics.reorient_mult * -1;
804  vm_vec_add2( &lighter->phys_info.rotvel, &landing_delta_rotvel );
805  }
806 
807  // Find final positions
808  // We will try not to worry about the left over time in the frame
809  // heavy's position unchanged by collision
810  // light's position is heavy's position plus relative position from heavy
811  vm_vec_add(&lighter->pos, &heavy->pos, &ship_ship_hit_info->light_collision_cm_pos);
812 
813  // Try to move each body back to its position just before collision occured to prevent interpenetration
814  // Move away in direction of light and away in direction of normal
815  vec3d direction_light; // direction light is moving relative to heavy
816  vm_vec_sub(&direction_light, &ship_ship_hit_info->light_rel_vel, &local_vel_from_submodel);
817  vm_vec_normalize_safe(&direction_light);
818 
819  Assert( !vm_is_vec_nan(&direction_light) );
820  vm_vec_scale_add2(&heavy->pos, &direction_light, 0.2f * lighter->phys_info.mass / (heavy->phys_info.mass + lighter->phys_info.mass));
821  vm_vec_scale_add2(&heavy->pos, &ship_ship_hit_info->collision_normal, -0.1f * lighter->phys_info.mass / (heavy->phys_info.mass + lighter->phys_info.mass));
822  //For landings, we want minimal movement on the light ship (just enough to keep the collision detection honest)
823  if (ship_ship_hit_info->is_landing) {
824  vm_vec_scale_add2(&lighter->pos, &ship_ship_hit_info->collision_normal, LANDING_POS_OFFSET);
825  }
826  else {
827  vm_vec_scale_add2(&lighter->pos, &direction_light, -0.2f * heavy->phys_info.mass / (heavy->phys_info.mass + lighter->phys_info.mass));
828  vm_vec_scale_add2(&lighter->pos, &ship_ship_hit_info->collision_normal, 0.1f * heavy->phys_info.mass / (heavy->phys_info.mass + lighter->phys_info.mass));
829  }
830 
831  // restore mass in case of special cruiser / asteroid collision
832  if (special_cruiser_asteroid_collision) {
833  if (cruiser_light) {
834  lighter->phys_info.mass = copy_mass;
835  } else {
836  heavy->phys_info.mass = copy_mass;
837  }
838  }
839 }
840 
841 
842 // ------------------------------------------------------------------------------------------------
843 // get_I_inv()
844 //
845 // input: I_inv_body => inverse moment of inertia matrix in body coordinates
846 // orient => orientation matrix
847 //
848 // output: I_inv => inverse moment of inertia matrix in world coordinates
849 // ------------------------------------------------------------------------------------------------
850 //
851 // calculates the inverse moment of inertia matrix from the body matrix and oreint matrix
852 //
853 void get_I_inv (matrix* I_inv, matrix* I_inv_body, matrix* orient)
854 {
855  matrix Mtemp1, Mtemp2;
856  // I_inv = (Rt)(I_inv_body)(R)
857  // This is opposite to what is commonly seen in books since we are rotating coordianates axes
858  // which is equivalent to rotating in the opposite direction (or transpose)
859 
860  vm_matrix_x_matrix(&Mtemp1, I_inv_body, orient);
861  vm_copy_transpose(&Mtemp2, orient);
862  vm_matrix_x_matrix(I_inv, &Mtemp2, &Mtemp1);
863 }
864 
865 #define PLANET_DAMAGE_SCALE 4.0f
866 #define PLANET_DAMAGE_RANGE 3 // If within this factor of radius, apply damage.
867 
869 extern void hud_start_text_flash(char *txt, int t, int interval);
870 
875 void mcp_1(object *player_objp, object *planet_objp)
876 {
877  float planet_radius;
878  float dist;
879 
880  planet_radius = planet_objp->radius;
881  dist = vm_vec_dist_quick(&player_objp->pos, &planet_objp->pos);
882 
883  if (dist > planet_radius*PLANET_DAMAGE_RANGE)
884  return;
885 
886  ship_apply_global_damage( player_objp, planet_objp, NULL, PLANET_DAMAGE_SCALE * flFrametime * (float)pow((planet_radius*PLANET_DAMAGE_RANGE)/dist, 3.0f) );
887 
888  if ((Missiontime - Last_planet_damage_time > F1_0) || (Missiontime < Last_planet_damage_time)) {
889  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Too close to planet. Taking damage!", 465));
890  Last_planet_damage_time = Missiontime;
891  snd_play_3d( &Snds[ship_get_sound(player_objp, SND_ABURN_ENGAGE)], &player_objp->pos, &View_position );
892  }
893 
894 }
895 
900 int is_planet(object *objp)
901 {
902  return (strnicmp(Ships[objp->instance].ship_name, NOX("planet"), 6) == 0);
903 }
904 
905 
910 int maybe_collide_planet (object *obj1, object *obj2)
911 {
912  ship_info *sip1, *sip2;
913 
914  sip1 = &Ship_info[Ships[obj1->instance].ship_info_index];
915  sip2 = &Ship_info[Ships[obj2->instance].ship_info_index];
916 
917  if (sip1->flags & SIF_PLAYER_SHIP) {
918  if (is_planet(obj2)) {
919  mcp_1(obj1, obj2);
920  return 1;
921  }
922  } else if (sip2->flags & SIF_PLAYER_SHIP) {
923  if (is_planet(obj1)) {
924  mcp_1(obj2, obj1);
925  return 1;
926  }
927  }
928 
929  return 0;
930 }
931 
935 int get_ship_quadrant_from_global(vec3d *global_pos, object *objp)
936 {
937  vec3d tpos;
938  vec3d rotpos;
939 
940  vm_vec_sub(&tpos, global_pos, &objp->pos);
941  vm_vec_rotate(&rotpos, &tpos, &objp->orient);
942  return get_quadrant(&rotpos, objp);
943 }
944 
945 #define MIN_REL_SPEED_FOR_LOUD_COLLISION 50 // relative speed of two colliding objects at which we play the "loud" collide sound
946 
948 {
949  Player_collide_sound = -1;
950  AI_collide_sound = -1;
951  Player_collide_shield_sound = -1;
952  AI_collide_shield_sound = -1;
953 }
954 
958 void collide_ship_ship_do_sound(vec3d *world_hit_pos, object *A, object *B, int player_involved)
959 {
960  vec3d rel_vel;
961  float rel_speed;
962 
964  rel_speed = vm_vec_mag_quick(&rel_vel);
965 
966  if ( rel_speed > MIN_REL_SPEED_FOR_LOUD_COLLISION ) {
967  snd_play_3d( &Snds[SND_SHIP_SHIP_HEAVY], world_hit_pos, &View_position );
968  } else {
969  if ( player_involved ) {
970  if ( !snd_is_playing(Player_collide_sound) ) {
971  Player_collide_sound = snd_play_3d( &Snds[SND_SHIP_SHIP_LIGHT], world_hit_pos, &View_position );
972  }
973  } else {
974  if ( !snd_is_playing(AI_collide_sound) ) {
975  AI_collide_sound = snd_play_3d( &Snds[SND_SHIP_SHIP_LIGHT], world_hit_pos, &View_position );
976  }
977  }
978  }
979 
980  // maybe play a "shield" collision sound overlay if appropriate
981  if ( (shield_get_strength(A) > 5) || (shield_get_strength(B) > 5) ) {
982  if ( player_involved ) {
983  if ( !snd_is_playing(Player_collide_sound) ) {
984  Player_collide_shield_sound = snd_play_3d( &Snds[SND_SHIP_SHIP_SHIELD], world_hit_pos, &View_position );
985  }
986  } else {
987  if ( !snd_is_playing(Player_collide_sound) ) {
988  AI_collide_shield_sound = snd_play_3d( &Snds[SND_SHIP_SHIP_SHIELD], world_hit_pos, &View_position );
989  }
990  }
991  }
992 }
993 
998 void do_kamikaze_crash(object *obj1, object *obj2)
999 {
1000  ai_info *aip1, *aip2;
1001  ship *ship1, *ship2;
1002 
1003  ship1 = &Ships[obj1->instance];
1004  ship2 = &Ships[obj2->instance];
1005 
1006  aip1 = &Ai_info[ship1->ai_index];
1007  aip2 = &Ai_info[ship2->ai_index];
1008 
1009  if (ship1->team != ship2->team) {
1010  if (aip1->ai_flags & AIF_KAMIKAZE) {
1011  if (Ship_info[ship2->ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) {
1013  shield_set_strength(obj1, 0.0f);
1014  }
1015  } if (aip2->ai_flags & AIF_KAMIKAZE) {
1016  if (Ship_info[ship1->ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) {
1018  shield_set_strength(obj2, 0.0f);
1019  }
1020  }
1021  }
1022 }
1023 
1027 void maybe_push_little_ship_from_fast_big_ship(object *big_obj, object *small_obj, float impulse, vec3d *normal)
1028 {
1029  // Move player out of the way of a BIG|HUGE ship warping in or out
1030  int big_class = Ship_info[Ships[big_obj->instance].ship_info_index].class_type;
1031  int small_class = Ship_info[Ships[small_obj->instance].ship_info_index].class_type;
1032  if (big_class > -1 && Ship_types[big_class].ship_bools & STI_SHIP_WARP_PUSHES) {
1033  if (small_class > -1 && Ship_types[small_class].ship_bools & STI_SHIP_WARP_PUSHABLE) {
1034  float big_speed = vm_vec_mag_quick(&big_obj->phys_info.vel);
1035  if (big_speed > 3*big_obj->phys_info.max_vel.xyz.z) {
1036  // push player away in direction perp to forward of big ship
1037  // get perp vec
1038  vec3d temp, perp;
1039  vm_vec_sub(&temp, &small_obj->pos, &big_obj->pos);
1040  vm_vec_scale_add(&perp, &temp, &big_obj->orient.vec.fvec, -vm_vec_dot(&temp, &big_obj->orient.vec.fvec));
1041  vm_vec_normalize_quick(&perp);
1042 
1043  // don't drive into sfc we just collided with
1044  if (vm_vec_dot(&perp, normal) < 0) {
1045  vm_vec_negate(&perp);
1046  }
1047 
1048  // get magnitude of added perp vel
1049  float added_perp_vel_mag = impulse / small_obj->phys_info.mass;
1050 
1051  // add to vel and ramp vel
1052  vm_vec_scale_add2(&small_obj->phys_info.vel, &perp, added_perp_vel_mag);
1053  vm_vec_rotate(&small_obj->phys_info.prev_ramp_vel, &small_obj->phys_info.vel, &small_obj->orient);
1054  }
1055  }
1056  }
1057 }
1058 
1065 {
1066  int player_involved;
1067  float dist;
1068  object *A = pair->a;
1069  object *B = pair->b;
1070 
1071  if ( A->type == OBJ_WAYPOINT ) return 1;
1072  if ( B->type == OBJ_WAYPOINT ) return 1;
1073 
1074  Assert( A->type == OBJ_SHIP );
1075  Assert( B->type == OBJ_SHIP );
1076 
1077  if (reject_due_collision_groups(A,B))
1078  return 0;
1079 
1080  // If the player is one of the two colliding ships, flag this... it is used in
1081  // several places this function.
1082  if ( A == Player_obj || B == Player_obj ) {
1083  player_involved = 1;
1084  } else {
1085  player_involved = 0;
1086  }
1087 
1088  // Don't check collisions for warping out player if past stage 1.
1089  if ( player_involved && (Player->control_mode > PCM_WARPOUT_STAGE1) ) {
1090  return 0;
1091  }
1092 
1093  dist = vm_vec_dist( &A->pos, &B->pos );
1094 
1095  // If one of these is a planet, do special stuff.
1096  if (maybe_collide_planet(A, B))
1097  return 0;
1098 
1099  if ( dist < A->radius + B->radius ) {
1100  int hit;
1101 
1102  object *HeavyOne, *LightOne;
1103  // if two objects have the same mass, make the one with the larger pointer address the HeavyOne.
1104  if ( fl_abs(A->phys_info.mass - B->phys_info.mass) < 1 ) {
1105  if (A > B) {
1106  HeavyOne = A;
1107  LightOne = B;
1108  } else {
1109  HeavyOne = B;
1110  LightOne = A;
1111  }
1112  } else {
1113  if (A->phys_info.mass > B->phys_info.mass) {
1114  HeavyOne = A;
1115  LightOne = B;
1116  } else {
1117  HeavyOne = B;
1118  LightOne = A;
1119  }
1120  }
1121 
1122  ship_info *light_sip = &Ship_info[Ships[LightOne->instance].ship_info_index];
1123 
1124  collision_info_struct ship_ship_hit_info;
1125  init_collision_info_struct(&ship_ship_hit_info);
1126 
1127  ship_ship_hit_info.heavy = HeavyOne; // heavy object, generally slower moving
1128  ship_ship_hit_info.light = LightOne; // light object, generally faster moving
1129 
1130  vec3d world_hit_pos;
1131 
1132  hit = ship_ship_check_collision(&ship_ship_hit_info, &world_hit_pos);
1133 
1134  pair->next_check_time = timestamp(0);
1135 
1136  if ( hit )
1137  {
1138  Script_system.SetHookObjects(4, "Ship", A, "ShipB", B, "Self", A, "Object", B);
1139  bool a_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, A);
1140 
1141  //Yes this should be reversed.
1142  Script_system.SetHookObjects(4, "Ship", B, "ShipB", A, "Self", B, "Object", A);
1143  bool b_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, B);
1144  if(!a_override && !b_override)
1145  {
1146  float damage;
1147 
1148  if ( player_involved && (Player->control_mode == PCM_WARPOUT_STAGE1) ) {
1150  HUD_printf(XSTR( "Warpout sequence aborted.", 466));
1151  }
1152 
1153  damage = 0.005f * ship_ship_hit_info.impulse; // Cut collision-based damage in half.
1154  // Decrease heavy damage by 2x.
1155  if (damage > 5.0f){
1156  damage = 5.0f + (damage - 5.0f)/2.0f;
1157  }
1158 
1159  do_kamikaze_crash(A, B);
1160 
1161  if (ship_ship_hit_info.impulse > 0) {
1162  //Only flash the "Collision" text if not landing
1163  if ( player_involved && !ship_ship_hit_info.is_landing) {
1164  hud_start_text_flash(XSTR("Collision", 1431), 2000);
1165  }
1166  }
1167 
1168  //If this is a landing, play a different sound
1169  if (ship_ship_hit_info.is_landing) {
1170  if (vm_vec_mag(&ship_ship_hit_info.light_rel_vel) > MIN_LANDING_SOUND_VEL) {
1171  if ( player_involved ) {
1172  if ( !snd_is_playing(Player_collide_sound) ) {
1173  Player_collide_sound = snd_play_3d( &Snds[light_sip->collision_physics.landing_sound_idx], &world_hit_pos, &View_position );
1174  }
1175  } else {
1176  if ( !snd_is_playing(AI_collide_sound) ) {
1177  AI_collide_sound = snd_play_3d( &Snds[light_sip->collision_physics.landing_sound_idx], &world_hit_pos, &View_position );
1178  }
1179  }
1180  }
1181  }
1182  else {
1183  collide_ship_ship_do_sound(&world_hit_pos, A, B, player_involved);
1184  }
1185 
1186  // check if we should do force feedback stuff
1187  if (player_involved && (ship_ship_hit_info.impulse > 0)) {
1188  float scaler;
1189  vec3d v;
1190 
1191  scaler = -ship_ship_hit_info.impulse / Player_obj->phys_info.mass * 300;
1192  vm_vec_copy_normalize(&v, &world_hit_pos);
1193  joy_ff_play_vector_effect(&v, scaler);
1194  }
1195 
1196  #ifndef NDEBUG
1197  if ( !Collide_friendly ) {
1198  if ( Ships[A->instance].team == Ships[B->instance].team ) {
1199  vec3d collision_vec, right_angle_vec;
1200  vm_vec_normalized_dir(&collision_vec, &ship_ship_hit_info.hit_pos, &A->pos);
1201  if (vm_vec_dot(&collision_vec, &A->orient.vec.fvec) > 0.999f){
1202  right_angle_vec = A->orient.vec.rvec;
1203  } else {
1204  vm_vec_cross(&right_angle_vec, &A->orient.vec.uvec, &collision_vec);
1205  }
1206 
1207  vm_vec_scale_add2( &A->phys_info.vel, &right_angle_vec, +2.0f);
1208  vm_vec_scale_add2( &B->phys_info.vel, &right_angle_vec, -2.0f);
1209 
1210  return 0;
1211  }
1212  }
1213  #endif
1214 
1215  //Only do damage if not a landing
1216  if (!ship_ship_hit_info.is_landing) {
1217  // Scale damage based on skill level for player.
1218  if ((LightOne->flags & OF_PLAYER_SHIP) || (HeavyOne->flags & OF_PLAYER_SHIP)) {
1220  } else if (Ships[LightOne->instance].team == Ships[HeavyOne->instance].team) {
1221  // Decrease damage if non-player ships and not large.
1222  // Looks dumb when fighters are taking damage from bumping into each other.
1223  if ((LightOne->radius < 50.0f) && (HeavyOne->radius <50.0f)) {
1224  damage /= 4.0f;
1225  }
1226  }
1227 
1228  float dam2 = (100.0f * damage/LightOne->phys_info.mass);
1229 
1230  int quadrant_num = get_ship_quadrant_from_global(&world_hit_pos, ship_ship_hit_info.heavy);
1231  if ((ship_ship_hit_info.heavy->flags & OF_NO_SHIELDS) || !ship_is_shield_up(ship_ship_hit_info.heavy, quadrant_num) ) {
1232  quadrant_num = -1;
1233  }
1234 
1235  ship_apply_local_damage(ship_ship_hit_info.heavy, ship_ship_hit_info.light, &world_hit_pos, 100.0f * damage/HeavyOne->phys_info.mass, quadrant_num, CREATE_SPARKS, ship_ship_hit_info.submodel_num, &ship_ship_hit_info.collision_normal);
1236  hud_shield_quadrant_hit(ship_ship_hit_info.heavy, quadrant_num);
1237 
1238  // don't draw sparks (using sphere hitpos)
1239  ship_apply_local_damage(ship_ship_hit_info.light, ship_ship_hit_info.heavy, &world_hit_pos, dam2, MISS_SHIELDS, NO_SPARKS, -1, &ship_ship_hit_info.collision_normal);
1240  hud_shield_quadrant_hit(ship_ship_hit_info.light, -1);
1241 
1242  maybe_push_little_ship_from_fast_big_ship(ship_ship_hit_info.heavy, ship_ship_hit_info.light, ship_ship_hit_info.impulse, &ship_ship_hit_info.collision_normal);
1243  }
1244  }
1245 
1246  if(!(b_override && !a_override))
1247  {
1248  Script_system.SetHookObjects(4, "Ship", A, "ShipB", B, "Self", A, "Object", B);
1249  Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, A);
1250  }
1251  if((b_override && !a_override) || (!b_override && !a_override))
1252  {
1253  //Yes this should be reversed.
1254  Script_system.SetHookObjects(4, "Ship", B, "ShipB", A, "Self", B, "Object", A);
1255  Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, B);
1256  }
1257 
1258  Script_system.RemHookVars(4, "Ship", "ShipB", "Self", "Object");
1259  return 0;
1260  }
1261  } else {
1262  // estimate earliest time at which pair can hit
1263 
1264  // cap ships warping in/out can exceed ship's expected velocity
1265  // if ship is warping in, in stage 1, its velocity is 0, so make ship try to collide next frame
1266  int sif_a_flags, sif_b_flags;
1267  sif_a_flags = Ship_info[Ships[A->instance].ship_info_index].flags;
1268  sif_b_flags = Ship_info[Ships[B->instance].ship_info_index].flags;
1269 
1270  // if ship is huge and warping in or out
1271  if ( ((Ships[A->instance].flags & SF_ARRIVING_STAGE_1) && (sif_a_flags & (SIF_HUGE_SHIP)))
1272  || ((Ships[B->instance].flags & SF_ARRIVING_STAGE_1) && (sif_b_flags & (SIF_HUGE_SHIP))) ) {
1273  pair->next_check_time = timestamp(0); // check next time
1274  return 0;
1275  }
1276 
1277  // get max of (1) max_vel.z, (2) 10, (3) afterburner_max_vel.z, (4) vel.z (for warping in ships exceeding expected max vel)
1278  float shipA_max_speed, shipB_max_speed, time;
1279 
1280  // get shipA max speed
1282  shipA_max_speed = MAX(ship_get_max_speed(&Ships[A->instance]), ship_get_warpout_speed(A));
1283  } else {
1284  shipA_max_speed = ship_get_max_speed(&Ships[A->instance]);
1285  }
1286 
1287  // Maybe warping in or finished warping in with excessive speed
1288  shipA_max_speed = MAX(shipA_max_speed, vm_vec_mag(&A->phys_info.vel));
1289  shipA_max_speed = MAX(shipA_max_speed, 10.0f);
1290 
1291  // get shipB max speed
1293  shipB_max_speed = MAX(ship_get_max_speed(&Ships[B->instance]), ship_get_warpout_speed(B));
1294  } else {
1295  shipB_max_speed = ship_get_max_speed(&Ships[B->instance]);
1296  }
1297 
1298  // Maybe warping in or finished warping in with excessive speed
1299  shipB_max_speed = MAX(shipB_max_speed, vm_vec_mag(&B->phys_info.vel));
1300  shipB_max_speed = MAX(shipB_max_speed, 10.0f);
1301 
1302  time = 1000.0f * (dist - A->radius - B->radius) / (shipA_max_speed + shipB_max_speed);
1303  time -= 200.0f; // allow one frame slow frame at ~5 fps
1304 
1305  if (time > 0) {
1306  pair->next_check_time = timestamp( fl2i(time) );
1307  } else {
1308  pair->next_check_time = timestamp(0); // check next time
1309  }
1310  }
1311 
1312  return 0;
1313 }
1314 
1315 void collect_ship_ship_physics_info(object *heavier_obj, object *lighter_obj, mc_info *mc_info_obj, collision_info_struct *ship_ship_hit_info)
1316 {
1317  // slower moving object [A] is checked at its final position (polygon and position is found on obj)
1318  // faster moving object [B] is reduced to a point and a ray is drawn from its last_pos to pos
1319  // collision code returns hit position and normal on [A]
1320 
1321  // estimate location on B that contacts A
1322  // first find orientation of B relative to the normal it collides against.
1323  // then find an approx hit location using the position hit on the bounding box
1324 
1325  vec3d *r_heavy = &ship_ship_hit_info->r_heavy;
1326  vec3d *r_light = &ship_ship_hit_info->r_light;
1327  vec3d *heavy_collide_cm_pos = &ship_ship_hit_info->heavy_collision_cm_pos;
1328  vec3d *light_collide_cm_pos = &ship_ship_hit_info->light_collision_cm_pos;
1329 
1330  float core_rad = model_get_core_radius(Ship_info[Ships[lighter_obj->instance].ship_info_index].model_num);
1331 
1332  // get info needed for ship_ship_collision_physics
1333  Assert(mc_info_obj->hit_dist > 0);
1334 
1335  // get light_collide_cm_pos
1336  if ( !ship_ship_hit_info->submodel_rot_hit ) {
1337  vec3d displacement;
1338  vm_vec_sub(&displacement, mc_info_obj->p1, mc_info_obj->p0);
1339 
1340  *light_collide_cm_pos = *mc_info_obj->p0;
1341  vm_vec_scale_add2(light_collide_cm_pos, &displacement, ship_ship_hit_info->hit_time);
1342  }
1343 
1344  // get r_light
1345  vm_vec_sub(r_light, &ship_ship_hit_info->hit_pos, light_collide_cm_pos);
1346 
1347  float mag = float(fabs(vm_vec_mag(r_light) - core_rad));
1348  if (mag > 0.1) {
1349  nprintf(("Physics", "Framecount: %i |r_light - core_rad| > 0.1)\n", Framecount));
1350  }
1351 
1352  if (ship_ship_hit_info->edge_hit) {
1353  // For an edge hit, just take the closest valid plane normal as the collision normal
1354  vm_vec_copy_normalize(&ship_ship_hit_info->collision_normal, r_light);
1355  vm_vec_negate(&ship_ship_hit_info->collision_normal);
1356  }
1357 
1358  // r dot n may not be negative if hit by moving model parts.
1359  float dot = vm_vec_dot( r_light, &ship_ship_hit_info->collision_normal );
1360  if ( dot > 0 )
1361  {
1362  nprintf(("Physics", "Framecount: %i r dot normal %f > 0\n", Framecount, dot));
1363  }
1364 
1365  vm_vec_zero(heavy_collide_cm_pos);
1366 
1367  float q = vm_vec_dist(heavy_collide_cm_pos, light_collide_cm_pos) / (heavier_obj->radius + core_rad);
1368  if (q > 1.0f) {
1369  nprintf(("Physics", "Warning: q = %f. Supposed to be <= 1.0.\n", q));
1370  }
1371 
1372  *r_heavy = ship_ship_hit_info->hit_pos;
1373 
1374 
1375 // sphere_sphere_case_handled separately
1376 #ifdef COLLIDE_DEBUG
1377  nprintf(("Physics", "Frame: %i %s info: last_pos: [%4.1f, %4.1f, %4.1f], collide_pos: [%4.1f, %4.1f %4.1f] vel: [%4.1f, %4.1f %4.1f]\n",
1378  Framecount, Ships[heavier_obj->instance].ship_name, heavier_obj->last_pos.x, heavier_obj->last_pos.y, heavier_obj->last_pos.z,
1379  heavy_collide_cm_pos.x, heavy_collide_cm_pos.y, heavy_collide_cm_pos.z,
1380  heavier_obj->phys_info.vel.x, heavier_obj->phys_info.vel.y, heavier_obj->phys_info.vel.z));
1381 
1382  nprintf(("Physics", "Frame: %i %s info: last_pos: [%4.1f, %4.1f, %4.1f], collide_pos: [%4.1f, %4.1f, %4.1f] vel: [%4.1f, %4.1f, %4.1f]\n",
1383  Framecount, Ships[lighter_obj->instance].ship_name, lighter_obj->last_pos.x, lighter_obj->last_pos.y, lighter_obj->last_pos.z,
1384  light_collide_cm_pos.x, light_collide_cm_pos.y, light_collide_cm_pos.z,
1385  lighter_obj->phys_info.vel.x, lighter_obj->phys_info.vel.y, lighter_obj->phys_info.vel.z));
1386 #endif
1387 
1388 }
void mc_info_init(mc_info *mc)
Definition: model.h:1138
#define MOVEMENT_AXIS_X
Definition: model.h:43
int model_collide(mc_info *mc_info_obj)
bsp_info * submodel
Definition: model.h:764
int timestamp(int delta_ms)
Definition: timer.cpp:226
void vm_vec_projection_onto_plane(vec3d *projection, const vec3d *src, const vec3d *unit_normal)
Definition: vecmat.cpp:112
int collide_ship_ship(obj_pair *pair)
int Framecount
Definition: systemvars.cpp:22
int i
Definition: multi_pxo.cpp:466
fix Missiontime
Definition: systemvars.cpp:19
light ship-ship collide sound
Definition: gamesnd.h:120
void mcp_1(object *player_objp, object *planet_objp)
#define STI_SHIP_WARP_PUSHES
Definition: ship.h:997
int maybe_collide_planet(object *obj1, object *obj2)
vec3d hit_point
Definition: model.h:1123
#define MIN(a, b)
Definition: pstypes.h:296
vec3d * pos
Definition: model.h:1113
#define AIM_BAY_DEPART
Definition: ai.h:184
int team
Definition: ship.h:606
#define MSS_FLAG_ALLOW_LANDING
Definition: model.h:126
float vm_vec_mag_quick(const vec3d *v)
Definition: vecmat.cpp:371
matrix * vm_matrix_x_matrix(matrix *dest, const matrix *src0, const matrix *src1)
Definition: vecmat.cpp:1006
#define PCM_WARPOUT_STAGE1
Definition: player.h:59
#define SUBMODEL_ROT_HIT
Definition: objcollide.h:72
float ship_get_max_speed(ship *shipp)
Definition: ship.cpp:17279
vec3d vmd_z_vector
Definition: vecmat.cpp:27
vec3d View_position
Definition: 3dsetup.cpp:20
#define F1_0
Definition: fix.h:15
vec3d rotvel
Definition: physics.h:78
#define AIM_BAY_EMERGE
Definition: ai.h:183
#define SIF_PLAYER_SHIP
Definition: ship.h:875
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
submodel_instance_info * sii
Definition: model.h:94
float shield_get_strength(object *objp)
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
float flFrametime
Definition: fredstubs.cpp:22
vec3d desired_vel
Definition: physics.h:70
asteroid Asteroids[MAX_ASTEROIDS]
Definition: asteroid.cpp:63
float ship_get_warpout_speed(object *objp)
Definition: ship.cpp:17306
physics_info phys_info
Definition: object.h:157
int get_quadrant(vec3d *hit_pnt, object *shipobjp)
Definition: shield.cpp:988
void model_get_rotating_submodel_list(SCP_vector< int > *submodel_vector, object *objp)
Definition: modelread.cpp:4468
int id
Definition: model.h:732
void calculate_ship_ship_collision_physics(collision_info_struct *ship_ship_hit_info)
int model_num
Definition: ship.h:1189
int ship_is_beginning_warpout_speedup(object *objp)
Definition: ship.cpp:17334
#define OF_WAS_RENDERED
Definition: object.h:113
int model_instance_num
Definition: ship.h:802
float vm_vec_normalize_quick(vec3d *src)
Definition: vecmat.cpp:529
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
int target_objnum
Definition: ai.h:339
int submode
Definition: ai.h:394
float reorient_min_angle
Definition: ship.h:1142
int detail[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:738
#define SUBMODEL_NO_ROT_HIT
Definition: objcollide.h:71
Definition: pstypes.h:88
int ai_index
Definition: ship.h:538
#define NUM_SKILL_LEVELS
Definition: systemvars.h:150
#define OBJ_ASTEROID
Definition: object.h:44
hull_check p0
Definition: lua.cpp:5051
struct vec3d::@225::@227 xyz
#define MOVEMENT_AXIS_Y
Definition: model.h:44
vec3d max_vel
Definition: physics.h:49
#define SF2_DONT_COLLIDE_INVIS
Definition: ship.h:486
heavy ship-ship collide sound
Definition: gamesnd.h:119
GLclampf f
Definition: Glext.h:7097
int model_num
Definition: debris.h:34
int snd_is_playing(int sig)
Definition: sound.cpp:1047
#define OF_NO_SHIELDS
Definition: object.h:110
float model_get_core_radius(int modelnum)
Definition: modelread.cpp:3114
matrix * vm_copy_transpose(matrix *dest, const matrix *src)
Definition: vecmat.cpp:984
bool dock_check_find_direct_docked_object(object *objp, object *other_objp)
Definition: objectdock.cpp:91
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
int lod
Definition: model.h:1118
model_subsystem * subsystems
Definition: ship.h:1271
#define KAMIKAZE_HULL_ON_DEATH
Definition: ai.h:121
float landing_rest_angle
Definition: ship.h:1147
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
Definition: ai.h:329
uint flags
Definition: ship.h:644
matrix * B
Definition: lua.cpp:445
hull_check orient
Definition: lua.cpp:5049
#define OF_PLAYER_SHIP
Definition: object.h:109
object * objp
Definition: lua.cpp:3105
int next_check_time
Definition: objcollide.h:58
float hit_dist
Definition: model.h:1122
matrix I_body_inv
Definition: physics.h:41
#define Int3()
Definition: pstypes.h:292
vec3d max_rotvel
Definition: physics.h:52
void HUD_sourced_printf(int source, const char *format,...)
Definition: hudmessage.cpp:571
#define AIF_KAMIKAZE
Definition: ai.h:55
int reject_due_collision_groups(object *A, object *B)
Definition: objcollide.cpp:165
vec3d pos
Definition: object.h:152
vec3d * p0
Definition: model.h:1114
int ai_flags
Definition: ai.h:330
float vm_vec_mag_squared(const vec3d *v)
Definition: vecmat.cpp:339
int asteroid_subtype
Definition: asteroid.h:103
script_state Script_system("FS2_Open Scripting")
int subobj_num
Definition: model.h:175
fix Last_planet_damage_time
int model_num
Definition: model.h:1110
#define COLLISION_ROTATION_FACTOR
Definition: objcollide.h:43
#define LANDING_POS_OFFSET
Definition: objcollide.h:45
int asteroid_type
Definition: asteroid.h:102
bool no_collisions
Definition: model.h:390
#define COLLISION_FRICTION_FACTOR
Definition: objcollide.h:42
void physics_collide_whack(vec3d *impulse, vec3d *world_delta_rotvel, physics_info *pi, matrix *orient, bool is_landing)
Definition: physics.cpp:1026
int ship_ship_check_collision(collision_info_struct *ship_ship_hit_info, vec3d *hitpos)
vec3d heavy_collision_cm_pos
Definition: objcollide.h:25
#define SIF_BOMBER
Definition: ship.h:886
#define OBJ_WAYPOINT
Definition: object.h:36
void model_instance_find_world_point(vec3d *outpnt, vec3d *mpnt, int model_instance_num, int submodel_num, const matrix *objorient, const vec3d *objpos)
Definition: modelread.cpp:4135
int instance
Definition: object.h:150
object * a
Definition: objcollide.h:55
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
vec3d last_pos
Definition: object.h:155
#define SIF2_ALLOW_LANDINGS
Definition: ship.h:930
void collide_ship_ship_do_sound(vec3d *world_hit_pos, object *A, object *B, int player_involved)
int check_special_cruiser_asteroid_collision(object *heavy, object *lighter, float *cruiser_mass, int *cruiser_light)
#define SIF_BIG_SHIP
Definition: ship.h:944
int flags
Definition: model.h:1116
void get_I_inv(matrix *I_inv, matrix *I_inv_body, matrix *orient)
struct matrix::@228::@230 vec
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
uint flags
Definition: model.h:169
#define nprintf(args)
Definition: pstypes.h:239
vec3d * p1
Definition: model.h:1115
int flags
Definition: ship.h:1227
#define SIF_SMALL_SHIP
Definition: ship.h:943
#define strnicmp(s1, s2, n)
Definition: config.h:272
int ship_get_sound(object *objp, GameSoundsIndex id)
Returns a ship-specific sound index.
Definition: ship.cpp:18614
int snd_play_3d(game_snd *gs, vec3d *source_pos, vec3d *listen_pos, float radius, vec3d *source_vel, int looping, float vol_scale, int priority, vec3d *sound_fvec, float range_factor, int force, bool is_ambient)
Definition: sound.cpp:594
int mode
Definition: ai.h:336
afterburner engage
Definition: gamesnd.h:89
float hull_strength
Definition: object.h:160
#define OBJ_DEBRIS
Definition: object.h:37
void vm_vec_sub2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:187
void world_find_model_instance_point(vec3d *out, vec3d *world_pt, const polymodel_instance *pmi, int submodel_num, const matrix *orient, const vec3d *pos)
Definition: modelread.cpp:4215
submodel_instance * submodel
Definition: model.h:100
void hud_shield_quadrant_hit(object *objp, int quadrant)
Definition: hudshield.cpp:541
int n_subsystems
Definition: ship.h:1270
bool check_subsystem_landing_allowed(ship_info *heavy_sip, collision_info_struct *ship_ship_hit_info)
#define vm_vec_negate(v)
Definition: vecmat.h:70
char * Mode_text[MAX_AI_BEHAVIORS]
Definition: aicode.cpp:108
#define HUD_SOURCE_HIDDEN
Definition: hudmessage.h:23
hull_check p1
Definition: lua.cpp:5052
float reorient_max_rot_angle
Definition: ship.h:1143
int hit_submodel
Definition: model.h:1125
#define fl_abs(fl)
Definition: floating.h:31
#define AIM_CHASE
Definition: ai.h:166
float vm_vec_normalized_dir(vec3d *dest, const vec3d *end, const vec3d *start)
Definition: vecmat.cpp:591
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
float z
Definition: pstypes.h:91
float landing_min_angle
Definition: ship.h:1132
void hud_start_text_flash(char *txt, int t, int interval)
#define NO_SPARKS
Definition: shiphit.h:20
int flags2
Definition: ship.h:1228
void model_init_submodel_axis_pt(submodel_instance_info *sii, int model_num, int submodel_num)
Definition: modelread.cpp:4936
Definition: ship.h:534
float radius
Definition: model.h:1117
float vm_vec_normalize_safe(vec3d *v)
Definition: vecmat.cpp:471
vec3d vmd_y_vector
Definition: vecmat.cpp:26
GLdouble GLdouble t
Definition: Glext.h:5329
debris Debris[MAX_DEBRIS_PIECES]
Definition: debris.cpp:41
#define MC_CHECK_SPHERELINE
Definition: model.h:1177
void model_instance_find_obj_dir(vec3d *w_vec, vec3d *m_vec, int model_instance_num, int submodel_num, matrix *objorient)
Definition: modelread.cpp:3416
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
shield ship-ship collide overlay sound
Definition: gamesnd.h:121
void ship_apply_global_damage(object *ship_objp, object *other_obj, vec3d *force_center, float damage)
Definition: shiphit.cpp:2476
vec3d vmd_x_vector
Definition: vecmat.cpp:25
#define MC_SUBMODEL_INSTANCE
Definition: model.h:1179
char name[NAME_LENGTH]
Definition: ship.h:1163
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
long fix
Definition: pstypes.h:54
#define AIM_DOCK
Definition: ai.h:174
#define MISS_SHIELDS
Definition: shiphit.h:23
#define vm_vec_zero(v)
Definition: vecmat.h:37
#define SF_ARRIVING_STAGE_1
Definition: ship.h:451
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
#define OBJ_INDEX(objp)
Definition: object.h:235
#define PLANET_DAMAGE_RANGE
matrix orient
Definition: object.h:153
#define NOX(s)
Definition: pstypes.h:473
#define OBJ_SHIP
Definition: object.h:32
void set_hit_struct_info(collision_info_struct *hit, mc_info *mc, int submodel_rot_hit)
#define SIF_HUGE_SHIP
Definition: ship.h:945
float x
Definition: pstypes.h:91
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
int Player_use_ai
void SetHookObjects(int num,...)
Definition: scripting.cpp:556
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
vec3d vel
Definition: physics.h:77
void collide_ship_ship_sounds_init()
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
int movement_axis
Definition: model.h:327
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
GLdouble GLdouble GLdouble GLdouble q
Definition: Glext.h:5345
#define DCF_BOOL(function_name, bool_variable)
Definition: console.h:71
polymodel_instance * model_get_instance(int model_instance_num)
Definition: modelread.cpp:3154
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
#define MOVEMENT_AXIS_Z
Definition: model.h:45
bool collision_checked
Definition: model.h:92
#define fl2i(fl)
Definition: floating.h:33
player * Player
#define MC_CHECK_MODEL
Definition: model.h:1169
void collect_ship_ship_physics_info(object *heavier_obj, object *lighter_obj, mc_info *mc_info_obj, collision_info_struct *ship_ship_hit_info)
int model_instance_num
Definition: asteroid.h:101
float y
Definition: pstypes.h:91
float both_small_bounce
Definition: ship.h:1117
#define CREATE_SPARKS
Definition: shiphit.h:21
float vm_vec_copy_normalize(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:427
void RemHookVars(unsigned int num,...)
Definition: scripting.cpp:754
#define vm_is_vec_nan(v)
Definition: vecmat.h:19
int ship_info_index
Definition: ship.h:539
bool blown_off
Definition: model.h:93
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
#define SIF_FIGHTER
Definition: ship.h:885
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
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
#define PI
Definition: pstypes.h:303
#define STI_SHIP_WARP_PUSHABLE
Definition: ship.h:998
int Game_skill_level
Definition: fredstubs.cpp:170
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
int model_instance_num
Definition: model.h:1109
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
char * Submode_text[]
Definition: aicode.cpp:133
void shield_set_strength(object *objp, float strength)
void init_collision_info_struct(collision_info_struct *cis)
matrix * A
Definition: lua.cpp:444
object * Player_obj
Definition: object.cpp:56
uint flags2
Definition: ship.h:645
vec3d prev_ramp_vel
Definition: physics.h:69
int temp
Definition: lua.cpp:4996
int goal_objnum
Definition: ai.h:355
ship_collision_physics collision_physics
Definition: ship.h:1234
polymodel * pm
Definition: lua.cpp:1598
vec3d hit_normal
Definition: model.h:1129
#define MIN_LANDING_SOUND_VEL
Definition: objcollide.h:44
#define MAX(a, b)
Definition: pstypes.h:299
int ship_hit_shield(object *obj, mc_info *mc, collision_info_struct *sshs)
void HUD_printf(const char *format,...)
Definition: hudmessage.cpp:527
int bay_emerge_or_depart(object *heavy_objp, object *light_objp)
float mass
Definition: physics.h:39
#define CHA_COLLIDESHIP
Definition: scripting.h:47
vec3d * vm_vec_cross(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:645
#define MC_CHECK_INVISIBLE_FACES
Definition: model.h:1180
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
matrix last_orient
Definition: object.h:156
int collision_lod
Definition: ship.h:1187
int model_instance_num
Definition: lua.cpp:4996
int submodel_num
Definition: model.h:1111
int is_planet(object *objp)
char type
Definition: object.h:146
angles angs
Definition: model.h:88
float landing_max_rot_angle
Definition: ship.h:1133
#define MC_ONLY_SPHERE
Definition: model.h:1171
bool IsConditionOverride(int action, object *objp=NULL)
Definition: scripting.cpp:938
SCP_vector< asteroid_info > Asteroid_info
Definition: asteroid.cpp:62
void gameseq_post_event(int event)
matrix * orient
Definition: model.h:1112
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
const GLdouble * v
Definition: Glext.h:5322
int ships_are_docking(object *objp1, object *objp2)
matrix vmd_identity_matrix
Definition: vecmat.cpp:28
void joy_ff_play_vector_effect(vec3d *v, float scaler)
Definition: joy-unix.cpp:635
#define AIF_TARGET_COLLISION
Definition: ai.h:47
char ship_name[NAME_LENGTH]
Definition: ship.h:604
int ship_is_shield_up(object *obj, int quadrant)
Definition: shield.cpp:964
void maybe_push_little_ship_from_fast_big_ship(object *big_obj, object *small_obj, float impulse, vec3d *normal)
int get_ship_quadrant_from_global(vec3d *global_pos, object *objp)
angles prev_angs
Definition: model.h:89
SCP_vector< ship_type_info > Ship_types
Definition: ship.cpp:168
vec3d light_collision_cm_pos
Definition: objcollide.h:26
#define PLANET_DAMAGE_SCALE
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
#define MIN_REL_SPEED_FOR_LOUD_COLLISION
void do_kamikaze_crash(object *obj1, object *obj2)