FS2_Open
Open source remastering of the Freespace 2 engine
beam.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 
13 #include <algorithm>
14 
15 #include "asteroid/asteroid.h"
16 #include "cmdline/cmdline.h"
17 #include "debris/debris.h"
18 #include "debugconsole/console.h"
19 #include "freespace2/freespace.h"
20 #include "gamesnd/gamesnd.h"
21 #include "globalincs/linklist.h"
22 #include "hud/hudmessage.h"
23 #include "hud/hudshield.h"
24 #include "iff_defs/iff_defs.h"
25 #include "io/timer.h"
26 #include "lighting/lighting.h"
27 #include "network/multi.h"
28 #include "network/multimsgs.h"
29 #include "object/objcollide.h"
30 #include "object/object.h"
31 #include "object/objectshield.h"
32 #include "parse/parselo.h"
33 #include "parse/scripting.h"
34 #include "particle/particle.h"
35 #include "playerman/player.h"
36 #include "render/3d.h"
37 #include "ship/ship.h"
38 #include "ship/shiphit.h"
39 #include "weapon/beam.h"
40 #include "weapon/weapon.h"
41 
42 extern int Cmdline_nohtl;
43 // ------------------------------------------------------------------------------------------------
44 // BEAM WEAPON DEFINES/VARS
45 //
46 
47 // this is the constant which defines when a beam is an "area" beam. meaning, when we switch on sphereline checking and when
48 // a beam gets "stopped" by an object. It is a percentage of the object radius which the beam must be wider than
49 #define BEAM_AREA_PERCENT 0.4f
50 
51 // randomness factor - all beam weapon aiming is adjusted by +/- some factor within this range
52 #define BEAM_RANDOM_FACTOR 0.4f
53 
54 #define BEAM_DAMAGE_TIME 170 // apply damage
55 #define MAX_SHOT_POINTS 30
56 #define SHOT_POINT_TIME 200 // 5 arcs a second
57 
58 #define TOOLTIME 1500.0f
59 
60 beam Beams[MAX_BEAMS]; // all beams
61 beam Beam_free_list; // free beams
62 beam Beam_used_list; // used beams
63 int Beam_count = 0; // how many beams are in use
64 
65 // octant indices. These are "good" pairs of octants to use for beam target
66 #define BEAM_NUM_GOOD_OCTANTS 8
68  { 2, 5, 1, 0 }, // octant, octant, min/max pt, min/max pt
69  { 7, 0, 1, 0 },
70  { 1, 6, 1, 0 },
71  { 6, 1, 0, 1 },
72  { 5, 2, 0, 1 },
73  { 0, 7, 0, 1 },
74  { 7, 1, 1, 0 },
75  { 6, 0, 1, 0 },
76 };
78  { 5, 0, 1, 0 }, // octant, octant, min/max pt, min/max pt
79  { 7, 2, 1, 0 },
80  { 7, 1, 1, 0 },
81  { 6, 0, 1, 0 },
82  { 7, 3, 1, 0 },
83  { 6, 2, 1, 0 },
84  { 5, 1, 1, 0 },
85  { 4, 0, 1, 0 },
86 };
87 
88 // beam lighting effects
89 int Beam_lighting = 1;
90 
91 // debug stuff - keep track of how many collision tests we perform a second and how many we toss a second
92 #define BEAM_TEST_STAMP_TIME 4000 // every 4 seconds
93 int Beam_test_stamp = -1;
96 int Beam_test_ast = 0;
98 
99 // beam warmup completion %
100 #define BEAM_WARMUP_PCT(b) ( ((float)Weapon_info[b->weapon_info_index].b_info.beam_warmup - (float)timestamp_until(b->warmup_stamp)) / (float)Weapon_info[b->weapon_info_index].b_info.beam_warmup )
101 
102 // beam warmdown completion %
103 #define BEAM_WARMDOWN_PCT(b) ( ((float)Weapon_info[b->weapon_info_index].b_info.beam_warmdown - (float)timestamp_until(b->warmdown_stamp)) / (float)Weapon_info[b->weapon_info_index].b_info.beam_warmdown )
104 
105 // link into the physics paused system
106 extern int physics_paused;
107 
108 // beam lighting info
109 #define MAX_BEAM_LIGHT_INFO 100
110 typedef struct beam_light_info {
111  beam *bm; // beam casting the light
112  int objnum; // object getting light cast on it
113  ubyte source; // 0 to light the shooter, 1 for lighting any ship the beam passes, 2 to light the collision ship
114  vec3d c_point; // collision point for type 2 lights
116 
119 
120 float b_whack_small = 2000.0f; // used to be 500.0f with the retail whack bug
121 float b_whack_big = 10000.0f; // used to be 1500.0f with the retail whack bug
122 float b_whack_damage = 150.0f;
123 
124 DCF(b_whack_small, "Sets the whack factor for small whacks (Default is 2000f)")
125 {
127 }
128 DCF(b_whack_big, "Sets the whack factor for big whacks (Default is 10000f)")
129 {
131 }
132 DCF(b_whack_damage, "Sets the whack damage threshold (Default is 150f)")
133 {
134  if (dc_optional_string_either("help", "--help")) {
135  dc_printf("Sets the threshold to determine whether a big whack or a small whack should be applied. Values equal or greater than this threshold will trigger a big whack, while smaller values will trigger a small whack\n");
136  return;
137  }
138 
140 }
141 
142 
143 // ------------------------------------------------------------------------------------------------
144 // BEAM WEAPON FORWARD DECLARATIONS
145 //
146 
147 // delete a beam
148 void beam_delete(beam *b);
149 
150 // handle a hit on a specific object
152 
153 // fills in binfo
154 void beam_get_binfo(beam *b, float accuracy, int num_shots);
155 
156 // aim the beam (setup last_start and last_shot - the endpoints). also recalculates object collision info
157 void beam_aim(beam *b);
158 
159 // type A functions
160 void beam_type_a_move(beam *b);
161 
162 // type B functions
163 void beam_type_b_move(beam *b);
164 
165 // type C functions
166 void beam_type_c_move(beam *b);
167 
168 // type D functions
169 void beam_type_d_move(beam *b);
170 void beam_type_d_get_status(beam *b, int *shot_index, int *fire_wait);
171 
172 // type e functions
173 void beam_type_e_move(beam *b);
174 
175 // given a model #, and an object, stuff 2 good world coord points
176 void beam_get_octant_points(int modelnum, object *objp, int oct_index, int oct_array[BEAM_NUM_GOOD_OCTANTS][4], vec3d *v1, vec3d *v2);
177 
178 // given an object, return its model num
179 int beam_get_model(object *objp);
180 
181 // for a given object, and a firing beam, determine its critical dot product and range
182 void beam_get_cull_vals(object *objp, beam *b, float *cull_dot, float *cull_dist);
183 
184 // get the total possible cone for a given beam in radians
185 float beam_get_cone_dot(beam *b);
186 
187 // for rendering the beam effect
188 // output top and bottom vectors
189 // fvec == forward vector (eye viewpoint basically. in world coords)
190 // pos == world coordinate of the point we're calculating "around"
191 // w == width of the diff between top and bottom around pos
192 void beam_calc_facing_pts(vec3d *top, vec3d *bot, vec3d *fvec, vec3d *pos, float w, float z_add);
193 
194 // render the muzzle glow for a beam weapon
196 
197 // generate particles for the muzzle glow
199 
200 // throw some jitter into the aim - based upon shot_aim
201 void beam_jitter_aim(beam *b, float aim);
202 
203 // if it is legal for the beam to continue firing
204 // returns -1 if the beam should stop firing immediately
205 // returns 0 if the beam should go to warmdown
206 // returns 1 if the beam can continue along its way
207 int beam_ok_to_fire(beam *b);
208 
209 // start the warmup phase for the beam
210 void beam_start_warmup(beam *b);
211 
212 // start the firing phase for the beam, return 0 if the beam failed to start, and should be deleted altogether
213 int beam_start_firing(beam *b);
214 
215 // start the warmdown phase for the beam
216 void beam_start_warmdown(beam *b);
217 
218 // add a collision to the beam for this frame (to be evaluated later)
219 void beam_add_collision(beam *b, object *hit_object, mc_info *cinfo, int quad = -1, int exit_flag = 0);
220 
221 // get the width of the widest section of the beam
222 float beam_get_widest(beam *b);
223 
224 // mark an object as being lit
225 void beam_add_light(beam *b, int objnum, int source, vec3d *c_point);
226 
227 // apply lighting from any beams
228 void beam_apply_lighting();
229 
230 // recalculate beam sounds (looping sounds relative to the player)
231 void beam_recalc_sounds(beam *b);
232 
233 // apply a whack to a ship
234 void beam_apply_whack(beam *b, object *objp, vec3d *hit_point);
235 
236 // return the amount of damage which should be applied to a ship. basically, filters friendly fire damage
237 float beam_get_ship_damage(beam *b, object *objp);
238 
239 // if the beam is likely to tool a given target before its lifetime expires
240 int beam_will_tool_target(beam *b, object *objp);
241 
242 // ------------------------------------------------------------------------------------------------
243 // BEAM WEAPON FUNCTIONS
244 //
245 
246 // init at game startup
247 void beam_init()
248 {
250 }
251 
252 // initialize beam weapons for this level
254 {
255  // intialize beams
256  int idx;
257 
258  Beam_count = 0;
259  list_init( &Beam_free_list );
260  list_init( &Beam_used_list );
261  memset(Beams, 0, sizeof(beam) * MAX_BEAMS);
262 
263  // Link all object slots into the free list
264  for (idx=0; idx<MAX_BEAMS; idx++) {
265  Beams[idx].objnum = -1;
266  list_append(&Beam_free_list, &Beams[idx] );
267  }
268 
269  // reset muzzle particle spew timestamp
270 }
271 
272 // shutdown beam weapons for this level
274 {
275  // clear the beams
276  list_init( &Beam_free_list );
277  list_init( &Beam_used_list );
278 }
279 
280 // fire a beam, returns nonzero on success. the innards of the code handle all the rest, foo
281 int beam_fire(beam_fire_info *fire_info)
282 {
283  beam *new_item;
284  weapon_info *wip;
285  ship *firing_ship = NULL;
286  int objnum;
287 
288  // sanity check
289  if(fire_info == NULL){
290  Int3();
291  return -1;
292  }
293 
294  // if we're out of beams, bail
295  if(Beam_count >= MAX_BEAMS){
296  return -1;
297  }
298 
299  // for now, only allow ship targets
300  if (!(fire_info->bfi_flags & BFIF_IS_FIGHTER_BEAM)) {
301  if (
302  ((fire_info->target == NULL) && !(fire_info->bfi_flags & BFIF_TARGETING_COORDS)) ||
303  ((fire_info->target != NULL) && (fire_info->target->type != OBJ_SHIP) && (fire_info->target->type != OBJ_ASTEROID) && (fire_info->target->type != OBJ_DEBRIS) && (fire_info->target->type != OBJ_WEAPON))
304  ) {
305  return -1;
306  }
307  }
308 
309  // make sure the beam_info_index is valid
310  if ((fire_info->beam_info_index < 0) || (fire_info->beam_info_index >= Num_weapon_types) || !(Weapon_info[fire_info->beam_info_index].wi_flags & WIF_BEAM)) {
311  Assertion(false, "beam_info_index (%d) invalid (either <0, >= %d, or not actually a beam)!\n", fire_info->beam_info_index, Num_weapon_types);
312  return -1;
313  }
314 
315  wip = &Weapon_info[fire_info->beam_info_index];
316  // make sure a ship is firing this
317  if (!(fire_info->bfi_flags & BFIF_FLOATING_BEAM) && ((fire_info->shooter->type != OBJ_SHIP) || (fire_info->shooter->instance < 0) || (fire_info->shooter->instance >= MAX_SHIPS)) ) {
318  Assertion(false, "Fixed beam fired without a valid ship!\n");
319  return -1;
320  }
321  if (fire_info->shooter != NULL) {
322  firing_ship = &Ships[fire_info->shooter->instance];
323  }
324 
325  // get a free beam
326  new_item = GET_FIRST(&Beam_free_list);
327  Assert( new_item != &Beam_free_list ); // shouldn't have the dummy element
328  if(new_item == &Beam_free_list){
329  return -1;
330  }
331 
332  // make sure that our textures are loaded as well
333  extern bool weapon_is_used(int weapon_index);
334  extern void weapon_load_bitmaps(int weapon_index);
335  if ( !weapon_is_used(fire_info->beam_info_index) ) {
337  }
338 
339  // remove from the free list
340  list_remove( &Beam_free_list, new_item );
341 
342  // insert onto the end of used list
343  list_append( &Beam_used_list, new_item );
344 
345  // increment counter
346  Beam_count++;
347 
348  // fill in some values
349  new_item->warmup_stamp = -1;
350  new_item->warmdown_stamp = -1;
351  new_item->weapon_info_index = fire_info->beam_info_index;
352  new_item->objp = fire_info->shooter;
353  new_item->sig = (fire_info->shooter != NULL) ? fire_info->shooter->signature : 0;
354  new_item->subsys = fire_info->turret;
355  new_item->life_left = wip->b_info.beam_life;
356  new_item->life_total = wip->b_info.beam_life;
357  new_item->r_collision_count = 0;
358  new_item->f_collision_count = 0;
359  new_item->target = fire_info->target;
360  new_item->target_subsys = fire_info->target_subsys;
361  new_item->target_sig = (fire_info->target != NULL) ? fire_info->target->signature : 0;
362  new_item->beam_sound_loop = -1;
363  new_item->type = wip->b_info.beam_type;
364  new_item->targeting_laser_offset = fire_info->targeting_laser_offset;
365  new_item->framecount = 0;
366  new_item->flags = 0;
367  new_item->shot_index = 0;
368  new_item->shrink = 1.0f;
369  new_item->team = (firing_ship == NULL) ? fire_info->team : static_cast<char>(firing_ship->team);
370  new_item->range = wip->b_info.range;
371  new_item->damage_threshold = wip->b_info.damage_threshold;
372  new_item->bank = fire_info->bank;
373  new_item->Beam_muzzle_stamp = -1;
374  new_item->beam_glow_frame = 0.0f;
375  new_item->firingpoint = (fire_info->bfi_flags & BFIF_FLOATING_BEAM) ? -1 : fire_info->turret->turret_next_fire_pos;
376  new_item->beam_width = wip->b_info.beam_width;
377  new_item->last_start = fire_info->starting_pos;
378 
379  if (fire_info->bfi_flags & BFIF_FORCE_FIRING)
380  new_item->flags |= BF_FORCE_FIRING;
381  if (fire_info->bfi_flags & BFIF_IS_FIGHTER_BEAM)
382  new_item->flags |= BF_IS_FIGHTER_BEAM;
383  if (fire_info->bfi_flags & BFIF_FLOATING_BEAM)
384  new_item->flags |= BF_FLOATING_BEAM;
385 
386  if (fire_info->bfi_flags & BFIF_TARGETING_COORDS) {
387  new_item->flags |= BF_TARGETING_COORDS;
388  new_item->target_pos1 = fire_info->target_pos1;
389  new_item->target_pos2 = fire_info->target_pos2;
390  } else {
391  vm_vec_zero(&new_item->target_pos1);
392  vm_vec_zero(&new_item->target_pos2);
393  }
394 
395  for (int i = 0; i < MAX_BEAM_SECTIONS; i++)
396  new_item->beam_section_frame[i] = 0.0f;
397 
398  if (fire_info->bfi_flags & BFIF_IS_FIGHTER_BEAM) {
399  new_item->type = BEAM_TYPE_C;
400  }
401 
402  // if the targeted subsystem is not NULL, force it to be a type A beam
403  if(new_item->target_subsys != NULL && new_item->type != BEAM_TYPE_C){
404  new_item->type = BEAM_TYPE_A;
405  }
406 
407  // type D weapons can only fire at small ships and missiles
408  if(new_item->type == BEAM_TYPE_D){
409  // if its a targeted ship, get the target ship
410  if((fire_info->target != NULL) && (fire_info->target->type == OBJ_SHIP) && (fire_info->target->instance >= 0)){
411  ship *target_ship = &Ships[fire_info->target->instance];
412 
413  // maybe force to be a type A
414  if(Ship_info[target_ship->ship_info_index].class_type > -1 && (Ship_types[Ship_info[target_ship->ship_info_index].class_type].weapon_bools & STI_WEAP_BEAMS_EASILY_HIT)){
415  new_item->type = BEAM_TYPE_A;
416  }
417  }
418  }
419 
420  // ----------------------------------------------------------------------
421  // THIS IS THE CRITICAL POINT FOR MULTIPLAYER
422  // beam_get_binfo(...) determines exactly how the beam will behave over the course of its life
423  // it fills in binfo, which we can pass to clients in multiplayer
424  if(fire_info->beam_info_override != NULL){
425  new_item->binfo = *fire_info->beam_info_override;
426  } else {
427  beam_get_binfo(new_item, fire_info->accuracy, wip->b_info.beam_shots); // to fill in b_info - the set of directional aim vectors
428  }
429 
430  // create the associated object
431  objnum = obj_create(OBJ_BEAM, ((fire_info->shooter != NULL) ? OBJ_INDEX(fire_info->shooter) : -1), new_item - Beams, &vmd_identity_matrix, &vmd_zero_vector, 1.0f, OF_COLLIDES);
432  if(objnum < 0){
433  beam_delete(new_item);
434  nprintf(("General", "obj_create() failed for beam weapon! bah!\n"));
435  Int3();
436  return -1;
437  }
438  new_item->objnum = objnum;
439 
440  // this sets up all info for the first frame the beam fires
441  beam_aim(new_item); // to fill in shot_point, etc.
442 
443  // check to see if its legal to fire at this guy
444  if (beam_ok_to_fire(new_item) != 1) {
445  beam_delete(new_item);
446  mprintf(("Killing beam at initial fire because of illegal targeting!!!\n"));
447  return -1;
448  }
449 
450  // if we're a multiplayer master - send a packet
451  if (MULTIPLAYER_MASTER) {
452  int bank_point = -1;
453 
454  if (fire_info->bfi_flags & BFIF_IS_FIGHTER_BEAM) {
455  // magic numbers suck, be we need to make sure that we are always below UCHAR_MAX (255)
456  Assert( fire_info->point <= 25 );
457  Assert( fire_info->bank <= 5 );
458 
459  bank_point = (fire_info->point * 10) + fire_info->bank;
460  }
461 
462  send_beam_fired_packet(fire_info->shooter, fire_info->turret, fire_info->target, fire_info->beam_info_index, &new_item->binfo, fire_info->bfi_flags, bank_point);
463  }
464 
465  // start the warmup phase
466  beam_start_warmup(new_item);
467 
468  return objnum;
469 }
470 
471 // fire a targeting beam, returns objnum on success. a much much simplified version of a beam weapon
472 // targeting lasers last _one_ frame. For a continuous stream - they must be created every frame.
473 // this allows it to work smoothly in multiplayer (detect "trigger down". every frame just create a targeting laser firing straight out of the
474 // object. this way you get all the advantages of nice rendering and collisions).
475 // NOTE : only references beam_info_index and shooter
477 {
478  beam *new_item;
479  weapon_info *wip;
480  int objnum;
481  ship *firing_ship;
482 
483  // sanity check
484  if(fire_info == NULL){
485  Int3();
486  return -1;
487  }
488 
489  // if we're out of beams, bail
490  if(Beam_count >= MAX_BEAMS){
491  return -1;
492  }
493 
494  // make sure the beam_info_index is valid
495  Assert((fire_info->beam_info_index >= 0) && (fire_info->beam_info_index < MAX_WEAPON_TYPES) && (Weapon_info[fire_info->beam_info_index].wi_flags & WIF_BEAM));
496  if((fire_info->beam_info_index < 0) || (fire_info->beam_info_index >= MAX_WEAPON_TYPES) || !(Weapon_info[fire_info->beam_info_index].wi_flags & WIF_BEAM)){
497  return -1;
498  }
499  wip = &Weapon_info[fire_info->beam_info_index];
500 
501  // make sure a ship is firing this
502  Assert((fire_info->shooter->type == OBJ_SHIP) && (fire_info->shooter->instance >= 0) && (fire_info->shooter->instance < MAX_SHIPS));
503  if ( (fire_info->shooter->type != OBJ_SHIP) || (fire_info->shooter->instance < 0) || (fire_info->shooter->instance >= MAX_SHIPS) ) {
504  return -1;
505  }
506  firing_ship = &Ships[fire_info->shooter->instance];
507 
508 
509  // get a free beam
510  new_item = GET_FIRST(&Beam_free_list);
511  Assert( new_item != &Beam_free_list ); // shouldn't have the dummy element
512 
513  // remove from the free list
514  list_remove( &Beam_free_list, new_item );
515 
516  // insert onto the end of used list
517  list_append( &Beam_used_list, new_item );
518 
519  // increment counter
520  Beam_count++;
521 
522  // maybe allocate some extra data based on the beam type
524  if(wip->b_info.beam_type != BEAM_TYPE_C){
525  return -1;
526  }
527 
528  // fill in some values
529  new_item->warmup_stamp = fire_info->warmup_stamp;
530  new_item->warmdown_stamp = fire_info->warmdown_stamp;
531  new_item->weapon_info_index = fire_info->beam_info_index;
532  new_item->objp = fire_info->shooter;
533  new_item->sig = fire_info->shooter->signature;
534  new_item->subsys = NULL;
535  new_item->life_left = fire_info->life_left;
536  new_item->life_total = fire_info->life_total;
537  new_item->r_collision_count = 0;
538  new_item->f_collision_count = 0;
539  new_item->target = NULL;
540  new_item->target_subsys = NULL;
541  new_item->target_sig = 0;
542  new_item->beam_sound_loop = -1;
543  new_item->type = BEAM_TYPE_C;
544  new_item->targeting_laser_offset = fire_info->targeting_laser_offset;
545  new_item->framecount = 0;
546  new_item->flags = 0;
547  new_item->shot_index = 0;
548  new_item->shrink = 1.0f;
549  new_item->team = (char)firing_ship->team;
550  new_item->range = wip->b_info.range;
551  new_item->damage_threshold = wip->b_info.damage_threshold;
552  new_item->beam_width = wip->b_info.beam_width;
553 
554  // type c is a very special weapon type - binfo has no meaning
555 
556  // create the associated object
557  objnum = obj_create(OBJ_BEAM, OBJ_INDEX(fire_info->shooter), new_item - Beams, &vmd_identity_matrix, &vmd_zero_vector, 1.0f, OF_COLLIDES);
558 
559  if(objnum < 0){
560  beam_delete(new_item);
561  nprintf(("General", "obj_create() failed for beam weapon! bah!\n"));
562  Int3();
563  return -1;
564  }
565  new_item->objnum = objnum;
566 
567  // this sets up all info for the first frame the beam fires
568  beam_aim(new_item); // to fill in shot_point, etc.
569 
570  if(Beams[Objects[objnum].instance].objnum != objnum){
571  Int3();
572  return -1;
573  }
574 
575  return objnum;
576 }
577 
578 // return an object index of the guy who's firing this beam
579 int beam_get_parent(object *bm)
580 {
581  beam *b;
582 
583  // get a handle to the beam
584  Assert(bm->type == OBJ_BEAM);
585  Assert(bm->instance >= 0);
586  if(bm->type != OBJ_BEAM){
587  return -1;
588  }
589  if(bm->instance < 0){
590  return -1;
591  }
592  b = &Beams[bm->instance];
593 
594  if(b->objp == NULL){
595  return -1;
596  }
597 
598  // if the object handle is invalid
599  if(b->objp->signature != b->sig){
600  return -1;
601  }
602 
603  // return the handle
604  return OBJ_INDEX(b->objp);
605 }
606 
607 // return weapon_info_index of beam
609 {
610  Assert(bm->type == OBJ_BEAM);
611  if (bm->type != OBJ_BEAM) {
612  return -1;
613  }
614 
615  Assert(bm->instance >= 0 && bm->instance < MAX_BEAMS);
616  if (bm->instance < 0) {
617  return -1;
618  }
619  //make sure it's returning a valid info index
620  Assert((Beams[bm->instance].weapon_info_index > -1) && (Beams[bm->instance].weapon_info_index < Num_weapon_types));
621 
622  // return weapon_info_index
623  return Beams[bm->instance].weapon_info_index;
624 }
625 
626 
627 
628 // given a beam object, get the # of collisions which happened during the last collision check (typically, last frame)
629 int beam_get_num_collisions(int objnum)
630 {
631  // sanity checks
632  if((objnum < 0) || (objnum >= MAX_OBJECTS)){
633  Int3();
634  return -1;
635  }
636  if((Objects[objnum].instance < 0) || (Objects[objnum].instance >= MAX_BEAMS)){
637  Int3();
638  return -1;
639  }
640  if(Beams[Objects[objnum].instance].objnum != objnum){
641  Int3();
642  return -1;
643  }
644 
645  if(Beams[Objects[objnum].instance].objnum < 0){
646  Int3();
647  return -1;
648  }
649 
650  // return the # of recent collisions
651  return Beams[Objects[objnum].instance].r_collision_count;
652 }
653 
654 // stuff collision info, returns 1 on success
655 int beam_get_collision(int objnum, int num, int *collision_objnum, mc_info **cinfo)
656 {
657  // sanity checks
658  if((objnum < 0) || (objnum >= MAX_OBJECTS)){
659  Int3();
660  return 0;
661  }
662  if((Objects[objnum].instance < 0) || (Objects[objnum].instance >= MAX_BEAMS)){
663  Int3();
664  return 0;
665  }
666  if((Beams[Objects[objnum].instance].objnum != objnum) || (Beams[Objects[objnum].instance].objnum < 0)){
667  Int3();
668  return 0;
669  }
670  if(num >= Beams[Objects[objnum].instance].r_collision_count){
671  Int3();
672  return 0;
673  }
674 
675  // return - success
676  *cinfo = &Beams[Objects[objnum].instance].r_collisions[num].cinfo;
677  *collision_objnum = Beams[Objects[objnum].instance].r_collisions[num].c_objnum;
678  return 1;
679 }
680 
681 // pause all looping beam sounds
683 {
684  beam *moveup = NULL;
685 
686  // set all beam volumes to 0
687  moveup = GET_FIRST(&Beam_used_list);
688  if(moveup == NULL){
689  return;
690  }
691  while(moveup != END_OF_LIST(&Beam_used_list)){
692  // set the volume to 0, if he has a looping beam sound
693  if(moveup->beam_sound_loop >= 0){
694  snd_set_volume(moveup->beam_sound_loop, 0.0f);
695  }
696 
697  // next beam
698  moveup = GET_NEXT(moveup);
699  }
700 }
701 
702 // unpause looping beam sounds
704 {
705  beam *moveup = NULL;
706 
707  // recalc all beam sounds
708  moveup = GET_FIRST(&Beam_used_list);
709  if(moveup == NULL){
710  return;
711  }
712  while(moveup != END_OF_LIST(&Beam_used_list)){
713  beam_recalc_sounds(moveup);
714 
715  // next beam
716  moveup = GET_NEXT(moveup);
717  }
718 }
719 
720 void beam_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp, bool fighter_beam){
721  ship_get_global_turret_gun_info(objp, ssp, gpos, gvec, use_angles, targetp);
722  if(fighter_beam)*gvec = objp->orient.vec.fvec;
723 }
724 
725 // -----------------------------===========================------------------------------
726 // BEAM MOVEMENT FUNCTIONS
727 // -----------------------------===========================------------------------------
728 
729 // move a type A beam weapon
731 {
732  vec3d dir;
733  vec3d temp, temp2;
734 
735  // LEAVE THIS HERE OTHERWISE MUZZLE GLOWS DRAW INCORRECTLY WHEN WARMING UP OR DOWN
736  // get the "originating point" of the beam for this frame. essentially bashes last_start
737  if (b->subsys != NULL)
738  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 1, &temp2, (b->flags & BF_IS_FIGHTER_BEAM) > 0);
739 
740  // if the "warming up" timestamp has not expired
741  if((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)){
742  return;
743  }
744 
745  // put the "last_shot" point arbitrarily far away
746  vm_vec_sub(&dir, &b->last_shot, &b->last_start);
748  vm_vec_scale_add(&b->last_shot, &b->last_start, &dir, b->range);
750 }
751 
752 // move a type B beam weapon
753 #define BEAM_T(b) ( ((b->binfo.delta_ang / b->life_total) * (b->life_total - b->life_left)) / b->binfo.delta_ang )
755 {
756  vec3d actual_dir;
757  vec3d temp, temp2;
758  float dot_save;
759 
760  // LEAVE THIS HERE OTHERWISE MUZZLE GLOWS DRAW INCORRECTLY WHEN WARMING UP OR DOWN
761  // get the "originating point" of the beam for this frame. essentially bashes last_start
762  if (b->subsys != NULL)
763  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 1, &temp2, (b->flags & BF_IS_FIGHTER_BEAM) > 0);
764 
765  // if the "warming up" timestamp has not expired
766  if((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)){
767  return;
768  }
769 
770  // if the two direction vectors are _really_ close together, just use the original direction
771  dot_save = vm_vec_dot(&b->binfo.dir_a, &b->binfo.dir_b);
772  if((double)dot_save >= 0.999999999){
773  actual_dir = b->binfo.dir_a;
774  }
775  // otherwise move towards the dir we calculated when firing this beam
776  else {
777  vm_vec_interp_constant(&actual_dir, &b->binfo.dir_a, &b->binfo.dir_b, BEAM_T(b));
778  }
779 
780  // now recalculate shot_point to be shooting through our new point
781  vm_vec_scale_add(&b->last_shot, &b->last_start, &actual_dir, b->range);
782  int is_valid = is_valid_vec(&b->last_shot);
783  Assert(is_valid);
784  if(!is_valid){
785  actual_dir = b->binfo.dir_a;
786  vm_vec_scale_add(&b->last_shot, &b->last_start, &actual_dir, b->range);
787  }
788 }
789 
790 // type C functions
792 {
793  vec3d temp;
794  ship *shipp;
795  int num_fire_points = 1;
796 
797  // ugh
798  if ( (b->objp == NULL) || (b->objp->instance < 0) ) {
799  Int3();
800  return;
801  }
802 
803  // type c beams only last one frame so we never have to "move" them.
804  temp = b->targeting_laser_offset;
805  vm_vec_unrotate(&b->last_start, &temp, &b->objp->orient);
806  vm_vec_add2(&b->last_start, &b->objp->pos);
807  vm_vec_scale_add(&b->last_shot, &b->last_start, &b->objp->orient.vec.fvec, b->range);
808 
809  shipp = &Ships[b->objp->instance];
810 
811  if (shipp->beam_sys_info.turret_num_firing_points > 1) {
812  num_fire_points = shipp->beam_sys_info.turret_num_firing_points;
813  }
814 
815  shipp->weapon_energy -= num_fire_points * Weapon_info[b->weapon_info_index].energy_consumed * flFrametime;
816 
817  if (shipp->weapon_energy < 0.0f) {
818  shipp->weapon_energy = 0.0f;
819  }
820 }
821 
822 // type D functions
824 {
825  int shot_index, fire_wait;
826  vec3d temp, temp2, dir;
827 
828  // LEAVE THIS HERE OTHERWISE MUZZLE GLOWS DRAW INCORRECTLY WHEN WARMING UP OR DOWN
829  // get the "originating point" of the beam for this frame. essentially bashes last_start
830  if (b->subsys != NULL)
831  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 1, &temp2, (b->flags & BF_IS_FIGHTER_BEAM) > 0);
832 
833  // if the "warming up" timestamp has not expired
834  if((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)){
835  return;
836  }
837 
838  // determine what stage of the beam we're in
839  beam_type_d_get_status(b, &shot_index, &fire_wait);
840 
841  // if we've changed shot index
842  if(shot_index != b->shot_index){
843  // set the new index
844  b->shot_index = shot_index;
845 
846  // re-aim
847  beam_aim(b);
848  }
849 
850  // if we're in the fire wait stage
851  b->flags &= ~BF_SAFETY;
852  if(fire_wait){
853  b->flags |= BF_SAFETY;
854  }
855 
856  // put the "last_shot" point arbitrarily far away
857  vm_vec_sub(&dir, &b->last_shot, &b->last_start);
859  vm_vec_scale_add(&b->last_shot, &b->last_start, &dir, b->range);
861 }
862 void beam_type_d_get_status(beam *b, int *shot_index, int *fire_wait)
863 {
864  float shot_time = b->life_total / (float)b->binfo.shot_count;
865  float beam_time = b->life_total - b->life_left;
866 
867  // determine what "shot" we're on
868  *shot_index = (int)(beam_time / shot_time);
869 
870  if(*shot_index >= b->binfo.shot_count){
871  nprintf(("Beam","Shot of type D beam had bad shot_index value\n"));
872  *shot_index = b->binfo.shot_count - 1;
873  }
874 
875  // determine if its the firing or waiting section of the shot (fire happens first, THEN wait)
876  *fire_wait = 0;
877  if(beam_time > ((shot_time * (*shot_index)) + (shot_time * 0.5f))){
878  *fire_wait = 1;
879  }
880 }
881 
882 // type e functions
884 {
885  vec3d temp, turret_norm;
886 
887  if (b->subsys == NULL) { // If we're a free-floating beam, there's nothing to calculate here.
888  return;
889  }
890 
891  // LEAVE THIS HERE OTHERWISE MUZZLE GLOWS DRAW INCORRECTLY WHEN WARMING UP OR DOWN
892  // get the "originating point" of the beam for this frame. essentially bashes last_start
893  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &turret_norm, 1, &temp, (b->flags & BF_IS_FIGHTER_BEAM) > 0);
894 
895  // if the "warming up" timestamp has not expired
896  if((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)){
897  return;
898  }
899 
900  // put the "last_shot" point arbitrarily far away
901  vm_vec_scale_add(&b->last_shot, &b->last_start, &turret_norm, b->range);
903 }
904 
905 // pre-move (before collision checking - but AFTER ALL OTHER OBJECTS HAVE BEEN MOVED)
907 {
908  beam *b;
909  beam *moveup;
910 
911  // zero lights for this frame yet
912  Beam_light_count = 0;
913 
914  // traverse through all active beams
915  moveup = GET_FIRST(&Beam_used_list);
916  while (moveup != END_OF_LIST(&Beam_used_list)) {
917  // get the beam
918  b = moveup;
919 
920  // check if parent object has died, if so then delete beam
921  if (b->objp != NULL && b->objp->type == OBJ_NONE) {
922  // set next beam
923  moveup = GET_NEXT(moveup);
924  // delete current beam
925  beam_delete(b);
926 
927  continue;
928  }
929 
930  // unset collision info
931  b->f_collision_count = 0;
932 
933  if ( !physics_paused ) {
934  // make sure to check that firingpoint is still properly set
935  int temp = -1;
936  if (b->subsys != NULL) {
937  temp = b->subsys->turret_next_fire_pos;
938 
939  if (!(b->flags & BF_IS_FIGHTER_BEAM))
941  }
942 
943  // move the beam
944  switch (b->type)
945  {
946  // type A beam weapons don't move
947  case BEAM_TYPE_A :
948  beam_type_a_move(b);
949  break;
950 
951  // type B beam weapons move across the target somewhat randomly
952  case BEAM_TYPE_B :
953  beam_type_b_move(b);
954  break;
955 
956  // type C beam weapons are attached to a fighter - pointing forward
957  case BEAM_TYPE_C:
958  beam_type_c_move(b);
959  break;
960 
961  // type D
962  case BEAM_TYPE_D:
963  beam_type_d_move(b);
964  break;
965 
966  // type E
967  case BEAM_TYPE_E:
968  beam_type_e_move(b);
969  break;
970 
971  // illegal beam type
972  default :
973  Int3();
974  }
975  if (b->subsys != NULL) {
977  }
978  }
979 
980  // next
981  moveup = GET_NEXT(moveup);
982  }
983 }
984 
985 // post-collision time processing for beams
987 {
988  beam *moveup;
989  beam *next_one;
990  int bf_status;
991  beam_weapon_info *bwi;
992 
993  // traverse through all active beams
994  moveup = GET_FIRST(&Beam_used_list);
995  while(moveup != END_OF_LIST(&Beam_used_list)){
996  bwi = &Weapon_info[moveup->weapon_info_index].b_info;
997 
998  // check the status of the beam
999  bf_status = beam_ok_to_fire(moveup);
1000 
1001  // if we're warming up
1002  if(moveup->warmup_stamp != -1){
1003  next_one = GET_NEXT(moveup);
1004 
1005  // should we be stopping?
1006  if(bf_status < 0){
1007  beam_delete(moveup);
1008  } else {
1009  if (moveup->objp != NULL) {
1010  // add a muzzle light for the shooter
1011  beam_add_light(moveup, OBJ_INDEX(moveup->objp), 0, NULL);
1012  }
1013 
1014  // if the warming up timestamp has expired, start firing
1015  if(timestamp_elapsed(moveup->warmup_stamp)){
1016  // start firing
1017  if(!beam_start_firing(moveup)){
1018  beam_delete(moveup);
1019  }
1020  }
1021  }
1022 
1023  // next
1024  moveup = next_one;
1025  continue;
1026  }
1027  // if we're warming down
1028  else if(moveup->warmdown_stamp != -1){
1029  next_one = GET_NEXT(moveup);
1030 
1031  // should we be stopping?
1032  if(bf_status < 0){
1033  beam_delete(moveup);
1034  } else {
1035  if (moveup->objp != NULL) {
1036  // add a muzzle light for the shooter
1037  beam_add_light(moveup, OBJ_INDEX(moveup->objp), 0, NULL);
1038  }
1039 
1040  // if we're done warming down, the beam is finished
1041  if(timestamp_elapsed(moveup->warmdown_stamp)){
1042  beam_delete(moveup);
1043  }
1044  }
1045 
1046  // next
1047  moveup = next_one;
1048  continue;
1049  }
1050  // otherwise, we're firing away.........
1051 
1052  if (moveup->objp != NULL) {
1053  // add a muzzle light for the shooter
1054  beam_add_light(moveup, OBJ_INDEX(moveup->objp), 0, NULL);
1055  }
1056 
1057  // subtract out the life left for the beam
1058  if(!physics_paused){
1059  moveup->life_left -= flFrametime;
1060  }
1061 
1062  // if we're past the shrink point, start shrinking the beam
1063  if(moveup->life_left <= (moveup->life_total * bwi->beam_shrink_factor)){
1064  moveup->flags |= BF_SHRINK;
1065  }
1066 
1067  // if we're shrinking the beam
1068  if(moveup->flags & BF_SHRINK){
1069  moveup->shrink -= bwi->beam_shrink_pct * flFrametime;
1070  if(moveup->shrink < 0.1f){
1071  moveup->shrink = 0.1f;
1072  }
1073  }
1074 
1075  // add tube light for the beam
1076  if(is_minimum_GLSL_version() && moveup->objp != NULL)
1077  beam_add_light(moveup, OBJ_INDEX(moveup->objp), 1, NULL);
1078 
1079  // stop shooting?
1080  if(bf_status <= 0){
1081  next_one = GET_NEXT(moveup);
1082 
1083  // if beam should abruptly stop
1084  if(bf_status == -1){
1085  beam_delete(moveup);
1086  }
1087  // if the beam should just power down
1088  else {
1089  beam_start_warmdown(moveup);
1090  }
1091 
1092  // next beam
1093  moveup = next_one;
1094  continue;
1095  }
1096 
1097  // increment framecount
1098  moveup->framecount++;
1099  // type c weapons live for one frame only
1100  // done firing, so go into the warmdown phase
1101  {
1102  if((moveup->life_left <= 0.0f) &&
1103  (moveup->warmdown_stamp == -1) &&
1104  (moveup->framecount > 1))
1105  {
1106  beam_start_warmdown(moveup);
1107 
1108  moveup = GET_NEXT(moveup);
1109  continue;
1110  }
1111  }
1112 
1113  // handle any collisions which occured collision (will take care of applying damage to all objects which got hit)
1114  beam_handle_collisions(moveup);
1115 
1116  // recalculate beam sounds
1117  beam_recalc_sounds(moveup);
1118 
1119  // next item
1120  moveup = GET_NEXT(moveup);
1121  }
1122 
1123  // apply all beam lighting
1125 }
1126 
1127 // -----------------------------===========================------------------------------
1128 // BEAM RENDERING FUNCTIONS
1129 // -----------------------------===========================------------------------------
1130 
1131 // render a beam weapon
1132 #define STUFF_VERTICES() do {\
1133  verts[0]->texture_position.u = 0.0f;\
1134  verts[0]->texture_position.v = 0.0f;\
1135  verts[1]->texture_position.u = 1.0f;\
1136  verts[1]->texture_position.v = 0.0f;\
1137  verts[2]->texture_position.u = 1.0f;\
1138  verts[2]->texture_position.v = 1.0f;\
1139  verts[3]->texture_position.u = 0.0f;\
1140  verts[3]->texture_position.v = 1.0f;\
1141 } while(0);
1142 
1143 #define P_VERTICES() do {\
1144  for(idx=0; idx<4; idx++){\
1145  g3_project_vertex(verts[idx]);\
1146  }\
1147 } while(0);
1148 
1149 void beam_render(beam *b, float u_offset)
1150 {
1151  int idx, s_idx;
1152  vertex h1[4]; // halves of a beam section
1153  vertex *verts[4] = { &h1[0], &h1[1], &h1[2], &h1[3] };
1154  vec3d fvec, top1, bottom1, top2, bottom2;
1155  float scale;
1156  float u_scale; // beam tileing -Bobboau
1157  float length; // beam tileing -Bobboau
1159  beam_weapon_info *bwi;
1160 
1161  memset( h1, 0, sizeof(vertex) * 4 );
1162 
1163  // bogus weapon info index
1164  if ( (b == NULL) || (b->weapon_info_index < 0) )
1165  return;
1166 
1167  // if the beam start and endpoints are the same
1168  if ( vm_vec_same(&b->last_start, &b->last_shot) )
1169  return;
1170 
1171  // get beam direction
1172  vm_vec_sub(&fvec, &b->last_shot, &b->last_start);
1173  vm_vec_normalize_quick(&fvec);
1174 
1175  // turn off backface culling
1176  int cull = gr_set_cull(0);
1177 
1178  length = vm_vec_dist(&b->last_start, &b->last_shot); // beam tileing -Bobboau
1179 
1181 
1182  // draw all sections
1183  for (s_idx = 0; s_idx < bwi->beam_num_sections; s_idx++) {
1184  bwsi = &bwi->sections[s_idx];
1185 
1186  if ( (bwsi->texture.first_frame < 0) || (bwsi->width <= 0.0f) )
1187  continue;
1188 
1189  // calculate the beam points
1190  scale = frand_range(1.0f - bwsi->flicker, 1.0f + bwsi->flicker);
1191  beam_calc_facing_pts(&top1, &bottom1, &fvec, &b->last_start, bwsi->width * scale * b->shrink, bwsi->z_add);
1192  beam_calc_facing_pts(&top2, &bottom2, &fvec, &b->last_shot, bwsi->width * scale * scale * b->shrink, bwsi->z_add);
1193 
1194  if (Cmdline_nohtl) {
1195  g3_rotate_vertex(verts[0], &bottom1);
1196  g3_rotate_vertex(verts[1], &bottom2);
1197  g3_rotate_vertex(verts[2], &top2);
1198  g3_rotate_vertex(verts[3], &top1);
1199  } else {
1200  g3_transfer_vertex(verts[0], &bottom1);
1201  g3_transfer_vertex(verts[1], &bottom2);
1202  g3_transfer_vertex(verts[2], &top2);
1203  g3_transfer_vertex(verts[3], &top1);
1204  }
1205 
1206  P_VERTICES();
1207  STUFF_VERTICES(); // stuff the beam with creamy goodness (texture coords)
1208 
1209  if (bwsi->tile_type == 1)
1210  u_scale = length / (bwsi->width * 0.5f) / bwsi->tile_factor; // beam tileing, might make a tileing factor in beam index later -Bobboau
1211  else
1212  u_scale = bwsi->tile_factor;
1213 
1214  verts[1]->texture_position.u = (u_scale + (u_offset * bwsi->translation)); // beam tileing -Bobboau
1215  verts[2]->texture_position.u = (u_scale + (u_offset * bwsi->translation)); // beam tileing -Bobboau
1216  verts[3]->texture_position.u = (0 + (u_offset * bwsi->translation));
1217  verts[0]->texture_position.u = (0 + (u_offset * bwsi->translation));
1218 
1219  float per = 1.0f;
1220  if (bwi->range)
1221  per -= length / bwi->range;
1222 
1223  //this should never happen but, just to be safe
1224  CLAMP(per, 0.0f, 1.0f);
1225 
1226  ubyte alpha = (ubyte)(255.0f * per);
1227 
1228  verts[1]->r = alpha;
1229  verts[2]->r = alpha;
1230  verts[1]->g = alpha;
1231  verts[2]->g = alpha;
1232  verts[1]->b = alpha;
1233  verts[2]->b = alpha;
1234  verts[1]->a = alpha;
1235  verts[2]->a = alpha;
1236 
1237  verts[0]->r = 255;
1238  verts[3]->r = 255;
1239  verts[0]->g = 255;
1240  verts[3]->g = 255;
1241  verts[0]->b = 255;
1242  verts[3]->b = 255;
1243  verts[0]->a = 255;
1244  verts[3]->a = 255;
1245 
1246  // set the right texture with additive alpha, and draw the poly
1247  int framenum = 0;
1248 
1249  if (bwsi->texture.num_frames > 1) {
1250  b->beam_section_frame[s_idx] += flFrametime;
1251 
1252  // Sanity checks
1253  if (b->beam_section_frame[s_idx] < 0.0f)
1254  b->beam_section_frame[s_idx] = 0.0f;
1255  if (b->beam_section_frame[s_idx] > 100.0f)
1256  b->beam_section_frame[s_idx] = 0.0f;
1257 
1258  while (b->beam_section_frame[s_idx] > bwsi->texture.total_time)
1259  b->beam_section_frame[s_idx] -= bwsi->texture.total_time;
1260 
1261  framenum = fl2i( (b->beam_section_frame[s_idx] * bwsi->texture.num_frames) / bwsi->texture.total_time );
1262 
1263  CLAMP(framenum, 0, bwsi->texture.num_frames-1);
1264  }
1265 
1267 
1268  // added TMAP_FLAG_TILED flag for beam texture tileing -Bobboau
1269  // added TMAP_FLAG_RGB and TMAP_FLAG_GOURAUD so the beam would apear to fade along it's length-Bobboau
1271  }
1272 
1273  // turn backface culling back on
1274  gr_set_cull(cull);
1275 }
1276 
1277 // generate particles for the muzzle glow
1278 int hack_time = 100;
1279 DCF(h_time, "Sets the hack time for beam muzzle glow (Default is 100)")
1280 {
1281  dc_stuff_int(&hack_time);
1282 }
1283 
1285 {
1286  int particle_count;
1287  int idx;
1288  weapon_info *wip;
1289  vec3d turret_norm, turret_pos, particle_pos, particle_dir;
1290  matrix m;
1291  particle_info pinfo;
1292 
1293  // if our hack stamp has expired
1294  if(!((b->Beam_muzzle_stamp == -1) || timestamp_elapsed(b->Beam_muzzle_stamp))){
1295  return;
1296  }
1297 
1298  // never generate anything past about 1/5 of the beam fire time
1299  if(b->warmup_stamp == -1){
1300  return;
1301  }
1302 
1303  // get weapon info
1304  wip = &Weapon_info[b->weapon_info_index];
1305 
1306  // no specified particle for this beam weapon
1307  if (wip->b_info.beam_particle_ani.first_frame < 0)
1308  return;
1309 
1310 
1311  // reset the hack stamp
1312  b->Beam_muzzle_stamp = timestamp(hack_time);
1313 
1314  // randomly generate 10 to 20 particles
1315  particle_count = (int)frand_range(0.0f, (float)wip->b_info.beam_particle_count);
1316 
1317  // get turret info - position and normal
1318  turret_pos = b->last_start;
1319  if (b->subsys != NULL) {
1320  turret_norm = b->subsys->system_info->turret_norm;
1321  } else {
1322  vm_vec_normalized_dir(&turret_norm, &b->last_shot, &b->last_start);
1323  }
1324 
1325  // randomly perturb a vector within a cone around the normal
1326  vm_vector_2_matrix(&m, &turret_norm, NULL, NULL);
1327  for(idx=0; idx<particle_count; idx++){
1328  // get a random point in the cone
1329  vm_vec_random_cone(&particle_dir, &turret_norm, wip->b_info.beam_particle_angle, &m);
1330  vm_vec_scale_add(&particle_pos, &turret_pos, &particle_dir, wip->b_info.beam_muzzle_radius * frand_range(0.75f, 0.9f));
1331 
1332  // now generate some interesting values for the particle
1333  float p_time_ref = wip->b_info.beam_life + ((float)wip->b_info.beam_warmup / 1000.0f);
1334  float p_life = frand_range(p_time_ref * 0.5f, p_time_ref * 0.7f);
1335  float p_vel = (wip->b_info.beam_muzzle_radius / p_life) * frand_range(0.85f, 1.2f);
1336  vm_vec_scale(&particle_dir, -p_vel);
1337  if (b->objp != NULL) {
1338  vm_vec_add2(&particle_dir, &b->objp->phys_info.vel); //move along with our parent
1339  }
1340 
1341  memset(&pinfo, 0, sizeof(particle_info));
1342  pinfo.pos = particle_pos;
1343  pinfo.vel = particle_dir;
1344  pinfo.lifetime = p_life;
1345  pinfo.attached_objnum = -1;
1346  pinfo.attached_sig = 0;
1347  pinfo.rad = wip->b_info.beam_particle_radius;
1348  pinfo.reverse = 1;
1349  pinfo.type = PARTICLE_BITMAP;
1351  pinfo.tracer_length = -1.0f;
1352  particle_create(&pinfo);
1353  }
1354 }
1355 
1356 static float get_current_alpha(vec3d *pos)
1357 {
1358  float dist;
1359  float alpha;
1360 
1361  const float inner_radius = 15.0f;
1362  const float magic_num = 2.75f;
1363 
1364  // determine what alpha to draw this bitmap with
1365  // higher alpha the closer the bitmap gets to the eye
1366  dist = vm_vec_dist_quick(&Eye_position, pos);
1367 
1368  // if the point is inside the inner radius, alpha is based on distance to the player's eye,
1369  // becoming more transparent as it gets close
1370  if (dist <= inner_radius) {
1371  // alpha per meter between the magic # and the inner radius
1372  alpha = 0.8f / (inner_radius - magic_num);
1373 
1374  // above value times the # of meters away we are
1375  alpha *= (dist - magic_num);
1376  return (alpha < 0.005f) ? 0.0f : alpha;
1377  }
1378 
1379  return 0.8f;
1380 }
1381 
1382 // render the muzzle glow for a beam weapon
1384 {
1385  vertex pt;
1387  beam_weapon_info *bwi = &wip->b_info;
1388  float rad, pct, rand_val;
1389  int tmap_flags = TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT;
1390  pt.flags = 0; // avoid potential read of uninit var
1391 
1392  // if we don't have a glow bitmap
1393  if (bwi->beam_glow.first_frame < 0)
1394  return;
1395 
1396  // if the beam is warming up, scale the glow
1397  if (b->warmup_stamp != -1) {
1398  // get warmup pct
1399  pct = BEAM_WARMUP_PCT(b);
1400  rand_val = 1.0f;
1401  } else
1402  // if the beam is warming down
1403  if (b->warmdown_stamp != -1) {
1404  // get warmup pct
1405  pct = 1.0f - BEAM_WARMDOWN_PCT(b);
1406  rand_val = 1.0f;
1407  }
1408  // otherwise the beam is really firing
1409  else {
1410  pct = 1.0f;
1411  rand_val = frand_range(0.90f, 1.0f);
1412  }
1413 
1414  rad = wip->b_info.beam_muzzle_radius * pct * rand_val;
1415 
1416  // don't bother trying to draw if there is no radius
1417  if (rad <= 0.0f)
1418  return;
1419 
1420  float alpha = get_current_alpha(&b->last_start);
1421 
1422  if (alpha <= 0.0f)
1423  return;
1424 
1425  if (bwi->directional_glow == true){
1426  vertex h1[4];
1427  vertex *verts[4] = { &h1[0], &h1[1], &h1[2], &h1[3] };
1428  vec3d fvec, top1, top2, bottom1, bottom2, sub1, sub2, start, end;
1429 
1430  vm_vec_sub(&fvec, &b->last_shot, &b->last_start);
1431  vm_vec_normalize_quick(&fvec);
1432 
1433  vm_vec_copy_scale(&sub1, &fvec, rad);
1434  vm_vec_sub(&start, &b->last_start, &sub1);
1435  vm_vec_copy_scale(&sub2, &fvec, bwi->glow_length);
1436  vm_vec_add(&end, &start, &sub2);
1437 
1438  int cull = gr_set_cull(0);
1439 
1440  beam_calc_facing_pts(&top1, &bottom1, &fvec, &start, rad, 1.0f);
1441  beam_calc_facing_pts(&top2, &bottom2, &fvec, &end, rad, 1.0f);
1442 
1443  if (Cmdline_nohtl) {
1444  g3_rotate_vertex(verts[0], &bottom1);
1445  g3_rotate_vertex(verts[1], &bottom2);
1446  g3_rotate_vertex(verts[2], &top2);
1447  g3_rotate_vertex(verts[3], &top1);
1448  }
1449  else {
1450  g3_transfer_vertex(verts[0], &bottom1);
1451  g3_transfer_vertex(verts[1], &bottom2);
1452  g3_transfer_vertex(verts[2], &top2);
1453  g3_transfer_vertex(verts[3], &top1);
1454  }
1455 
1456  for (int idx = 0; idx < 4; idx++) {
1457  g3_project_vertex(verts[idx]);
1458  }
1459 
1460  verts[0]->texture_position.u = 1.0f;
1461  verts[0]->texture_position.v = 0.0f;
1462  verts[1]->texture_position.u = 0.0f;
1463  verts[1]->texture_position.v = 0.0f;
1464  verts[2]->texture_position.u = 0.0f;
1465  verts[2]->texture_position.v = 1.0f;
1466  verts[3]->texture_position.u = 1.0f;
1467  verts[3]->texture_position.v = 1.0f;
1468 
1469  verts[0]->r = 255;
1470  verts[1]->r = 255;
1471  verts[2]->r = 255;
1472  verts[3]->r = 255;
1473  verts[0]->g = 255;
1474  verts[1]->g = 255;
1475  verts[2]->g = 255;
1476  verts[3]->g = 255;
1477  verts[0]->b = 255;
1478  verts[1]->b = 255;
1479  verts[2]->b = 255;
1480  verts[3]->b = 255;
1481  verts[0]->a = 255;
1482  verts[1]->a = 255;
1483  verts[2]->a = 255;
1484  verts[3]->a = 255;
1485 
1486  int framenum = 0;
1487 
1488  if (bwi->beam_glow.num_frames > 1) {
1490 
1491  // Sanity checks
1492  if (b->beam_glow_frame < 0.0f)
1493  b->beam_glow_frame = 0.0f;
1494  else if (b->beam_glow_frame > 100.0f)
1495  b->beam_glow_frame = 0.0f;
1496 
1497  while (b->beam_glow_frame > bwi->beam_glow.total_time)
1499 
1500  framenum = fl2i((b->beam_glow_frame * bwi->beam_glow.num_frames) / bwi->beam_glow.total_time);
1501 
1502  CLAMP(framenum, 0, bwi->beam_glow.num_frames - 1);
1503  }
1504 
1506 
1507  // draw a poly
1509 
1510  gr_set_cull(cull);
1511 
1512  } else {
1513 
1514  // draw the bitmap
1515  if (Cmdline_nohtl)
1516  g3_rotate_vertex(&pt, &b->last_start);
1517  else
1518  g3_transfer_vertex(&pt, &b->last_start);
1519 
1520 
1521  int framenum = 0;
1522 
1523  if (bwi->beam_glow.num_frames > 1) {
1525 
1526  // Sanity checks
1527  if (b->beam_glow_frame < 0.0f)
1528  b->beam_glow_frame = 0.0f;
1529  else if (b->beam_glow_frame > 100.0f)
1530  b->beam_glow_frame = 0.0f;
1531 
1532  while (b->beam_glow_frame > bwi->beam_glow.total_time)
1534 
1535  framenum = fl2i((b->beam_glow_frame * bwi->beam_glow.num_frames) / bwi->beam_glow.total_time);
1536 
1537  CLAMP(framenum, 0, bwi->beam_glow.num_frames - 1);
1538  }
1539 
1541 
1542  // draw 1 bitmap
1543  g3_draw_bitmap(&pt, 0, rad, tmap_flags);
1544 
1545  // maybe draw more
1546  if (pct > 0.3f)
1547  g3_draw_bitmap(&pt, 0, rad * 0.75f, tmap_flags, rad * 0.25f);
1548 
1549  if (pct > 0.5f)
1550  g3_draw_bitmap(&pt, 0, rad * 0.45f, tmap_flags, rad * 0.55f);
1551 
1552  if (pct > 0.7f)
1553  g3_draw_bitmap(&pt, 0, rad * 0.25f, tmap_flags, rad * 0.75f);
1554  }
1555 }
1556 
1557 // render all beam weapons
1559 {
1560  beam *moveup;
1561 
1562  // moves the U value of texture coods in beams if desired-Bobboau
1563  static float u_offset = 0.0f;
1564  u_offset += flFrametime;
1565 
1566  // traverse through all active beams
1567  moveup = GET_FIRST(&Beam_used_list);
1568  while ( moveup != END_OF_LIST(&Beam_used_list) ) {
1569  // each beam type renders a little bit differently
1570  if ( (moveup->warmup_stamp == -1) && (moveup->warmdown_stamp == -1) && !(moveup->flags & BF_SAFETY) ) {
1571  // HACK - if this is the first frame the beam is firing, don't render it
1572  if (moveup->framecount <= 0) {
1573  moveup = GET_NEXT(moveup);
1574  continue;
1575  }
1576 
1577  // render the beam itself
1578  Assert(moveup->weapon_info_index >= 0);
1579 
1580  if (moveup->weapon_info_index < 0) {
1581  moveup = GET_NEXT(moveup);
1582  continue;
1583  }
1584 
1585  beam_render(moveup, u_offset);
1586  }
1587 
1588  // render the muzzle glow
1589  beam_render_muzzle_glow(moveup);
1590 
1591  // maybe generate some muzzle particles
1593 
1594  // next item
1595  moveup = GET_NEXT(moveup);
1596  }
1597 }
1598 
1599 // output top and bottom vectors
1600 // fvec == forward vector (eye viewpoint basically. in world coords)
1601 // pos == world coordinate of the point we're calculating "around"
1602 // w == width of the diff between top and bottom around pos
1603 void beam_calc_facing_pts( vec3d *top, vec3d *bot, vec3d *fvec, vec3d *pos, float w, float z_add )
1604 {
1605  vec3d uvec, rvec;
1606  vec3d temp;
1607 
1608  temp = *pos;
1609 
1610  vm_vec_sub( &rvec, &Eye_position, &temp );
1611  vm_vec_normalize( &rvec );
1612 
1613  vm_vec_cross(&uvec,fvec,&rvec);
1614  // VECMAT-ERROR: NULL VEC3D (value of, fvec == rvec)
1615  vm_vec_normalize_safe(&uvec);
1616 
1617  vm_vec_scale_add( top, &temp, &uvec, w * 0.5f );
1618  vm_vec_scale_add( bot, &temp, &uvec, -w * 0.5f );
1619 }
1620 
1621 // light scale factor
1622 float blight = 25.5f;
1623 DCF(blight, "Sets the beam light scale factor (Default is 25.5f)")
1624 {
1625  dc_stuff_float(&blight);
1626 }
1627 
1628 // call to add a light source to a small object
1629 void beam_add_light_small(beam *bm, object *objp, vec3d *pt_override = NULL)
1630 {
1631  weapon_info *wip;
1632  beam_weapon_info *bwi;
1633  float noise;
1634 
1635  // no lighting
1636  if(!Beam_lighting){
1637  return;
1638  }
1639 
1640  // sanity
1641  Assert(bm != NULL);
1642  if(bm == NULL){
1643  return;
1644  }
1645  Assert(objp != NULL);
1646  if(objp == NULL){
1647  return;
1648  }
1649  Assert(bm->weapon_info_index >= 0);
1650  wip = &Weapon_info[bm->weapon_info_index];
1651  bwi = &wip->b_info;
1652 
1653  // some noise
1654  if ( (bm->warmup_stamp < 0) && (bm->warmdown_stamp < 0) ) // disable noise when warming up or down
1655  noise = frand_range(1.0f - bwi->sections[0].flicker, 1.0f + bwi->sections[0].flicker);
1656  else
1657  noise = 1.0f;
1658 
1659  // widest part of the beam
1660  float light_rad = beam_get_widest(bm) * blight * noise;
1661 
1662  // nearest point on the beam, and its distance to the ship
1663  vec3d near_pt;
1664  if(pt_override == NULL){
1665  float dist;
1666  vm_vec_dist_to_line(&objp->pos, &bm->last_start, &bm->last_shot, &near_pt, &dist);
1667  if(dist > light_rad){
1668  return;
1669  }
1670  } else {
1671  near_pt = *pt_override;
1672  }
1673 
1674  // average rgb of the beam
1675  float fr = (float)wip->laser_color_1.red / 255.0f;
1676  float fg = (float)wip->laser_color_1.green / 255.0f;
1677  float fb = (float)wip->laser_color_1.blue / 255.0f;
1678 
1679  float pct = 0.0f;
1680 
1681  if (bm->warmup_stamp != -1) { // calculate muzzle light intensity
1682  // get warmup pct
1683  pct = BEAM_WARMUP_PCT(bm)*0.5f;
1684  } else
1685  // if the beam is warming down
1686  if (bm->warmdown_stamp != -1) {
1687  // get warmup pct
1688  pct = MAX(1.0f - BEAM_WARMDOWN_PCT(bm)*1.3f,0.0f)*0.5f;
1689  }
1690  // otherwise the beam is really firing
1691  else {
1692  pct = 1.0f;
1693  }
1694  // add a unique light
1695  light_add_point_unique(&near_pt, light_rad * 0.0001f, light_rad, pct, fr, fg, fb, OBJ_INDEX(objp));
1696 }
1697 
1698 // call to add a light source to a large object
1699 void beam_add_light_large(beam *bm, object *objp, vec3d *pt0, vec3d *pt1)
1700 {
1701  weapon_info *wip;
1702  beam_weapon_info *bwi;
1703  float noise;
1704 
1705  // no lighting
1706  if(!Beam_lighting){
1707  return;
1708  }
1709 
1710  // sanity
1711  Assert(bm != NULL);
1712  if(bm == NULL){
1713  return;
1714  }
1715  Assert(objp != NULL);
1716  if(objp == NULL){
1717  return;
1718  }
1719  Assert(bm->weapon_info_index >= 0);
1720  wip = &Weapon_info[bm->weapon_info_index];
1721  bwi = &wip->b_info;
1722 
1723  // some noise
1724  noise = frand_range(1.0f - bwi->sections[0].flicker, 1.0f + bwi->sections[0].flicker);
1725 
1726  // widest part of the beam
1727  float light_rad = beam_get_widest(bm) * blight * noise;
1728 
1729  // average rgb of the beam
1730  float fr = (float)wip->laser_color_1.red / 255.0f;
1731  float fg = (float)wip->laser_color_1.green / 255.0f;
1732  float fb = (float)wip->laser_color_1.blue / 255.0f;
1733 
1735  light_add_tube(pt0, pt1, 1.0f, light_rad, 1.0f * noise, fr, fg, fb, OBJ_INDEX(objp));
1736  else {
1737  vec3d near_pt, a;
1738  float dist,max_dist;
1739  vm_vec_sub(&a, pt1, pt0);
1741  vm_vec_dist_squared_to_line(&objp->pos, pt0, pt1, &near_pt, &dist); // Calculate nearest point for fallback fake tube pointlight
1742  max_dist = light_rad + objp->radius;
1743  max_dist *= max_dist;
1744  if ( dist > max_dist)
1745  return; // Too far away
1746  light_add_tube(pt0, &near_pt, 1.0f, light_rad, 1.0f * noise, fr, fg, fb, OBJ_INDEX(objp));
1747  }
1748 }
1749 
1750 // mark an object as being lit
1751 void beam_add_light(beam *b, int objnum, int source, vec3d *c_point)
1752 {
1753  beam_light_info *l;
1754 
1755  // if we're out of light slots!
1757  return;
1758  }
1759 
1760  // otherwise add it
1761  l = &Beam_lights[Beam_light_count++];
1762  l->bm = b;
1763  l->objnum = objnum;
1764  l->source = (ubyte)source;
1765 
1766  // only type 2 lights (from collisions) need a collision point
1767  if(c_point != NULL){
1768  l->c_point = *c_point;
1769  } else {
1770  Assert(source != 2);
1771  if(source == 2){
1772  Beam_light_count--;
1773  }
1774  }
1775 }
1776 
1777 // apply lighting from any beams
1779 {
1780  int idx;
1781  beam_light_info *l;
1782  vec3d pt, dir;
1783  beam_weapon_info *bwi;
1784 
1785  // convert all beam lights into real lights
1786  for(idx=0; idx<Beam_light_count; idx++){
1787  // get the light
1788  l = &Beam_lights[idx];
1789 
1790  // bad object
1791  if((l->objnum < 0) || (l->objnum >= MAX_OBJECTS) || (l->bm == NULL)){
1792  continue;
1793  }
1794 
1795  bwi = &Weapon_info[l->bm->weapon_info_index].b_info;
1796 
1797  // different light types
1798  switch(l->source){
1799  // from the muzzle of the gun
1800  case 0:
1801  // a few meters in from the of muzzle
1802  vm_vec_sub(&dir, &l->bm->last_start, &l->bm->last_shot);
1803  vm_vec_normalize_quick(&dir);
1804  vm_vec_scale(&dir, -0.8f); // TODO: This probably needs to *not* be stupid. -taylor
1805  vm_vec_scale_add(&pt, &l->bm->last_start, &dir, bwi->beam_muzzle_radius * 5.0f);
1806 
1807  beam_add_light_small(l->bm, &Objects[l->objnum], &pt);
1808  break;
1809 
1810  // from the beam passing by
1811  case 1:
1812  Assert( Objects[l->objnum].instance >= 0 );
1813  // Valathil: Everyone gets tube lights now
1815  break;
1816 
1817  // from a collision
1818  case 2:
1819  // Valathil: Dont render impact lights for shaders, handled by tube lighting
1820  if ( is_minimum_GLSL_version() ) {
1821  break;
1822  }
1823  // a few meters from the collision point
1824  vm_vec_sub(&dir, &l->bm->last_start, &l->c_point);
1825  vm_vec_normalize_quick(&dir);
1826  vm_vec_scale_add(&pt, &l->c_point, &dir, bwi->beam_muzzle_radius * 5.0f);
1827 
1828  beam_add_light_small(l->bm, &Objects[l->objnum], &pt);
1829  break;
1830  }
1831  }
1832 }
1833 
1834 // -----------------------------===========================------------------------------
1835 // BEAM BOOKKEEPING FUNCTIONS
1836 // -----------------------------===========================------------------------------
1837 
1838 // delete a beam
1840 {
1841  // remove from active list and put on free list
1842  list_remove(&Beam_used_list, b);
1843  list_append(&Beam_free_list, b);
1844 
1845  // delete our associated object
1846  if(b->objnum >= 0){
1847  obj_delete(b->objnum);
1848  }
1849  b->objnum = -1;
1850 
1851  // kill the beam looping sound
1852  if(b->beam_sound_loop != -1){
1854  b->beam_sound_loop = -1;
1855  }
1856 
1857  // handle model animation reversal (closing)
1858  // (beam animations should end pretty much immediately - taylor)
1859  if ((b->subsys) &&
1861  {
1863  }
1864 
1865  // subtract one
1866  Beam_count--;
1867  Assert(Beam_count >= 0);
1868  nprintf(("Beam", "Recycled beam (%d beams remaining)\n", Beam_count));
1869 }
1870 
1871 // given an object, return its model num
1872 int beam_get_model(object *objp)
1873 {
1874  int pof;
1875 
1876  if (objp == NULL) {
1877  return -1;
1878  }
1879 
1880  Assert(objp->instance >= 0);
1881  if(objp->instance < 0){
1882  return -1;
1883  }
1884 
1885  switch(objp->type){
1886  case OBJ_SHIP:
1887  return Ship_info[Ships[objp->instance].ship_info_index].model_num;
1888 
1889  case OBJ_WEAPON:
1891  if(Weapons[objp->instance].weapon_info_index < 0){
1892  return -1;
1893  }
1895 
1896  case OBJ_DEBRIS:
1897  Assert(Debris[objp->instance].is_hull);
1898  if(!Debris[objp->instance].is_hull){
1899  return -1;
1900  }
1901  return Debris[objp->instance].model_num;
1902 
1903  case OBJ_ASTEROID:
1904  pof = Asteroids[objp->instance].asteroid_subtype;
1905  Assert(Asteroids[objp->instance].asteroid_type >= 0);
1906  if(Asteroids[objp->instance].asteroid_type < 0){
1907  return -1;
1908  }
1909  return Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[pof];
1910 
1911  default:
1912  // this shouldn't happen too often
1913  mprintf(("Beam couldn't find a good object model/type!! (%d)\n", objp->type));
1914  return -1;
1915  }
1916 }
1917 
1918 // start the warmup phase for the beam
1920 {
1921  // set the warmup stamp
1923 
1924  // start playing warmup sound
1927  }
1928 }
1929 
1930 // start the firing phase for the beam, return 0 if the beam failed to start, and should be deleted altogether
1932 {
1933  // kill the warmup stamp so the rest of the code knows its firing
1934  b->warmup_stamp = -1;
1935 
1936  // any special stuff for each weapon type
1937  switch(b->type){
1938  // re-aim type A and D beam weapons here, otherwise they tend to miss
1939  case BEAM_TYPE_A:
1940  case BEAM_TYPE_D:
1941  beam_aim(b);
1942  break;
1943 
1944  case BEAM_TYPE_B:
1945  break;
1946 
1947  case BEAM_TYPE_C:
1948  break;
1949 
1950  case BEAM_TYPE_E:
1951  break;
1952 
1953  default:
1954  Int3();
1955  }
1956 
1957  // determine if we can legitimately start firing, or if we need to take other action
1958  switch(beam_ok_to_fire(b)){
1959  case -1 :
1960  return 0;
1961 
1962  case 0 :
1964  return 1;
1965  }
1966 
1967  // start the beam firing sound now, if we haven't already
1968  if((b->beam_sound_loop == -1) && (Weapon_info[b->weapon_info_index].b_info.beam_loop_sound >= 0)){
1970 
1971  // "shot" sound
1972  if (Weapon_info[b->weapon_info_index].launch_snd >= 0)
1973  snd_play_3d(&Snds[Weapon_info[b->weapon_info_index].launch_snd], &b->last_start, &View_position);
1974  // niffwan - if launch_snd < 0, don't play any sound
1975  }
1976 
1977  Script_system.SetHookObjects(3, "Beam", &Objects[b->objnum], "User", b->objp, "Target", b->target);
1979  Script_system.RemHookVars(3, "Beam", "User", "Target");
1980 
1981  // success
1982  return 1;
1983 }
1984 
1985 // start the warmdown phase for the beam
1987 {
1988  // timestamp
1990 
1991  // start the warmdown sound
1994  }
1995 
1996  // kill the beam looping sound
1997  if(b->beam_sound_loop != -1){
1999  b->beam_sound_loop = -1;
2000  }
2001 }
2002 
2003 // recalculate beam sounds (looping sounds relative to the player)
2005 {
2006  beam_weapon_info *bwi;
2007  vec3d pos;
2008 
2009  Assert(b->weapon_info_index >= 0);
2010  if(b->weapon_info_index < 0){
2011  return;
2012  }
2014 
2015  // update the sound position relative to the player
2016  if(b->beam_sound_loop != -1){
2017  // get the point closest to the player's viewing position
2018  switch(vm_vec_dist_to_line(&View_position, &b->last_start, &b->last_shot, &pos, NULL)){
2019  // behind the beam, so use the start pos
2020  case -1:
2021  pos = b->last_start;
2022  break;
2023 
2024  // use the closest point
2025  case 0:
2026  // already calculated in vm_vec_dist_to_line(...)
2027  break;
2028 
2029  // past the beam, so use the shot pos
2030  case 1:
2031  pos = b->last_shot;
2032  break;
2033  }
2034 
2036  }
2037 }
2038 
2039 
2040 // -----------------------------===========================------------------------------
2041 // BEAM AIMING FUNCTIONS
2042 // -----------------------------===========================------------------------------
2043 
2044 // fills in binfo
2045 void beam_get_binfo(beam *b, float accuracy, int num_shots)
2046 {
2047  vec3d p2;
2048  int model_num, idx;
2049  vec3d oct1, oct2;
2050  vec3d turret_point, turret_norm;
2051  beam_weapon_info *bwi;
2052  float miss_factor;
2053 
2054  if (b->subsys != NULL) {
2055  int temp = b->subsys->turret_next_fire_pos;
2056 
2057  if (!(b->flags & BF_IS_FIGHTER_BEAM))
2059 
2060  // where the shot is originating from (b->last_start gets filled in)
2061  beam_get_global_turret_gun_info(b->objp, b->subsys, &turret_point, &turret_norm, 1, &p2, (b->flags & BF_IS_FIGHTER_BEAM) > 0);
2062 
2064  } else {
2065  turret_point = b->last_start;
2066  if (b->flags & BF_TARGETING_COORDS) {
2067  p2 = b->target_pos1;
2068  } else {
2069  p2 = b->target->pos;
2070  }
2071  vm_vec_normalized_dir(&turret_norm, &p2, &turret_point);
2072  }
2073 
2074  // get a model # to work with
2075  model_num = beam_get_model(b->target);
2076  if ((model_num < 0) && !(b->flags & BF_TARGETING_COORDS)) {
2077  return;
2078  }
2079 
2080  // get beam weapon info
2081  Assert(b->weapon_info_index >= 0);
2082  if(b->weapon_info_index < 0){
2083  return;
2084  }
2086 
2087  // stuff num shots even though its only used for type D weapons
2088  b->binfo.shot_count = (ubyte)num_shots;
2089  if(b->binfo.shot_count > MAX_BEAM_SHOTS){
2091  }
2092 
2093  // generate the proper amount of directional vectors
2094  switch(b->type){
2095  // pick an accuracy. beam will be properly aimed at actual fire time
2096  case BEAM_TYPE_A:
2097  // determine the miss factor
2099  Assert(b->team >= 0 && b->team < Num_iffs);
2100  miss_factor = bwi->beam_iff_miss_factor[b->team][Game_skill_level];
2101 
2102  // all we will do is decide whether or not we will hit - type A beam weapons are re-aimed immediately before firing
2103  b->binfo.shot_aim[0] = frand_range(0.0f, 1.0f + miss_factor * accuracy);
2104  b->binfo.shot_count = 1;
2105 
2106  if (b->flags & BF_TARGETING_COORDS) {
2107  // these aren't used for type A beams, so zero them out
2108  vm_vec_zero(&b->binfo.dir_a);
2109  vm_vec_zero(&b->binfo.dir_b);
2110  } else {
2111  // get random model points, this is useful for big ships, because we never miss when shooting at them
2112  if ( Cmdline_old_collision_sys ) {
2113  submodel_get_two_random_points(model_num, 0, &b->binfo.dir_a, &b->binfo.dir_b);
2114  } else {
2116  }
2117  }
2118  break;
2119 
2120  // just 2 points in the "slash"
2121  case BEAM_TYPE_B:
2122  if (b->flags & BF_TARGETING_COORDS) {
2123  // slash between the two
2124  oct1 = b->target_pos1;
2125  oct2 = b->target_pos2;
2126  } else {
2128  }
2129 
2130  // point 1
2131  vm_vec_sub(&b->binfo.dir_a, &oct1, &turret_point);
2133 
2134  // point 2
2135  vm_vec_sub(&b->binfo.dir_b, &oct2, &turret_point);
2137 
2138  // delta angle
2140  break;
2141 
2142  // nothing for this beam - its very special case
2143  case BEAM_TYPE_C:
2144  break;
2145 
2146  // type D beams fire at small ship multiple times
2147  case BEAM_TYPE_D:
2148  // determine the miss factor
2150  Assert(b->team >= 0 && b->team < Num_iffs);
2151  miss_factor = bwi->beam_iff_miss_factor[b->team][Game_skill_level];
2152 
2153  // get a bunch of shot aims
2154  for(idx=0; idx<b->binfo.shot_count; idx++){
2155  // MK, 9/3/99: Added pow() function to make increasingly likely to miss with subsequent shots. 30% more likely with each shot.
2156  float r = ((float) pow(1.3f, idx)) * miss_factor * accuracy;
2157  b->binfo.shot_aim[idx] = frand_range(0.0f, 1.0f + r);
2158  }
2159  break;
2160 
2161  // type e beams just fire straight
2162  case BEAM_TYPE_E:
2163  b->binfo.shot_aim[0] = 0.0000001f;
2164  b->binfo.shot_count = 1;
2165  b->binfo.dir_a = turret_norm;
2166  b->binfo.dir_b = turret_norm;
2167  break;
2168 
2169  default:
2170  break;
2171  }
2172 }
2173 
2174 // aim the beam (setup last_start and last_shot - the endpoints). also recalculates collision pairs
2176 {
2177  vec3d temp, p2;
2178 
2179  if (!(b->flags & BF_TARGETING_COORDS)) {
2180  // type C beam weapons have no target
2181  if (b->target == NULL) {
2182  Assert(b->type == BEAM_TYPE_C);
2183  if(b->type != BEAM_TYPE_C){
2184  return;
2185  }
2186  }
2187  // get a model # to work with
2188  else {
2189  // this can happen if we fire at a target that was just destroyed
2190  if (beam_get_model(b->target) < 0) {
2191  return;
2192  }
2193  }
2194  }
2195 
2196  if (b->subsys != nullptr && b->type != BEAM_TYPE_C) { // Type C beams don't use this information.
2197  int temp_int = b->subsys->turret_next_fire_pos;
2198 
2199  if (!(b->flags & BF_IS_FIGHTER_BEAM))
2201 
2203  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 0, nullptr, (b->flags & BF_IS_FIGHTER_BEAM) != 0);
2204  } else {
2205  // where the shot is originating from (b->last_start gets filled in)
2206  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 1, &p2, (b->flags & BF_IS_FIGHTER_BEAM) != 0);
2207  }
2208 
2209  b->subsys->turret_next_fire_pos = temp_int;
2210  }
2211 
2212  // setup our initial shot point and aim direction
2213  switch(b->type){
2214  case BEAM_TYPE_A:
2215  // if we're targeting a subsystem - shoot directly at it
2216  if(b->target_subsys != nullptr){
2218  vm_vec_add2(&b->last_shot, &b->target->pos);
2219 
2220  if ((b->subsys != nullptr) && (b->subsys->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION)) {
2221  float dist = vm_vec_dist(&b->last_shot,&b->last_start);
2222  vm_vec_scale(&temp, dist);
2223  } else {
2224  vm_vec_sub(&temp, &b->last_shot, &b->last_start);
2225  }
2226 
2227  vm_vec_scale_add(&b->last_shot, &b->last_start, &temp, 2.0f);
2228  break;
2229  }
2230 
2231  // if we're shooting at a big ship - shoot directly at the model
2232  if((b->target != nullptr) && (b->target->type == OBJ_SHIP) && (Ship_info[Ships[b->target->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP))){
2233  if ((b->subsys != nullptr) && (b->subsys->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION)) {
2234  vec3d pnt;
2235  vm_vec_unrotate(&pnt, &b->binfo.dir_a, &b->target->orient);
2236  vm_vec_add2(&pnt, &b->target->pos);
2237 
2238  float dist = vm_vec_dist(&pnt, &b->last_start);
2239  vm_vec_scale(&temp, dist);
2240  p2 = temp;
2241  } else {
2242  // rotate into world coords
2243  vm_vec_unrotate(&temp, &b->binfo.dir_a, &b->target->orient);
2244  vm_vec_add2(&temp, &b->target->pos);
2245 
2246  // get the shot point
2247  vm_vec_sub(&p2, &temp, &b->last_start);
2248  }
2249  vm_vec_scale_add(&b->last_shot, &b->last_start, &p2, 2.0f);
2250  break;
2251  }
2252 
2253  // point at the center of the target...
2254  if (b->flags & BF_TARGETING_COORDS) {
2255  if ((b->subsys != nullptr) && (b->subsys->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION)) {
2257  float dist = vm_vec_dist(&b->target_pos1, &b->last_start);
2258  vm_vec_scale_add(&b->last_shot, &b->last_start, &temp, dist);
2259  } else {
2260  b->last_shot = b->target_pos1;
2261  }
2262  } else {
2263  if ((b->subsys != nullptr) && (b->subsys->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION)) {
2264  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 0, &b->target->pos, (b->flags & BF_IS_FIGHTER_BEAM) != 0);
2265  float dist = vm_vec_dist(&b->target->pos, &b->last_start);
2266  vm_vec_scale_add(&b->last_shot, &b->last_start, &temp, dist);
2267  } else {
2268  b->last_shot = b->target->pos;
2269  }
2270  // ...then jitter based on shot_aim (requires target)
2271  beam_jitter_aim(b, b->binfo.shot_aim[0]);
2272  }
2273  break;
2274 
2275  case BEAM_TYPE_B:
2276  if ((b->subsys != nullptr) && (b->subsys->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION)) {
2277  vm_vec_scale(&b->binfo.dir_a, b->range);
2278  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 0, &b->binfo.dir_a, (b->flags & BF_IS_FIGHTER_BEAM) != 0);
2279  vm_vec_add(&b->last_shot, &b->last_start, &temp);
2280  } else {
2281  // set the shot point
2283  }
2285  break;
2286 
2287  case BEAM_TYPE_C:
2288  // start point
2289  temp = b->targeting_laser_offset;
2290  vm_vec_unrotate(&b->last_start, &temp, &b->objp->orient);
2291  vm_vec_add2(&b->last_start, &b->objp->pos);
2292  vm_vec_scale_add(&b->last_shot, &b->last_start, &b->objp->orient.vec.fvec, b->range);
2293  break;
2294 
2295  case BEAM_TYPE_D:
2296  // point at the center of the target...
2297  if (b->flags & BF_TARGETING_COORDS) {
2298  if ((b->subsys != nullptr) && (b->subsys->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION)) {
2300  float dist = vm_vec_dist(&b->target_pos1, &b->last_start);
2301  vm_vec_scale_add(&b->last_shot, &b->last_start, &temp, dist);
2302  } else {
2303  b->last_shot = b->target_pos1;
2304  }
2305  } else {
2306  if ((b->subsys != nullptr) && (b->subsys->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION)) {
2307  beam_get_global_turret_gun_info(b->objp, b->subsys, &b->last_start, &temp, 0, &b->target->pos, (b->flags & BF_IS_FIGHTER_BEAM) != 0);
2308  float dist = vm_vec_dist(&b->target->pos, &b->last_start);
2309  vm_vec_scale_add(&b->last_shot, &b->last_start, &temp, dist);
2310  } else {
2311  b->last_shot = b->target->pos;
2312  }
2313  // ...then jitter based on shot_aim (requires target)
2315  }
2316  nprintf(("AI", "Frame %i: FIRING\n", Framecount));
2317  break;
2318 
2319  case BEAM_TYPE_E:
2320  // point directly in the direction of the turret
2321  vm_vec_scale_add(&b->last_shot, &b->last_start, &temp, b->range);
2322  break;
2323 
2324  default:
2325  Assertion(false, "Impossible beam type (%d); get a coder!\n", b->type);
2326  }
2327 
2328  // recalculate object pairs
2330 }
2331 
2332 // given a model #, and an object, stuff 2 good world coord points
2333 void beam_get_octant_points(int modelnum, object *objp, int oct_index, int oct_array[BEAM_NUM_GOOD_OCTANTS][4], vec3d *v1, vec3d *v2)
2334 {
2335  vec3d t1, t2, temp;
2336  polymodel *m = model_get(modelnum);
2337 
2338  // bad bad bad bad bad bad
2339  if(m == NULL){
2340  Int3();
2341  return;
2342  }
2343 
2344  Assert((oct_index >= 0) && (oct_index < BEAM_NUM_GOOD_OCTANTS));
2345 
2346  // randomly pick octants
2347  t1 = oct_array[oct_index][2] ? m->octants[oct_array[oct_index][0]].max : m->octants[oct_array[oct_index][0]].min;
2348  t2 = oct_array[oct_index][3] ? m->octants[oct_array[oct_index][1]].max : m->octants[oct_array[oct_index][1]].min;
2349  Assert(!vm_vec_same(&t1, &t2));
2350 
2351  // get them in world coords
2352  vm_vec_unrotate(&temp, &t1, &objp->orient);
2353  vm_vec_add(v1, &temp, &objp->pos);
2354  vm_vec_unrotate(&temp, &t2, &objp->orient);
2355  vm_vec_add(v2, &temp, &objp->pos);
2356 }
2357 
2358 // throw some jitter into the aim - based upon shot_aim
2359 void beam_jitter_aim(beam *b, float aim)
2360 {
2361  Assert(b->target != NULL);
2362  vec3d forward, circle;
2363  matrix m;
2364  float subsys_strength;
2365 
2366  // if the weapons subsystem is damaged or destroyed
2367  if((b->objp != NULL) && (b->objp->signature == b->sig) && (b->objp->type == OBJ_SHIP) && (b->objp->instance >= 0) && (b->objp->instance < MAX_SHIPS)){
2368  // get subsytem strength
2370 
2371  // when subsytem strength is 0, double the aim error factor
2372  aim += aim * (1.0f - subsys_strength);
2373  }
2374 
2375  // shot aim is a direct linear factor of the target model's radius.
2376  // so, pick a random point on the circle
2377  vm_vec_sub(&forward, &b->last_shot, &b->last_start);
2378  vm_vec_normalize_quick(&forward);
2379 
2380  // vector
2381  vm_vector_2_matrix(&m, &forward, NULL, NULL);
2382 
2383  // get a vector on the circle - this should appear to be pretty random
2384  vm_vec_random_in_circle(&circle, &b->last_shot, &m, aim * b->target->radius, 0);
2385 
2386  // get the vector pointing to the circle point
2387  vm_vec_sub(&forward, &circle, &b->last_start);
2388  vm_vec_scale_add(&b->last_shot, &b->last_start, &forward, 2.0f);
2389 }
2390 
2391 
2392 // -----------------------------===========================------------------------------
2393 // BEAM COLLISION FUNCTIONS
2394 // -----------------------------===========================------------------------------
2395 
2396 // collide a beam with a ship, returns 1 if we can ignore all future collisions between the 2 objects
2398 {
2399  beam *b;
2400  object *weapon_objp;
2401  object *ship_objp;
2402  ship *shipp;
2403  ship_info *sip;
2404  weapon_info *bwi;
2405  mc_info mc, mc_shield, mc_hull_enter, mc_hull_exit;
2406  int model_num;
2407  float widest;
2408 
2409  // bogus
2410  if (pair == NULL) {
2411  return 0;
2412  }
2413 
2414  // get the beam
2415  Assert(pair->a->instance >= 0);
2416  Assert(pair->a->type == OBJ_BEAM);
2417  Assert(Beams[pair->a->instance].objnum == OBJ_INDEX(pair->a));
2418  weapon_objp = pair->a;
2419  b = &Beams[pair->a->instance];
2420 
2421  // Don't check collisions for warping out player if past stage 1.
2423  if ( pair->a == Player_obj ) return 0;
2424  if ( pair->b == Player_obj ) return 0;
2425  }
2426 
2427  // if the "warming up" timestamp has not expired
2428  if ((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)) {
2429  return 0;
2430  }
2431 
2432  // if the beam is on "safety", don't collide with anything
2433  if (b->flags & BF_SAFETY) {
2434  return 0;
2435  }
2436 
2437  // if the colliding object is the shooting object, return 1 so this is culled
2438  if (pair->b == b->objp) {
2439  return 1;
2440  }
2441 
2442  // try and get a model
2443  model_num = beam_get_model(pair->b);
2444  if (model_num < 0) {
2445  return 1;
2446  }
2447 
2448 #ifndef NDEBUG
2449  Beam_test_ints++;
2450  Beam_test_ship++;
2451 #endif
2452 
2453  // get the ship
2454  Assert(pair->b->instance >= 0);
2455  Assert(pair->b->type == OBJ_SHIP);
2456  Assert(Ships[pair->b->instance].objnum == OBJ_INDEX(pair->b));
2457  if ((pair->b->type != OBJ_SHIP) || (pair->b->instance < 0))
2458  return 1;
2459  ship_objp = pair->b;
2460  shipp = &Ships[ship_objp->instance];
2461 
2462  int quadrant_num = -1;
2463  int valid_hit_occurred = 0;
2464  sip = &Ship_info[shipp->ship_info_index];
2465  bwi = &Weapon_info[b->weapon_info_index];
2466 
2467  polymodel *pm = model_get(model_num);
2468 
2469  // get the widest portion of the beam
2470  widest = beam_get_widest(b);
2471 
2472 
2473  // Goober5000 - I tried to make collision code much saner... here begin the (major) changes
2474  mc_info_init(&mc);
2475 
2476  // set up collision structs, part 1
2478  mc.model_num = model_num;
2479  mc.submodel_num = -1;
2480  mc.orient = &ship_objp->orient;
2481  mc.pos = &ship_objp->pos;
2482  mc.p0 = &b->last_start;
2483  mc.p1 = &b->last_shot;
2484 
2485  // maybe do a sphereline
2486  if (widest > ship_objp->radius * BEAM_AREA_PERCENT) {
2487  mc.radius = widest * 0.5f;
2489  } else {
2490  mc.flags = MC_CHECK_RAY;
2491  }
2492 
2493  // set up collision structs, part 2
2494  memcpy(&mc_shield, &mc, sizeof(mc_info));
2495  memcpy(&mc_hull_enter, &mc, sizeof(mc_info));
2496  memcpy(&mc_hull_exit, &mc, sizeof(mc_info));
2497 
2498  // reverse this vector so that we check for exit holes as opposed to entrance holes
2499  mc_hull_exit.p1 = &b->last_start;
2500  mc_hull_exit.p0 = &b->last_shot;
2501 
2502  // set flags
2503  mc_shield.flags |= MC_CHECK_SHIELD;
2504  mc_hull_enter.flags |= MC_CHECK_MODEL;
2505  mc_hull_exit.flags |= MC_CHECK_MODEL;
2506 
2507  // check all three kinds of collisions
2508  int shield_collision = (pm->shield.ntris > 0) ? model_collide(&mc_shield) : 0;
2509  int hull_enter_collision = model_collide(&mc_hull_enter);
2510  int hull_exit_collision = (beam_will_tool_target(b, ship_objp)) ? model_collide(&mc_hull_exit) : 0;
2511 
2512  // If we have a range less than the "far" range, check if the ray actually hit within the range
2513  if (b->range < BEAM_FAR_LENGTH
2514  && (shield_collision || hull_enter_collision || hull_exit_collision))
2515  {
2516  // We can't use hit_dist as "1" is the distance between p0 and p1
2517  float rangeSq = b->range * b->range;
2518 
2519  // actually make sure that the collision points are within range of our beam
2520  if (shield_collision && vm_vec_dist_squared(&b->last_start, &mc_shield.hit_point_world) > rangeSq)
2521  {
2522  shield_collision = 0;
2523  }
2524 
2525  if (hull_enter_collision && vm_vec_dist_squared(&b->last_start, &mc_hull_enter.hit_point_world) > rangeSq)
2526  {
2527  hull_enter_collision = 0;
2528  }
2529 
2530  if (hull_exit_collision && vm_vec_dist_squared(&mc_hull_exit.hit_point_world, &b->last_start) > rangeSq)
2531  {
2532  hull_exit_collision = 0;
2533  }
2534  }
2535 
2536  // check shields for impact
2537  // (tooled ships are probably not going to be maintaining a shield over their exit hole,
2538  // therefore we need only check the entrance, just as with conventional weapons)
2539  if (!(ship_objp->flags & OF_NO_SHIELDS))
2540  {
2541  // pick out the shield quadrant
2542  if (shield_collision)
2543  quadrant_num = get_quadrant(&mc_shield.hit_point, ship_objp);
2544  else if (hull_enter_collision && (sip->flags2 & SIF2_SURFACE_SHIELDS))
2545  quadrant_num = get_quadrant(&mc_hull_enter.hit_point, ship_objp);
2546 
2547  // make sure that the shield is active in that quadrant
2548  if ((quadrant_num >= 0) && ((shipp->flags & SF_DYING) || !ship_is_shield_up(ship_objp, quadrant_num)))
2549  quadrant_num = -1;
2550 
2551  // see if we hit the shield
2552  if (quadrant_num >= 0)
2553  {
2554  // do the hit effect
2555  if (shield_collision) {
2556  if (mc_shield.shield_hit_tri != -1) {
2557  add_shield_point(OBJ_INDEX(ship_objp), mc_shield.shield_hit_tri, &mc_shield.hit_point);
2558  }
2559  } else {
2560  /* TODO */;
2561  }
2562 
2563  // if this weapon pierces the shield, then do the hit effect, but act like a shield collision never occurred;
2564  // otherwise, we have a valid hit on this shield
2565  if (bwi->wi_flags2 & WIF2_PIERCE_SHIELDS)
2566  quadrant_num = -1;
2567  else
2568  valid_hit_occurred = 1;
2569  }
2570  }
2571 
2572  // see which impact we use
2573  if (shield_collision && valid_hit_occurred)
2574  {
2575  memcpy(&mc, &mc_shield, sizeof(mc_info));
2576  Assert(quadrant_num >= 0);
2577  }
2578  else if (hull_enter_collision)
2579  {
2580  memcpy(&mc, &mc_hull_enter, sizeof(mc_info));
2581  valid_hit_occurred = 1;
2582  }
2583 
2584  // if we got a hit
2585  if (valid_hit_occurred) {
2586  // add to the collision_list
2587 
2588  Script_system.SetHookObjects(4, "Ship", ship_objp, "Beam", weapon_objp, "Self",ship_objp, "Object", weapon_objp);
2589  bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEBEAM, ship_objp);
2590 
2591  Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp);
2592  bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, weapon_objp);
2593 
2594  if(!ship_override && !weapon_override) {
2595  beam_add_collision(b, ship_objp, &mc, quadrant_num);
2596  }
2597 
2598  Script_system.SetHookObjects(2, "Self",ship_objp, "Object", weapon_objp);
2599  if(!(weapon_override && !ship_override))
2600  Script_system.RunCondition(CHA_COLLIDEBEAM, '\0', NULL, ship_objp);
2601 
2602  Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp);
2603  if((weapon_override && !ship_override) || (!weapon_override && !ship_override))
2604  Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, weapon_objp);
2605 
2606  Script_system.RemHookVars(4, "Ship", "Beam", "Self","Object");
2607 
2608  // if we got "tooled", add an exit hole too
2609  if (hull_exit_collision)
2610  beam_add_collision(b, ship_objp, &mc_hull_exit, quadrant_num, 1);
2611  }
2612 
2613  // add this guy to the lighting list
2615  beam_add_light(b, OBJ_INDEX(ship_objp), 1, NULL);
2616 
2617  // reset timestamp to timeout immediately
2618  pair->next_check_time = timestamp(0);
2619 
2620  return 0;
2621 }
2622 
2623 
2624 // collide a beam with an asteroid, returns 1 if we can ignore all future collisions between the 2 objects
2626 {
2627  beam *b;
2628  mc_info test_collide;
2629  int model_num;
2630 
2631  // bogus
2632  if(pair == NULL){
2633  return 0;
2634  }
2635 
2636  // get the beam
2637  Assert(pair->a->instance >= 0);
2638  Assert(pair->a->type == OBJ_BEAM);
2639  Assert(Beams[pair->a->instance].objnum == OBJ_INDEX(pair->a));
2640  b = &Beams[pair->a->instance];
2641 
2642  // if the "warming up" timestamp has not expired
2643  if((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)){
2644  return 0;
2645  }
2646 
2647  // if the beam is on "safety", don't collide with anything
2648  if(b->flags & BF_SAFETY){
2649  return 0;
2650  }
2651 
2652  // if the colliding object is the shooting object, return 1 so this is culled
2653  if(pair->b == b->objp){
2654  return 1;
2655  }
2656 
2657  // try and get a model
2658  model_num = beam_get_model(pair->b);
2659  if(model_num < 0){
2660  Int3();
2661  return 1;
2662  }
2663 
2664 #ifndef NDEBUG
2665  Beam_test_ints++;
2666  Beam_test_ast++;
2667 #endif
2668 
2669  // do the collision
2670  mc_info_init(&test_collide);
2671  test_collide.model_instance_num = -1;
2672  test_collide.model_num = model_num;
2673  test_collide.submodel_num = -1;
2674  test_collide.orient = &pair->b->orient;
2675  test_collide.pos = &pair->b->pos;
2676  test_collide.p0 = &b->last_start;
2677  test_collide.p1 = &b->last_shot;
2678  test_collide.flags = MC_CHECK_MODEL | MC_CHECK_RAY;
2679  model_collide(&test_collide);
2680 
2681  // if we got a hit
2682  if(test_collide.num_hits){
2683  // add to the collision list
2684 
2685  Script_system.SetHookObjects(4, "Beam", pair->a, "Asteroid", pair->b, "Self",pair->a, "Object", pair->b);
2686  bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDEASTEROID, pair->a);
2687 
2688  Script_system.SetHookObjects(2, "Self",pair->b, "Object", pair->a);
2689  bool asteroid_override = Script_system.IsConditionOverride(CHA_COLLIDEBEAM, pair->b);
2690 
2691  if(!weapon_override && !asteroid_override)
2692  {
2693  beam_add_collision(b, pair->b, &test_collide);
2694  }
2695 
2696  Script_system.SetHookObjects(2, "Self",pair->a, "Object", pair->b);
2697  if(!(asteroid_override && !weapon_override))
2698  Script_system.RunCondition(CHA_COLLIDEASTEROID, '\0', NULL, pair->a);
2699 
2700  Script_system.SetHookObjects(2, "Self",pair->b, "Object", pair->a);
2701  if((asteroid_override && !weapon_override) || (!asteroid_override && !weapon_override))
2702  Script_system.RunCondition(CHA_COLLIDEBEAM, '\0', NULL, pair->b);
2703 
2704  Script_system.RemHookVars(4, "Beam", "Asteroid", "Self","Object");
2705  return 0;
2706 
2707 
2708  }
2709 
2710  // add this guy to the lighting list
2712  beam_add_light(b, OBJ_INDEX(pair->b), 1, NULL);
2713 
2714  // reset timestamp to timeout immediately
2715  pair->next_check_time = timestamp(0);
2716 
2717  return 0;
2718 }
2719 
2720 // collide a beam with a missile, returns 1 if we can ignore all future collisions between the 2 objects
2722 {
2723  beam *b;
2724  mc_info test_collide;
2725  int model_num;
2726 
2727  // bogus
2728  if(pair == NULL){
2729  return 0;
2730  }
2731 
2732  // get the beam
2733  Assert(pair->a->instance >= 0);
2734  Assert(pair->a->type == OBJ_BEAM);
2735  Assert(Beams[pair->a->instance].objnum == OBJ_INDEX(pair->a));
2736  b = &Beams[pair->a->instance];
2737 
2738  // if the "warming up" timestamp has not expired
2739  if((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)){
2740  return 0;
2741  }
2742 
2743  // if the beam is on "safety", don't collide with anything
2744  if(b->flags & BF_SAFETY){
2745  return 0;
2746  }
2747 
2748  // if the colliding object is the shooting object, return 1 so this is culled
2749  if(pair->b == b->objp){
2750  return 1;
2751  }
2752 
2753  // try and get a model
2754  model_num = beam_get_model(pair->b);
2755  if(model_num < 0){
2756  return 1;
2757  }
2758 
2759 #ifndef NDEBUG
2760  Beam_test_ints++;
2761 #endif
2762 
2763  // do the collision
2764  mc_info_init(&test_collide);
2765  test_collide.model_instance_num = -1;
2766  test_collide.model_num = model_num;
2767  test_collide.submodel_num = -1;
2768  test_collide.orient = &pair->b->orient;
2769  test_collide.pos = &pair->b->pos;
2770  test_collide.p0 = &b->last_start;
2771  test_collide.p1 = &b->last_shot;
2772  test_collide.flags = MC_CHECK_MODEL | MC_CHECK_RAY;
2773  model_collide(&test_collide);
2774 
2775  // if we got a hit
2776  if(test_collide.num_hits){
2777  // add to the collision list
2778 
2779  Script_system.SetHookObjects(4, "Beam", pair->a, "Weapon", pair->b, "Self",pair->a, "Object", pair->b);
2780  bool a_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, pair->a);
2781 
2782  //Should be reversed
2783  Script_system.SetHookObjects(2, "Self",pair->b, "Object", pair->a);
2784  bool b_override = Script_system.IsConditionOverride(CHA_COLLIDEBEAM, pair->b);
2785 
2786  if(!a_override && !b_override){
2787  beam_add_collision(b, pair->b, &test_collide);
2788  }
2789 
2790 
2791  if(!(b_override && !a_override))
2792  {
2793  Script_system.SetHookObjects(4, "Beam", pair->a, "Weapon", pair->b, "Self",pair->a, "Object", pair->b);
2794  Script_system.RunCondition(CHA_COLLIDEWEAPON, '\0', NULL, pair->a);
2795  }
2796  if((b_override && !a_override) || (!b_override && !a_override))
2797  {
2798  //Should be reversed
2799  Script_system.SetHookObjects(4, "Weapon", pair->b, "Beam", pair->a, "Self",pair->b, "Object", pair->a);
2800  Script_system.RunCondition(CHA_COLLIDEBEAM, '\0', NULL, pair->b);
2801  }
2802 
2803  Script_system.RemHookVars(4, "Weapon", "Beam", "Self","Object");
2804 
2805  }
2806 
2807  // reset timestamp to timeout immediately
2808  pair->next_check_time = timestamp(0);
2809 
2810  return 0;
2811 }
2812 
2813 // collide a beam with debris, returns 1 if we can ignore all future collisions between the 2 objects
2815 {
2816  beam *b;
2817  mc_info test_collide;
2818  int model_num;
2819 
2820  // bogus
2821  if(pair == NULL){
2822  return 0;
2823  }
2824 
2825  // get the beam
2826  Assert(pair->a->instance >= 0);
2827  Assert(pair->a->type == OBJ_BEAM);
2828  Assert(Beams[pair->a->instance].objnum == OBJ_INDEX(pair->a));
2829  b = &Beams[pair->a->instance];
2830 
2831  // if the "warming up" timestamp has not expired
2832  if((b->warmup_stamp != -1) || (b->warmdown_stamp != -1)){
2833  return 0;
2834  }
2835 
2836  // if the beam is on "safety", don't collide with anything
2837  if(b->flags & BF_SAFETY){
2838  return 0;
2839  }
2840 
2841  // if the colliding object is the shooting object, return 1 so this is culled
2842  if(pair->b == b->objp){
2843  return 1;
2844  }
2845 
2846  // try and get a model
2847  model_num = beam_get_model(pair->b);
2848  if(model_num < 0){
2849  return 1;
2850  }
2851 
2852 #ifndef NDEBUG
2853  Beam_test_ints++;
2854 #endif
2855 
2856  // do the collision
2857  mc_info_init(&test_collide);
2858  test_collide.model_instance_num = -1;
2859  test_collide.model_num = model_num;
2860  test_collide.submodel_num = -1;
2861  test_collide.orient = &pair->b->orient;
2862  test_collide.pos = &pair->b->pos;
2863  test_collide.p0 = &b->last_start;
2864  test_collide.p1 = &b->last_shot;
2865  test_collide.flags = MC_CHECK_MODEL | MC_CHECK_RAY;
2866  model_collide(&test_collide);
2867 
2868  // if we got a hit
2869  if(test_collide.num_hits){
2870 
2871  Script_system.SetHookObjects(4, "Beam", pair->a, "Debris", pair->b, "Self", pair->a, "Object", pair->b);
2872  bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDEDEBRIS, pair->a);
2873 
2874  Script_system.SetHookObjects(2, "Self",pair->b, "Object", pair->a);
2875  bool debris_override = Script_system.IsConditionOverride(CHA_COLLIDEBEAM, pair->b);
2876 
2877  if(!weapon_override && !debris_override)
2878  {
2879  // add to the collision list
2880  beam_add_collision(b, pair->b, &test_collide);
2881  }
2882 
2883  Script_system.SetHookObjects(2, "Self", pair->a, "Object", pair->b);
2884  if(!(debris_override && !weapon_override))
2885  Script_system.RunCondition(CHA_COLLIDEDEBRIS, '\0', NULL, pair->a);
2886 
2887  Script_system.SetHookObjects(2, "Self", pair->b, "Object", pair->a);
2888  if((debris_override && !weapon_override) || (!debris_override && !weapon_override))
2889  Script_system.RunCondition(CHA_COLLIDEBEAM, '\0', NULL, pair->b);
2890 
2891  Script_system.RemHookVars(4, "Beam", "Debris", "Self","Object");
2892 
2893  }
2894 
2895  // add this guy to the lighting list
2897  beam_add_light(b, OBJ_INDEX(pair->b), 1, NULL);
2898 
2899  // reset timestamp to timeout immediately
2900  pair->next_check_time = timestamp(0);
2901 
2902  return 0;
2903 }
2904 
2905 // early-out function for when adding object collision pairs, return 1 if the pair should be ignored
2906 int beam_collide_early_out(object *a, object *b)
2907 {
2908  beam *bm;
2909  weapon_info *bwi;
2910  float cull_dist, cull_dot;
2911  vec3d dot_test, dot_test2, dist_test;
2912 
2913  // get the beam
2914  Assert(a->instance >= 0);
2915  if(a->instance < 0){
2916  return 1;
2917  }
2918  Assert(a->type == OBJ_BEAM);
2919  if(a->type != OBJ_BEAM){
2920  return 1;
2921  }
2922  Assert(Beams[a->instance].objnum == OBJ_INDEX(a));
2923  if(Beams[a->instance].objnum != OBJ_INDEX(a)){
2924  return 1;
2925  }
2926  bm = &Beams[a->instance];
2927  Assert(bm->weapon_info_index >= 0);
2928  if(bm->weapon_info_index < 0){
2929  return 1;
2930  }
2931  bwi = &Weapon_info[bm->weapon_info_index];
2932 
2933  // if the second object has an invalid instance, bail
2934  if(b->instance < 0){
2935  return 1;
2936  }
2937 
2938  if((vm_vec_dist(&bm->last_start, &b->pos)-b->radius) > bwi->b_info.range){
2939  return 1;
2940  }//if the object is too far away, don't bother trying to colide with it-Bobboau
2941 
2942  // baseline bails
2943  switch(b->type){
2944  case OBJ_SHIP:
2945  break;
2946  case OBJ_ASTEROID:
2947  // targeting lasers only hit ships
2948 /* if(bwi->b_info.beam_type == BEAM_TYPE_C){
2949  return 1;
2950  }*/
2951  break;
2952  case OBJ_DEBRIS:
2953  // targeting lasers only hit ships
2954 /* if(bwi->b_info.beam_type == BEAM_TYPE_C){
2955  return 1;
2956  }*/
2957  // don't ever collide with non hull pieces
2958  if(!Debris[b->instance].is_hull){
2959  return 1;
2960  }
2961  break;
2962  case OBJ_WEAPON:
2963  // targeting lasers only hit ships
2964 /* if(bwi->b_info.beam_type == BEAM_TYPE_C){
2965  return 1;
2966  }*/
2969  return 1;
2970  }
2971  } else {
2972  // don't ever collide against laser weapons - duh
2974  return 1;
2975  }
2976  }
2977  break;
2978  }
2979 
2980  // get full cull value
2981  beam_get_cull_vals(b, bm, &cull_dot, &cull_dist);
2982 
2983  // if the object fails these conditions, bail
2984  vm_vec_sub(&dist_test, &b->pos, &bm->last_start);
2985  dot_test = dist_test;
2986  vm_vec_sub(&dot_test2, &bm->last_shot, &bm->last_start);
2987  vm_vec_normalize_quick(&dot_test);
2988  vm_vec_normalize_quick(&dot_test2);
2989  // cull_dist == DIST SQUARED FOO!
2990  if((vm_vec_dot(&dot_test, &dot_test2) < cull_dot) && (vm_vec_mag_squared(&dist_test) > cull_dist)){
2991  return 1;
2992  }
2993 
2994  // don't cull
2995  return 0;
2996 }
2997 
2998 // add a collision to the beam for this frame (to be evaluated later)
2999 // Goober5000 - erg. Rearranged for clarity, and also to fix a bug that caused is_exit_collision to hardly ever be assigned,
3000 // resulting in "tooled" ships taking twice as much damage (in a later function) as they should.
3001 void beam_add_collision(beam *b, object *hit_object, mc_info *cinfo, int quadrant_num, int exit_flag)
3002 {
3003  beam_collision *bc = NULL;
3004  int idx;
3005 
3006  // if we haven't reached the limit for beam collisions, just add it
3008  bc = &b->f_collisions[b->f_collision_count++];
3009  }
3010  // otherwise, we've got to do some checking, ick.
3011  // I guess we can always just remove the farthest item
3012  else {
3013  for (idx = 0; idx < MAX_FRAME_COLLISIONS; idx++) {
3014  if ((bc == NULL) || (b->f_collisions[idx].cinfo.hit_dist > bc->cinfo.hit_dist))
3015  bc = &b->f_collisions[idx];
3016  }
3017  }
3018 
3019  if (bc == NULL) {
3020  Int3();
3021  return;
3022  }
3023 
3024  // copy in
3025  bc->c_objnum = OBJ_INDEX(hit_object);
3026  bc->cinfo = *cinfo;
3027  bc->quadrant = quadrant_num;
3028  bc->is_exit_collision = exit_flag;
3029 
3030  // let the hud shield gauge know when Player or Player target is hit
3031  if (quadrant_num >= 0)
3032  hud_shield_quadrant_hit(hit_object, quadrant_num);
3033 }
3034 
3035 // sort collisions for the frame
3037 {
3038  return (b1.cinfo.hit_dist < b2.cinfo.hit_dist);
3039 }
3040 
3041 // handle a hit on a specific object
3043 {
3044  int idx, s_idx;
3046  int r_coll_count = 0;
3047  weapon_info *wi;
3048  float widest;
3049 
3050  // early out if we had no collisions
3051  if(b->f_collision_count <= 0){
3052  return;
3053  }
3054 
3055  // get beam weapon info
3056  if((b->weapon_info_index < 0) || (b->weapon_info_index >= Num_weapon_types)){
3057  Int3();
3058  return;
3059  }
3060  wi = &Weapon_info[b->weapon_info_index];
3061 
3062  // get the widest part of the beam
3063  widest = beam_get_widest(b);
3064 
3065  // the first thing we need to do is sort the collisions, from closest to farthest
3067 
3068  // now apply all collisions until we reach a ship which "stops" the beam or we reach the end of the list
3069  for(idx=0; idx<b->f_collision_count; idx++){
3070  int model_num = -1;
3071  int do_damage = 0;
3072  int draw_effects = 1;
3073  int first_hit = 1;
3074  int target = b->f_collisions[idx].c_objnum;
3075 
3076  // if we have an invalid object
3077  if((target < 0) || (target >= MAX_OBJECTS)){
3078  continue;
3079  }
3080 
3081  // try and get a model to deal with
3082  model_num = beam_get_model(&Objects[target]);
3083  if(model_num < 0){
3084  continue;
3085  }
3086 
3087  if (wi->wi_flags & WIF_HUGE) {
3088  if (Objects[target].type == OBJ_SHIP) {
3089  ship_type_info *sti;
3090  sti = ship_get_type_info(&Objects[target]);
3092  draw_effects = 0;
3093  }
3094  }
3095 
3096  //Don't draw effects if we're in the cockpit of the hit ship
3097  if (Viewer_obj == &Objects[target])
3098  draw_effects = 0;
3099 
3100  // add lighting
3102  beam_add_light(b, target, 2, &b->f_collisions[idx].cinfo.hit_point_world);
3103 
3104  // add to the recent collision list
3105  r_coll[r_coll_count].c_objnum = target;
3106  r_coll[r_coll_count].c_sig = Objects[target].signature;
3107  r_coll[r_coll_count].c_stamp = -1;
3108  r_coll[r_coll_count].cinfo = b->f_collisions[idx].cinfo;
3109  r_coll[r_coll_count].quadrant = -1;
3110  r_coll[r_coll_count].is_exit_collision = 0;
3111 
3112  // if he was already on the recent collision list, copy his timestamp
3113  // also, be sure not to play the impact sound again.
3114  for(s_idx=0; s_idx<b->r_collision_count; s_idx++){
3115  if((r_coll[r_coll_count].c_objnum == b->r_collisions[s_idx].c_objnum) && (r_coll[r_coll_count].c_sig == b->r_collisions[s_idx].c_sig)){
3116  // timestamp
3117  r_coll[r_coll_count].c_stamp = b->r_collisions[s_idx].c_stamp;
3118 
3119  // don't play the impact sound again
3120  first_hit = 0;
3121  }
3122  }
3123 
3124  // if the damage timestamp has expired or is not set yet, apply damage
3125  if((r_coll[r_coll_count].c_stamp == -1) || timestamp_elapsed(r_coll[r_coll_count].c_stamp))
3126  {
3127  float time_compression = f2fl(Game_time_compression);
3128  float delay_time = i2fl(BEAM_DAMAGE_TIME) / time_compression;
3129  do_damage = 1;
3130  r_coll[r_coll_count].c_stamp = timestamp(fl2i(delay_time));
3131  }
3132 
3133  // increment collision count
3134  r_coll_count++;
3135 
3136  // play the impact sound
3137  if ( first_hit && (wi->impact_snd >= 0) ) {
3139  }
3140 
3141  // KOMET_EXT -->
3142 
3143  // draw flash, explosion
3144  if (draw_effects && ((wi->piercing_impact_explosion_radius > 0) || (wi->flash_impact_explosion_radius > 0))) {
3145  float flash_rad = (1.2f + 0.007f * (float)(rand()%100));
3146  float rnd = frand();
3147  int do_expl = 0;
3148  if((rnd < 0.2f || do_damage) && wi->impact_weapon_expl_index >= 0){
3149  do_expl = 1;
3150  }
3151  float ani_radius;
3152  vec3d temp_pos, temp_local_pos;
3153 
3154  vm_vec_sub(&temp_pos, &b->f_collisions[idx].cinfo.hit_point_world, &Objects[target].pos);
3155  vm_vec_rotate(&temp_local_pos, &temp_pos, &Objects[target].orient);
3156 
3157  if (wi->flash_impact_explosion_radius > 0) {
3158  ani_radius = wi->flash_impact_explosion_radius * flash_rad;
3159  if (wi->flash_impact_weapon_expl_index > -1) {
3160  int ani_handle = Weapon_explosions.GetAnim(wi->flash_impact_weapon_expl_index, &b->f_collisions[idx].cinfo.hit_point_world, ani_radius);
3161  particle_create( &temp_local_pos, &vmd_zero_vector, 0.005f * ani_radius, ani_radius, PARTICLE_BITMAP_PERSISTENT, ani_handle, -1, &Objects[target] );
3162  } else {
3163  particle_create( &temp_local_pos, &vmd_zero_vector, 0.005f * ani_radius, ani_radius, PARTICLE_SMOKE, 0, -1, &Objects[target] );
3164  }
3165  }
3166  if(do_expl){
3167  ani_radius = 0.7f * wi->impact_explosion_radius * flash_rad;
3168  int ani_handle = Weapon_explosions.GetAnim(wi->impact_weapon_expl_index, &b->f_collisions[idx].cinfo.hit_point_world, ani_radius);
3169  particle_create( &temp_local_pos, &vmd_zero_vector, 0.0f, ani_radius, PARTICLE_BITMAP_PERSISTENT, ani_handle, -1, &Objects[target] );
3170  }
3171 
3172  if (wi->piercing_impact_explosion_radius > 0) {
3173  vec3d fvec;
3174  vm_vec_sub(&fvec, &b->last_shot, &b->last_start);
3175 
3176  if(!IS_VEC_NULL(&fvec)){
3177  // get beam direction
3178 
3179  int ok_to_draw = 0;
3180 
3181  if (beam_will_tool_target(b, &Objects[target])) {
3182  ok_to_draw = 1;
3183 
3184  if (Objects[target].type == OBJ_SHIP) {
3186 
3187  if (shipp->armor_type_idx != -1) {
3188  if (Armor_types[shipp->armor_type_idx].GetPiercingType(wi->damage_type_idx) == SADTF_PIERCING_RETAIL) {
3189  ok_to_draw = 0;
3190  }
3191  }
3192  }
3193  } else {
3194  ok_to_draw = 0;
3195 
3196  if (Objects[target].type == OBJ_SHIP) {
3197  float draw_limit, hull_pct;
3198  int dmg_type_idx, piercing_type;
3199 
3201 
3202  hull_pct = Objects[target].hull_strength / shipp->ship_max_hull_strength;
3203  dmg_type_idx = wi->damage_type_idx;
3204  draw_limit = Ship_info[shipp->ship_info_index].piercing_damage_draw_limit;
3205 
3206  if (shipp->armor_type_idx != -1) {
3207  piercing_type = Armor_types[shipp->armor_type_idx].GetPiercingType(dmg_type_idx);
3208  if (piercing_type == SADTF_PIERCING_DEFAULT) {
3209  draw_limit = Armor_types[shipp->armor_type_idx].GetPiercingLimit(dmg_type_idx);
3210  } else if ((piercing_type == SADTF_PIERCING_NONE) || (piercing_type == SADTF_PIERCING_RETAIL)) {
3211  draw_limit = -1.0f;
3212  }
3213  }
3214 
3215  if ((draw_limit != -1.0f) && (hull_pct <= draw_limit))
3216  ok_to_draw = 1;
3217  }
3218  }
3219 
3220  if (ok_to_draw){
3221  vm_vec_normalize_quick(&fvec);
3222 
3223  // stream of fire for big ships
3224  if (widest <= Objects[target].radius * BEAM_AREA_PERCENT) {
3225 
3226  vec3d expl_vel, expl_splash_vel;
3227 
3228  float flame_size = wi->piercing_impact_explosion_radius * frand_range(0.5f,2.0f);
3229  float base_v, back_v;
3230  vec3d rnd_vec;
3231 
3232  vm_vec_rand_vec_quick(&rnd_vec);
3233 
3234  if (wi->piercing_impact_particle_velocity != 0.0f)
3235  base_v = wi->piercing_impact_particle_velocity;
3236  else
3237  base_v = wi->piercing_impact_explosion_radius;
3238 
3241  else
3242  back_v = base_v * (-0.2f);
3243 
3244  vm_vec_copy_scale( &expl_vel, &fvec, base_v * frand_range(1.0f, 2.0f));
3245  vm_vec_copy_scale( &expl_splash_vel, &fvec, back_v * frand_range(1.0f, 2.0f));
3246  vm_vec_scale_add2( &expl_vel, &rnd_vec, base_v * wi->piercing_impact_particle_variance);
3247  vm_vec_scale_add2( &expl_splash_vel, &rnd_vec, back_v * wi->piercing_impact_particle_variance);
3248 
3249  if (wi->piercing_impact_weapon_expl_index > -1) {
3251  particle_create( &b->f_collisions[idx].cinfo.hit_point_world, &expl_vel, 0.0f, flame_size, PARTICLE_BITMAP_PERSISTENT, ani_handle );
3252  particle_create( &b->f_collisions[idx].cinfo.hit_point_world, &expl_splash_vel, 0.0f, flame_size, PARTICLE_BITMAP_PERSISTENT, ani_handle );
3253  } else {
3254  particle_create( &b->f_collisions[idx].cinfo.hit_point_world, &expl_vel, 0.3f, flame_size, PARTICLE_SMOKE );
3255  particle_create( &b->f_collisions[idx].cinfo.hit_point_world, &expl_splash_vel, 0.6f, flame_size, PARTICLE_SMOKE );
3256  }
3257  }
3258  }
3259  }
3260  }
3261  // <-- KOMET_EXT
3262  } else {
3263  if(draw_effects && do_damage && !physics_paused){
3264  // maybe draw an explosion, if we aren't hitting shields
3265  if ( (wi->impact_weapon_expl_index >= 0) && (b->f_collisions[idx].quadrant < 0) ) {
3268  }
3269  }
3270  }
3271 
3272  if(do_damage && !physics_paused){
3273 
3274  switch(Objects[target].type){
3275  case OBJ_DEBRIS:
3276  // hit the debris - the debris hit code takes care of checking for MULTIPLAYER_CLIENT, etc
3277  debris_hit(&Objects[target], &Objects[b->objnum], &b->f_collisions[idx].cinfo.hit_point_world, wi->damage);
3278  break;
3279 
3280  case OBJ_WEAPON:
3283  object *trgt = &Objects[target];
3284 
3285  if (trgt->hull_strength > 0) {
3286  float attenuation = 1.0f;
3287  if ((b->damage_threshold >= 0.0f) && (b->damage_threshold < 1.0f)) {
3288  float dist = vm_vec_dist(&b->last_shot, &b->last_start);
3289  float range = b->range;
3290  float atten_dist = range * b->damage_threshold;
3291  if ((range > dist) && (atten_dist < dist)) {
3292  attenuation = (dist - atten_dist) / (range - atten_dist);
3293  }
3294  }
3295 
3296  float damage = wi->damage * attenuation;
3297 
3298  trgt->hull_strength -= damage;
3299 
3300  if (trgt->hull_strength < 0) {
3301  weapon_hit(trgt, NULL, &trgt->pos);
3302  }
3303  } else {
3304  if (!(Game_mode & GM_MULTIPLAYER) || MULTIPLAYER_MASTER) {
3305  weapon_hit(&Objects[target], NULL, &Objects[target].pos);
3306  }
3307  }
3308 
3309 
3310  }
3311  } else {
3312  // detonate the missile
3313  Assert(Weapon_info[Weapons[Objects[target].instance].weapon_info_index].subtype == WP_MISSILE);
3314 
3316  weapon_hit(&Objects[target], NULL, &Objects[target].pos);
3317  }
3318  }
3319  break;
3320 
3321  case OBJ_ASTEROID:
3322  // hit the asteroid
3324  asteroid_hit(&Objects[target], &Objects[b->objnum], &b->f_collisions[idx].cinfo.hit_point_world, wi->damage);
3325  }
3326  break;
3327  case OBJ_SHIP:
3328  // hit the ship - again, the innards of this code handle multiplayer cases
3329  // maybe vaporize ship.
3330  //only apply damage if the collision is not an exit collision. this prevents twice the damage from being done, although it probably be more realistic since two holes are being punched in the ship instead of one.
3331  if (!b->f_collisions[idx].is_exit_collision)
3333 
3334  // if this is the first hit on the player ship. whack him
3335  if(do_damage)
3336  {
3337  // Goober5000 - AGH! BAD BAD BAD BAD BAD BAD BAD BAD bug! The whack's hit point is in *local*
3338  // coordinates, NOT world coordinates!
3339  beam_apply_whack(b, &Objects[target], &b->f_collisions[idx].cinfo.hit_point);
3340  }
3341  break;
3342  }
3343  }
3344 
3345  // if the radius of the target is somewhat close to the radius of the beam, "stop" the beam here
3346  // for now : if its smaller than about 1/3 the radius of the ship
3347  if(widest <= (Objects[target].radius * BEAM_AREA_PERCENT) && !beam_will_tool_target(b, &Objects[target])){
3348  // set last_shot so we know where to properly draw the beam
3350  Assert(is_valid_vec(&b->last_shot));
3351 
3352  // done wif the beam
3353  break;
3354  }
3355  }
3356 
3357  // store the new recent collisions
3358  for(idx=0; idx<r_coll_count; idx++){
3359  b->r_collisions[idx] = r_coll[idx];
3360  }
3361  b->r_collision_count = r_coll_count;
3362 }
3363 
3364 // for a given object, and a firing beam, determine its critical dot product and range
3365 void beam_get_cull_vals(object *objp, beam *b, float *cull_dot, float *cull_dist)
3366 {
3367  switch(objp->type){
3368  // debris and asteroids are classified as slow moving small objects
3369  // use cull_dot == potential cone of beam + 10% and 50.0 meters
3370  case OBJ_DEBRIS:
3371  case OBJ_ASTEROID:
3372  *cull_dot = 1.0f - ((1.0f - beam_get_cone_dot(b)) * 1.10f);
3373  *cull_dist = 50.0f * 50.0f;
3374  return;
3375 
3376  // treat missiles as fast-moving small objects
3377  case OBJ_WEAPON:
3378  *cull_dot = 1.0f - ((1.0f - beam_get_cone_dot(b)) * 1.5f);
3379  *cull_dist = 300.0f * 300.0f;
3380  return;
3381 
3382  case OBJ_SHIP:
3383  // for large ships, cull at some multiple of the radius
3385  *cull_dot = 1.0f - ((1.0f - beam_get_cone_dot(b)) * 1.25f);
3386 
3387  *cull_dist = (objp->radius * 1.3f) * (objp->radius * 1.3f);
3388  return;
3389  }
3390 
3391  // for everthing else, cull the same as missiles
3392  *cull_dot = 1.0f - ((1.0f - beam_get_cone_dot(b)) * 1.5f);
3393  *cull_dist = 300.0f * 300.0f;
3394  return;
3395  }
3396 
3397  // BAD BAD BAD - but this code will cause everything to cull properly
3398  Int3();
3399  *cull_dot = 1.0f;
3400  *cull_dist = 0.0f;
3401  return;
3402 }
3403 
3404 // FIXME - make sure we are truthfull representing the "cone" for all beam types
3405 // get the total possible cone for a given beam in radians
3407 {
3408  switch(b->type){
3409  case BEAM_TYPE_A:
3410  case BEAM_TYPE_C:
3411  case BEAM_TYPE_D:
3412  case BEAM_TYPE_E:
3413  // even though these beams don't move, return a _very_ small value
3414  return cosf(fl_radians(50.5f));
3415 
3416  case BEAM_TYPE_B:
3417  return vm_vec_dot(&b->binfo.dir_a, &b->binfo.dir_b);
3418 
3419  default:
3420  Int3();
3421  }
3422 
3423  Int3();
3424  return 0.0f;
3425 }
3426 
3427 // if it is legal for the beam to fire, or continue firing
3429 {
3430  if (b->objp == NULL) { // If we don't have a firing object, none of these checks make sense.
3431  return 1;
3432  }
3433  // if my own object is invalid, stop firing
3434  if (b->objp->signature != b->sig) {
3435  mprintf(("BEAM : killing beam because of invalid parent object SIGNATURE!\n"));
3436  return -1;
3437  }
3438 
3439  // if my own object is a ghost
3440  if (b->objp->type != OBJ_SHIP) {
3441  mprintf(("BEAM : killing beam because of invalid parent object TYPE!\n"));
3442  return -1;
3443  }
3444 
3445  // type C beams are ok to fire all the time
3446  if (b->type == BEAM_TYPE_C) {
3447  ship *shipp = &Ships[b->objp->instance];
3448 
3449  if (shipp->weapon_energy <= 0.0f) {
3450 
3451  if ( OBJ_INDEX(Player_obj) == shipp->objnum && !(b->life_left>0.0f)) {
3452  extern void ship_maybe_play_primary_fail_sound();
3454  }
3455 
3456  return 0;
3457  } else {
3458  return 1;
3459  }
3460  }
3461 
3462  if (b->subsys == NULL) { // IF we don't have a firing turret, none of these checks make sense.
3463  return 1;
3464  }
3465 
3466  if (!(b->flags & BF_FORCE_FIRING)) {
3467  // if the shooting turret is destroyed
3468  if (b->subsys->current_hits <= 0.0f) {
3469  mprintf(("BEAM : killing beam because turret has been destroyed!\n"));
3470  return -1;
3471  }
3472 
3473  // kill it if its disrupted
3474  if (ship_subsys_disrupted(b->subsys)) {
3475  return -1;
3476  }
3477 
3478  // if the beam will be firing out of its FOV, power it down
3479  vec3d aim_dir;
3480  vm_vec_sub(&aim_dir, &b->last_shot, &b->last_start);
3481  vm_vec_normalize(&aim_dir);
3482 
3484  vec3d turret_normal;
3485 
3486  if (b->flags & BF_IS_FIGHTER_BEAM) {
3487  turret_normal = b->objp->orient.vec.fvec;
3489  } else {
3490  vm_vec_unrotate(&turret_normal, &b->subsys->system_info->turret_norm, &b->objp->orient);
3491  }
3492 
3493  if (!(turret_fov_test(b->subsys, &turret_normal, &aim_dir))) {
3494  nprintf(("BEAM", "BEAM : powering beam down because of FOV condition!\n"));
3495  return 0;
3496  }
3497  } else {
3498  vec3d turret_dir, turret_pos, temp;
3499  beam_get_global_turret_gun_info(b->objp, b->subsys, &turret_pos, &turret_dir, 1, &temp, (b->flags & BF_IS_FIGHTER_BEAM) > 0);
3500  if (vm_vec_dot(&aim_dir, &turret_dir) < b->subsys->system_info->turret_fov) {
3501  nprintf(("BEAM", "BEAM : powering beam down because of FOV condition!\n"));
3502  return 0;
3503  }
3504  }
3505  }
3506 
3507  // ok to fire/continue firing
3508  return 1;
3509 }
3510 
3511 // get the width of the widest section of the beam
3513 {
3514  int idx;
3515  float widest = -1.0f;
3516 
3517  // sanity
3518  Assert(b->weapon_info_index >= 0);
3519  if(b->weapon_info_index < 0){
3520  return -1.0f;
3521  }
3522 
3523  if (b->beam_width > 0.0f) {
3524  widest = b->beam_width;
3525  } else {
3526  // lookup
3527  for(idx=0; idx<Weapon_info[b->weapon_info_index].b_info.beam_num_sections; idx++){
3528  if(Weapon_info[b->weapon_info_index].b_info.sections[idx].width > widest){
3530  }
3531  }
3532  }
3533 
3534  // return
3535  return widest * b->shrink;
3536 }
3537 
3538 // apply a whack to a ship
3539 void beam_apply_whack(beam *b, object *objp, vec3d *hit_point)
3540 {
3541  weapon_info *wip;
3542  ship *shipp;
3543 
3544  // sanity
3545  Assert((b != NULL) && (objp != NULL) && (hit_point != NULL));
3546  if((b == NULL) || (objp == NULL) || (hit_point == NULL)){
3547  return;
3548  }
3549  Assert(b->weapon_info_index >= 0);
3550  wip = &Weapon_info[b->weapon_info_index];
3551  Assert((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >= 0) && (objp->instance < MAX_SHIPS));
3552  if((objp == NULL) || (objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
3553  return;
3554  }
3555  shipp = &Ships[objp->instance];
3556  if((shipp->ai_index < 0) || (shipp->ai_index >= MAX_AI_INFO)){
3557  return;
3558  }
3559 
3560  // don't whack docked ships
3561  // Goober5000 - whacking docked ships should work now, so whack them
3562  // Goober5000 - weapons with no mass don't whack (bypass the calculations)
3563  if(wip->mass == 0.0f) {
3564  return;
3565  }
3566 
3567  // determine how big of a whack to apply
3568  float whack;
3569 
3570  // this if block was added by Bobboau to make beams whack properly while preserving reverse compatibility
3571  if(wip->mass == 100.0f){
3572  if(wip->damage < b_whack_damage){
3573  whack = b_whack_small;
3574  } else {
3575  whack = b_whack_big;
3576  }
3577  }else{
3578  whack = wip->mass;
3579  }
3580 
3581  // whack direction
3582  vec3d whack_dir;
3583  vm_vec_sub(&whack_dir, &b->last_shot, &b->last_start); // Valathil - use the beam direction as the force direction (like a high pressure water jet)
3584  vm_vec_normalize(&whack_dir);
3585  vm_vec_scale(&whack_dir, whack);
3586 
3587  // apply the whack
3588  ship_apply_whack(&whack_dir, hit_point, objp);
3589 }
3590 
3591 // return the amount of damage which should be applied to a ship. basically, filters friendly fire damage
3593 {
3594  // if the beam is on the same team as the object
3595  if ( (objp == NULL) || (b == NULL) ) {
3596  Int3();
3597  return 0.0f;
3598  }
3599 
3600  if ( (objp->type != OBJ_SHIP) || (objp->instance < 0) || (objp->instance >= MAX_SHIPS) ) {
3601  Int3();
3602  return 0.0f;
3603  }
3604 
3606 
3607  if (wip->damage <= 0)
3608  return 0.0f; // Not much point in calculating the attenuation if the beam doesn't hurt in the first place.
3609 
3610  float attenuation = 1.0f;
3611 
3612  if ((b->damage_threshold >= 0.0f) && (b->damage_threshold < 1.0f)) {
3613  float dist = vm_vec_dist(&b->last_shot, &b->last_start);
3614  float range = b->range;
3615  float atten_dist = range * b->damage_threshold;
3616  if ((range > dist) && (atten_dist < dist)) {
3617  attenuation = (dist - atten_dist) / (range - atten_dist);
3618  }
3619  }
3620 
3621  float damage = 0.0f;
3622 
3623  // same team. yikes
3626  } else {
3627  // normal damage
3628  damage = wip->damage * attenuation;
3629  }
3630 
3631  return damage;
3632 }
3633 
3634 // if the beam is likely to tool a given target before its lifetime expires
3636 {
3638  float total_strength, damage_in_a_few_seconds, hp_limit, hp_pct;
3639 
3640  // sanity
3641  if(objp == NULL){
3642  return 0;
3643  }
3644 
3645  // if the object is not a ship, bail
3646  if(objp->type != OBJ_SHIP){
3647  return 0;
3648  }
3649  if((objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
3650  return 0;
3651  }
3652 
3653  ship *shipp = &Ships[objp->instance];
3654  total_strength = objp->hull_strength;
3655 
3656  if (shipp->armor_type_idx != -1) {
3657  if (Armor_types[shipp->armor_type_idx].GetPiercingType(wip->damage_type_idx) == SADTF_PIERCING_NONE) {
3658  return 0;
3659  }
3660  hp_limit = Armor_types[shipp->armor_type_idx].GetPiercingLimit(wip->damage_type_idx);
3661  if (hp_limit > 0.0f) {
3662  hp_pct = total_strength / shipp->ship_max_hull_strength;
3663  if (hp_limit >= hp_pct)
3664  return 1;
3665  }
3666  }
3667 
3668  // calculate total strength, factoring in shield
3669  if (!(wip->wi_flags2 & WIF2_PIERCE_SHIELDS))
3670  total_strength += shield_get_strength(objp);
3671 
3672  // if the beam is going to apply more damage in about 1 and a half than the ship can take
3673  damage_in_a_few_seconds = (TOOLTIME / (float)BEAM_DAMAGE_TIME) * wip->damage;
3674  return (damage_in_a_few_seconds > total_strength);
3675 }
3676 
3677 float beam_accuracy = 1.0f;
3678 DCF(b_aim, "Adjusts the beam accuracy factor (Default is 1.0f)")
3679 {
3680  dc_stuff_float(&beam_accuracy);
3681 }
3682 DCF(beam_list, "Lists all beams")
3683 {
3684  int idx;
3685  int b_count = 0;
3686 
3687  for(idx=0; idx<Num_weapon_types; idx++){
3688  if(Weapon_info[idx].wi_flags & WIF_BEAM){
3689  b_count++;
3690  dc_printf("Beam %d : %s\n", b_count, Weapon_info[idx].name);
3691  }
3692  }
3693 }
void beam_move_all_post()
Definition: beam.cpp:986
void mc_info_init(mc_info *mc)
Definition: model.h:1138
int beam_ok_to_fire(beam *b)
Definition: beam.cpp:3428
int beam_collide_asteroid(obj_pair *pair)
Definition: beam.cpp:2625
int model_collide(mc_info *mc_info_obj)
void beam_add_light_large(beam *bm, object *objp, vec3d *pt0, vec3d *pt1)
Definition: beam.cpp:1699
#define BF_FORCE_FIRING
Definition: beam.h:108
int framecount
Definition: beam.h:128
int timestamp(int delta_ms)
Definition: timer.cpp:226
#define SIF2_SURFACE_SHIELDS
Definition: ship.h:922
void beam_apply_lighting()
Definition: beam.cpp:1778
vec3d target_pos2
Definition: beam.h:65
int Framecount
Definition: systemvars.cpp:22
int i
Definition: multi_pxo.cpp:466
model_subsystem * system_info
Definition: ship.h:314
void send_beam_fired_packet(object *shooter, ship_subsys *turret, object *target, int beam_info_index, beam_info *override, int bfi_flags, int bank_point)
Definition: multimsgs.cpp:7835
float range
Definition: beam.h:162
weapon Weapons[MAX_WEAPONS]
Definition: weapons.cpp:78
SCP_vector< ArmorType > Armor_types
Definition: ship.cpp:170
vec3d hit_point
Definition: model.h:1123
int flags
Definition: beam.h:129
vec3d turret_norm
Definition: model.h:186
vec3d * pos
Definition: model.h:1113
EModelAnimationPosition turret_animation_position
Definition: ship.h:351
int warmup_stamp
Definition: beam.h:133
float beam_friendly_damage_cap[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:111
int team
Definition: ship.h:606
int Cmdline_old_collision_sys
Definition: cmdline.cpp:489
int shield_hit_tri
Definition: model.h:1128
#define PCM_WARPOUT_STAGE1
Definition: player.h:59
int beam_info_index
Definition: beam.h:57
vec3d View_position
Definition: 3dsetup.cpp:20
int objnum
Definition: ship.h:537
int Game_mode
Definition: systemvars.cpp:24
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
#define MAX_BEAMS
Definition: beam.h:40
float shield_get_strength(object *objp)
int f_collision_count
Definition: beam.h:154
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
object * target
Definition: beam.h:62
void weapon_load_bitmaps(int weapon_index)
Definition: weapons.cpp:3275
float v
Definition: pstypes.h:135
#define AIPF2_BEAMS_DAMAGE_WEAPONS
Definition: ai_profiles.h:62
float flFrametime
Definition: fredstubs.cpp:22
ubyte g
Definition: pstypes.h:175
int beam_loop_sound
Definition: weapon.h:263
asteroid Asteroids[MAX_ASTEROIDS]
Definition: asteroid.cpp:63
beam Beam_used_list
Definition: beam.cpp:62
int r_collision_count
Definition: beam.h:150
physics_info phys_info
Definition: object.h:157
generic_anim beam_glow
Definition: weapon.h:267
#define WIF_HUGE
Definition: weapon.h:64
int get_quadrant(vec3d *hit_pnt, object *shipobjp)
Definition: shield.cpp:988
#define MAX_SHIPS
Definition: globals.h:37
int warmdown_stamp
Definition: beam.h:134
int type
Definition: beam.h:135
vec3d target_pos1
Definition: beam.h:64
void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp)
Definition: aiturret.cpp:1327
void beam_type_d_move(beam *b)
Definition: beam.cpp:823
void beam_start_warmup(beam *b)
Definition: beam.cpp:1919
#define BEAM_FAR_LENGTH
Definition: weapon.h:305
ubyte g3_transfer_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:84
int beam_get_collision(int objnum, int num, int *collision_objnum, mc_info **cinfo)
Definition: beam.cpp:655
float glow_length
Definition: weapon.h:268
int model_instance_num
Definition: ship.h:802
ship_type_info * ship_get_type_info(object *objp)
Definition: ship.cpp:16121
float vm_vec_normalize_quick(vec3d *src)
Definition: vecmat.cpp:529
float shrink
Definition: beam.h:130
int beam_collide_missile(obj_pair *pair)
Definition: beam.cpp:2721
Assert(pm!=NULL)
uint flags2
Definition: model.h:170
void beam_calc_facing_pts(vec3d *top, vec3d *bot, vec3d *fvec, vec3d *pos, float w, float z_add)
Definition: beam.cpp:1603
vec3d max
Definition: model.h:585
int bfi_flags
Definition: beam.h:71
Definition: pstypes.h:88
#define BEAM_T(b)
Definition: beam.cpp:753
#define mprintf(args)
Definition: pstypes.h:238
int ai_index
Definition: ship.h:538
float delta_ang
Definition: beam.h:45
int beam_get_parent(object *bm)
Definition: beam.cpp:579
#define NUM_SKILL_LEVELS
Definition: systemvars.h:150
float beam_get_cone_dot(beam *b)
Definition: beam.cpp:3406
#define OBJ_ASTEROID
Definition: object.h:44
void beam_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp, bool fighter_beam)
Definition: beam.cpp:720
float total_time
Definition: generic.h:27
ship_subsys * turret
Definition: beam.h:60
#define MC_CHECK_RAY
Definition: model.h:1176
#define BEAM_AREA_PERCENT
Definition: beam.cpp:49
float piercing_impact_particle_variance
Definition: weapon.h:442
#define TMAP_HTL_3D_UNLIT
Definition: tmapper.h:63
ship_subsys * target_subsys
Definition: beam.h:63
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
ship_subsys * subsys
Definition: beam.h:125
int GetAnim(int weapon_expl_index, vec3d *pos, float size)
Definition: weapons.cpp:253
int Beam_test_stamp
Definition: beam.cpp:93
#define BFIF_TARGETING_COORDS
Definition: beam.h:52
int model_num
Definition: debris.h:34
int beam_will_tool_target(beam *b, object *objp)
Definition: beam.cpp:3635
int beam_collide_debris(obj_pair *pair)
Definition: beam.cpp:2814
#define OF_NO_SHIELDS
Definition: object.h:110
object * target
Definition: beam.h:120
#define STI_WEAP_BEAMS_EASILY_HIT
Definition: ship.h:1001
int Cmdline_nohtl
Definition: cmdline.cpp:438
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
#define Assertion(expr, msg,...)
Definition: clang.h:41
vec3d target_pos1
Definition: beam.h:122
vec3d starting_pos
Definition: beam.h:66
#define f2fl(fx)
Definition: floating.h:37
fix t2
Definition: animplay.cpp:37
int Beam_lighting
Definition: beam.cpp:89
void vm_vec_random_cone(vec3d *out, const vec3d *in, float max_angle, const matrix *orient)
Definition: vecmat.cpp:2418
float shot_aim[MAX_BEAM_SHOTS]
Definition: beam.h:47
void beam_generate_muzzle_particles(beam *b)
Definition: beam.cpp:1284
DCF(beam_list,"Lists all beams")
Definition: beam.cpp:3682
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
void beam_add_light(beam *b, int objnum, int source, vec3d *c_point)
Definition: beam.cpp:1751
#define OF_COLLIDES
Definition: object.h:104
float beam_life
Definition: weapon.h:254
float weapon_energy
Definition: ship.h:640
uint flags
Definition: ship.h:644
ubyte blue
Definition: 2d.h:102
hull_check orient
Definition: lua.cpp:5049
float piercing_impact_particle_back_velocity
Definition: weapon.h:441
object * objp
Definition: lua.cpp:3105
void beam_get_cull_vals(object *objp, beam *b, float *cull_dot, float *cull_dist)
Definition: beam.cpp:3365
int next_check_time
Definition: objcollide.h:58
float hit_dist
Definition: model.h:1122
GLenum GLenum GLenum GLenum GLenum scale
Definition: Glext.h:8503
#define PARTICLE_BITMAP
Definition: particle.h:49
float beam_width
Definition: beam.h:173
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
Definition: 2d.cpp:2105
int beam_particle_count
Definition: weapon.h:258
GLfloat GLfloat GLfloat v2
Definition: Glext.h:5640
void vm_vec_dist_squared_to_line(const vec3d *p, const vec3d *l0, const vec3d *l1, vec3d *nearest, float *dist_squared)
Definition: vecmat.cpp:2543
#define BF_TARGETING_COORDS
Definition: beam.h:110
int subtype
Definition: weapon.h:326
#define Int3()
Definition: pstypes.h:292
float beam_get_ship_damage(beam *b, object *objp)
Definition: beam.cpp:3592
int beam_warmdown
Definition: weapon.h:256
void snd_update_3d_pos(int soundnum, game_snd *gs, vec3d *new_pos, float radius, float range_factor)
Definition: sound.cpp:693
#define BF_IS_FIGHTER_BEAM
Definition: beam.h:109
ship * shipp
Definition: lua.cpp:9162
void beam_init()
Definition: beam.cpp:247
void beam_type_a_move(beam *b)
Definition: beam.cpp:730
vec3d pos
Definition: object.h:152
int beam_collide_early_out(object *a, object *b)
Definition: beam.cpp:2906
void ship_apply_whack(vec3d *force, vec3d *hit_pos, object *objp)
Definition: shiphit.cpp:1740
vec3d * p0
Definition: model.h:1114
void beam_render_all()
Definition: beam.cpp:1558
#define IS_VEC_NULL(v)
Definition: vecmat.h:28
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")
mc_info cinfo
Definition: beam.h:97
void beam_type_b_move(beam *b)
Definition: beam.cpp:754
int piercing_impact_weapon_expl_index
Definition: weapon.h:436
int signature
Definition: object.h:145
int c_sig
Definition: beam.h:99
#define BEAM_TYPE_D
Definition: beam.h:35
int model_num
Definition: model.h:1110
GLenum type
Definition: Gl.h:1492
#define MAX_BEAM_LIGHT_INFO
Definition: beam.cpp:109
float beam_iff_miss_factor[MAX_IFFS][NUM_SKILL_LEVELS]
Definition: weapon.h:262
#define CLAMP(x, min, max)
Definition: pstypes.h:488
void debris_hit(object *debris_obj, object *other_obj, vec3d *hitpos, float damage)
Definition: debris.cpp:751
ubyte green
Definition: 2d.h:101
int weapon_info_index
Definition: weapon.h:164
int beam_fire_targeting(fighter_beam_fire_info *fire_info)
Definition: beam.cpp:476
vec3d targeting_laser_offset
Definition: beam.h:127
int weapon_info_index
Definition: beam.h:117
float damage_threshold
Definition: weapon.h:275
int asteroid_type
Definition: asteroid.h:102
void beam_get_octant_points(int modelnum, object *objp, int oct_index, int oct_array[BEAM_NUM_GOOD_OCTANTS][4], vec3d *v1, vec3d *v2)
Definition: beam.cpp:2333
bool directional_glow
Definition: weapon.h:269
uv_pair texture_position
Definition: pstypes.h:174
#define MC_CHECK_SHIELD
Definition: model.h:1170
float beam_particle_radius
Definition: weapon.h:259
int Beam_muzzle_stamp
Definition: beam.h:170
ubyte a
Definition: pstypes.h:175
int flash_impact_weapon_expl_index
Definition: weapon.h:433
int is_hull
Definition: debris.h:37
int num_frames
Definition: generic.h:20
#define BF_SHRINK
Definition: beam.h:107
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int Beam_good_slash_octants[BEAM_NUM_GOOD_OCTANTS][4]
Definition: beam.cpp:67
Definition: beam.h:114
int instance
Definition: object.h:150
beam_weapon_info b_info
Definition: weapon.h:456
int optional_data
Definition: particle.h:67
int weapon_hitpoints
Definition: weapon.h:530
object * a
Definition: objcollide.h:55
int shot_index
Definition: beam.h:144
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
ubyte shot_count
Definition: beam.h:46
GLenum GLint * range
Definition: Glext.h:7096
float ship_get_subsystem_strength(ship *shipp, int type)
Definition: ship.cpp:13446
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
#define GR_ALPHABLEND_FILTER
Definition: 2d.h:349
float b_whack_small
Definition: beam.cpp:120
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
int objnum
Definition: beam.h:116
#define BEAM_TYPE_E
Definition: beam.h:36
#define SIF_BIG_SHIP
Definition: ship.h:944
int flags
Definition: model.h:1116
#define STI_WEAP_NO_HUGE_IMPACT_EFF
Definition: ship.h:1002
struct matrix::@228::@230 vec
void beam_delete(beam *b)
Definition: beam.cpp:1839
float mass
Definition: weapon.h:358
beam * bm
Definition: beam.cpp:111
int subtype
Definition: lua.cpp:9763
float ship_max_hull_strength
Definition: ship.h:597
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
float beam_particle_angle
Definition: weapon.h:260
void beam_recalc_sounds(beam *b)
Definition: beam.cpp:2004
uint flags
Definition: model.h:169
#define nprintf(args)
Definition: pstypes.h:239
#define TMAP_FLAG_GOURAUD
Definition: tmapper.h:40
#define GM_MULTIPLAYER
Definition: systemvars.h:18
int first_frame
Definition: generic.h:19
void beam_get_binfo(beam *b, float accuracy, int num_shots)
Definition: beam.cpp:2045
int Beam_test_ints
Definition: beam.cpp:94
float beam_shrink_pct
Definition: weapon.h:272
#define CHA_COLLIDEDEBRIS
Definition: scripting.h:49
#define PARTICLE_SMOKE
Definition: particle.h:52
int Beam_test_ship
Definition: beam.cpp:95
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
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
float flash_impact_explosion_radius
Definition: weapon.h:434
beam_collision r_collisions[MAX_FRAME_COLLISIONS]
Definition: beam.h:149
int ship_subsys_disrupted(ship_subsys *ss)
Definition: ship.cpp:9033
#define SADTF_PIERCING_DEFAULT
Definition: ship.h:246
ai_profile_t * ai_profile
Definition: missionparse.h:168
int Beam_test_framecount
Definition: beam.cpp:97
generic_anim beam_particle_ani
Definition: weapon.h:261
int damage_type_idx
Definition: weapon.h:519
#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
vec3d vel
Definition: particle.h:63
void beam_render_muzzle_glow(beam *b)
Definition: beam.cpp:1383
#define WP_LASER
Definition: weapon.h:27
#define MAX_WEAPON_TYPES
Definition: globals.h:73
void weapon_hit(object *weapon_obj, object *other_obj, vec3d *hitpos, int quadrant=-1)
Definition: weapons.cpp:6253
int target_sig
Definition: beam.h:124
int point
Definition: beam.h:70
float hull_strength
Definition: object.h:160
int vm_vec_dist_to_line(const vec3d *p, const vec3d *l0, const vec3d *l1, vec3d *nearest, float *dist)
Definition: vecmat.cpp:2503
#define BEAM_TYPE_A
Definition: beam.h:32
#define OBJ_DEBRIS
Definition: object.h:37
int weapon_bools
Definition: ship.h:1026
#define BFIF_FLOATING_BEAM
Definition: beam.h:53
void hud_shield_quadrant_hit(object *objp, int quadrant)
Definition: hudshield.cpp:541
int is_exit_collision
Definition: beam.h:102
ubyte red
Definition: 2d.h:100
char team
Definition: beam.h:160
beam_weapon_section_info sections[MAX_BEAM_SECTIONS]
Definition: weapon.h:273
object * Viewer_obj
Definition: object.cpp:57
#define MAX_BEAM_SECTIONS
Definition: globals.h:89
shield_info shield
Definition: model.h:778
ubyte g3_rotate_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:97
model_subsystem beam_sys_info
Definition: ship.h:744
void beam_aim(beam *b)
Definition: beam.cpp:2175
bool turret_fov_test(ship_subsys *ss, vec3d *gvec, vec3d *v2e, float size_mod)
Definition: aiturret.cpp:2873
#define BEAM_DAMAGE_TIME
Definition: beam.cpp:54
#define fl_abs(fl)
Definition: floating.h:31
void beam_jitter_aim(beam *b, float aim)
Definition: beam.cpp:2359
float u
Definition: pstypes.h:135
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 beam_get_num_collisions(int objnum)
Definition: beam.cpp:629
bool beam_sort_collisions_func(const beam_collision &b1, const beam_collision &b2)
Definition: beam.cpp:3036
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
int hack_time
Definition: beam.cpp:1278
#define TMAP_FLAG_TILED
Definition: tmapper.h:45
float current_hits
Definition: ship.h:319
int flags2
Definition: ship.h:1228
#define SADTF_PIERCING_RETAIL
Definition: ship.h:247
#define MAX_BEAM_SHOTS
Definition: beam.h:39
Definition: ship.h:534
vec3d pos
Definition: particle.h:62
int Beam_light_count
Definition: beam.cpp:118
#define MSS_FLAG_TURRET_ALT_MATH
Definition: model.h:124
float radius
Definition: model.h:1117
int beam_fire(beam_fire_info *fire_info)
Definition: beam.cpp:281
float piercing_impact_explosion_radius
Definition: weapon.h:437
int turret_num_firing_points
Definition: model.h:191
float vm_vec_normalize_safe(vec3d *v)
Definition: vecmat.cpp:471
int g3_project_vertex(vertex *point)
Definition: 3dmath.cpp:202
int idx
Definition: multiui.cpp:761
debris Debris[MAX_DEBRIS_PIECES]
Definition: debris.cpp:41
beam_info * beam_info_override
Definition: beam.h:67
#define MC_CHECK_SPHERELINE
Definition: model.h:1177
#define CHA_COLLIDEASTEROID
Definition: scripting.h:50
#define SUBSYSTEM_WEAPONS
Definition: model.h:58
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
float piercing_impact_particle_velocity
Definition: weapon.h:440
beam Beams[MAX_BEAMS]
Definition: beam.cpp:60
float vm_vec_dist_squared(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:344
beam_info binfo
Definition: beam.h:167
float damage_threshold
Definition: beam.h:163
float life_total
Definition: beam.h:137
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
bool weapon_is_used(int weapon_index)
Definition: weapons.cpp:3269
void submodel_get_two_random_points(int model_num, int submodel_num, vec3d *v1, vec3d *v2, vec3d *n1=NULL, vec3d *n2=NULL)
#define MSS_FLAG2_SHARE_FIRE_DIRECTION
Definition: model.h:146
unsigned char ubyte
Definition: pstypes.h:62
#define BEAM_TYPE_B
Definition: beam.h:33
int wi_flags
Definition: weapon.h:384
vec3d targeting_laser_offset
Definition: beam.h:59
#define vm_vec_zero(v)
Definition: vecmat.h:37
#define TOOLTIME
Definition: beam.cpp:58
#define CHA_BEAMFIRE
Definition: scripting.h:81
#define OBJ_INDEX(objp)
Definition: object.h:235
void vm_vec_interp_constant(vec3d *out, const vec3d *v0, const vec3d *v1, float t)
Definition: vecmat.cpp:2401
#define CHA_COLLIDEWEAPON
Definition: scripting.h:48
vec3d hit_point_world
Definition: model.h:1124
object * objp
Definition: beam.h:119
#define gr_set_cull
Definition: 2d.h:838
void beam_add_light_small(beam *bm, object *objp, vec3d *pt_override=NULL)
Definition: beam.cpp:1629
matrix orient
Definition: object.h:153
int beam_sound_loop
Definition: beam.h:157
int wi_flags2
Definition: weapon.h:385
void beam_level_init()
Definition: beam.cpp:253
#define TMAP_FLAG_RGB
Definition: tmapper.h:39
void beam_apply_whack(beam *b, object *objp, vec3d *hit_point)
Definition: beam.cpp:3539
vec3d targeting_laser_offset
Definition: beam.h:78
#define BEAM_WARMDOWN_PCT(b)
Definition: beam.cpp:103
GLuint start
Definition: Gl.h:1502
ubyte b
Definition: pstypes.h:175
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
#define SADTF_PIERCING_NONE
Definition: ship.h:245
void add_shield_point(int objnum, int tri_num, vec3d *hit_pos)
Definition: shield.cpp:779
#define OBJ_SHIP
Definition: object.h:32
GLfloat GLfloat v1
Definition: Glext.h:5639
int Beam_test_ast
Definition: beam.cpp:96
#define GM_STANDALONE_SERVER
Definition: systemvars.h:27
#define TMAP_FLAG_CORRECT
Definition: tmapper.h:37
float blight
Definition: beam.cpp:1622
void dc_stuff_float(float *f)
Stuffs a float to the given variable.
void vm_vec_random_in_circle(vec3d *out, const vec3d *in, const matrix *orient, float radius, int on_edge)
Definition: vecmat.cpp:2481
ubyte flags
Definition: pstypes.h:178
void vm_vec_rand_vec_quick(vec3d *rvec)
Definition: vecmat.cpp:1379
float tracer_length
Definition: particle.h:70
int Num_weapon_types
Definition: weapons.cpp:105
color laser_color_1
Definition: weapon.h:350
int is_valid_vec(const vec3d *vec)
Definition: vecmat.cpp:2389
#define WIF2_PIERCE_SHIELDS
Definition: weapon.h:85
#define SIF_HUGE_SHIP
Definition: ship.h:945
int turret_animation_done_time
Definition: ship.h:352
int beam_get_weapon_info_index(object *bm)
Definition: beam.cpp:608
int control_mode
Definition: player.h:134
void dc_stuff_int(int *i)
Stuffs an int to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats...
GLuint const GLchar * name
Definition: Glext.h:5608
int RunCondition(int condition, char format='\0', void *data=NULL, class object *objp=NULL, int more_data=0)
Definition: scripting.cpp:924
int beam_collide_ship(obj_pair *pair)
Definition: beam.cpp:2397
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
fix t1
Definition: animplay.cpp:37
#define STUFF_VERTICES()
Definition: beam.cpp:1132
vec3d Eye_position
Definition: 3dsetup.cpp:27
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
int num_hits
Definition: model.h:1121
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
int bank
Definition: beam.h:168
ubyte source
Definition: beam.cpp:113
int firingpoint
Definition: beam.h:171
void light_add_tube(const vec3d *p0, const vec3d *p1, float r1, float r2, float intensity, float r, float g, float b, int affected_objnum, float spec_r, float spec_g, float spec_b, bool specular)
Definition: lighting.cpp:343
#define BEAM_TYPE_C
Definition: beam.h:34
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
GLuint GLuint num
Definition: Glext.h:9089
vec3d dir_b
Definition: beam.h:44
float beam_section_frame[MAX_BEAM_SECTIONS]
Definition: beam.h:146
void obj_delete(int objnum)
Definition: object.cpp:522
int attached_sig
Definition: particle.h:72
vec3d pnt
Definition: model.h:178
int vm_vec_same(const vec3d *v1, const vec3d *v2)
Definition: vecmat.cpp:1526
#define BFIF_IS_FIGHTER_BEAM
Definition: beam.h:50
float turret_fov
Definition: model.h:188
#define MAX_AI_INFO
Definition: ai.h:564
int turret_next_fire_pos
Definition: ship.h:339
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
int beam_start_firing(beam *b)
Definition: beam.cpp:1931
int c_objnum
Definition: beam.h:98
vec3d dir_a
Definition: beam.h:44
int Beam_count
Definition: beam.cpp:63
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
#define BFIF_FORCE_FIRING
Definition: beam.h:51
GLubyte GLubyte GLubyte GLubyte w
Definition: Glext.h:5679
#define WP_MISSILE
Definition: weapon.h:28
ship_subsys * target_subsys
Definition: beam.h:121
#define BF_FLOATING_BEAM
Definition: beam.h:111
vec3d target_pos2
Definition: beam.h:123
void submodel_get_two_random_points_better(int model_num, int submodel_num, vec3d *v1, vec3d *v2)
#define BEAM_WARMUP_PCT(b)
Definition: beam.cpp:100
#define fl2i(fl)
Definition: floating.h:33
#define PARTICLE_BITMAP_PERSISTENT
Definition: particle.h:54
player * Player
float beam_accuracy
Definition: beam.cpp:3677
int c_stamp
Definition: beam.h:100
#define MC_CHECK_MODEL
Definition: model.h:1169
GLenum target
Definition: Glext.h:6872
void beam_start_warmdown(beam *b)
Definition: beam.cpp:1986
void beam_type_d_get_status(beam *b, int *shot_index, int *fire_wait)
Definition: beam.cpp:862
float lifetime
Definition: particle.h:64
void beam_render(beam *b, float u_offset)
Definition: beam.cpp:1149
#define WIF_BEAM
Definition: weapon.h:76
float b_whack_big
Definition: beam.cpp:121
float beam_shrink_factor
Definition: weapon.h:271
int quadrant
Definition: beam.h:101
#define MAX_FRAME_COLLISIONS
Definition: beam.h:93
int beam_get_model(object *objp)
Definition: beam.cpp:1872
beam Beam_free_list
Definition: beam.cpp:61
object * shooter
Definition: beam.h:58
vec3d c_point
Definition: beam.cpp:114
void RemHookVars(unsigned int num,...)
Definition: scripting.cpp:754
long Game_time_compression
Definition: fredstubs.cpp:202
int ship_info_index
Definition: ship.h:539
#define MULTIPLAYER_MASTER
Definition: multi.h:130
int impact_snd
Definition: weapon.h:415
vec3d last_shot
Definition: beam.h:142
int physics_paused
Definition: object.cpp:677
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
void snd_set_volume(int sig, float volume)
Definition: sound.cpp:920
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
int Beam_good_shot_octants[BEAM_NUM_GOOD_OCTANTS][4]
Definition: beam.cpp:77
#define TMAP_FLAG_TEXTURED
Definition: tmapper.h:36
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
int bank
Definition: beam.h:69
object * b
Definition: objcollide.h:56
#define SND_PRIORITY_SINGLE_INSTANCE
Definition: sound.h:27
#define timestamp_elapsed(stamp)
Definition: timer.h:102
int beam_warmdown_sound
Definition: weapon.h:265
void beam_add_collision(beam *b, object *hit_object, mc_info *cinfo, int quad=-1, int exit_flag=0)
Definition: beam.cpp:3001
int g3_draw_bitmap(vertex *pos, int orient, float radius, uint tmap_flags, float depth=0.0f)
Definition: 3ddraw.cpp:649
hull_check pos
Definition: lua.cpp:5050
int Game_skill_level
Definition: fredstubs.cpp:170
#define BEAM_NUM_GOOD_OCTANTS
Definition: beam.cpp:66
const GLfloat * m
Definition: Glext.h:10319
int model_instance_num
Definition: model.h:1109
int armor_type_idx
Definition: ship.h:796
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
GLenum GLuint GLenum GLsizei length
Definition: Glext.h:5156
int model_num
Definition: weapon.h:329
float accuracy
Definition: beam.h:61
#define i2fl(i)
Definition: floating.h:32
beam_collision f_collisions[MAX_FRAME_COLLISIONS]
Definition: beam.h:153
void asteroid_hit(object *pasteroid_obj, object *other_obj, vec3d *hitpos, float damage)
Definition: asteroid.cpp:1368
GLsizei GLsizei GLchar * source
Definition: Glext.h:5625
float energy_consumed
Definition: weapon.h:383
#define GR_BITBLT_MODE_NORMAL
Definition: 2d.h:351
float impact_explosion_radius
Definition: weapon.h:427
float b_whack_damage
Definition: beam.cpp:122
object * Player_obj
Definition: object.cpp:56
weapon_explosions Weapon_explosions
Definition: weapons.cpp:101
#define P_VERTICES()
Definition: beam.cpp:1143
#define SF_DYING
Definition: ship.h:447
void beam_type_e_move(beam *b)
Definition: beam.cpp:883
int temp
Definition: lua.cpp:4996
int beam_warmup_sound
Definition: weapon.h:264
void dc_printf(const char *format,...)
Prints the given char string to the debug console.
Definition: console.cpp:358
bool is_minimum_GLSL_version()
Definition: gropengl.cpp:2064
polymodel * pm
Definition: lua.cpp:1598
float rad
Definition: particle.h:65
model_octant octants[8]
Definition: model.h:791
#define MAX(a, b)
Definition: pstypes.h:299
int Num_iffs
Definition: iff_defs.cpp:19
void light_add_point_unique(const vec3d *pos, float r1, float r2, float intensity, float r, float g, float b, int affected_objnum, float spec_r, float spec_g, float spec_b, bool specular)
Definition: lighting.cpp:300
#define OBJ_NONE
Definition: object.h:31
#define OBJ_BEAM
Definition: object.h:46
#define CHA_COLLIDESHIP
Definition: scripting.h:47
vec3d * vm_vec_cross(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:645
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
particle * particle_create(particle_info *pinfo)
Definition: particle.cpp:105
void beam_move_all_pre()
Definition: beam.cpp:906
void snd_stop(int sig)
Definition: sound.cpp:875
mission The_mission
int beam_num_sections
Definition: weapon.h:266
int g3_draw_poly(int nv, vertex **pointlist, uint tmap_flags)
Definition: 3ddraw.cpp:207
void beam_pause_sounds()
Definition: beam.cpp:682
vec3d last_start
Definition: beam.h:143
int model_num
Definition: lua.cpp:4996
char team
Definition: beam.h:72
GLclampf GLclampf GLclampf alpha
Definition: Glext.h:5177
int submodel_num
Definition: model.h:1111
char type
Definition: object.h:146
float life_left
Definition: beam.h:136
struct beam_light_info beam_light_info
generic_anim texture
Definition: weapon.h:249
vec3d vmd_zero_vector
Definition: vecmat.cpp:24
GLdouble GLdouble GLdouble GLdouble top
Definition: Glext.h:10330
float damage
Definition: weapon.h:363
void beam_type_c_move(beam *b)
Definition: beam.cpp:791
object * shooter
Definition: beam.h:77
void beam_handle_collisions(beam *b)
Definition: beam.cpp:3042
float beam_glow_frame
Definition: beam.h:145
bool IsConditionOverride(int action, object *objp=NULL)
Definition: scripting.cpp:938
ubyte reverse
Definition: particle.h:73
SCP_vector< asteroid_info > Asteroid_info
Definition: asteroid.cpp:62
int attached_objnum
Definition: particle.h:71
matrix * orient
Definition: model.h:1112
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
int impact_weapon_expl_index
Definition: weapon.h:426
matrix vmd_identity_matrix
Definition: vecmat.cpp:28
int ntris
Definition: model.h:568
int sig
Definition: beam.h:118
int ship_is_shield_up(object *obj, int quadrant)
Definition: shield.cpp:964
void beam_unpause_sounds()
Definition: beam.cpp:703
float beam_muzzle_radius
Definition: weapon.h:257
SCP_vector< ship_type_info > Ship_types
Definition: ship.cpp:168
float beam_width
Definition: weapon.h:276
beam_light_info Beam_lights[MAX_BEAM_LIGHT_INFO]
Definition: beam.cpp:117
#define AIPF_FORCE_BEAM_TURRET_FOV
Definition: ai_profiles.h:50
GLuint GLuint end
Definition: Gl.h:1502
void beam_level_close()
Definition: beam.cpp:273
ubyte r
Definition: pstypes.h:175
#define BF_SAFETY
Definition: beam.h:106
float beam_get_widest(beam *b)
Definition: beam.cpp:3512
#define CHA_COLLIDEBEAM
Definition: scripting.h:74
#define OBJ_RECALC_PAIRS(obj_to_reset)
Definition: object.h:274
float vm_vec_delta_ang_norm(const vec3d *v0, const vec3d *v1, const vec3d *fvec)
Definition: vecmat.cpp:706
vec3d min
Definition: model.h:585
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
#define fl_radians(fl)
Definition: floating.h:42
void ship_maybe_play_primary_fail_sound()
Definition: ship.cpp:10524