FS2_Open
Open source remastering of the Freespace 2 engine
asteroid.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 "debugconsole/console.h"
14 #include "fireball/fireballs.h"
15 #include "freespace2/freespace.h"
16 #include "gamesnd/gamesnd.h"
18 #include "globalincs/linklist.h"
19 #include "globalincs/systemvars.h"
20 #include "hud/hud.h"
21 #include "hud/hudescort.h"
22 #include "hud/hudgauges.h"
23 #include "hud/hudtarget.h"
24 #include "iff_defs/iff_defs.h"
25 #include "io/timer.h"
26 #include "localization/localize.h"
27 #include "math/staticrand.h"
28 #include "math/vecmat.h"
29 #include "model/model.h"
30 #include "network/multi.h"
31 #include "network/multimsgs.h"
32 #include "network/multiutil.h"
33 #include "object/objcollide.h"
34 #include "object/object.h"
35 #include "parse/parselo.h"
36 #include "parse/scripting.h"
37 #include "particle/particle.h"
38 #include "render/3d.h"
39 #include "ship/ship.h"
40 #include "ship/shiphit.h"
42 #include "stats/scoring.h"
43 #include "weapon/weapon.h"
44 
45 #include <algorithm>
46 
47 #define ASTEROID_OBJ_USED (1<<0) // flag used in asteroid_obj struct
48 #define MAX_ASTEROID_OBJS MAX_ASTEROIDS // max number of asteroids tracked in asteroid list
49 asteroid_obj Asteroid_objs[MAX_ASTEROID_OBJS]; // array used to store asteroid object indexes
50 asteroid_obj Asteroid_obj_list; // head of linked list of asteroid_obj structs
51 
52 // used for randomly generating debris type when there are multiple sizes.
53 #define SMALL_DEBRIS_WEIGHT 8
54 #define MEDIUM_DEBRIS_WEIGHT 4
55 #define LARGE_DEBRIS_WEIGHT 1
56 
58 int Num_asteroids = 0;
59 int Asteroid_throw_objnum = -1; // Object index of ship to throw asteroids at.
61 
65 
66 
67 static int Asteroid_impact_explosion_ani;
68 static float Asteroid_impact_explosion_radius;
72 
73 #define ASTEROID_CHECK_WRAP_TIMESTAMP 2000 // how often an asteroid gets checked for wrapping
74 #define ASTEROID_UPDATE_COLLIDE_TIMESTAMP 2000 // how often asteroid is checked for impending collisions with escort ships
75 #define ASTEROID_MIN_COLLIDE_TIME 24 // time in seconds to check for asteroid colliding
76 
81 {
82  // Asteroid has wrapped, update collide objnum and flags
83  Asteroids[objp->instance].collide_objnum = -1;
84  Asteroids[objp->instance].collide_objsig = -1;
85  OBJ_RECALC_PAIRS(objp);
86 }
87 
92 {
93  int i;
94 
95  list_init(&Asteroid_obj_list);
96  for ( i = 0; i < MAX_ASTEROID_OBJS; i++ ) {
97  Asteroid_objs[i].flags = 0;
98  }
99 }
100 
105 int asteroid_obj_list_add(int objnum)
106 {
107  int index;
108 
109  asteroid *cur_asteroid = &Asteroids[Objects[objnum].instance];
110  index = cur_asteroid - Asteroids;
111 
112  Assert(index >= 0 && index < MAX_ASTEROID_OBJS);
113  Assert(!(Asteroid_objs[index].flags & ASTEROID_OBJ_USED));
114 
115  Asteroid_objs[index].flags = 0;
116  Asteroid_objs[index].objnum = objnum;
117  list_append(&Asteroid_obj_list, &Asteroid_objs[index]);
118  Asteroid_objs[index].flags |= ASTEROID_OBJ_USED;
119 
120  return index;
121 }
122 
128 {
129  int index = obj->instance;
130 
131  Assert(index >= 0 && index < MAX_ASTEROID_OBJS);
132  Assert(Asteroid_objs[index].flags & ASTEROID_OBJ_USED);
133 
134  list_remove(&Asteroid_obj_list, &Asteroid_objs[index]);
135  Asteroid_objs[index].flags = 0;
136 }
137 
138 
142 float asteroid_cap_speed(int asteroid_info_index, float speed)
143 {
144  float max, double_max;
145 
146  Assert( asteroid_info_index < (int)Asteroid_info.size() );
147 
148  max = Asteroid_info[asteroid_info_index].max_speed;
149  double_max = max * 2;
150 
151  while (speed > double_max){
152  speed *= 0.5f;
153  }
154 
155  if (speed > max){
156  speed *= 0.75f;
157  }
158 
159  return speed;
160 }
161 
169 {
170  Assert(asfieldp->has_inner_bound);
171 
172  int rval = 0;
173  if ( (pos->xyz.x > asfieldp->inner_min_bound.xyz.x - delta) && (pos->xyz.x < asfieldp->inner_max_bound.xyz.x + delta) ) {
174  rval += 1;
175  }
176 
177  if ( (pos->xyz.y > asfieldp->inner_min_bound.xyz.y - delta) && (pos->xyz.y < asfieldp->inner_max_bound.xyz.y + delta) ) {
178  rval += 2;
179  }
180 
181  if ( (pos->xyz.z > asfieldp->inner_min_bound.xyz.z - delta) && (pos->xyz.z < asfieldp->inner_max_bound.xyz.z + delta) ) {
182  rval += 4;
183  }
184 
185  return rval;
186 }
187 
193 
194  if (!asfieldp->has_inner_bound) {
195  return 0;
196  }
197 
198  return (asteroid_in_inner_bound_with_axes(asfieldp, pos, delta) == 7);
199 }
200 
207 {
208  if (!asteroid_in_inner_bound(asfieldp, pos, 0)) {
209  return;
210  }
211 
212  float dist1, dist2;
213  int axis;
214 
215  for (axis=0; axis<3; axis++) {
216  dist1 = pos->a1d[axis] - asfieldp->inner_min_bound.a1d[axis];
217  dist2 = asfieldp->inner_max_bound.a1d[axis] - pos->a1d[axis];
218  Assert(dist1 >= 0 && dist2 >= 0);
219 
220  if (dist1 < dist2) {
221  pos->a1d[axis] = asfieldp->inner_max_bound.a1d[axis] + dist1;
222  } else {
223  pos->a1d[axis] = asfieldp->inner_min_bound.a1d[axis] - dist2;
224  }
225  }
226 }
227 
231 object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype)
232 {
233  int n, objnum;
234  matrix orient;
235  object *objp;
236  asteroid *asp;
237  asteroid_info *asip;
238  vec3d pos, delta_bound;
239  angles angs;
240  float radius;
241  ushort signature;
242  int rand_base;
243 
244  // bogus
245  if(asfieldp == NULL) {
246  return NULL;
247  }
248 
249  for (n=0; n<MAX_ASTEROIDS; n++) {
250  if (!(Asteroids[n].flags & AF_USED)) {
251  break;
252  }
253  }
254 
255  if (n >= MAX_ASTEROIDS) {
256  nprintf(("Warning","Could not create asteroid, no more slots left\n"));
257  return NULL;
258  }
259 
260  if((asteroid_type < 0) || (asteroid_type >= (((int)Species_info.size() + 1) * NUM_DEBRIS_SIZES))) {
261  return NULL;
262  }
263 
264  if((asteroid_subtype < 0) || (asteroid_subtype >= NUM_DEBRIS_POFS)) {
265  return NULL;
266  }
267 
268  // HACK: multiplayer asteroid subtype always 0 to keep subtype in sync
269  if ( Game_mode & GM_MULTIPLAYER) {
270  asteroid_subtype = 0;
271  }
272 
273  asip = &Asteroid_info[asteroid_type];
274 
275  // bogus
276  if(asip->modelp[asteroid_subtype] == NULL) {
277  return NULL;
278  }
279 
280  asp = &Asteroids[n];
281  asp->asteroid_type = asteroid_type;
282  asp->asteroid_subtype = asteroid_subtype;
283  asp->flags = 0;
284  asp->flags |= AF_USED;
287  asp->final_death_time = timestamp(-1);
288  asp->collide_objnum = -1;
289  asp->collide_objsig = -1;
290  asp->target_objnum = -1;
291 
292  radius = model_get_radius(asip->model_num[asteroid_subtype]);
293 
294  vm_vec_sub(&delta_bound, &asfieldp->max_bound, &asfieldp->min_bound);
295 
296  // for multiplayer, we want to do a static_rand so that everything behaves the same on all machines
297  signature = 0;
298  rand_base = 0;
299  if ( Game_mode & GM_NORMAL ) {
300  pos.xyz.x = asfieldp->min_bound.xyz.x + delta_bound.xyz.x * frand();
301  pos.xyz.y = asfieldp->min_bound.xyz.y + delta_bound.xyz.y * frand();
302  pos.xyz.z = asfieldp->min_bound.xyz.z + delta_bound.xyz.z * frand();
303 
304  inner_bound_pos_fixup(asfieldp, &pos);
305  angs.p = frand() * PI2;
306  angs.b = frand() * PI2;
307  angs.h = frand() * PI2;
308  } else {
310  rand_base = signature;
311 
312  pos.xyz.x = asfieldp->min_bound.xyz.x + delta_bound.xyz.x * static_randf( rand_base++ );
313  pos.xyz.y = asfieldp->min_bound.xyz.y + delta_bound.xyz.y * static_randf( rand_base++ );
314  pos.xyz.z = asfieldp->min_bound.xyz.z + delta_bound.xyz.z * static_randf( rand_base++ );
315 
316  inner_bound_pos_fixup(asfieldp, &pos);
317  angs.p = static_randf( rand_base++ ) * PI2;
318  angs.b = static_randf( rand_base++ ) * PI2;
319  angs.h = static_randf( rand_base++ ) * PI2;
320  }
321 
322  vm_angles_2_matrix(&orient, &angs);
323 
324  objnum = obj_create( OBJ_ASTEROID, -1, n, &orient, &pos, radius, OF_RENDERS | OF_PHYSICS | OF_COLLIDES);
325 
326  if ( (objnum == -1) || (objnum >= MAX_OBJECTS) ) {
327  mprintf(("Couldn't create asteroid -- out of object slots\n"));
328  return NULL;
329  }
330 
331  asp->objnum = objnum;
332  asp->model_instance_num = -1;
333 
334  if (model_get(asip->model_num[asteroid_subtype])->flags & PM_FLAG_HAS_INTRINSIC_ROTATE) {
335  asp->model_instance_num = model_create_instance(false, asip->model_num[asteroid_subtype]);
336  }
337 
338  // Add to Asteroid_used_list
339  asteroid_obj_list_add(objnum);
340 
341  objp = &Objects[objnum];
342 
343  if ( Game_mode & GM_MULTIPLAYER ){
344  objp->net_signature = signature;
345  }
346 
347  Num_asteroids++;
348 
349  if (radius < 1.0) {
350  radius = 1.0f;
351  }
352 
353  vec3d rotvel;
354  if ( Game_mode & GM_NORMAL ) {
355  vm_vec_rand_vec_quick(&rotvel);
356  vm_vec_scale(&rotvel, frand()/4.0f + 0.1f);
357  objp->phys_info.rotvel = rotvel;
359  } else {
360  static_randvec( rand_base++, &rotvel );
361  vm_vec_scale(&rotvel, static_randf(rand_base++)/4.0f + 0.1f);
362  objp->phys_info.rotvel = rotvel;
363  static_randvec( rand_base++, &objp->phys_info.vel );
364  }
365 
366 
367  float speed;
368 
369  if ( Game_mode & GM_NORMAL ) {
370  speed = asteroid_cap_speed(asteroid_type, asfieldp->speed*frand_range(0.5f + (float) Game_skill_level/NUM_SKILL_LEVELS, 2.0f + (float) (2*Game_skill_level)/NUM_SKILL_LEVELS));
371  } else {
372  speed = asteroid_cap_speed(asteroid_type, asfieldp->speed*static_randf_range(rand_base++, 0.5f + (float) Game_skill_level/NUM_SKILL_LEVELS, 2.0f + (float) (2*Game_skill_level)/NUM_SKILL_LEVELS));
373  }
374 
375  vm_vec_scale(&objp->phys_info.vel, speed);
376  objp->phys_info.desired_vel = objp->phys_info.vel;
377 
378  // blow out his reverse thrusters. Or drag, same thing.
379  objp->phys_info.rotdamp = 10000.0f;
380  objp->phys_info.side_slip_time_const = 10000.0f;
381  objp->phys_info.flags |= (PF_REDUCED_DAMP | PF_DEAD_DAMP); // set damping equal for all axis and not changable
382 
383  // Fill in the max_vel field, so the collision pair stuff knows
384  // how fast this can move maximum in order to throw out collisions.
385  // This is in local coordinates, so Z is forward velocity.
386  objp->phys_info.max_vel.xyz.x = 0.0f;
387  objp->phys_info.max_vel.xyz.y = 0.0f;
389 
390  objp->phys_info.mass = asip->modelp[asteroid_subtype]->rad * 700.0f;
391  objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*asip->modelp[asteroid_subtype]->rad);
392  objp->phys_info.I_body_inv.vec.uvec.xyz.y = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
393  objp->phys_info.I_body_inv.vec.fvec.xyz.z = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
395 
396  // ensure vel is valid
397  Assert( !vm_is_vec_nan(&objp->phys_info.vel) );
398 
399  return objp;
400 }
401 
405 void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
406 {
407  object *new_objp;
408  float speed;
409 
410  Assert(parent_objp->type == OBJ_ASTEROID);
411  int subtype = Asteroids[parent_objp->instance].asteroid_subtype;
412  new_objp = asteroid_create(&Asteroid_field, asteroid_type, subtype);
413 
414  if (new_objp == NULL)
415  return;
416 
417  if ( MULTIPLAYER_MASTER ){
418  send_asteroid_create( new_objp, parent_objp, asteroid_type, relvec );
419  }
420 
421  // Now, bash some values.
422  vm_vec_scale_add(&new_objp->pos, &parent_objp->pos, relvec, 0.5f * parent_objp->radius);
423  float parent_speed = vm_vec_mag_quick(&parent_objp->phys_info.vel);
424 
425  if ( parent_speed < 0.1f ) {
426  parent_speed = vm_vec_mag_quick(&Asteroid_field.vel);
427  }
428 
429  new_objp->phys_info.vel = parent_objp->phys_info.vel;
430  if ( Game_mode & GM_NORMAL )
431  speed = asteroid_cap_speed(asteroid_type, (frand() + 2.0f) * parent_speed);
432  else
433  speed = asteroid_cap_speed(asteroid_type, (static_randf(new_objp->net_signature)+2.0f) * parent_speed);
434 
435  vm_vec_scale_add2(&new_objp->phys_info.vel, relvec, speed);
436  if (vm_vec_mag_quick(&new_objp->phys_info.vel) > 80.0f)
437  vm_vec_scale(&new_objp->phys_info.vel, 0.5f);
438 
439  new_objp->phys_info.desired_vel = new_objp->phys_info.vel;
440  vm_vec_scale_add(&new_objp->last_pos, &new_objp->pos, &new_objp->phys_info.vel, -flFrametime);
441 }
442 
446 void asteroid_load(int asteroid_info_index, int asteroid_subtype)
447 {
448  int i;
449  asteroid_info *asip;
450 
451  Assert( asteroid_info_index < (int)Asteroid_info.size() );
452  Assert( asteroid_subtype < NUM_DEBRIS_POFS );
453 
454  if ( (asteroid_info_index >= (int)Asteroid_info.size()) || (asteroid_subtype >= NUM_DEBRIS_POFS) ) {
455  return;
456  }
457 
458  asip = &Asteroid_info[asteroid_info_index];
459 
460  if ( !VALID_FNAME(asip->pof_files[asteroid_subtype]) )
461  return;
462 
463  asip->model_num[asteroid_subtype] = model_load( asip->pof_files[asteroid_subtype], 0, NULL );
464 
465  if (asip->model_num[asteroid_subtype] >= 0)
466  {
467  polymodel *pm = asip->modelp[asteroid_subtype] = model_get(asip->model_num[asteroid_subtype]);
468 
469  if ( asip->num_detail_levels != pm->n_detail_levels )
470  {
471  if ( !Is_standalone )
472  {
473  // just log to file for standalone servers
474  Warning(LOCATION, "For asteroid '%s', detail level\nmismatch (POF needs %d)", asip->name, pm->n_detail_levels );
475  }
476  else
477  {
478  nprintf(("Warning", "For asteroid '%s', detail level mismatch (POF needs %d)", asip->name, pm->n_detail_levels));
479  }
480  }
481  // Stuff detail level distances.
482  for ( i=0; i<pm->n_detail_levels; i++ )
483  pm->detail_depth[i] = (i < asip->num_detail_levels) ? i2fl(asip->detail_distance[i]) : 0.0f;
484  }
485 }
486 
491  int group_base, group_offset;
492 
493  group_base = (index / NUM_DEBRIS_SIZES) * NUM_DEBRIS_SIZES;
494  group_offset = index - group_base;
495 
496  // group base + offset
497  // offset is formed by adding 1 or 2 (since 3 in model group) and mapping back in the 0-2 range
498  return group_base + ((group_offset + rand()%(NUM_DEBRIS_SIZES-1) + 1) % NUM_DEBRIS_SIZES);
499 }
500 
506 int get_debris_weight(int ship_debris_index)
507 {
508  int size = ship_debris_index % NUM_DEBRIS_SIZES;
509  switch (size)
510  {
511  case ASTEROID_TYPE_SMALL:
512  return SMALL_DEBRIS_WEIGHT;
513 
515  return MEDIUM_DEBRIS_WEIGHT;
516 
517  case ASTEROID_TYPE_LARGE:
518  return LARGE_DEBRIS_WEIGHT;
519 
520  default:
521  Int3();
522  return 1;
523  }
524 }
525 
530 {
531  int i, idx;
532 
533  // ship_debris_odds_table keeps track of debris type of the next debris piece
534  // each different type (size) of debris piece has a diffenent weight, smaller weighted more heavily than larger.
535  // choose next type from table ship_debris_odds_table by rand()%max_weighted_range,
536  // the threshold *below* which the debris type is selected.
537  struct {
538  int random_threshold;
539  int debris_type;
540  } ship_debris_odds_table[MAX_ACTIVE_DEBRIS_TYPES];
541 
542  int max_weighted_range = 0;
543 
544  if (!Asteroids_enabled)
545  return;
546 
547  if (Asteroid_field.num_initial_asteroids <= 0 ) {
548  return;
549  }
550 
551  int max_asteroids = Asteroid_field.num_initial_asteroids; // * (1.0f - 0.1f*(MAX_DETAIL_LEVEL-Detail.asteroid_density)));
552 
553  int num_debris_types = 0;
554 
555  // get number of ship debris types
556  if (Asteroid_field.debris_genre == DG_SHIP) {
557  for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
558  if (Asteroid_field.field_debris_type[idx] != -1) {
559  num_debris_types++;
560  }
561  }
562 
563  // Calculate the odds table
564  for (idx=0; idx<num_debris_types; idx++) {
565  int debris_weight = get_debris_weight(Asteroid_field.field_debris_type[idx]);
566  ship_debris_odds_table[idx].random_threshold = max_weighted_range + debris_weight;
567  ship_debris_odds_table[idx].debris_type = Asteroid_field.field_debris_type[idx];
568  max_weighted_range += debris_weight;
569  }
570  }
571 
572  // Load Asteroid/ship models
573  if (Asteroid_field.debris_genre == DG_SHIP) {
574  for (idx=0; idx<num_debris_types; idx++) {
575  asteroid_load(Asteroid_field.field_debris_type[idx], 0);
576  }
577  } else {
578  if (Asteroid_field.field_debris_type[0] != -1) {
582  }
583 
584  if (Asteroid_field.field_debris_type[1] != -1) {
588  }
589 
590  if (Asteroid_field.field_debris_type[2] != -1) {
594  }
595  }
596 
597  // load all the asteroid/debris pieces
598  for (i=0; i<max_asteroids; i++) {
599  if (Asteroid_field.debris_genre == DG_ASTEROID) {
600  // For asteroid, load only large asteroids
601 
602  // get a valid subtype
603  int subtype = rand() % NUM_DEBRIS_POFS;
604  while (Asteroid_field.field_debris_type[subtype] == -1) {
605  subtype = (subtype + 1) % NUM_DEBRIS_POFS;
606  }
607 
608  asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
609  } else {
610  Assert(num_debris_types > 0);
611 
612  int rand_choice = rand() % max_weighted_range;
613 
614  for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
615  // for ship debris, choose type according to odds table
616  if (rand_choice < ship_debris_odds_table[idx].random_threshold) {
617  asteroid_create(&Asteroid_field, ship_debris_odds_table[idx].debris_type, 0);
618  break;
619  }
620  }
621  }
622  }
623 }
624 
629 {
630  Asteroid_field.num_initial_asteroids=0;
631  Num_asteroids = 0;
635  for (ast = Asteroid_info.begin(); ast != Asteroid_info.end(); ++ast)
636  ast->damage_type_idx = ast->damage_type_idx_sav;
637 }
638 
645 int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
646 {
647  if ( MULTIPLAYER_CLIENT )
648  return 0;
649 
650  if (objp->pos.xyz.x < asfieldp->min_bound.xyz.x) {
651  return 1;
652  }
653 
654  if (objp->pos.xyz.y < asfieldp->min_bound.xyz.y) {
655  return 1;
656  }
657 
658  if (objp->pos.xyz.z < asfieldp->min_bound.xyz.z) {
659  return 1;
660  }
661 
662  if (objp->pos.xyz.x > asfieldp->max_bound.xyz.x) {
663  return 1;
664  }
665 
666  if (objp->pos.xyz.y > asfieldp->max_bound.xyz.y) {
667  return 1;
668  }
669 
670  if (objp->pos.xyz.z > asfieldp->max_bound.xyz.z) {
671  return 1;
672  }
673 
674  // check against inner bound
675  if (asfieldp->has_inner_bound) {
676  if ( (objp->pos.xyz.x > asfieldp->inner_min_bound.xyz.x) && (objp->pos.xyz.x < asfieldp->inner_max_bound.xyz.x)
677  && (objp->pos.xyz.y > asfieldp->inner_min_bound.xyz.y) && (objp->pos.xyz.y < asfieldp->inner_max_bound.xyz.y)
678  && (objp->pos.xyz.z > asfieldp->inner_min_bound.xyz.z) && (objp->pos.xyz.z < asfieldp->inner_max_bound.xyz.z) ) {
679 
680  return 1;
681  }
682  }
683 
684  return 0;
685 }
686 
690 void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
691 {
692  if (objp->pos.xyz.x < asfieldp->min_bound.xyz.x) {
693  objp->pos.xyz.x = asfieldp->max_bound.xyz.x + (objp->pos.xyz.x - asfieldp->min_bound.xyz.x);
694  }
695 
696  if (objp->pos.xyz.y < asfieldp->min_bound.xyz.y) {
697  objp->pos.xyz.y = asfieldp->max_bound.xyz.y + (objp->pos.xyz.y - asfieldp->min_bound.xyz.y);
698  }
699 
700  if (objp->pos.xyz.z < asfieldp->min_bound.xyz.z) {
701  objp->pos.xyz.z = asfieldp->max_bound.xyz.z + (objp->pos.xyz.z - asfieldp->min_bound.xyz.z);
702  }
703 
704  if (objp->pos.xyz.x > asfieldp->max_bound.xyz.x) {
705  objp->pos.xyz.x = asfieldp->min_bound.xyz.x + (objp->pos.xyz.x - asfieldp->max_bound.xyz.x);
706  }
707 
708  if (objp->pos.xyz.y > asfieldp->max_bound.xyz.y) {
709  objp->pos.xyz.y = asfieldp->min_bound.xyz.y + (objp->pos.xyz.y - asfieldp->max_bound.xyz.y);
710  }
711 
712  if (objp->pos.xyz.z > asfieldp->max_bound.xyz.z) {
713  objp->pos.xyz.z = asfieldp->min_bound.xyz.z + (objp->pos.xyz.z - asfieldp->max_bound.xyz.z);
714  }
715 
716  // wrap on inner bound, check all 3 axes as needed, use of rand ok for multiplayer with send_asteroid_throw()
717  inner_bound_pos_fixup(asfieldp, &objp->pos);
718 
719 }
720 
721 
728 {
729  ship_obj *so;
730  object *ship_objp;
731  int asteroid_obj_index;
732 
733  asteroid_obj_index=OBJ_INDEX(objp);
734 
735  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
736  ship_objp = &Objects[so->objnum];
737  if ( Ai_info[Ships[ship_objp->instance].ai_index].target_objnum == asteroid_obj_index ) {
738  return 1;
739  }
740  }
741 
742  return 0;
743 }
744 
748 void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
749 {
750  vec3d predicted_center_pos;
751  vec3d rand_vec;
752  float speed;
753 
754  vm_vec_scale_add(&predicted_center_pos, &objp->pos, &objp->phys_info.vel, delta_time);
755  vm_vec_rand_vec_quick(&rand_vec);
756  vm_vec_scale_add2(&predicted_center_pos, &rand_vec, objp->radius/2.0f);
757 
758  vm_vec_add2(&rand_vec, &objp->orient.vec.fvec);
759  if (vm_vec_mag_quick(&rand_vec) < 0.1f)
760  vm_vec_add2(&rand_vec, &objp->orient.vec.rvec);
761  vm_vec_normalize(&rand_vec);
762 
763  speed = Asteroid_info[0].max_speed * (frand()/2.0f + 0.5f);
764 
765  vm_vec_copy_scale(&asteroid_objp->phys_info.vel, &rand_vec, -speed);
766  asteroid_objp->phys_info.desired_vel = asteroid_objp->phys_info.vel;
767  vm_vec_scale_add(&asteroid_objp->pos, &predicted_center_pos, &asteroid_objp->phys_info.vel, -delta_time);
768  vm_vec_scale_add(&asteroid_objp->last_pos, &asteroid_objp->pos, &asteroid_objp->phys_info.vel, -flFrametime);
769 }
770 
777 {
779  return;
780  }
781 
782  if (Asteroid_throw_objnum == -1) {
783  return;
784  }
785 
786  nprintf(("AI", "Incoming asteroids: %i\n", count));
787 
789  return;
790 
791  Next_asteroid_throw = timestamp(1000 + 1200 * count/(Game_skill_level+1));
792 
793  ship_obj *so;
794  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
795  object *A = &Objects[so->objnum];
796  if (so->objnum == Asteroid_throw_objnum) {
797  int subtype = rand() % NUM_DEBRIS_POFS;
798  while (Asteroid_field.field_debris_type[subtype] == -1) {
799  subtype = (subtype + 1) % NUM_DEBRIS_POFS;
800  }
801  object *objp = asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
802  if (objp != NULL) {
804 
805  // if asteroid is inside inner bound, kill it
806  if (asteroid_in_inner_bound(&Asteroid_field, &objp->pos, 0.0f)) {
807  objp->flags |= OF_SHOULD_BE_DEAD;
808  } else {
809  Asteroids[objp->instance].target_objnum = so->objnum;
810 
811  if ( MULTIPLAYER_MASTER ) {
812  send_asteroid_throw( objp );
813  }
814  }
815  }
816 
817  return;
818  }
819  }
820 
821 }
822 
826 void asteroid_delete( object * obj )
827 {
828  int num;
829  asteroid *asp;
830 
831  num = obj->instance;
832  Assert( Asteroids[num].objnum == OBJ_INDEX(obj));
833 
834  asp = &Asteroids[num];
835 
836  if (asp->model_instance_num >= 0)
838 
839  asp->flags = 0;
840  Num_asteroids--;
841  Assert(Num_asteroids >= 0);
842 
844 }
845 
851 {
852  // passive field does not wrap
853  if (asfieldp->field_type == FT_PASSIVE) {
854  return;
855  }
856 
857  if ( asteroid_should_wrap(objp, asfieldp) ) {
858  vec3d vec_to_asteroid, old_asteroid_pos, old_vel;
859  float dot, dist;
860 
861  old_asteroid_pos = objp->pos;
862  old_vel = objp->phys_info.vel;
863 
864  // don't wrap asteroid if it is a target of some ship
865  if ( !asteroid_is_targeted(objp) ) {
866 
867  // only wrap if player won't see asteroid disappear/reverse direction
868  dist = vm_vec_normalized_dir(&vec_to_asteroid, &objp->pos, &Eye_position);
869  dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
870 
871  if ( (dot < 0.7f) || (dist > asfieldp->bound_rad) ) {
872  if (Num_asteroids > MAX_ASTEROIDS-10) {
873  objp->flags |= OF_SHOULD_BE_DEAD;
874  } else {
875  // check to ensure player won't see asteroid appear either
876  asteroid_wrap_pos(objp, asfieldp);
877  Asteroids[objp->instance].target_objnum = -1;
878 
879  dist = vm_vec_normalized_dir(&vec_to_asteroid, &objp->pos, &Eye_position);
880  dot = vm_vec_dot(&Eye_matrix.vec.fvec, &vec_to_asteroid);
881 
882  if ( (dot > 0.7f) && (dist < (asfieldp->bound_rad * 1.3f)) ) {
883  // player would see asteroid pop out other side, so reverse velocity instead of wrapping
884  objp->pos = old_asteroid_pos;
885  vm_vec_copy_scale(&objp->phys_info.vel, &old_vel, -1.0f);
886  objp->phys_info.desired_vel = objp->phys_info.vel;
887  Asteroids[objp->instance].target_objnum = -1;
888  }
889 
890  // update last pos (after vel is known)
891  vm_vec_scale_add(&objp->last_pos, &objp->pos, &objp->phys_info.vel, -flFrametime);
892 
894 
895  if ( MULTIPLAYER_MASTER )
896  send_asteroid_throw( objp );
897  }
898  }
899  }
900  }
901 }
902 
903 void lerp(float *goal, float f1, float f2, float scale)
904 {
905  *goal = (f2 - f1) * scale + f1;
906 }
907 
908 void asteroid_process_pre( object *objp )
909 {
910  if (Asteroids_enabled) {
911  // Make vel chase desired_vel
912  lerp(&objp->phys_info.vel.xyz.x, objp->phys_info.vel.xyz.x, objp->phys_info.desired_vel.xyz.x, flFrametime);
913  lerp(&objp->phys_info.vel.xyz.y, objp->phys_info.vel.xyz.y, objp->phys_info.desired_vel.xyz.y, flFrametime);
914  lerp(&objp->phys_info.vel.xyz.z, objp->phys_info.vel.xyz.z, objp->phys_info.desired_vel.xyz.z, flFrametime);
915  }
916 }
917 
918 int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos, collision_info_struct *asteroid_hit_info)
919 {
920  if (!Asteroids_enabled) {
921  return 0;
922  }
923 
924  mc_info mc;
925  mc_info_init(&mc);
926  int num, asteroid_subtype;
927 
928  Assert( pasteroid->type == OBJ_ASTEROID );
929 
930  num = pasteroid->instance;
931  Assert( num >= 0 );
932 
933  Assert( Asteroids[num].objnum == OBJ_INDEX(pasteroid));
934  asteroid_subtype = Asteroids[num].asteroid_subtype;
935 
936  // asteroid_hit_info NULL -- asteroid-weapon collision
937  if ( asteroid_hit_info == NULL ) {
938  // asteroid weapon collision
939  Assert( other_obj->type == OBJ_WEAPON );
940  mc.model_instance_num = Asteroids[num].model_instance_num;
941  mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
943  mc.orient = &pasteroid->orient; // The object's orient
944  mc.pos = &pasteroid->pos; // The object's position
945  mc.p0 = &other_obj->last_pos; // Point 1 of ray to check
946  mc.p1 = &other_obj->pos; // Point 2 of ray to check
947  mc.flags = (MC_CHECK_MODEL);
948 
949  if (model_collide(&mc))
950  *hitpos = mc.hit_point_world;
951 
952  return mc.num_hits;
953  }
954 
955  // asteroid ship collision -- use asteroid_hit_info to calculate physics
956  object *pship_obj = other_obj;
957  Assert( pship_obj->type == OBJ_SHIP );
958 
959  object* heavy = asteroid_hit_info->heavy;
960  object* lighter = asteroid_hit_info->light;
961  object *heavy_obj = heavy;
962  object *light_obj = lighter;
963 
964  vec3d zero, p0, p1;
965  vm_vec_zero( &zero );
966  vm_vec_sub( &p0, &lighter->last_pos, &heavy->last_pos );
967  vm_vec_sub( &p1, &lighter->pos, &heavy->pos );
968 
969  mc.pos = &zero; // The object's position
970  mc.p0 = &p0; // Point 1 of ray to check
971  mc.p1 = &p1; // Point 2 of ray to check
972 
973  // find the light object's position in the heavy object's reference frame at last frame and also in this frame.
974  vec3d p0_temp, p0_rotated;
975 
976  // Collision detection from rotation enabled if at rotaion is less than 30 degree in frame
977  // This should account for all ships
978  if ( (vm_vec_mag_squared( &heavy->phys_info.rotvel ) * flFrametime*flFrametime) < (PI*PI/36) ) {
979  // collide_rotate calculate (1) start position and (2) relative velocity
980  asteroid_hit_info->collide_rotate = 1;
981  vm_vec_rotate( &p0_temp, &p0, &heavy->last_orient );
982  vm_vec_unrotate( &p0_rotated, &p0_temp, &heavy->orient );
983  mc.p0 = &p0_rotated; // Point 1 of ray to check
984  vm_vec_sub( &asteroid_hit_info->light_rel_vel, &p1, &p0_rotated );
985  vm_vec_scale( &asteroid_hit_info->light_rel_vel, 1/flFrametime );
986  // HACK - this applies to big ships warping in/out of asteroid fields - not sure what it does
987  if (vm_vec_mag(&asteroid_hit_info->light_rel_vel) > 300) {
988  asteroid_hit_info->collide_rotate = 0;
989  vm_vec_sub( &asteroid_hit_info->light_rel_vel, &lighter->phys_info.vel, &heavy->phys_info.vel );
990  }
991  } else {
992  asteroid_hit_info->collide_rotate = 0;
993  vm_vec_sub( &asteroid_hit_info->light_rel_vel, &lighter->phys_info.vel, &heavy->phys_info.vel );
994  }
995 
996  int mc_ret_val = 0;
997 
998  if ( asteroid_hit_info->heavy == pship_obj ) { // ship is heavier, so asteroid is sphere. Check sphere collision against ship poly model
1000  mc.model_num = Ship_info[Ships[pship_obj->instance].ship_info_index].model_num; // Fill in the model to check
1001  mc.orient = &pship_obj->orient; // The object's orient
1002  mc.radius = pasteroid->radius;
1004 
1005  // copy important data
1006  int copy_flags = mc.flags; // make a copy of start end positions of sphere in big ship RF
1007  vec3d copy_p0, copy_p1;
1008  copy_p0 = *mc.p0;
1009  copy_p1 = *mc.p1;
1010 
1011  // first test against the sphere - if this fails then don't do any submodel tests
1013 
1014  SCP_vector<int> submodel_vector;
1015  polymodel_instance *pmi;
1016 
1017  if (model_collide(&mc)) {
1018 
1019  // Set earliest hit time
1020  asteroid_hit_info->hit_time = FLT_MAX;
1021 
1022  // Do collision the cool new way
1023  if ( asteroid_hit_info->collide_rotate ) {
1024  // We collide with the sphere, find the list of rotating submodels and test one at a time
1025  model_get_rotating_submodel_list(&submodel_vector, heavy_obj);
1026 
1027  // Get polymodel and turn off all rotating submodels, collide against only 1 at a time.
1029 
1030  // turn off all rotating submodels and test for collision
1031  for (size_t j=0; j<submodel_vector.size(); j++) {
1032  pmi->submodel[submodel_vector[j]].collision_checked = true;
1033  }
1034 
1035  // reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
1036  mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
1037 
1038 
1039  // check each submodel in turn
1040  for (size_t i=0; i<submodel_vector.size(); i++) {
1041  // turn on submodel for collision test
1042  pmi->submodel[submodel_vector[i]].collision_checked = false;
1043 
1044  // set angles for last frame (need to set to prev to get p0)
1045  angles copy_angles = pmi->submodel[submodel_vector[i]].angs;
1046 
1047  // find the start and end positions of the sphere in submodel RF
1048  pmi->submodel[submodel_vector[i]].angs = pmi->submodel[submodel_vector[i]].prev_angs;
1049  world_find_model_instance_point(&p0, &light_obj->last_pos, pmi, submodel_vector[i], &heavy_obj->last_orient, &heavy_obj->last_pos);
1050 
1051  pmi->submodel[submodel_vector[i]].angs = copy_angles;
1052  world_find_model_instance_point(&p1, &light_obj->pos, pmi, submodel_vector[i], &heavy_obj->orient, &heavy_obj->pos);
1053 
1054  mc.p0 = &p0;
1055  mc.p1 = &p1;
1056 
1058  mc.submodel_num = submodel_vector[i];
1059 
1060  if ( model_collide(&mc) ) {
1061  if ( mc.hit_dist < asteroid_hit_info->hit_time ) {
1062  mc_ret_val = 1;
1063 
1064  // set up asteroid_hit_info common
1065  set_hit_struct_info(asteroid_hit_info, &mc, SUBMODEL_ROT_HIT);
1066 
1067  // set up asteroid_hit_info for rotating submodel
1068  if (asteroid_hit_info->edge_hit == 0) {
1069  model_instance_find_obj_dir(&asteroid_hit_info->collision_normal, &mc.hit_normal, Ships[heavy_obj->instance].model_instance_num, mc.hit_submodel, &heavy_obj->orient);
1070  }
1071 
1072  // find position in submodel RF of light object at collison
1073  vec3d int_light_pos, diff;
1074  vm_vec_sub(&diff, mc.p1, mc.p0);
1075  vm_vec_scale_add(&int_light_pos, mc.p0, &diff, mc.hit_dist);
1076  model_instance_find_world_point(&asteroid_hit_info->light_collision_cm_pos, &int_light_pos, mc.model_instance_num, mc.hit_submodel, &heavy_obj->orient, &zero);
1077  }
1078  }
1079  // Don't look at this submodel again
1080  pmi->submodel[submodel_vector[i]].collision_checked = true;
1081  }
1082 
1083  }
1084 
1085  // Recover and do usual ship_ship collision, but without rotating submodels
1086  mc.flags = copy_flags;
1087  *mc.p0 = copy_p0;
1088  *mc.p1 = copy_p1;
1089  mc.orient = &heavy_obj->orient;
1090 
1091  // usual ship_ship collision test
1092  if ( model_collide(&mc) ) {
1093  // check if this is the earliest hit
1094  if (mc.hit_dist < asteroid_hit_info->hit_time) {
1095  mc_ret_val = 1;
1096 
1097  set_hit_struct_info(asteroid_hit_info, &mc, SUBMODEL_NO_ROT_HIT);
1098 
1099  // get collision normal if not edge hit
1100  if (asteroid_hit_info->edge_hit == 0) {
1101  model_instance_find_obj_dir(&asteroid_hit_info->collision_normal, &mc.hit_normal, Ships[heavy_obj->instance].model_instance_num, mc.hit_submodel, &heavy_obj->orient);
1102  }
1103 
1104  // find position in submodel RF of light object at collison
1105  vec3d diff;
1106  vm_vec_sub(&diff, mc.p1, mc.p0);
1107  vm_vec_scale_add(&asteroid_hit_info->light_collision_cm_pos, mc.p0, &diff, mc.hit_dist);
1108 
1109  }
1110  }
1111  }
1112 
1113  } else {
1114  // Asteroid is heavier obj
1115  mc.model_instance_num = Asteroids[num].model_instance_num;
1116  mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
1118  mc.orient = &pasteroid->orient; // The object's orient
1119  mc.radius = model_get_core_radius(Ship_info[Ships[pship_obj->instance].ship_info_index].model_num);
1120 
1121  // check for collision between asteroid model and ship sphere
1123 
1124  mc_ret_val = model_collide(&mc);
1125 
1126  if (mc_ret_val) {
1127  set_hit_struct_info(asteroid_hit_info, &mc, SUBMODEL_NO_ROT_HIT);
1128 
1129  // set normal if not edge hit
1130  if ( !asteroid_hit_info->edge_hit ) {
1131  vm_vec_unrotate(&asteroid_hit_info->collision_normal, &mc.hit_normal, &heavy->orient);
1132  }
1133 
1134  // find position in submodel RF of light object at collison
1135  vec3d diff;
1136  vm_vec_sub(&diff, mc.p1, mc.p0);
1137  vm_vec_scale_add(&asteroid_hit_info->light_collision_cm_pos, mc.p0, &diff, mc.hit_dist);
1138 
1139  }
1140  }
1141 
1142 
1143  if ( mc_ret_val ) {
1144 
1145  // SET PHYSICS PARAMETERS
1146  // already have (hitpos - heavy) and light_cm_pos
1147  // get heavy cm pos - already have light_cm_pos
1148  asteroid_hit_info->heavy_collision_cm_pos = zero;
1149 
1150  // get r_heavy and r_light
1151  asteroid_hit_info->r_heavy = asteroid_hit_info->hit_pos;
1152  vm_vec_sub(&asteroid_hit_info->r_light, &asteroid_hit_info->hit_pos, &asteroid_hit_info->light_collision_cm_pos);
1153 
1154  // set normal for edge hit
1155  if ( asteroid_hit_info->edge_hit ) {
1156  vm_vec_copy_normalize(&asteroid_hit_info->collision_normal, &asteroid_hit_info->r_light);
1157  vm_vec_negate(&asteroid_hit_info->collision_normal);
1158  }
1159 
1160  // get world hitpos
1161  vm_vec_add(hitpos, &asteroid_hit_info->heavy->pos, &asteroid_hit_info->r_heavy);
1162 
1163  return 1;
1164  } else {
1165  // no hit
1166  return 0;
1167  }
1168 }
1169 
1171 {
1172  if (Asteroids_enabled) {
1173  int num;
1174  asteroid *asp;
1175 
1176  num = obj->instance;
1177 
1178  Assert((num >= 0) && (num < MAX_ASTEROIDS));
1179  asp = &Asteroids[num];
1180 
1181  Assert( asp->flags & AF_USED );
1182 
1183  model_clear_instance( Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype]);
1184 
1185  model_render_DEPRECATED(Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype], &obj->orient, &obj->pos, MR_DEPRECATED_NORMAL|MR_DEPRECATED_IS_ASTEROID, OBJ_INDEX(obj) ); // Replace MR_NORMAL with 0x07 for big yellow blobs
1186  }
1187 }
1188 
1189 void asteroid_render(object * obj, draw_list *scene)
1190 {
1191  if (Asteroids_enabled) {
1192  int num;
1193  asteroid *asp;
1194 
1195  num = obj->instance;
1196 
1197  Assert((num >= 0) && (num < MAX_ASTEROIDS));
1198  asp = &Asteroids[num];
1199 
1200  Assert( asp->flags & AF_USED );
1201 
1202  model_clear_instance( Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype]);
1203 
1204  model_render_params render_info;
1205 
1206  render_info.set_object_number( OBJ_INDEX(obj) );
1207  render_info.set_flags(MR_IS_ASTEROID);
1208 
1209  model_render_queue(&render_info, scene, Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype], &obj->orient, &obj->pos); // Replace MR_NORMAL with 0x07 for big yellow blobs
1210  }
1211 }
1212 
1216 void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
1217 {
1218  vec3d tvec, rand_vec;
1219  int count = 0;
1220 
1221  vm_vec_normalized_dir(&tvec, &other_obj->pos, hitpos);
1222 
1223  // Try up to three times to get a good vector.
1224  while (count++ < 3) {
1225  vm_vec_rand_vec_quick(&rand_vec);
1226  vm_vec_add(relvec, &tvec, &rand_vec);
1227  float mag = vm_vec_mag_quick(relvec);
1228  if ((mag > 0.2f) && (mag < 1.7f))
1229  break;
1230  }
1231 
1232  vm_vec_normalize_quick(relvec);
1233 }
1234 
1239 {
1240  if (Asteroids[num].flags & AF_USED) {
1241  asteroid_info *asip = &Asteroid_info[Asteroids[num].asteroid_type];
1242 
1243  if (asip->fireball_radius_multiplier >= 0) {
1244  return asip->fireball_radius_multiplier;
1245  } else {
1246  switch(Asteroids[num].asteroid_type) {
1247  case ASTEROID_TYPE_LARGE:
1248  return 1.5f;
1249  break;
1250 
1251  default:
1252  return 1.0f;
1253  break;
1254  }
1255  }
1256  }
1257 
1258  Int3(); // this should not happen. asteroid should be used.
1259  return 1.0f;
1260 }
1261 
1262 
1268 {
1269  int fireball_objnum;
1270  float explosion_life, fireball_scale_multiplier;
1271  asteroid_info *asip = &Asteroid_info[Asteroids[objp->instance].asteroid_type];
1272 
1273  int fireball_type = fireball_asteroid_explosion_type(asip);
1274  if (fireball_type < 0) {
1275  fireball_type = FIREBALL_ASTEROID;
1276  }
1277 
1278  if (fireball_type >= Num_fireball_types) {
1279  Warning(LOCATION, "Invalid fireball type %i specified for an asteroid, only %i fireball types are defined.", fireball_type, Num_fireball_types);
1280 
1281  return 0;
1282  }
1283 
1284  fireball_scale_multiplier = asteroid_get_fireball_scale_multiplier(objp->instance);
1285 
1286  fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), objp->radius*fireball_scale_multiplier, 0, &objp->phys_info.vel );
1287  if ( fireball_objnum > -1 ) {
1288  explosion_life = fireball_lifeleft(&Objects[fireball_objnum]);
1289  } else {
1290  explosion_life = 0.0f;
1291  }
1292 
1293  return explosion_life;
1294 }
1295 
1299 void asteriod_explode_sound(object *objp, int type, int play_loud)
1300 {
1301  int sound_index = -1;
1302  float range_factor = 1.0f; // how many times sound should traver farther than normal
1303 
1304  if (type % NUM_DEBRIS_SIZES <= 1)
1305  {
1306  sound_index = SND_ASTEROID_EXPLODE_SMALL;
1307  range_factor = 5.0;
1308  }
1309  else
1310  {
1311  sound_index = SND_ASTEROID_EXPLODE_LARGE;
1312  range_factor = 10.0f;
1313  }
1314 
1315  Assert(sound_index != -1);
1316 
1317  if ( !play_loud ) {
1318  range_factor = 1.0f;
1319  }
1320 
1321  snd_play_3d( &Snds[sound_index], &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
1322 }
1323 
1329 void asteroid_do_area_effect(object *asteroid_objp)
1330 {
1331  object *ship_objp;
1332  float damage, blast;
1333  ship_obj *so;
1334  asteroid *asp;
1335  asteroid_info *asip;
1336 
1337  asp = &Asteroids[asteroid_objp->instance];
1338  asip = &Asteroid_info[asp->asteroid_type];
1339 
1340  if ( asip->damage <= 0 ) { // do a quick out if there is no damage to apply
1341  return;
1342  }
1343 
1344  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1345  ship_objp = &Objects[so->objnum];
1346 
1347  // don't blast navbuoys
1348  if ( ship_get_SIF(ship_objp->instance) & SIF_NAVBUOY ) {
1349  continue;
1350  }
1351 
1352  if ( weapon_area_calc_damage(ship_objp, &asteroid_objp->pos, asip->inner_rad, asip->outer_rad, asip->blast, asip->damage, &blast, &damage, asip->outer_rad) == -1 )
1353  continue;
1354 
1355  ship_apply_global_damage(ship_objp, asteroid_objp, &asteroid_objp->pos, damage );
1356  weapon_area_apply_blast(NULL, ship_objp, &asteroid_objp->pos, blast, 0);
1357  } // end for
1358 }
1359 
1368 void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, float damage )
1369 {
1370  float explosion_life;
1371  asteroid *asp;
1372 
1373  asp = &Asteroids[pasteroid_obj->instance];
1374 
1375  if (pasteroid_obj->flags & OF_SHOULD_BE_DEAD){
1376  return;
1377  }
1378 
1379  if ( MULTIPLAYER_MASTER ){
1380  send_asteroid_hit( pasteroid_obj, other_obj, hitpos, damage );
1381  }
1382 
1383  pasteroid_obj->hull_strength -= damage;
1384 
1385  if (pasteroid_obj->hull_strength < 0.0f) {
1386  if ( asp->final_death_time <= 0 ) {
1387  int play_loud_collision = 0;
1388 
1389  explosion_life = asteroid_create_explosion(pasteroid_obj);
1390 
1391  asteriod_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
1392  asteroid_do_area_effect(pasteroid_obj);
1393 
1394  asp->final_death_time = timestamp( fl2i(explosion_life*1000.0f)/5 ); // Wait till 30% of vclip time before breaking the asteroid up.
1395  if ( hitpos ) {
1396  asp->death_hit_pos = *hitpos;
1397  } else {
1398  asp->death_hit_pos = pasteroid_obj->pos;
1399  // randomize hit pos a bit, otherwise we will get a NULL vector when trying to find direction to toss child asteroids
1400  vec3d rand_vec;
1401  vm_vec_rand_vec_quick(&rand_vec);
1402  vm_vec_add2(&asp->death_hit_pos, &rand_vec);
1403  }
1404  }
1405  } else if ( other_obj ) {
1406  if ( other_obj->type == OBJ_WEAPON ) {
1407  weapon_info *wip;
1408  wip = &Weapon_info[Weapons[other_obj->instance].weapon_info_index];
1409  // If the weapon didn't play any impact animation, play custom asteroid impact animation
1410  if ( wip->impact_weapon_expl_index < 0 ) {
1411  particle_create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, PARTICLE_BITMAP, Asteroid_impact_explosion_ani );
1412  }
1413  }
1414  }
1415 
1416  // evaluate any relevant player scoring implications
1417  scoring_eval_hit(pasteroid_obj,other_obj);
1418 }
1419 
1424 {
1425  int i;
1426 
1427  for (i=0; i<MAX_ASTEROIDS; i++) {
1428  if (Asteroids[i].flags & AF_USED) {
1429  Asteroids[i].flags &= ~AF_USED;
1430  Assert(Asteroids[i].objnum >=0 && Asteroids[i].objnum < MAX_OBJECTS);
1431  Objects[Asteroids[i].objnum].flags |= OF_SHOULD_BE_DEAD;
1432  }
1433  }
1434 
1435  Asteroid_field.num_initial_asteroids=0;
1436 }
1437 
1438 DCF_BOOL2(asteroids, Asteroids_enabled, "enables or disables asteroids", "Usage: asteroids [bool]\nTurns asteroid system on/off. If nothing passed, then toggles it.\n");
1439 
1440 
1442 {
1443  int i;
1444  int start_index = 0, end_index = MAX_ASTEROIDS;
1445 
1446  if (Player_ai->target_objnum != -1) {
1448  start_index = Objects[Player_ai->target_objnum].instance+1;
1449  end_index = start_index-1;
1450  if (end_index < 0)
1451  end_index = MAX_ASTEROIDS;
1452  }
1453  }
1454 
1455  i = start_index;
1456  while (i != end_index) {
1457  if (i == MAX_ASTEROIDS)
1458  i = 0;
1459 
1460  if (Asteroids[i].flags & AF_USED) {
1461  Assert(Objects[Asteroids[i].objnum].type == OBJ_ASTEROID);
1462  set_target_objnum( Player_ai, Asteroids[i].objnum);
1463  break;
1464  }
1465 
1466  i++;
1467  }
1468 }
1469 
1474 {
1475  return Num_asteroids;
1476 }
1477 
1482 void asteroid_maybe_break_up(object *pasteroid_obj)
1483 {
1484  asteroid *asp;
1485  asteroid_info *asip;
1486 
1487  asp = &Asteroids[pasteroid_obj->instance];
1488  asip = &Asteroid_info[asp->asteroid_type];
1489 
1490  if ( timestamp_elapsed(asp->final_death_time) ) {
1491  vec3d relvec, vfh, tvec;
1492 
1493  Script_system.SetHookObject("Self", pasteroid_obj);
1494  if(!Script_system.IsConditionOverride(CHA_DEATH, pasteroid_obj))
1495  {
1496  pasteroid_obj->flags |= OF_SHOULD_BE_DEAD;
1497 
1498  // multiplayer clients won't go through the following code. asteroid_sub_create will send
1499  // a create packet to the client in the above named function
1500  // if the second condition isn't true it's just debris, and debris doesn't break up
1502  if (asip->split_info.empty()) {
1503  switch (asp->asteroid_type) {
1504  case ASTEROID_TYPE_SMALL:
1505  break;
1506  case ASTEROID_TYPE_MEDIUM:
1507  asc_get_relvec(&relvec, pasteroid_obj, &asp->death_hit_pos);
1508  asteroid_sub_create(pasteroid_obj, ASTEROID_TYPE_SMALL, &relvec);
1509 
1510  vm_vec_normalized_dir(&vfh, &pasteroid_obj->pos, &asp->death_hit_pos);
1511  vm_vec_copy_scale(&tvec, &vfh, 2.0f);
1512  vm_vec_sub2(&tvec, &relvec);
1513  asteroid_sub_create(pasteroid_obj, ASTEROID_TYPE_SMALL, &tvec);
1514 
1515  break;
1516  case ASTEROID_TYPE_LARGE:
1517  asc_get_relvec(&relvec, pasteroid_obj, &asp->death_hit_pos);
1518  asteroid_sub_create(pasteroid_obj, ASTEROID_TYPE_MEDIUM, &relvec);
1519 
1520  vm_vec_normalized_dir(&vfh, &pasteroid_obj->pos, &asp->death_hit_pos);
1521  vm_vec_copy_scale(&tvec, &vfh, 2.0f);
1522  vm_vec_sub2(&tvec, &relvec);
1523  asteroid_sub_create(pasteroid_obj, ASTEROID_TYPE_MEDIUM, &tvec);
1524 
1525  while (frand() > 0.6f) {
1526  vec3d rvec, tvec2;
1527  vm_vec_rand_vec_quick(&rvec);
1528  vm_vec_scale_add(&tvec2, &vfh, &rvec, 0.75f);
1529  asteroid_sub_create(pasteroid_obj, ASTEROID_TYPE_SMALL, &tvec2);
1530  }
1531  break;
1532 
1533  default: // this isn't going to happen.. really
1534  break;
1535  }
1536  } else {
1537  SCP_vector<int> roids_to_create;
1539  for (split = asip->split_info.begin(); split != asip->split_info.end(); ++split) {
1540  int num_roids = split->min;
1541  int num_roids_var = split->max - split->min;
1542 
1543  if (num_roids_var > 0)
1544  num_roids += rand() % num_roids_var;
1545 
1546  if (num_roids > 0)
1547  for (int i=0; i<num_roids; i++)
1548  roids_to_create.push_back(split->asteroid_type);
1549  }
1550 
1551  random_shuffle(roids_to_create.begin(), roids_to_create.end());
1552 
1553  int total_roids = roids_to_create.size();
1554  for (int i = 0; i < total_roids; i++) {
1555  vec3d dir_vec,final_vec;
1556  vec3d parent_vel,hit_rel_vec;
1557 
1558  // The roid directions are picked from the so-called
1559  // "golden section spiral" to prevent them from
1560  // clustering and thus clipping
1561 
1562  float inc = PI * (3.0f - sqrt(5.0f));
1563  float offset = 2.0f / total_roids;
1564 
1565  float y = i * offset - 1 + (offset / 2);
1566  float r = sqrt(1.0f - y*y);
1567  float phi = i * inc;
1568 
1569  dir_vec.xyz.x = cosf(phi)*r;
1570  dir_vec.xyz.y = sinf(phi)*r;
1571  dir_vec.xyz.z = y;
1572 
1573  // Randomize the direction a bit
1574  vec3d tempv = dir_vec;
1575  vm_vec_random_cone(&dir_vec, &tempv, (360.0f / total_roids / 2));
1576 
1577  // Make the roid inherit half of the parent's velocity
1578  vm_vec_copy_normalize(&parent_vel, &pasteroid_obj->phys_info.vel);
1579  vm_vec_scale(&parent_vel, 0.5f);
1580 
1581  // Make the hit position affect the direction, but only a little
1582  vm_vec_sub(&hit_rel_vec, &pasteroid_obj->pos, &asp->death_hit_pos);
1583  vm_vec_normalize(&hit_rel_vec);
1584  vm_vec_scale(&hit_rel_vec, 0.25f);
1585 
1586  vm_vec_avg3(&final_vec, &parent_vel, &hit_rel_vec, &dir_vec);
1587  vm_vec_normalize(&final_vec);
1588 
1589  asteroid_sub_create(pasteroid_obj, roids_to_create[i], &final_vec);
1590  }
1591  }
1592  }
1593  asp->final_death_time = timestamp(-1);
1594  }
1595  Script_system.RunCondition(CHA_DEATH, '\0', NULL, pasteroid_obj);
1596  Script_system.RemHookVar("Self");
1597  }
1598 }
1599 
1600 int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger)
1601 {
1602  int idx;
1603  vec3d asteroid_dir;
1604 
1605  // just pick the first asteroid which satisfies our condition
1606  for(idx=0; idx<Num_asteroids; idx++){
1607  vm_vec_sub(&asteroid_dir, &Objects[Asteroids[idx].objnum].pos, pos);
1608  vm_vec_normalize_quick(&asteroid_dir);
1609 
1610  // if it satisfies the condition
1611  if(vm_vec_dot(dir, &asteroid_dir) >= ang){
1612  return idx;
1613  }
1614  }
1615 
1616  return -1;
1617 }
1618 
1619 void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy = false)
1620 {
1621  float asteroid_ray_dist;
1622  vec3d asteroid_fvec, terminus;
1623 
1624  // See if ray from asteroid intersects bounding box of escort ship
1625  asteroid_ray_dist = vm_vec_mag_quick(&pasteroid_obj->phys_info.desired_vel) * ASTEROID_MIN_COLLIDE_TIME;
1626  asteroid_fvec = pasteroid_obj->phys_info.desired_vel;
1627 
1628  if(IS_VEC_NULL_SQ_SAFE(&asteroid_fvec)){
1629  terminus = pasteroid_obj->pos;
1630  } else {
1631  vm_vec_normalize(&asteroid_fvec);
1632  vm_vec_scale_add(&terminus, &pasteroid_obj->pos, &asteroid_fvec, asteroid_ray_dist);
1633  }
1634 
1635  Assert(pship_obj->type == OBJ_SHIP);
1636 
1638  mc->model_num = Ship_info[Ships[pship_obj->instance].ship_info_index].model_num; // Fill in the model to check
1639  mc->orient = &pship_obj->orient; // The object's orientation
1640  mc->pos = &pship_obj->pos; // The object's position
1641  mc->p0 = &pasteroid_obj->pos; // Point 1 of ray to check
1642  mc->p1 = &terminus; // Point 2 of ray to check
1643  if (lazy) {
1645  } else {
1647  }
1648  mc->radius = pasteroid_obj->radius;
1649 
1650  model_collide(mc);
1651 
1652  // PVS-Studio says that mc->p1 will become invalid... on the one hand, it will; on the other hand, we won't use it again; on the *other* other hand, we should keep things proper in case of future changes
1653  mc->p1 = NULL;
1654 }
1655 
1661 int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
1662 {
1663  mc_info mc;
1664  mc_info_init(&mc);
1665 
1666  asteroid_test_collide(pasteroid_obj, escort_objp, &mc);
1667 
1668  if ( !mc.num_hits ) {
1669  return 0;
1670  }
1671 
1672  return 1;
1673 }
1674 
1680 {
1681  if ( !(Ship_info[shipp->ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
1682  return 0;
1683  }
1684 
1685  if ( shipp->flags & (SF_DYING|SF_DEPART_WARP) ) {
1686  return 0;
1687  }
1688 
1689  // Goober5000 used to be if teams were unequal and player was not traitor, but this works for allies not on your team
1690  if ( iff_x_attacks_y(Player_ship->team, shipp->team) ) {
1691  return 0;
1692  }
1693 
1694  return 1;
1695 }
1696 
1701 void asteroid_update_collide_flag(object *asteroid_objp)
1702 {
1703  int i, num_escorts, escort_objnum, will_collide=0;
1704  ship *escort_shipp;
1705  asteroid *asp;
1706 
1707  asp = &Asteroids[asteroid_objp->instance];
1708  asp->collide_objnum = -1;
1709  asp->collide_objsig = -1;
1710 
1711  // multiplayer dogfight
1712  if(MULTI_DOGFIGHT){
1713  return;
1714  }
1715 
1716  num_escorts = hud_escort_num_ships_on_list();
1717 
1718  if ( num_escorts <= 0 ) {
1719  return;
1720  }
1721 
1722  for ( i = 0; i < num_escorts; i++ ) {
1723  escort_objnum = hud_escort_return_objnum(i);
1724  if ( escort_objnum >= 0 ) {
1725  escort_shipp = &Ships[Objects[escort_objnum].instance];
1726  if ( asteroid_valid_ship_to_warn_collide(escort_shipp) ) {
1727  will_collide = asteroid_will_collide(asteroid_objp, &Objects[escort_objnum]);
1728  if ( will_collide ) {
1729  asp->collide_objnum = escort_objnum;
1730  asp->collide_objsig = Objects[escort_objnum].signature;
1731  }
1732  }
1733  }
1734  }
1735 }
1736 
1741 {
1742  if ( asp->collide_objnum >= 0 ) {
1743  if ( Objects[asp->collide_objnum].signature != asp->collide_objsig ) {
1744  asp->collide_objnum = -1;
1745  asp->collide_objsig = -1;
1746  }
1747  }
1748 }
1749 
1751 {
1752  if (Asteroids_enabled) {
1753  int num;
1754  num = obj->instance;
1755 
1756  asteroid *asp = &Asteroids[num];
1757 
1758  // Only wrap if active field
1759  if (Asteroid_field.field_type == FT_ACTIVE) {
1760  if ( timestamp_elapsed(asp->check_for_wrap) ) {
1761  asteroid_maybe_reposition(obj, &Asteroid_field);
1763  }
1764  }
1765 
1767 
1768  if ( timestamp_elapsed(asp->check_for_collide) ) {
1771  }
1772 
1774  }
1775 }
1776 
1781 int asteroid_collide_objnum(object *asteroid_objp)
1782 {
1783  return Asteroids[asteroid_objp->instance].collide_objnum;
1784 }
1785 
1790 float asteroid_time_to_impact(object *asteroid_objp)
1791 {
1792  float time=-1.0f, total_dist, speed;
1793  asteroid *asp;
1794  mc_info mc;
1795  mc_info_init(&mc);
1796 
1797  asp = &Asteroids[asteroid_objp->instance];
1798 
1799  if ( asp->collide_objnum < 0 ) {
1800  return time;
1801  }
1802 
1803  asteroid_test_collide(asteroid_objp, &Objects[asp->collide_objnum], &mc, true);
1804 
1805  if ( mc.num_hits ) {
1806  total_dist = vm_vec_dist(&mc.hit_point_world, &asteroid_objp->pos) - asteroid_objp->radius;
1807  if ( total_dist < 0 ) {
1808  total_dist = 0.0f;
1809  }
1810  speed = vm_vec_mag(&asteroid_objp->phys_info.vel);
1811  time = total_dist/speed;
1812  }
1813 
1814  return time;
1815 }
1816 
1821 {
1822  required_string("$Name:");
1824 
1825  required_string( "$POF file1:" );
1827 
1828  required_string( "$POF file2:" );
1830 
1831  if ( (stristr(asip->name, "Asteroid") != NULL) ) {
1832  required_string( "$POF file3:" );
1834  }
1835 
1836  required_string("$Detail distance:");
1838 
1839  required_string("$Max Speed:");
1840  stuff_float(&asip->max_speed);
1841 
1842  if(optional_string("$Damage Type:")) {
1843  char buf[NAME_LENGTH];
1845  asip->damage_type_idx_sav = damage_type_add(buf);
1846  asip->damage_type_idx = asip->damage_type_idx_sav;
1847  }
1848 
1849  if(optional_string("$Explosion Animations:")){
1850  int temp[MAX_FIREBALL_TYPES];
1851  int parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
1852  asip->explosion_bitmap_anims.clear();
1853  asip->explosion_bitmap_anims.insert(asip->explosion_bitmap_anims.begin(), temp, temp+parsed_ints);
1854  }
1855 
1856  if(optional_string("$Explosion Radius Mult:"))
1858 
1859  required_string("$Expl inner rad:");
1860  stuff_float(&asip->inner_rad);
1861 
1862  required_string("$Expl outer rad:");
1863  stuff_float(&asip->outer_rad);
1864 
1865  required_string("$Expl damage:");
1866  stuff_float(&asip->damage);
1867 
1868  required_string("$Expl blast:");
1869  stuff_float(&asip->blast);
1870 
1871  required_string("$Hitpoints:");
1873 
1874  while(optional_string("$Split:")) {
1875  int split_type;
1876 
1877  stuff_int(&split_type);
1878 
1879  if (split_type>=0 && split_type<NUM_DEBRIS_SIZES) {
1880  asteroid_split_info new_split;
1881 
1882  new_split.asteroid_type = split_type;
1883 
1884  if(optional_string("+Min:"))
1885  stuff_int(&new_split.min);
1886  else
1887  new_split.min = 0;
1888 
1889  if(optional_string("+Max:"))
1890  stuff_int(&new_split.max);
1891  else
1892  new_split.max = 0;
1893 
1894  asip->split_info.push_back( new_split );
1895  } else
1896  Warning(LOCATION, "Invalid asteroid reference %i used for $Split in asteroids table, ignoring.", split_type);
1897  }
1898 }
1899 
1921 {
1922  char impact_ani_file[MAX_FILENAME_LEN];
1923 
1924  // How did we get here without having any species defined?
1925  Assertion(Species_info.size() > 0,
1926  "Cannot parse asteroids/debris if there "
1927  "are no species for them to belong to."
1928  );
1929 
1930  try
1931  {
1932  read_file_text("asteroid.tbl", CF_TYPE_TABLES);
1933  reset_parse();
1934 
1935  required_string("#Asteroid Types");
1936 
1937  int tally = 0;
1938  int max_asteroids =
1940 
1941 #ifndef NDEBUG
1942  SCP_vector<SCP_string> parsed_asteroids;
1943 #endif
1944 
1945  // parse and tally each asteroid
1946  while (required_string_either("#End", "$Name:"))
1947  {
1948  asteroid_info new_asteroid;
1949 
1950  asteroid_parse_section(&new_asteroid);
1951 
1952  int species = tally / NUM_DEBRIS_SIZES;
1953  if (tally >= max_asteroids)
1954  {
1955 #ifdef NDEBUG
1956  // Bump the warning count in release so they get something
1957  // even if the message never gets displayed.
1958  Warning(LOCATION, "Ignoring extra asteroid/debris");
1959 #else
1960  SCP_string msg("Ignoring extra asteroid/debris '");
1961  msg.append(new_asteroid.name);
1962  msg.append("'\n");
1963  Warning(LOCATION, "%s", msg.c_str());
1964  parsed_asteroids.push_back(msg);
1965 #endif
1966  }
1967  else
1968  {
1969 #ifndef NDEBUG
1970  SCP_string msg;
1971  msg.append("Parsing asteroid: '");
1972  msg.append(new_asteroid.name);
1973  msg.append("' as a '");
1974  msg.append((species == 0) ? "generic" : Species_info[species - 1].species_name);
1975  msg.append("'");
1976  switch (tally % NUM_DEBRIS_SIZES) {
1977  case ASTEROID_TYPE_SMALL:
1978  msg.append(" small\n");
1979  break;
1980  case ASTEROID_TYPE_MEDIUM:
1981  msg.append(" medium\n");
1982  break;
1983  case ASTEROID_TYPE_LARGE:
1984  msg.append(" large\n");
1985  break;
1986  default:
1987  Error(LOCATION, "Get a coder! Math has broken!\n"
1988  "Important numbers:\n"
1989  "\ttally: %d\n"
1990  "\tNUM_DEBRIS_SIZES: %d\n",
1991  tally, NUM_DEBRIS_SIZES
1992  );
1993  msg.append(" unknown\n");
1994  }
1995  parsed_asteroids.push_back(msg);
1996 #endif
1997  Asteroid_info.push_back(new_asteroid);
1998  }
1999  tally++;
2000  }
2001  required_string("#End");
2002 
2003  if (tally != max_asteroids)
2004  {
2005 #ifndef NDEBUG
2006  for (SCP_vector<SCP_string>::iterator iter = parsed_asteroids.begin();
2007  iter != parsed_asteroids.end(); ++iter)
2008  {
2009  mprintf(("Asteroid.tbl as parsed:\n"));
2010  mprintf(("%s", iter->c_str()));
2011  }
2012 #endif
2013  Error(LOCATION,
2014  "Found %d asteroids/debris when %d expected\n\n"
2015  "<Number expected> = <Number of species> * %d + %d generic asteroids\n"
2016  "%d = " SIZE_T_ARG "*%d + %d\n\n"
2017 #ifdef NDEBUG
2018  "Run a debug build to see a list of all parsed asteroids\n",
2019 #else
2020  "See the debug.log for a listing of all parsed asteroids\n",
2021 #endif
2022  tally, max_asteroids,
2024  max_asteroids, Species_info.size(), NUM_DEBRIS_SIZES, NUM_DEBRIS_SIZES
2025  );
2026  }
2027 
2028  Asteroid_impact_explosion_ani = -1;
2029  required_string("$Impact Explosion:");
2030  stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
2031 
2032  if (VALID_FNAME(impact_ani_file)) {
2033  int num_frames;
2034  Asteroid_impact_explosion_ani = bm_load_animation(impact_ani_file, &num_frames, NULL, NULL, 1);
2035  }
2036 
2037  required_string("$Impact Explosion Radius:");
2038  stuff_float(&Asteroid_impact_explosion_radius);
2039 
2040  if (optional_string("$Briefing Icon Closeup Model:")) {
2042  }
2043  else {
2044  strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].pof_files[0]); // magic file from retail
2045  }
2046 
2047  if (optional_string("$Briefing Icon Closeup Position:")) {
2048  stuff_vec3d(&Asteroid_icon_closeup_position);
2049  }
2050  else {
2051  vm_vec_make(&Asteroid_icon_closeup_position, 0.0f, 0.0f, -334.0f); // magic numbers from retail
2052  }
2053 
2054  if (optional_string("$Briefing Icon Closeup Zoom:")) {
2056  }
2057  else {
2058  Asteroid_icon_closeup_zoom = 0.5f; // magic number from retail
2059  }
2060  }
2061  catch (const parse::ParseException& e)
2062  {
2063  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "asteroid.tbl", e.what()));
2064  return;
2065  }
2066 }
2067 
2072 {
2073  object *asteroid_objp;
2074  int count;
2075 
2076  count = 0;
2077 
2078  for ( asteroid_objp = GET_FIRST(&obj_used_list); asteroid_objp !=END_OF_LIST(&obj_used_list); asteroid_objp = GET_NEXT(asteroid_objp) ) {
2079  if (asteroid_objp->type == OBJ_ASTEROID ) {
2080  asteroid *asp = &Asteroids[asteroid_objp->instance];
2081 
2082  if ( asp->target_objnum >= 0 ) {
2083  count++;
2084  }
2085  }
2086  }
2087 
2088  return count;
2089 }
2090 
2096 {
2097  if (Asteroid_field.num_initial_asteroids < 1)
2098  return -1;
2099 
2100  ship_obj *so;
2101  object *ship_objp;
2102 
2103  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
2104  ship_objp = &Objects[so->objnum];
2105  float radius = ship_objp->radius*2.0f;
2106 
2107  if (Ship_info[Ships[ship_objp->instance].ship_info_index].flags & (SIF_HUGE_SHIP | SIF_BIG_SHIP)) {
2108  if (ship_objp->pos.xyz.x + radius > Asteroid_field.min_bound.xyz.x)
2109  if (ship_objp->pos.xyz.y + radius > Asteroid_field.min_bound.xyz.y)
2110  if (ship_objp->pos.xyz.z + radius > Asteroid_field.min_bound.xyz.z)
2111  if (ship_objp->pos.xyz.x - radius < Asteroid_field.max_bound.xyz.x)
2112  if (ship_objp->pos.xyz.y - radius < Asteroid_field.max_bound.xyz.y)
2113  if (ship_objp->pos.xyz.z - radius < Asteroid_field.max_bound.xyz.z)
2114  if (!asteroid_in_inner_bound(&Asteroid_field, &ship_objp->pos, radius))
2115  return so->objnum;
2116  }
2117  }
2118  return -1;
2119 
2120 }
2121 
2123 {
2124  if (Num_asteroids < 1)
2125  return;
2126 
2127  // Only throw if active field
2128  if (Asteroid_field.field_type == FT_PASSIVE) {
2129  return;
2130  }
2131 
2133 
2135 }
2136 
2141 {
2143 }
2144 
2145 extern int Cmdline_targetinfo;
2146 
2151 {
2152  vertex asteroid_vertex;
2153  object *asteroid_objp, *player_target;
2154  asteroid *asp;
2155 
2156  // get pointer to player target, so we don't need to take OBJ_INDEX() of asteroid_objp to compare to target_objnum
2157  if ( Player_ai->target_objnum >= 0 ) {
2158  player_target = &Objects[Player_ai->target_objnum];
2159  } else {
2160  player_target = NULL;
2161  }
2162 
2163  for ( asteroid_objp = GET_FIRST(&obj_used_list); asteroid_objp !=END_OF_LIST(&obj_used_list); asteroid_objp = GET_NEXT(asteroid_objp) ) {
2164  if (asteroid_objp->type != OBJ_ASTEROID ) {
2165  continue;
2166  }
2167 
2168  asp = &Asteroids[asteroid_objp->instance];
2169 
2170  if ( asp->collide_objnum < 0 ) {
2171  continue;
2172  }
2173 
2174  if ( asteroid_objp == player_target ) {
2175  continue;
2176  }
2177 
2178  g3_rotate_vertex(&asteroid_vertex,&asteroid_objp->pos);
2179  g3_project_vertex(&asteroid_vertex);
2180 
2181  if ( Cmdline_targetinfo ) {
2182  hud_target_add_display_list(asteroid_objp, &asteroid_vertex, &asteroid_objp->pos, 0, NULL, NULL, TARGET_DISPLAY_DIST | TARGET_DISPLAY_LEAD);
2183  } else {
2184  hud_target_add_display_list(asteroid_objp, &asteroid_vertex, &asteroid_objp->pos, 0, NULL, NULL, TARGET_DISPLAY_DIST);
2185  }
2186  }
2187 }
2188 
2193 {
2194  object *asteroid_objp, *closest_asteroid_objp = NULL;
2195  asteroid *asp;
2196  float dist, closest_dist = 999999.0f;
2197 
2198  for ( asteroid_objp = GET_FIRST(&obj_used_list); asteroid_objp !=END_OF_LIST(&obj_used_list); asteroid_objp = GET_NEXT(asteroid_objp) ) {
2199  if (asteroid_objp->type != OBJ_ASTEROID ) {
2200  continue;
2201  }
2202 
2203  asp = &Asteroids[asteroid_objp->instance];
2204 
2205  if ( asp->collide_objnum < 0 ) {
2206  continue;
2207  }
2208 
2209  dist = vm_vec_dist_quick(&Player_obj->pos, &asteroid_objp->pos);
2210 
2211  if ( dist < closest_dist ) {
2212  closest_dist = dist;
2213  closest_asteroid_objp = asteroid_objp;
2214  }
2215  }
2216 
2217  if ( closest_asteroid_objp ) {
2218  set_target_objnum( Player_ai, OBJ_INDEX(closest_asteroid_objp) );
2219  }
2220 }
2221 
2223 {
2224  if (Asteroid_field.num_initial_asteroids > 0 ) {
2225  int i, j, k;
2226 
2227  nprintf(( "Paging", "Paging in asteroids\n" ));
2228 
2229 
2230  // max of MAX_ACTIVE_DEBRIS_TYPES possible debris field models
2231  for (i=0; i<MAX_ACTIVE_DEBRIS_TYPES; i++) {
2232  asteroid_info *asip;
2233 
2234  if (Asteroid_field.debris_genre == DG_ASTEROID) {
2235  // asteroid
2236  Assert(i < NUM_DEBRIS_SIZES);
2237  asip = &Asteroid_info[i];
2238  } else {
2239  // ship debris - always full until empty
2240  if (Asteroid_field.field_debris_type[i] != -1) {
2241  asip = &Asteroid_info[Asteroid_field.field_debris_type[i]];
2242  } else {
2243  break;
2244  }
2245  }
2246 
2247 
2248  for (k=0; k<NUM_DEBRIS_POFS; k++) {
2249 
2250  // SHIP DEBRIS - use subtype 0
2251  if (Asteroid_field.debris_genre == DG_SHIP) {
2252  if (k > 0) {
2253  break;
2254  }
2255  } else {
2256  // ASTEROID DEBRIS - use subtype (Asteroid_field.field_debris_type[] != -1)
2257  if (Asteroid_field.field_debris_type[k] == -1) {
2258  continue;
2259  }
2260  }
2261 
2262  if (asip->model_num[k] < 0)
2263  continue;
2264 
2265  asip->modelp[k] = model_get(asip->model_num[k]);
2266 
2267  // Page in textures
2268  for (j=0; j<asip->modelp[k]->n_textures; j++ ) {
2269  asip->modelp[k]->maps[j].PageIn();
2270  }
2271 
2272  }
2273  }
2274  }
2275 }
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
Definition: asteroid.cpp:405
void mc_info_init(mc_info *mc)
Definition: model.h:1138
asteroid_obj Asteroid_obj_list
Definition: asteroid.cpp:50
field_type_t field_type
Definition: asteroid.h:136
void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
Definition: asteroid.cpp:690
polymodel * modelp[NUM_DEBRIS_POFS]
Definition: asteroid.h:72
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int model_collide(mc_info *mc_info_obj)
float asteroid_create_explosion(object *objp)
Definition: asteroid.cpp:1267
void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
Definition: asteroid.cpp:748
int timestamp(int delta_ms)
Definition: timer.cpp:226
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta)
Definition: asteroid.cpp:192
int i
Definition: multi_pxo.cpp:466
#define ASTEROID_OBJ_USED
Definition: asteroid.cpp:47
int n_textures
Definition: model.h:761
float p
Definition: pstypes.h:111
#define MEDIUM_DEBRIS_WEIGHT
Definition: asteroid.cpp:54
weapon Weapons[MAX_WEAPONS]
Definition: weapons.cpp:78
#define SF_DEPART_WARP
Definition: ship.h:449
vec3d * pos
Definition: model.h:1113
ai_info * Player_ai
Definition: ai.cpp:24
int team
Definition: ship.h:606
int num_detail_levels
Definition: asteroid.h:61
float vm_vec_mag_quick(const vec3d *v)
Definition: vecmat.cpp:371
#define TARGET_DISPLAY_DIST
Definition: hudtarget.h:160
#define SUBMODEL_ROT_HIT
Definition: objcollide.h:72
int damage_type_idx_sav
Definition: asteroid.h:65
int Game_mode
Definition: systemvars.cpp:24
vec3d rotvel
Definition: physics.h:78
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
int fireball_asteroid_explosion_type(asteroid_info *aip)
Definition: fireballs.cpp:1014
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
int weapon_area_calc_damage(object *objp, vec3d *pos, float inner_rad, float outer_rad, float max_blast, float max_damage, float *blast, float *damage, float limit)
Definition: weapons.cpp:6025
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
void RemHookVar(char *name)
Definition: scripting.cpp:749
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
int get_debris_weight(int ship_debris_index)
Definition: asteroid.cpp:506
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
int Next_asteroid_throw
Definition: asteroid.cpp:60
#define FIREBALL_LARGE_EXPLOSION
Definition: fireballs.h:24
float flFrametime
Definition: fredstubs.cpp:22
vec3d desired_vel
Definition: physics.h:70
GLuint index
Definition: Glext.h:5608
asteroid Asteroids[MAX_ASTEROIDS]
Definition: asteroid.cpp:63
physics_info phys_info
Definition: object.h:157
matrix * vm_angles_2_matrix(matrix *m, const angles *a)
Definition: vecmat.cpp:752
void model_get_rotating_submodel_list(SCP_vector< int > *submodel_vector, object *objp)
Definition: modelread.cpp:4468
int hud_escort_num_ships_on_list()
Definition: hudescort.cpp:1026
int collide_objsig
Definition: asteroid.h:108
int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos, collision_info_struct *asteroid_hit_info)
Definition: asteroid.cpp:918
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
void lerp(float *goal, float f1, float f2, float scale)
Definition: asteroid.cpp:903
Assert(pm!=NULL)
int target_objnum
Definition: ai.h:339
#define SUBMODEL_NO_ROT_HIT
Definition: objcollide.h:71
Definition: pstypes.h:88
float detail_depth[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:739
#define ASTEROID_TYPE_SMALL
Definition: asteroid.h:29
float inner_rad
Definition: asteroid.h:66
#define mprintf(args)
Definition: pstypes.h:238
int ai_index
Definition: ship.h:538
ushort net_signature
Definition: object.h:163
int Num_fireball_types
Definition: fireballs.cpp:50
#define NUM_SKILL_LEVELS
Definition: systemvars.h:150
float side_slip_time_const
Definition: physics.h:44
#define OBJ_ASTEROID
Definition: object.h:44
hull_check p0
Definition: lua.cpp:5051
int target_objnum
Definition: asteroid.h:110
#define OF_RENDERS
Definition: object.h:103
float max_speed
Definition: asteroid.h:63
matrix Eye_matrix
Definition: 3dsetup.cpp:26
void asteroid_parse_tbl()
Definition: asteroid.cpp:1920
char pof_files[NUM_DEBRIS_POFS][MAX_FILENAME_LEN]
Definition: asteroid.h:60
void set_flags(uint flags)
struct vec3d::@225::@227 xyz
#define NUM_DEBRIS_SIZES
Definition: asteroid.h:26
void static_randvec(int num, vec3d *vp)
[To be described]
Definition: staticrand.cpp:111
vec3d max_vel
Definition: physics.h:49
void asteroid_parse_section(asteroid_info *asip)
Definition: asteroid.cpp:1820
int get_debris_from_same_group(int index)
Definition: asteroid.cpp:490
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
#define SIZE_T_ARG
Definition: clang.h:61
void send_asteroid_throw(object *objp)
Definition: multimsgs.cpp:6689
void random_shuffle(int *first, int *last)
float model_get_core_radius(int modelnum)
Definition: modelread.cpp:3114
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
#define Assertion(expr, msg,...)
Definition: clang.h:41
object obj_used_list
Definition: object.cpp:53
float fireball_radius_multiplier
Definition: asteroid.h:75
int set_asteroid_throw_objnum()
Definition: asteroid.cpp:2095
void vm_vec_random_cone(vec3d *out, const vec3d *in, float max_angle, const matrix *orient)
Definition: vecmat.cpp:2418
small asteroid blows up
Definition: gamesnd.h:131
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
#define OF_COLLIDES
Definition: object.h:104
uint flags
Definition: ship.h:644
hull_check orient
Definition: lua.cpp:5049
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
object * objp
Definition: lua.cpp:3105
float hit_dist
Definition: model.h:1122
GLenum GLenum GLenum GLenum GLenum scale
Definition: Glext.h:8503
#define PARTICLE_BITMAP
Definition: particle.h:49
vec3d inner_min_bound
Definition: asteroid.h:131
matrix I_body_inv
Definition: physics.h:41
GLsizeiptr size
Definition: Glext.h:5496
#define Int3()
Definition: pstypes.h:292
int collide_objnum
Definition: asteroid.h:107
vec3d min_bound
Definition: asteroid.h:127
int final_death_time
Definition: asteroid.h:106
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
ship * shipp
Definition: lua.cpp:9162
vec3d pos
Definition: object.h:152
#define MAX_FIREBALL_TYPES
Definition: fireballs.h:35
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
vec3d max_bound
Definition: asteroid.h:128
void asteroid_init()
Definition: asteroid.cpp:2140
vec3d * p0
Definition: model.h:1114
void hud_target_add_display_list(object *objp, vertex *target_point, vec3d *target_pos, int correction, color *bracket_clr, char *name, int flags)
Definition: hudtarget.cpp:6195
void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
Definition: asteroid.cpp:1216
char Asteroid_icon_closeup_model[NAME_LENGTH]
Definition: asteroid.cpp:69
void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy=false)
Definition: asteroid.cpp:1619
float vm_vec_mag_squared(const vec3d *v)
Definition: vecmat.cpp:339
void asteroid_target_closest_danger()
Definition: asteroid.cpp:2192
int asteroid_subtype
Definition: asteroid.h:103
script_state Script_system("FS2_Open Scripting")
Container & split(Container &result, const typename Container::value_type &s, const typename Container::value_type &delimiters, split_struct::empties_t empties=split_struct::empties_ok)
int signature
Definition: object.h:145
int model_num
Definition: model.h:1110
GLenum type
Definition: Gl.h:1492
void stuff_float(float *f)
Definition: parselo.cpp:2328
int hud_escort_return_objnum(int index)
Definition: hudescort.cpp:1032
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
#define IS_VEC_NULL_SQ_SAFE(v)
Definition: vecmat.h:24
void asteroid_level_init()
Definition: asteroid.cpp:628
int weapon_info_index
Definition: weapon.h:164
int asteroid_type
Definition: asteroid.h:102
void asteroid_maybe_break_up(object *pasteroid_obj)
Definition: asteroid.cpp:1482
int flags
Definition: asteroid.h:99
int num_initial_asteroids
Definition: asteroid.h:135
int objnum
Definition: ship.h:1483
#define ASTEROID_MIN_COLLIDE_TIME
Definition: asteroid.cpp:75
vec3d heavy_collision_cm_pos
Definition: objcollide.h:25
#define PM_FLAG_HAS_INTRINSIC_ROTATE
Definition: model.h:624
void model_render_queue(model_render_params *interp, draw_list *scene, int model_num, matrix *orient, vec3d *pos)
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
void asteroid_level_close()
Definition: asteroid.cpp:1423
int instance
Definition: object.h:150
GLintptr offset
Definition: Glext.h:5497
void send_asteroid_hit(object *objp, object *other_objp, vec3d *hitpos, float damage)
Definition: multimsgs.cpp:6706
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
float a1d[3]
Definition: pstypes.h:93
const float PI2
Definition: pstypes.h:305
vec3d last_pos
Definition: object.h:155
void model_delete_instance(int model_instance_num)
Definition: modelread.cpp:2907
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
#define MAX_ASTEROID_DETAIL_LEVELS
Definition: asteroid.h:37
#define SIF_BIG_SHIP
Definition: ship.h:944
int flags
Definition: model.h:1116
struct matrix::@228::@230 vec
#define SIF_NAVBUOY
Definition: ship.h:891
int subtype
Definition: lua.cpp:9763
#define PF_REDUCED_DAMP
Definition: physics.h:22
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
#define nprintf(args)
Definition: pstypes.h:239
#define GM_MULTIPLAYER
Definition: systemvars.h:18
float initial_asteroid_strength
Definition: asteroid.h:70
#define SMALL_DEBRIS_WEIGHT
Definition: asteroid.cpp:53
float rotdamp
Definition: physics.h:43
float blast
Definition: asteroid.h:69
void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
Definition: asteroid.cpp:850
int obj_create(ubyte type, int parent_obj, int instance, matrix *orient, vec3d *pos, float radius, uint flags)
Definition: object.cpp:467
vec3d * p1
Definition: model.h:1115
ai_profile_t * ai_profile
Definition: missionparse.h:168
void hud_target_asteroid()
Definition: asteroid.cpp:1441
void model_clear_instance(int model_num)
Definition: modelread.cpp:4624
int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
Definition: asteroid.cpp:645
int asteroid_valid_ship_to_warn_collide(ship *shipp)
Definition: asteroid.cpp:1679
#define OBJ_WEAPON
Definition: object.h:33
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
texture_map maps[MAX_MODEL_TEXTURES]
Definition: model.h:762
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
char * stristr(char *str, const char *substr)
Definition: parselo.cpp:3729
int ship_get_SIF(ship *shipp)
Definition: ship.cpp:16096
int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
Definition: asteroid.cpp:1661
float hull_strength
Definition: object.h:160
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
#define MAX_ASTEROID_OBJS
Definition: asteroid.cpp:48
#define NUM_DEBRIS_POFS
Definition: asteroid.h:27
#define CF_TYPE_TABLES
Definition: cfile.h:50
submodel_instance * submodel
Definition: model.h:100
void asteroid_render_DEPRECATED(object *obj)
Definition: asteroid.cpp:1170
#define vm_vec_negate(v)
Definition: vecmat.h:70
ubyte g3_rotate_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:97
hull_check p1
Definition: lua.cpp:5052
uint flags
Definition: model.h:736
int hit_submodel
Definition: model.h:1125
int required_string(const char *pstr)
Definition: parselo.cpp:468
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
int asteroid_count()
Definition: asteroid.cpp:1473
int optional_string(const char *pstr)
Definition: parselo.cpp:539
void maybe_throw_asteroid(int count)
Definition: asteroid.cpp:776
#define MULTI_DOGFIGHT
Definition: multi.h:656
float fireball_lifeleft(object *obj)
Definition: fireballs.cpp:669
Definition: ship.h:534
int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, int ferror=1, int duplicate=0)
Definition: modelread.cpp:2573
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
void SetHookObject(char *name, object *objp)
Definition: scripting.cpp:551
float asteroid_get_fireball_scale_multiplier(int num)
Definition: asteroid.cpp:1238
int check_for_collide
Definition: asteroid.h:105
float radius
Definition: model.h:1117
int Asteroids_enabled
Definition: asteroid.cpp:57
#define delta
Definition: fvi.cpp:418
int g3_project_vertex(vertex *point)
Definition: 3dmath.cpp:202
int idx
Definition: multiui.cpp:761
#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
#define AF_USED
Definition: asteroid.h:96
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
void ship_apply_global_damage(object *ship_objp, object *other_obj, vec3d *force_center, float damage)
Definition: shiphit.cpp:2476
int iff_x_attacks_y(int team_x, int team_y)
Definition: iff_defs.cpp:605
#define MC_SUBMODEL_INSTANCE
Definition: model.h:1179
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
large asteroid blows up
Definition: gamesnd.h:130
void asteroid_show_brackets()
Definition: asteroid.cpp:2150
GLclampd n
Definition: Glext.h:7286
void stuff_vec3d(vec3d *vp)
Definition: parselo.cpp:3082
#define vm_vec_zero(v)
Definition: vecmat.h:37
uint flags
Definition: physics.h:37
void asteroid_process_post(object *obj)
Definition: asteroid.cpp:1750
#define OBJ_INDEX(objp)
Definition: object.h:235
int objnum
Definition: asteroid.h:100
ship * Player_ship
Definition: ship.cpp:124
vec3d hit_point_world
Definition: model.h:1124
void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
Definition: asteroid.cpp:206
#define vm_vec_make(v, _x, _y, _z)
Definition: vecmat.h:48
int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger)
Definition: asteroid.cpp:1600
vec3d * vm_vec_avg3(vec3d *dest, const vec3d *src0, const vec3d *src1, const vec3d *src2)
Definition: vecmat.cpp:228
matrix orient
Definition: object.h:153
asteroid_obj Asteroid_objs[MAX_ASTEROID_OBJS]
Definition: asteroid.cpp:49
#define SND_PRIORITY_MUST_PLAY
Definition: sound.h:26
#define ASTEROID_TYPE_MEDIUM
Definition: asteroid.h:30
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
#define OBJ_SHIP
Definition: object.h:32
float asteroid_time_to_impact(object *asteroid_objp)
Definition: asteroid.cpp:1790
void set_hit_struct_info(collision_info_struct *hit, mc_info *mc, int submodel_rot_hit)
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
GLbitfield flags
Definition: Glext.h:6722
void vm_vec_rand_vec_quick(vec3d *rvec)
Definition: vecmat.cpp:1379
#define SIF_HUGE_SHIP
Definition: ship.h:945
int max_incoming_asteroids[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:86
void reset_parse(char *text)
Definition: parselo.cpp:3305
int Num_asteroids
Definition: asteroid.cpp:58
int model_num[NUM_DEBRIS_POFS]
Definition: asteroid.h:73
int RunCondition(int condition, char format='\0', void *data=NULL, class object *objp=NULL, int more_data=0)
Definition: scripting.cpp:924
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]
Definition: asteroid.h:62
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
vec3d vel
Definition: physics.h:77
#define LARGE_DEBRIS_WEIGHT
Definition: asteroid.cpp:55
vec3d Eye_position
Definition: 3dsetup.cpp:27
#define ASTEROID_UPDATE_COLLIDE_TIMESTAMP
Definition: asteroid.cpp:74
#define MULTI_SIG_ASTEROID
Definition: multiutil.h:33
int num_hits
Definition: model.h:1121
void stuff_int(int *i)
Definition: parselo.cpp:2372
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
int stuff_int_list(int *ilp, int max_ints, int lookup_type)
Definition: parselo.cpp:2782
#define ASTEROID_CHECK_WRAP_TIMESTAMP
Definition: asteroid.cpp:73
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
void asteroid_create_all()
Definition: asteroid.cpp:529
GLuint GLuint num
Definition: Glext.h:9089
void asteroid_load(int asteroid_info_index, int asteroid_subtype)
Definition: asteroid.cpp:446
void asteroid_render(object *obj, draw_list *scene)
Definition: asteroid.cpp:1189
vec3d death_hit_pos
Definition: asteroid.h:109
#define MR_DEPRECATED_NORMAL
Definition: model.h:892
polymodel_instance * model_get_instance(int model_instance_num)
Definition: modelread.cpp:3154
float bound_rad
Definition: asteroid.h:129
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
object * asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype)
Definition: asteroid.cpp:231
void model_render_DEPRECATED(int model_num, matrix *orient, vec3d *pos, uint flags=MR_DEPRECATED_NORMAL, int objnum=-1, int lighting_skip=-1, int *replacement_textures=NULL, int render=MODEL_RENDER_ALL, const bool is_skybox=false)
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]
Definition: asteroid.h:138
#define NAME_LENGTH
Definition: globals.h:15
float frand()
Return random value in range 0.0..1.0- (1.0- means the closest number less than 1.0)
Definition: floating.cpp:35
SCP_vector< int > explosion_bitmap_anims
Definition: asteroid.h:74
float rad
Definition: model.h:757
bool collision_checked
Definition: model.h:92
int set_target_objnum(ai_info *aip, int objnum)
Definition: aicode.cpp:1250
float asteroid_cap_speed(int asteroid_info_index, float speed)
Definition: asteroid.cpp:142
#define fl2i(fl)
Definition: floating.h:33
#define MC_CHECK_MODEL
Definition: model.h:1169
#define ASTEROID_TYPE_LARGE
Definition: asteroid.h:31
int model_instance_num
Definition: asteroid.h:101
int Asteroid_throw_objnum
Definition: asteroid.cpp:59
void asteriod_explode_sound(object *objp, int type, int play_loud)
Definition: asteroid.cpp:1299
int asteroid_collide_objnum(object *asteroid_objp)
Definition: asteroid.cpp:1781
#define MR_IS_ASTEROID
Definition: model.h:871
unsigned short ushort
Definition: pstypes.h:63
int check_for_wrap
Definition: asteroid.h:104
float Asteroid_icon_closeup_zoom
Definition: asteroid.cpp:71
int asteroid_is_targeted(object *objp)
Definition: asteroid.cpp:727
float vm_vec_copy_normalize(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:427
float model_get_radius(int modelnum)
Definition: modelread.cpp:3105
ship_obj Ship_obj_list
Definition: ship.cpp:162
#define vm_is_vec_nan(v)
Definition: vecmat.h:19
char name[NAME_LENGTH]
Definition: asteroid.h:59
int Cmdline_targetinfo
Definition: cmdline.cpp:367
#define OF_PHYSICS
Definition: object.h:105
int ship_info_index
Definition: ship.h:539
#define MULTIPLAYER_MASTER
Definition: multi.h:130
#define F_NAME
Definition: parselo.h:34
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
#define MC_ONLY_BOUND_BOX
Definition: model.h:1173
void asteroid_process_pre(object *objp)
Definition: asteroid.cpp:908
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
void asteroid_update_collide_flag(object *asteroid_objp)
Definition: asteroid.cpp:1701
#define PF_DEAD_DAMP
Definition: physics.h:24
void asteroid_frame()
Definition: asteroid.cpp:2122
int asteroid_obj_list_add(int objnum)
Definition: asteroid.cpp:105
#define timestamp_elapsed(stamp)
Definition: timer.h:102
int has_inner_bound
Definition: asteroid.h:130
SCP_vector< species_info > Species_info
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
void asteroid_obj_list_remove(object *obj)
Definition: asteroid.cpp:127
#define PI
Definition: pstypes.h:303
hull_check pos
Definition: lua.cpp:5050
int Game_skill_level
Definition: fredstubs.cpp:170
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
int model_instance_num
Definition: model.h:1109
#define VALID_FNAME(x)
Definition: pstypes.h:418
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
#define i2fl(i)
Definition: floating.h:32
void send_asteroid_create(object *new_objp, object *parent_objp, int asteroid_type, vec3d *relvec)
Definition: multimsgs.cpp:6663
void asteroid_hit(object *pasteroid_obj, object *other_obj, vec3d *hitpos, float damage)
Definition: asteroid.cpp:1368
int objnum
Definition: asteroid.h:43
vec3d inner_max_bound
Definition: asteroid.h:132
debris_genre_t debris_genre
Definition: asteroid.h:137
GLint GLsizei count
Definition: Gl.h:1491
#define timestamp_rand(a, b)
Definition: timer.h:92
matrix * A
Definition: lua.cpp:444
void weapon_area_apply_blast(vec3d *force_apply_pos, object *ship_objp, vec3d *blast_pos, float blast, int make_shockwave)
Definition: weapons.cpp:6080
object * Player_obj
Definition: object.cpp:56
DCF_BOOL2(asteroids, Asteroids_enabled,"enables or disables asteroids","Usage: asteroids [bool]\nTurns asteroid system on/off. If nothing passed, then toggles it.\n")
void scoring_eval_hit(object *hit_obj, object *other_obj, int from_blast)
Definition: scoring.cpp:1188
#define SF_DYING
Definition: ship.h:447
int temp
Definition: lua.cpp:4996
polymodel * pm
Definition: lua.cpp:1598
vec3d hit_normal
Definition: model.h:1129
int count_incident_asteroids()
Definition: asteroid.cpp:2071
#define FIREBALL_ASTEROID
Definition: fireballs.h:31
void asteroid_verify_collide_objnum(asteroid *asp)
Definition: asteroid.cpp:1740
#define MAX_ASTEROIDS
Definition: asteroid.h:24
asteroid_field Asteroid_field
Definition: asteroid.cpp:64
ushort multi_assign_network_signature(int what_kind)
Definition: multiutil.cpp:105
float mass
Definition: physics.h:39
int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
Definition: asteroid.cpp:168
#define GM_NORMAL
Definition: systemvars.h:19
#define TARGET_DISPLAY_LEAD
Definition: hudtarget.h:162
int damage_type_idx
Definition: asteroid.h:64
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
particle * particle_create(particle_info *pinfo)
Definition: particle.cpp:105
void asteroid_do_area_effect(object *asteroid_objp)
Definition: asteroid.cpp:1329
int model_create_instance(bool is_ship, int model_num)
Definition: modelread.cpp:2855
void asteroid_update_collide(object *objp)
Definition: asteroid.cpp:80
mission The_mission
void asteroid_page_in()
Definition: asteroid.cpp:2222
matrix last_orient
Definition: object.h:156
float h
Definition: pstypes.h:111
int submodel_num
Definition: model.h:1111
void set_object_number(int num)
char type
Definition: object.h:146
angles angs
Definition: model.h:88
vec3d vmd_zero_vector
Definition: vecmat.cpp:24
#define MAX_ACTIVE_DEBRIS_TYPES
Definition: asteroid.h:34
#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
float outer_rad
Definition: asteroid.h:67
matrix * orient
Definition: model.h:1112
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
SCP_vector< asteroid_split_info > split_info
Definition: asteroid.h:71
int impact_weapon_expl_index
Definition: weapon.h:426
matrix vmd_identity_matrix
Definition: vecmat.cpp:28
#define MR_DEPRECATED_IS_ASTEROID
Definition: model.h:905
void asteroid_obj_list_init()
Definition: asteroid.cpp:91
float static_randf(int num)
Return a random float in 0.0f .. 1.0f- (ie, it will never return 1.0f).
Definition: staticrand.cpp:61
int damage_type_add(char *name)
Definition: ship.cpp:17749
vec3d Asteroid_icon_closeup_position
Definition: asteroid.cpp:70
angles prev_angs
Definition: model.h:89
float static_randf_range(int num, float min, float max)
Return a random float within a range. Note: min and max are inclusive.
Definition: staticrand.cpp:95
vec3d light_collision_cm_pos
Definition: objcollide.h:26
void asteroid_delete(object *obj)
Definition: asteroid.cpp:826
int n_detail_levels
Definition: model.h:737
float b
Definition: pstypes.h:111
GLint y
Definition: Gl.h:1505
#define OBJ_RECALC_PAIRS(obj_to_reset)
Definition: object.h:274
#define RAW_INTEGER_TYPE
Definition: parselo.h:52
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_obj, float size, int reverse, vec3d *velocity, float warp_lifetime, int ship_class, matrix *orient_override, int low_res, int extra_flags, int warp_open_sound, int warp_close_sound)
Definition: fireballs.cpp:788
#define strcpy_s(...)
Definition: safe_strings.h:67
int Is_standalone
Definition: systemvars.cpp:59
float damage
Definition: asteroid.h:68
#define CHA_DEATH
Definition: scripting.h:45