FS2_Open
Open source remastering of the Freespace 2 engine
weapons.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "ai/aibig.h"
13 #include "asteroid/asteroid.h"
14 #include "cmdline/cmdline.h"
15 #include "cmeasure/cmeasure.h"
16 #include "debugconsole/console.h"
17 #include "fireball/fireballs.h"
18 #include "freespace2/freespace.h"
19 #include "gamesnd/gamesnd.h"
20 #include "globalincs/linklist.h"
21 #include "graphics/grbatch.h"
22 #include "hud/hud.h"
23 #include "hud/hudartillery.h"
24 #include "iff_defs/iff_defs.h"
25 #include "io/joy_ff.h"
26 #include "io/timer.h"
27 #include "localization/localize.h"
28 #include "math/staticrand.h"
29 #include "mod_table/mod_table.h"
30 #include "model/modelrender.h"
31 #include "network/multi.h"
32 #include "network/multimsgs.h"
33 #include "network/multiutil.h"
34 #include "object/objcollide.h"
35 #include "object/object.h"
36 #include "parse/parselo.h"
37 #include "parse/scripting.h"
38 #include "particle/particle.h"
39 #include "playerman/player.h"
40 #include "radar/radar.h"
41 #include "radar/radarsetup.h"
42 #include "render/3d.h"
43 #include "ship/ship.h"
44 #include "ship/shiphit.h"
45 #include "stats/scoring.h"
46 #include "weapon/beam.h" // for BEAM_TYPE_? definitions
47 #include "weapon/corkscrew.h"
48 #include "weapon/emp.h"
49 #include "weapon/flak.h"
50 #include "weapon/muzzleflash.h"
51 #include "weapon/swarm.h"
52 #include "weapon/weapon.h"
53 
54 // Since SSMs are parsed after weapons, if we want to allow SSM strikes to be specified by name, we need to store those names until after SSMs are parsed.
55 typedef struct delayed_ssm_data {
57  int linenum;
62 
63 typedef struct delayed_ssm_index_data {
65  int linenum;
69 
70 
71 #ifndef NDEBUG
73 DCF_BOOL( weapon_flyby, Weapon_flyby_sound_enabled )
74 #endif
75 
76 static int Weapon_flyby_sound_timer;
77 
80 
81 #define MISSILE_OBJ_USED (1<<0) // flag used in missile_obj struct
82 #define MAX_MISSILE_OBJS MAX_WEAPONS // max number of missiles tracked in missile list
83 missile_obj Missile_objs[MAX_MISSILE_OBJS]; // array used to store missile object indexes
84 missile_obj Missile_obj_list; // head of linked list of missile_obj structs
85 
86 //WEAPON SUBTYPE STUFF
88  "Laser",
89  "Missile",
90  "Beam"
91 };
92 int Num_weapon_subtypes = sizeof(Weapon_subtype_names)/sizeof(char *);
93 
95  { "fast firing", WBF_FAST_FIRING, 0 },
96  { "random length", WBF_RANDOM_LENGTH, 0 }
97 };
98 
100 
102 
104 
106 
107 int Num_weapons = 0;
110 
113 
114 int missile_model = -1;
115 
118 
119 static int *used_weapons = NULL;
120 
122 char **Spawn_names = NULL;
123 
124 int Num_player_weapon_precedence; // Number of weapon types in Player_weapon_precedence
125 int Player_weapon_precedence[MAX_WEAPON_TYPES]; // Array of weapon types, precedence list for player weapon selection
126 
127 // Used to avoid playing too many impact sounds in too short a time interval.
128 // This will elimate the odd "stereo" effect that occurs when two weapons impact at
129 // nearly the same time, like from a double laser (also saves sound channels!)
130 #define IMPACT_SOUND_DELTA 50 // in milliseconds
131 int Weapon_impact_timer; // timer, initialized at start of each mission
132 
133 // energy suck defines
134 #define ESUCK_DEFAULT_WEAPON_REDUCE (10.0f)
135 #define ESUCK_DEFAULT_AFTERBURNER_REDUCE (10.0f)
136 
137 // scale factor for supercaps taking damage from weapons which are not "supercap" weapons
138 #define SUPERCAP_DAMAGE_SCALE 0.25f
139 
140 // scale factor for big ships getting hit by flak
141 #define FLAK_DAMAGE_SCALE 0.05f
142 
143 //default time of a homing weapon to not home
144 #define HOMING_DEFAULT_FREE_FLIGHT_TIME 0.5f
145 
146 // time delay between each swarm missile that is fired
147 #define SWARM_MISSILE_DELAY 150
148 
149 // homing missiles have an extended lifetime so they don't appear to run out of gas before they can hit a moving target at extreme
150 // range. Check the comment in weapon_set_tracking_info() for more details
151 #define LOCKED_HOMING_EXTENDED_LIFE_FACTOR 1.2f
152 
153 extern int compute_num_homing_objects(object *target_objp);
154 
155 extern void fs2netd_add_table_validation(const char *tblname);
156 
157 
159 {
160  ExplosionInfo.clear();
161 }
162 
163 int weapon_explosions::GetIndex(char *filename)
164 {
165  if ( filename == NULL ) {
166  Int3();
167  return -1;
168  }
169 
170  for (size_t i = 0; i < ExplosionInfo.size(); i++) {
171  if ( !stricmp(ExplosionInfo[i].lod[0].filename, filename)) {
172  return (int)i;
173  }
174  }
175 
176  return -1;
177 }
178 
179 int weapon_explosions::Load(char *filename, int expected_lods)
180 {
181  char name_tmp[MAX_FILENAME_LEN] = "";
182  int bitmap_id = -1;
183  int nframes, nfps;
184  weapon_expl_info new_wei;
185 
186  Assert( expected_lods <= MAX_WEAPON_EXPL_LOD );
187 
188  //Check if it exists
189  int idx = GetIndex(filename);
190 
191  if (idx != -1)
192  return idx;
193 
194  new_wei.lod_count = 1;
195 
196  strcpy_s(new_wei.lod[0].filename, filename);
197  new_wei.lod[0].bitmap_id = bm_load_animation(filename, &new_wei.lod[0].num_frames, &new_wei.lod[0].fps, NULL, 1);
198 
199  if (new_wei.lod[0].bitmap_id < 0) {
200  Warning(LOCATION, "Weapon explosion '%s' does not have an LOD0 anim!", filename);
201 
202  // if we don't have the first then it's only safe to assume that the rest are missing or not usable
203  return -1;
204  }
205 
206  // 2 chars for the lod, 4 for the extension that gets added automatically
207  if ( (MAX_FILENAME_LEN - strlen(filename)) > 6 ) {
208  for (idx = 1; idx < expected_lods; idx++) {
209  sprintf(name_tmp, "%s_%d", filename, idx);
210 
211  bitmap_id = bm_load_animation(name_tmp, &nframes, &nfps, NULL, 1);
212 
213  if (bitmap_id > 0) {
214  strcpy_s(new_wei.lod[idx].filename, name_tmp);
215  new_wei.lod[idx].bitmap_id = bitmap_id;
216  new_wei.lod[idx].num_frames = nframes;
217  new_wei.lod[idx].fps = nfps;
218 
219  new_wei.lod_count++;
220  } else {
221  break;
222  }
223  }
224 
225  if (new_wei.lod_count != expected_lods)
226  Warning(LOCATION, "For '%s', %i of %i LODs are missing!", filename, expected_lods - new_wei.lod_count, expected_lods);
227  }
228  else {
229  Warning(LOCATION, "Filename '%s' is too long to have any LODs.", filename);
230  }
231 
232  ExplosionInfo.push_back( new_wei );
233 
234  return (int)(ExplosionInfo.size() - 1);
235 }
236 
238 {
239  int i;
240 
241  if ( (idx < 0) || (idx >= (int)ExplosionInfo.size()) )
242  return;
243 
244  weapon_expl_info *wei = &ExplosionInfo[idx];
245 
246  for ( i = 0; i < wei->lod_count; i++ ) {
247  if ( wei->lod[i].bitmap_id >= 0 ) {
249  }
250  }
251 }
252 
253 int weapon_explosions::GetAnim(int weapon_expl_index, vec3d *pos, float size)
254 {
255  if ( (weapon_expl_index < 0) || (weapon_expl_index >= (int)ExplosionInfo.size()) )
256  return -1;
257 
258  //Get our weapon expl for the day
259  weapon_expl_info *wei = &ExplosionInfo[weapon_expl_index];
260 
261  if (wei->lod_count == 1)
262  return wei->lod[0].bitmap_id;
263 
264  // now we have to do some work
265  vertex v;
266  int x, y, w, h, bm_size;
267  int must_stop = 0;
268  int best_lod = 1;
269  int behind = 0;
270 
271  // start the frame
272  extern int G3_count;
273 
274  if(!G3_count){
275  g3_start_frame(1);
276  must_stop = 1;
277  }
279 
280  // get extents of the rotated bitmap
281  g3_rotate_vertex(&v, pos);
282 
283  // if vertex is behind, find size if in front, then drop down 1 LOD
284  if (v.codes & CC_BEHIND) {
285  float dist = vm_vec_dist_quick(&Eye_position, pos);
286  vec3d temp;
287 
288  behind = 1;
289  vm_vec_scale_add(&temp, &Eye_position, &Eye_matrix.vec.fvec, dist);
290  g3_rotate_vertex(&v, &temp);
291 
292  // if still behind, bail and go with default
293  if (v.codes & CC_BEHIND) {
294  behind = 0;
295  }
296  }
297 
298  if (!g3_get_bitmap_dims(wei->lod[0].bitmap_id, &v, size, &x, &y, &w, &h, &bm_size)) {
299  if (Detail.hardware_textures == 4) {
300  // straight LOD
301  if(w <= bm_size/8){
302  best_lod = 3;
303  } else if(w <= bm_size/2){
304  best_lod = 2;
305  } else if(w <= 1.3f*bm_size){
306  best_lod = 1;
307  } else {
308  best_lod = 0;
309  }
310  } else {
311  // less aggressive LOD for lower detail settings
312  if(w <= bm_size/8){
313  best_lod = 3;
314  } else if(w <= bm_size/3){
315  best_lod = 2;
316  } else if(w <= (1.15f*bm_size)){
317  best_lod = 1;
318  } else {
319  best_lod = 0;
320  }
321  }
322  }
323 
324  // if it's behind, bump up LOD by 1
325  if (behind)
326  best_lod++;
327 
328  // end the frame
329  if (must_stop)
330  g3_end_frame();
331 
332  best_lod = MIN(best_lod, wei->lod_count - 1);
333  Assert( (best_lod >= 0) && (best_lod < MAX_WEAPON_EXPL_LOD) );
334 
335  return wei->lod[best_lod].bitmap_id;
336 }
337 
338 
339 void parse_weapon_expl_tbl(const char *filename)
340 {
341  uint i;
342  lod_checker lod_check;
343 
344  try
345  {
346  read_file_text(filename, CF_TYPE_TABLES);
347  reset_parse();
348 
349  required_string("#Start");
350  while (required_string_either("#End", "$Name:"))
351  {
352  memset(&lod_check, 0, sizeof(lod_checker));
353 
354  // base filename
355  required_string("$Name:");
357 
358  //Do we have an LOD num
359  if (optional_string("$LOD:"))
360  {
361  stuff_int(&lod_check.num_lods);
362  }
363 
364  // only bother with this if we have 1 or more lods and less than max lods,
365  // otherwise the stardard level loading will take care of the different effects
366  if ((lod_check.num_lods > 0) || (lod_check.num_lods < MAX_WEAPON_EXPL_LOD)) {
367  // name check, update lod count if it already exists
368  for (i = 0; i < LOD_checker.size(); i++) {
369  if (!stricmp(LOD_checker[i].filename, lod_check.filename)) {
370  LOD_checker[i].num_lods = lod_check.num_lods;
371  }
372  }
373 
374  // old entry not found, add new entry
375  if (i == LOD_checker.size()) {
376  LOD_checker.push_back(lod_check);
377  }
378  }
379  }
380  required_string("#End");
381  }
382  catch (const parse::ParseException& e)
383  {
384  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
385  return;
386  }
387 }
388 
393 {
394  int i;
395 
396  list_init(&Missile_obj_list);
397  for ( i = 0; i < MAX_MISSILE_OBJS; i++ ) {
398  Missile_objs[i].flags = 0;
399  }
400 }
401 
406 int missile_obj_list_add(int objnum)
407 {
408  int i;
409 
410  for ( i = 0; i < MAX_MISSILE_OBJS; i++ ) {
411  if ( !(Missile_objs[i].flags & MISSILE_OBJ_USED) )
412  break;
413  }
414  if ( i == MAX_MISSILE_OBJS ) {
415  Error(LOCATION, "Fatal Error: Ran out of missile object nodes\n");
416  return -1;
417  }
418 
419  Missile_objs[i].flags = 0;
420  Missile_objs[i].objnum = objnum;
421  list_append(&Missile_obj_list, &Missile_objs[i]);
422  Missile_objs[i].flags |= MISSILE_OBJ_USED;
423 
424  return i;
425 }
426 
432 {
433  Assert(index >= 0 && index < MAX_MISSILE_OBJS);
434  list_remove(&Missile_obj_list, &Missile_objs[index]);
435  Missile_objs[index].flags = 0;
436 }
437 
442 {
443  object *objp;
444 
446 
447  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
448  if ( objp->type == OBJ_WEAPON && Weapon_info[Weapons[objp->instance].weapon_info_index].subtype == WP_MISSILE ) {
450  }
451  }
452 }
453 
459 {
460  Assert(index >= 0 && index < MAX_MISSILE_OBJS);
461  return &Missile_objs[index];
462 }
463 
467 int weapon_info_lookup(const char *name)
468 {
469  // bogus
470  if (name == NULL)
471  return -1;
472 
473  for (int i=0; i<Num_weapon_types; i++)
474  if (!stricmp(name, Weapon_info[i].name))
475  return i;
476 
477  return -1;
478 }
479 
480 #define DEFAULT_WEAPON_SPAWN_COUNT 10
481 
482 // Parse the weapon flags.
483 void parse_wi_flags(weapon_info *weaponp, int wi_flags, int wi_flags2, int wi_flags3)
484 {
485  const char *spawn_str = NOX("Spawn");
486  const size_t spawn_str_len = strlen(spawn_str);
487 
488  //Make sure we HAVE flags :p
489  if(!optional_string("$Flags:"))
490  return;
491 
492  char weapon_strings[MAX_WEAPON_FLAGS][NAME_LENGTH];
493  int num_strings;
494 
495  num_strings = stuff_string_list(weapon_strings, MAX_WEAPON_FLAGS);
496 
497  if (optional_string("+override")) {
498  // reseting the flag values if set to override the existing flags
499  weaponp->wi_flags = wi_flags;
500  weaponp->wi_flags2 = wi_flags2;
501  weaponp->wi_flags3 = wi_flags3;
502  }
503 
504  bool set_pierce = false;
505  bool set_nopierce = false;
506 
507  for (int i=0; i<num_strings; i++) {
508  if (!strnicmp(spawn_str, weapon_strings[i], 5))
509  {
511  {
512  //We need more spawning slots
513  //allocate in slots of 10
514  if((Num_spawn_types % 10) == 0) {
515  Spawn_names = (char **)vm_realloc(Spawn_names, (Num_spawn_types + 10) * sizeof(*Spawn_names));
516  }
517 
518  int skip_length, name_length;
519  char *temp_string;
520 
521  temp_string = weapon_strings[i];
522 
523  weaponp->wi_flags |= WIF_SPAWN;
524  weaponp->spawn_info[weaponp->num_spawn_weapons_defined].spawn_type = (short)Num_spawn_types;
525  skip_length = spawn_str_len + strspn(&temp_string[spawn_str_len], NOX(" \t"));
526  char *num_start = strchr(&temp_string[skip_length], ',');
527  if (num_start == NULL) {
529  name_length = 999;
530  } else {
531  weaponp->spawn_info[weaponp->num_spawn_weapons_defined].spawn_count = (short)atoi(num_start+1);
532  name_length = num_start - temp_string - skip_length;
533  }
534 
536 
537  Spawn_names[Num_spawn_types] = vm_strndup( &weapon_strings[i][skip_length], name_length );
538  Num_spawn_types++;
539  weaponp->num_spawn_weapons_defined++;
540  } else {
541  Warning(LOCATION, "Illegal to have more than %d spawn types for one weapon.\nIgnoring weapon %s", MAX_SPAWN_TYPES_PER_WEAPON, weaponp->name);
542  }
543  } else if (!stricmp(NOX("Remote Detonate"), weapon_strings[i]))
544  weaponp->wi_flags |= WIF_REMOTE;
545  else if (!stricmp(NOX("Puncture"), weapon_strings[i]))
546  weaponp->wi_flags |= WIF_PUNCTURE;
547  else if (!stricmp(NOX("Big Ship"), weapon_strings[i]))
548  weaponp->wi_flags |= WIF_BIG_ONLY;
549  else if (!stricmp(NOX("Huge"), weapon_strings[i]))
550  weaponp->wi_flags |= WIF_HUGE;
551  else if (!stricmp(NOX("Bomber+"), weapon_strings[i]))
552  weaponp->wi_flags |= WIF_BOMBER_PLUS;
553  else if (!stricmp(NOX("child"), weapon_strings[i]))
554  weaponp->wi_flags |= WIF_CHILD;
555  else if (!stricmp(NOX("Bomb"), weapon_strings[i]))
556  weaponp->wi_flags |= WIF_BOMB;
557  else if (!stricmp(NOX("No Dumbfire"), weapon_strings[i]))
558  weaponp->wi_flags |= WIF_NO_DUMBFIRE;
559  else if (!stricmp(NOX("In tech database"), weapon_strings[i]))
560  weaponp->wi_flags |= WIF_IN_TECH_DATABASE;
561  else if (!stricmp(NOX("Player allowed"), weapon_strings[i]))
562  weaponp->wi_flags |= WIF_PLAYER_ALLOWED;
563  else if (!stricmp(NOX("Particle Spew"), weapon_strings[i]))
564  weaponp->wi_flags |= WIF_PARTICLE_SPEW;
565  else if (!stricmp(NOX("EMP"), weapon_strings[i]))
566  weaponp->wi_flags |= WIF_EMP;
567  else if (!stricmp(NOX("Esuck"), weapon_strings[i]))
568  weaponp->wi_flags |= WIF_ENERGY_SUCK;
569  else if (!stricmp(NOX("Flak"), weapon_strings[i]))
570  weaponp->wi_flags |= WIF_FLAK;
571  else if (!stricmp(NOX("Corkscrew"), weapon_strings[i]))
572  weaponp->wi_flags |= WIF_CORKSCREW;
573  else if (!stricmp(NOX("Shudder"), weapon_strings[i]))
574  weaponp->wi_flags |= WIF_SHUDDER;
575  else if (!stricmp(NOX("Electronics"), weapon_strings[i]))
576  weaponp->wi_flags |= WIF_ELECTRONICS;
577  else if (!stricmp(NOX("lockarm"), weapon_strings[i]))
578  weaponp->wi_flags |= WIF_LOCKARM;
579  else if (!stricmp(NOX("beam"), weapon_strings[i]))
580  {
581  weaponp->wi_flags |= WIF_BEAM;
582 
583  // IMPORTANT: beams pierce shields by default :rolleyes: :p - Goober5000
584  weaponp->wi_flags2 |= WIF2_PIERCE_SHIELDS;
585  }
586  else if (!stricmp(NOX("stream"), weapon_strings[i]))
587  weaponp->wi_flags |= WIF_STREAM;
588  else if (!stricmp(NOX("supercap"), weapon_strings[i]))
589  weaponp->wi_flags |= WIF_SUPERCAP;
590  else if (!stricmp(NOX("countermeasure"), weapon_strings[i]))
591  weaponp->wi_flags |= WIF_CMEASURE;
592  else if (!stricmp(NOX("ballistic"), weapon_strings[i]))
593  weaponp->wi_flags2 |= WIF2_BALLISTIC;
594  else if (!stricmp(NOX("pierce shields"), weapon_strings[i]))
595  set_pierce = true;
596  else if (!stricmp(NOX("no pierce shields"), weapon_strings[i])) // only for beams
597  set_nopierce = true;
598  else if (!stricmp(NOX("local ssm"), weapon_strings[i]))
599  weaponp->wi_flags2 |= WIF2_LOCAL_SSM;
600  else if (!stricmp(NOX("tagged only"), weapon_strings[i]))
601  weaponp->wi_flags2 |= WIF2_TAGGED_ONLY;
602  else if (!stricmp(NOX("beam no whack"), weapon_strings[i]))
603  {
604  Warning(LOCATION, "The \"beam no whack\" flag has been deprecated. Set the beam's mass to 0 instead. This has been done for you.\n");
605  weaponp->mass = 0.0f;
606  }
607  else if (!stricmp(NOX("cycle"), weapon_strings[i]))
608  weaponp->wi_flags2 |= WIF2_CYCLE;
609  else if (!stricmp(NOX("small only"), weapon_strings[i]))
610  weaponp->wi_flags2 |= WIF2_SMALL_ONLY;
611  else if (!stricmp(NOX("same turret cooldown"), weapon_strings[i]))
613  else if (!stricmp(NOX("apply no light"), weapon_strings[i]))
614  weaponp->wi_flags2 |= WIF2_MR_NO_LIGHTING;
615  else if (!stricmp(NOX("training"), weapon_strings[i]))
616  weaponp->wi_flags2 |= WIF2_TRAINING;
617  else if (!stricmp(NOX("smart spawn"), weapon_strings[i]))
618  weaponp->wi_flags2 |= WIF2_SMART_SPAWN;
619  else if (!stricmp(NOX("inherit parent target"), weapon_strings[i]))
621  else if (!stricmp(NOX("no emp kill"), weapon_strings[i]))
622  weaponp->wi_flags2 |= WIF2_NO_EMP_KILL;
623  else if (!stricmp(NOX("untargeted heat seeker"), weapon_strings[i]))
625  else if (!stricmp(NOX("no radius doubling"), weapon_strings[i])) {
626  if (weaponp->wi_flags & WIF_BOMB) {
627  weaponp->wi_flags2 |= WIF2_HARD_TARGET_BOMB;
628  }
629  else {
630  Warning(LOCATION, "Weapon %s is not a bomb but has \"no radius doubling\" set. Ignoring this flag", weaponp->name);
631  }
632  }
633  else if (!stricmp(NOX("no subsystem homing"), weapon_strings[i]))
634  weaponp->wi_flags2 |= WIF2_NON_SUBSYS_HOMING;
635  else if (!stricmp(NOX("no lifeleft penalty"), weapon_strings[i]))
637  else if (!stricmp(NOX("can be targeted"), weapon_strings[i]))
638  weaponp->wi_flags2 |= WIF2_CAN_BE_TARGETED;
639  else if (!stricmp(NOX("show on radar"), weapon_strings[i]))
640  weaponp->wi_flags2 |= WIF2_SHOWN_ON_RADAR;
641  else if (!stricmp(NOX("show friendly on radar"), weapon_strings[i]))
642  weaponp->wi_flags2 |= WIF2_SHOW_FRIENDLY;
643  else if (!stricmp(NOX("capital+"), weapon_strings[i]))
644  weaponp->wi_flags2 |= WIF2_CAPITAL_PLUS;
645  else if (!stricmp(NOX("chain external model fps"), weapon_strings[i]))
647  else if (!stricmp(NOX("external model launcher"), weapon_strings[i]))
649  else if (!stricmp(NOX("takes blast damage"), weapon_strings[i]))
651  else if (!stricmp(NOX("takes shockwave damage"), weapon_strings[i]))
653  else if (!stricmp(NOX("hide from radar"), weapon_strings[i]))
655  else if (!stricmp(NOX("render flak"), weapon_strings[i]))
656  weaponp->wi_flags2 |= WIF2_RENDER_FLAK;
657  else if (!stricmp(NOX("ciws"), weapon_strings[i]))
658  weaponp->wi_flags2 |= WIF2_CIWS;
659  else if (!stricmp(NOX("anti-subsystem beam"), weapon_strings[i]))
660  weaponp->wi_flags2 |= WIF2_ANTISUBSYSBEAM;
661  else if (!stricmp(NOX("no primary linking"), weapon_strings[i]))
662  weaponp->wi_flags3 |= WIF3_NOLINK;
663  else if (!stricmp(NOX("same emp time for capships"), weapon_strings[i]))
665  else if (!stricmp(NOX("no primary linked penalty"), weapon_strings[i]))
666  weaponp->wi_flags3 |= WIF3_NO_LINKED_PENALTY;
667  else if (!stricmp(NOX("no homing speed ramp"), weapon_strings[i]))
669  else if (!stricmp(NOX("pulls aspect seekers"), weapon_strings[i]))
670  {
671  if (!(weaponp->wi_flags & WIF_CMEASURE))
672  {
673  Warning(LOCATION, "\"pulls aspect seekers\" may only be used for countermeasures!");
674  }
675  else
676  {
678  }
679  }
680  else if (!stricmp(NOX("interceptable"), weapon_strings[i]))
682  else if (!stricmp(NOX("turret interceptable"), weapon_strings[i]))
684  else if (!stricmp(NOX("fighter interceptable"), weapon_strings[i]))
686  else if (!stricmp(NOX("apply recoil"), weapon_strings[i]))
687  weaponp->wi_flags3 |= WIF3_APPLY_RECOIL;
688  else if (!stricmp(NOX("don't spawn if shot"), weapon_strings[i]))
690  else if (!stricmp(NOX("die on lost lock"), weapon_strings[i])) {
691  if (!(weaponp->wi_flags & WIF_LOCKED_HOMING)) {
692  Warning(LOCATION, "\"die on lost lock\" may only be used for Homing Type ASPECT/JAVELIN!");
693  }
694  else {
695  weaponp->wi_flags3 |= WIF3_DIE_ON_LOST_LOCK;
696  }
697  }
698  else
699  Warning(LOCATION, "Bogus string in weapon flags: %s\n", weapon_strings[i]);
700  }
701 
702  // Goober5000 - fix up pierce/nopierce flags, per Mantis #2442
703  if (set_pierce)
704  weaponp->wi_flags2 |= WIF2_PIERCE_SHIELDS;
705  if (set_nopierce)
706  weaponp->wi_flags2 &= ~WIF2_PIERCE_SHIELDS;
707 
708  // set default tech room status - Goober5000
709  if (weaponp->wi_flags & WIF_IN_TECH_DATABASE)
711 
712  // SWARM, CORKSCREW and FLAK should be mutually exclusive
713  if (weaponp->wi_flags & WIF_FLAK)
714  {
715  if ((weaponp->wi_flags & WIF_SWARM) || (weaponp->wi_flags & WIF_CORKSCREW))
716  {
717  Warning(LOCATION, "Swarm, Corkscrew, and Flak are mutually exclusive! Removing Swarm and Corkscrew attributes.\n");
718  weaponp->wi_flags &= ~WIF_SWARM;
719  weaponp->wi_flags &= ~WIF_CORKSCREW;
720  }
721  }
722  else
723  {
724  if ((weaponp->wi_flags & WIF_SWARM) && (weaponp->wi_flags & WIF_CORKSCREW))
725  {
726  Warning(LOCATION, "Swarm and Corkscrew are mutually exclusive! Defaulting to Swarm.\n");
727  weaponp->wi_flags &= ~WIF_CORKSCREW;
728  }
729  }
730 
731  if (weaponp->wi_flags2 & WIF2_LOCAL_SSM)
732  {
733  if (!(weaponp->wi_flags & WIF_HOMING) || (weaponp->subtype !=WP_MISSILE))
734  {
735  Warning(LOCATION, "local ssm must be guided missile: %s", weaponp->name);
736  }
737  }
738 
739  if ((weaponp->wi_flags2 & WIF2_SMALL_ONLY) && (weaponp->wi_flags & WIF_HUGE))
740  {
741  Warning(LOCATION,"\"small only\" and \"huge\" flags are mutually exclusive.\nThey are used together in %s\nAI will most likely not use this weapon",weaponp->name);
742  }
743 
744  if (!(weaponp->wi_flags & WIF_SPAWN) && (weaponp->wi_flags2 & WIF2_SMART_SPAWN))
745  {
746  Warning(LOCATION,"\"smart spawn\" flag used without \"spawn\" flag in %s\n",weaponp->name);
747  }
748 
749  if ((weaponp->wi_flags2 & WIF2_INHERIT_PARENT_TARGET) && (!(weaponp->wi_flags & WIF_CHILD)))
750  {
751  Warning(LOCATION,"Weapon %s has the \"inherit parent target\" flag, but not the \"child\" flag. No changes in behavior will occur.", weaponp->name);
752  }
753 
754  if (!(weaponp->wi_flags & WIF_HOMING_HEAT) && (weaponp->wi_flags2 & WIF2_UNTARGETED_HEAT_SEEKER))
755  {
756  Warning(LOCATION,"Weapon '%s' has the \"untargeted heat seeker\" flag, but Homing Type is not set to \"HEAT\".", weaponp->name);
757  }
758 }
759 
760 void parse_shockwave_info(shockwave_create_info *sci, char *pre_char)
761 {
762  char buf[NAME_LENGTH];
763 
764  sprintf(buf, "%sShockwave damage:", pre_char);
765  if(optional_string(buf)) {
766  stuff_float(&sci->damage);
767  }
768 
769  sprintf(buf, "%sShockwave damage type:", pre_char);
770  if(optional_string(buf)) {
774  }
775 
776  sprintf(buf, "%sBlast Force:", pre_char);
777  if(optional_string(buf)) {
778  stuff_float(&sci->blast);
779  }
780 
781  sprintf(buf, "%sInner Radius:", pre_char);
782  if(optional_string(buf)) {
783  stuff_float(&sci->inner_rad);
784  }
785 
786  sprintf(buf, "%sOuter Radius:", pre_char);
787  if(optional_string(buf)) {
788  stuff_float(&sci->outer_rad);
789  }
790 
791  if (sci->outer_rad < sci->inner_rad) {
792  Warning(LOCATION, "Shockwave outer radius must be greater than or equal to the inner radius!");
793  sci->outer_rad = sci->inner_rad;
794  }
795 
796  sprintf(buf, "%sShockwave Speed:", pre_char);
797  if(optional_string(buf)) {
798  stuff_float(&sci->speed);
799  }
800 
801  sprintf(buf, "%sShockwave Rotation:", pre_char);
802  if(optional_string(buf)) {
803  float angs[3];
804  stuff_float_list(angs, 3);
805  for(int i = 0; i < 3; i++)
806  {
807  angs[i] = angs[i] * (PI2/180.0f);
808  while(angs[i] < 0)
809  {
810  angs[i] += PI2;
811  }
812  while(angs[i] > PI2)
813  {
814  angs[i] -= PI2;
815  }
816  }
817  sci->rot_angles.p = angs[0];
818  sci->rot_angles.b = angs[1];
819  sci->rot_angles.h = angs[2];
820  }
821 
822  sprintf(buf, "%sShockwave Model:", pre_char);
823  if(optional_string(buf)) {
825  }
826 
827  sprintf(buf, "%sShockwave Name:", pre_char);
828  if(optional_string(buf)) {
830  }
831 }
832 
833 void init_weapon_entry(int weap_info_index)
834 {
835  Assert(weap_info_index > -1 && weap_info_index < MAX_WEAPON_TYPES);
836  weapon_info *wip = &Weapon_info[weap_info_index];
837  int i, j;
838 
841 
842  wip->subtype = WP_UNUSED;
843  wip->render_type = WRT_NONE;
844 
845  memset(wip->name, 0, sizeof(wip->name));
846  memset(wip->title, 0, sizeof(wip->title));
847  wip->desc = NULL;
848 
849  memset(wip->tech_title, 0, sizeof(wip->tech_title));
850  memset(wip->tech_anim_filename, 0, sizeof(wip->tech_anim_filename));
851  wip->tech_desc = NULL;
852  memset(wip->tech_model, 0, sizeof(wip->tech_model));
853 
854  memset(wip->hud_filename, 0, sizeof(wip->hud_filename));
855  wip->hud_image_index = -1;
856 
857  memset(wip->pofbitmap_name, 0, sizeof(wip->pofbitmap_name));
858 
859  wip->model_num = -1;
860  wip->hud_target_lod = -1;
861  wip->num_detail_levels = -1;
862  for ( i = 0; i < MAX_MODEL_DETAIL_LEVELS; i++ )
863  {
864  wip->detail_distance[i] = -1;
865  }
866 
867  vm_vec_zero(&wip->closeup_pos);
868  wip->closeup_zoom = 1.0f;
869 
872 
873  gr_init_color(&wip->laser_color_1, 255, 255, 255);
874  gr_init_color(&wip->laser_color_2, 255, 255, 255);
875 
876  wip->laser_length = 10.0f;
877  wip->laser_head_radius = 1.0f;
878  wip->laser_tail_radius = 1.0f;
879 
880  memset(wip->external_model_name, 0, sizeof(wip->external_model_name));
881  wip->external_model_num = -1;
882 
883  wip->weapon_submodel_rotate_accell = 10.0f;
884  wip->weapon_submodel_rotate_vel = 0.0f;
885 
886  wip->mass = 1.0f;
887  wip->max_speed = 10.0f;
888  wip->acceleration_time = 0.0f;
889  wip->vel_inherit_amount = 1.0f;
890  wip->free_flight_time = 0.0f;
891  wip->fire_wait = 1.0f;
892  wip->max_delay = 0.0f;
893  wip->min_delay = 0.0f;
894  wip->damage = 0.0f;
895  wip->damage_time = -1.0f;
896  wip->atten_damage = -1.0f;
897 
898  wip->damage_type_idx = -1;
899  wip->damage_type_idx_sav = -1;
900 
901  wip->armor_type_idx = -1;
902 
903  wip->arm_time = 0;
904  wip->arm_dist = 0.0f;
905  wip->arm_radius = 0.0f;
906  wip->det_range = 0.0f;
907  wip->det_radius = 0.0f;
908  wip->flak_targeting_accuracy = 60.0f; // Standard value as defined in flak.cpp
909  wip->flak_detonation_accuracy = 65.0f;
910  wip->untargeted_flak_range_penalty = 20.0f;
911 
912  wip->armor_factor = 1.0f;
913  wip->shield_factor = 1.0f;
914  wip->subsystem_factor = 1.0f;
915 
916  wip->life_min = -1.0f;
917  wip->life_max = -1.0f;
918  wip->lifetime = 1.0f;
919  wip->energy_consumed = 0.0f;
920 
921  wip->cargo_size = 1.0f;
922 
923  wip->turn_time = 1.0f;
924  wip->fov = 0; //should be cos(pi), not pi
925 
926  wip->min_lock_time = 0.0f;
927  wip->lock_pixels_per_sec = 50;
928  wip->catchup_pixels_per_sec = 50;
929  wip->catchup_pixel_penalty = 50;
930  wip->seeker_strength = 1.0f;
931 
932  wip->swarm_count = -1;
933  // *Default is 150 -Et1
935 
936  wip->pre_launch_snd = -1;
938 
939  wip->launch_snd = -1;
940  wip->impact_snd = -1;
941  wip->disarmed_impact_snd = -1;
942  wip->flyby_snd = -1;
943 
944  wip->rearm_rate = 1.0f;
945 
946  wip->weapon_range = 999999999.9f;
947  // *Minimum weapon range, default is 0 -Et1
948  wip->WeaponMinRange = 0.0f;
949 
950  wip->num_spawn_weapons_defined = 0;
951 
952  for (i = 0; i < MAX_SPAWN_TYPES_PER_WEAPON; i++)
953  {
954  wip->spawn_info[i].spawn_type = -1;
955  wip->spawn_info[i].spawn_angle = 180;
957  }
958 
959  // Trails
960  wip->tr_info.pt = vmd_zero_vector;
961  wip->tr_info.w_start = 1.0f;
962  wip->tr_info.w_end = 1.0f;
963  wip->tr_info.a_start = 1.0f;
964  wip->tr_info.a_end = 1.0f;
965  wip->tr_info.max_life = 1.0f;
966  wip->tr_info.stamp = 0;
967  generic_bitmap_init(&wip->tr_info.texture, NULL);
968  wip->tr_info.n_fade_out_sections = 0;
969 
970  memset(wip->icon_filename, 0, sizeof(wip->icon_filename));
971 
972  memset(wip->anim_filename, 0, sizeof(wip->anim_filename));
973 
974  wip->impact_explosion_radius = 1.0f;
975  wip->impact_weapon_expl_index = -1;
976 
977  wip->shield_impact_explosion_radius = 1.0f;
978 
979  wip->dinky_impact_explosion_radius = 1.0f;
981 
983  wip->flash_impact_explosion_radius = 0.0f;
984 
987  wip->piercing_impact_particle_life = 0.0f;
992 
993  wip->muzzle_flash = -1;
994 
996  wip->emp_time = EMP_DEFAULT_TIME; // Goober5000: <-- Look! I fixed a Volition bug! Gimme $5, Dave!
997  wip->recoil_modifier = 1.0f;
1000 
1001  //customizeable corkscrew stuff
1002  wip->cs_num_fired=4;
1003  wip->cs_radius=1.25f;
1004  wip->cs_delay=30;
1005  wip->cs_crotate=1;
1006  wip->cs_twist=5.0f;
1007 
1008  wip->elec_time=8000;
1009  wip->elec_eng_mult=1.0f;
1010  wip->elec_weap_mult=1.0f;
1011  wip->elec_beam_mult=1.0f;
1012  wip->elec_sensors_mult=1.0f;
1013  wip->elec_randomness=2000;
1014  wip->elec_use_new_style=0;
1015 
1016  wip->lssm_warpout_delay=0; //delay between launch and warpout (ms)
1017  wip->lssm_warpin_delay=0; //delay between warpout and warpin (ms)
1018  wip->lssm_stage5_vel=0; //velocity during final stage
1019  wip->lssm_warpin_radius=0;
1020  wip->lssm_lock_range=1000000.0f; //local ssm lock range (optional)
1021 
1022  wip->cm_aspect_effectiveness = 1.0f;
1023  wip->cm_heat_effectiveness = 1.0f;
1026  wip->cm_kill_single = false;
1027 
1028  wip->b_info.beam_type = -1;
1029  wip->b_info.beam_life = -1.0f;
1030  wip->b_info.beam_warmup = -1;
1031  wip->b_info.beam_warmdown = -1;
1032  wip->b_info.beam_muzzle_radius = 0.0f;
1033  wip->b_info.beam_particle_count = -1;
1034  wip->b_info.beam_particle_radius = 0.0f;
1035  wip->b_info.beam_particle_angle = 0.0f;
1036  wip->b_info.beam_loop_sound = -1;
1037  wip->b_info.beam_warmup_sound = -1;
1038  wip->b_info.beam_warmdown_sound = -1;
1039  wip->b_info.beam_num_sections = 0;
1040  wip->b_info.glow_length = 0;
1041  wip->b_info.directional_glow = false;
1042  wip->b_info.beam_shots = 1;
1043  wip->b_info.beam_shrink_factor = 0.0f;
1044  wip->b_info.beam_shrink_pct = 0.0f;
1045  wip->b_info.range = BEAM_FAR_LENGTH;
1046  wip->b_info.damage_threshold = 1.0f;
1047  wip->b_info.beam_width = -1.0f;
1048 
1049  generic_anim_init(&wip->b_info.beam_glow, NULL);
1051 
1052  for (i = 0; i < MAX_IFFS; i++)
1053  for (j = 0; j < NUM_SKILL_LEVELS; j++)
1054  wip->b_info.beam_iff_miss_factor[i][j] = 0.00001f;
1055 
1056  //WMC - Okay, so this is needed now
1058  for (i = 0; i < MAX_BEAM_SECTIONS; i++) {
1059  bsip = &wip->b_info.sections[i];
1060 
1061  generic_anim_init(&bsip->texture, NULL);
1062 
1063  bsip->width = 1.0f;
1064  bsip->flicker = 0.1f;
1065  bsip->z_add = i2fl(MAX_BEAM_SECTIONS - i - 1);
1066  bsip->tile_type = 0;
1067  bsip->tile_factor = 1.0f;
1068  bsip->translation = 0.0f;
1069  }
1070 
1071  for (size_t s = 0; s < MAX_PARTICLE_SPEWERS; s++) { // default values for everything -nuke
1072  wip->particle_spewers[s].particle_spew_type = PSPEW_NONE; // added by nuke
1075  wip->particle_spewers[s].particle_spew_vel = 0.4f;
1078  wip->particle_spewers[s].particle_spew_scale = 0.8f;
1079  wip->particle_spewers[s].particle_spew_z_scale = 1.0f; // added by nuke
1084  }
1085 
1086  wip->tag_level = -1;
1087  wip->tag_time = -1.0f;
1088 
1089  wip->SSM_index =-1; // tag C SSM index, wich entry in the SSM table this weapon calls -Bobboau
1090 
1091  wip->field_of_fire = 0.0f;
1092  wip->fof_spread_rate = 0.0f;
1093  wip->fof_reset_rate = 0.0f;
1094  wip->max_fof_spread = 0.0f;
1095 
1096  wip->shots = 1;
1097 
1098  wip->alpha_max = 1.0f;
1099  wip->alpha_min = 0.0f;
1100  wip->alpha_cycle = 0.0f;
1101 
1104 
1105  wip->weapon_hitpoints = 0;
1106 
1107  wip->burst_delay = 1.0f; // 1 second, just incase its not defined
1108  wip->burst_shots = 0;
1109  wip->burst_flags = 0;
1110 
1113 
1114  wip->thruster_glow_factor = 1.0f;
1115  wip->target_lead_scaler = 0.0f;
1116 
1118 
1119  wip->hud_locked_snd = -1;
1120  wip->hud_tracking_snd = -1;
1121  wip->hud_in_flight_snd = -1;
1122 }
1123 
1124 // function to parse the information for a specific weapon type.
1125 // return 0 if successful, otherwise return -1
1126 #define WEAPONS_MULTITEXT_LENGTH 2048
1127 
1128 int parse_weapon(int subtype, bool replace, const char *filename)
1129 {
1131  weapon_info *wip = NULL;
1132  char fname[NAME_LENGTH];
1133  int iff, idx;
1134  int primary_rearm_rate_specified=0;
1135  bool first_time = false;
1136  bool create_if_not_found = true;
1137  int wi_flags = WIF_DEFAULT_VALUE;
1138  int wi_flags2 = WIF2_DEFAULT_VALUE;
1139  int wi_flags3 = WIF3_DEFAULT_VALUE;
1140 
1141  required_string("$Name:");
1142  stuff_string(fname, F_NAME, NAME_LENGTH);
1143  diag_printf ("Weapon name -- %s\n", fname);
1144 
1145  if(optional_string("+nocreate")) {
1146  if(!replace) {
1147  Warning(LOCATION, "+nocreate flag used for weapon in non-modular table");
1148  }
1149  create_if_not_found = false;
1150  }
1151 
1152  //Remove @ symbol
1153  //these used to be used to denote weapons that would
1154  //only be parsed in demo builds
1155  if ( fname[0] == '@' ) {
1156  backspace(fname);
1157  }
1158 
1159  int w_id = weapon_info_lookup(fname);
1160 
1161  if(w_id != -1)
1162  {
1163  wip = &Weapon_info[w_id];
1164  if(!replace)
1165  {
1166  Warning(LOCATION, "Weapon name %s already exists in weapons.tbl. All weapon names must be unique; the second entry has been skipped", wip->name);
1167  if ( !skip_to_start_of_string_either("$Name:", "#End")) {
1168  Int3();
1169  }
1170  return -1;
1171  }
1172  }
1173  else
1174  {
1175  //Don't create weapon if it has +nocreate and is in a modular table.
1176  if(!create_if_not_found && replace)
1177  {
1178  if ( !skip_to_start_of_string_either("$Name:", "#End")) {
1179  Int3();
1180  }
1181 
1182  return -1;
1183  }
1184 
1185  if(Num_weapon_types >= MAX_WEAPON_TYPES) {
1186  Error(LOCATION, "Too many weapon classes before '%s'; maximum is %d.\n", fname, MAX_WEAPON_TYPES);
1187  }
1188 
1189  wip = &Weapon_info[Num_weapon_types];
1190  init_weapon_entry(Num_weapon_types);
1191  first_time = true;
1192 
1193  strcpy_s(wip->name, fname);
1194  Num_weapon_types++;
1195  }
1196 
1197  if(optional_string("$Alt name:"))
1199 
1200  //Set subtype
1201  if(optional_string("$Subtype:"))
1202  {
1203  stuff_string(fname, F_NAME, NAME_LENGTH);
1204 
1205  if(!stricmp("Primary", fname)) {
1206  wip->subtype = WP_LASER;
1207  } else if(!stricmp("Secondary", fname)) {
1208  wip->subtype = WP_MISSILE;
1209  } else {
1210  Warning(LOCATION, "Unknown subtype on weapon '%s'", wip->name);
1211  }
1212  }
1213  else if(wip->subtype != WP_UNUSED && !first_time)
1214  {
1215  if(wip->subtype != subtype) {
1216  Warning(LOCATION, "Type of weapon %s entry does not agree with original entry type.", wip->name);
1217  }
1218  }
1219  else
1220  {
1221  wip->subtype = subtype;
1222  }
1223 
1224  if (optional_string("+Title:")) {
1226  }
1227 
1228  if (optional_string("+Description:")) {
1229  if (wip->desc != NULL) {
1230  vm_free(wip->desc);
1231  wip->desc = NULL;
1232  }
1233 
1235  }
1236 
1237  if (optional_string("+Tech Title:")) {
1239  }
1240 
1241  if (optional_string("+Tech Anim:")) {
1243  }
1244 
1245  if (optional_string("+Tech Description:")) {
1246  if (wip->tech_desc != NULL) {
1247  vm_free(wip->tech_desc);
1248  wip->tech_desc = NULL;
1249  }
1250 
1252  }
1253 
1254  if (optional_string("$Tech Model:")) {
1256 
1257  if (optional_string("+Closeup_pos:")) {
1258  stuff_vec3d(&wip->closeup_pos);
1259  }
1260 
1261  if (optional_string("+Closeup_zoom:")) {
1262  stuff_float(&wip->closeup_zoom);
1263  }
1264  }
1265 
1266  // Weapon fadein effect, used when no ani is specified or weapon_select_3d is active
1267  wip->selection_effect = Default_weapon_select_effect; // By default, use the FS2 effect
1268  if(optional_string("$Selection Effect:")) {
1269  char effect[NAME_LENGTH];
1270  stuff_string(effect, F_NAME, NAME_LENGTH);
1271  if (!stricmp(effect, "FS2"))
1272  wip->selection_effect = 2;
1273  else if (!stricmp(effect, "FS1"))
1274  wip->selection_effect = 1;
1275  else if (!stricmp(effect, "off"))
1276  wip->selection_effect = 0;
1277  }
1278 
1279  //Check for the HUD image string
1280  if(optional_string("$HUD Image:")) {
1282  }
1283 
1284  // Read the model file. It can be a POF file or none.
1285  // If there is no model file (Model file: = "none") then we use our special
1286  // laser renderer which requires inner, middle and outer information.
1287  if ( optional_string("$Model file:") ) {
1289 
1290  if ( VALID_FNAME(wip->pofbitmap_name) )
1291  wip->render_type = WRT_POF;
1292 
1293  diag_printf("Model pof file -- %s\n", wip->pofbitmap_name );
1294  }
1295 
1296  // a special LOD level to use when rendering the weapon in the hud targetbox
1297  if ( optional_string( "$POF target LOD:" ) )
1298  stuff_int(&wip->hud_target_lod);
1299 
1300  if(optional_string("$Detail distance:")) {
1302  }
1303 
1304  if ( optional_string("$External Model File:") )
1306 
1307  if ( optional_string("$Submodel Rotation Speed:") )
1309 
1310  if ( optional_string("$Submodel Rotation Acceleration:") )
1312 
1313  // No POF or AVI file specified, render as special laser type.(?)
1314  ubyte r,g,b;
1315 
1316  // laser bitmap itself
1317  if ( optional_string("@Laser Bitmap:") ) {
1318  stuff_string(fname, F_NAME, NAME_LENGTH);
1319 
1320  if (wip->render_type == WRT_POF) {
1321  mprintf(("WARNING: Weapon '%s' has both LASER and POF render types! Will only use POF type!\n", wip->name));
1322  generic_anim_init(&wip->laser_bitmap, NULL);
1323  } else {
1324  generic_anim_init(&wip->laser_bitmap, fname);
1325  wip->render_type = WRT_LASER;
1326  }
1327  }
1328 
1329  // optional laser glow
1330  if ( optional_string("@Laser Glow:") ) {
1331  stuff_string(fname, F_NAME, NAME_LENGTH);
1332 
1333  if (wip->render_type != WRT_LASER) {
1334  mprintf(("WARNING: Laser glow specified on non-LASER type weapon (%s)!\n", wip->name));
1335  Int3();
1336  } else {
1337  generic_anim_init(&wip->laser_glow_bitmap, fname);
1338  }
1339  }
1340 
1341  if(optional_string("@Laser Color:"))
1342  {
1343  // This might be confusing at first glance. If we're a modular table (!first_time),
1344  // AND we're providing a new color for the laser (being in this block at all),
1345  // AND the RGB values for laser_color_1 and laser_color_2 match...
1346  // THEN we conclude that laser_color_2 wasn't explicitly defined before, and the modder would probably prefer
1347  // it if the laser didn't suddenly start changing colors from the new to the old over its lifespan. -MageKing17
1348  bool reset = (!first_time && (
1349  (wip->laser_color_1.red == wip->laser_color_2.red) &&
1350  (wip->laser_color_1.green == wip->laser_color_2.green) &&
1351  (wip->laser_color_1.blue == wip->laser_color_2.blue)));
1352  stuff_ubyte(&r);
1353  stuff_ubyte(&g);
1354  stuff_ubyte(&b);
1355  gr_init_color( &wip->laser_color_1, r, g, b );
1356  if (reset) {
1358  }
1359  }
1360 
1361  // optional string for cycling laser colors
1362  if(optional_string("@Laser Color2:")){
1363  stuff_ubyte(&r);
1364  stuff_ubyte(&g);
1365  stuff_ubyte(&b);
1366  gr_init_color( &wip->laser_color_2, r, g, b );
1367  } else if (first_time) {
1369  }
1370 
1371  if(optional_string("@Laser Length:")) {
1372  stuff_float(&wip->laser_length);
1373  }
1374 
1375  if(optional_string("@Laser Head Radius:")) {
1377  }
1378 
1379  if(optional_string("@Laser Tail Radius:")) {
1381  }
1382 
1383  if(optional_string("$Mass:")) {
1384  stuff_float( &(wip->mass) );
1385 
1386  // Goober5000 - hack in order to make the beam whack behavior of these three beams match all other beams
1387  // this relies on Bobboau's beam whack hack in beam_apply_whack()
1388  if ((!strcmp(wip->name, "SAAA") && (wip->mass == 4.0f))
1389  || (!strcmp(wip->name, "MjolnirBeam") && (wip->mass == 1000.0f))
1390  || (!strcmp(wip->name, "MjolnirBeam#home") && (wip->mass == 1000.0f)))
1391  {
1392  wip->mass = 100.0f;
1393  }
1394 
1395  diag_printf ("Weapon mass -- %7.3f\n", wip->mass);
1396  }
1397 
1398  if(optional_string("$Velocity:")) {
1399  stuff_float( &(wip->max_speed) );
1400  diag_printf ("Weapon mass -- %7.3f\n", wip->max_speed);
1401  }
1402 
1403  if(optional_string("$Fire Wait:")) {
1404  stuff_float( &(wip->fire_wait) );
1405  diag_printf ("Weapon fire wait -- %7.3f\n", wip->fire_wait);
1406  // Min and max delay stuff for weapon fire wait randomization
1407  if (optional_string("+Max Delay:")) {
1408  stuff_float(&(wip->max_delay));
1409  diag_printf("Weapon fire max delay -- %7.3f\n", wip->max_delay);
1410  }
1411  if (optional_string("+Min Delay:")) {
1412  stuff_float(&(wip->min_delay));
1413  diag_printf("Weapon fire min delay -- %7.3f\n", wip->min_delay);
1414  }
1415  }
1416 
1417  if(optional_string("$Damage:")) {
1418  stuff_float(&wip->damage);
1419  //WMC - now that shockwave damage can be set for them individually,
1420  //do this automagically
1421  if(first_time) {
1422  wip->shockwave.damage = wip->damage;
1423  }
1424  }
1425 
1426  // Attenuation of non-beam primary weapon damage
1427  if(optional_string("$Damage Time:")) {
1428  stuff_float(&wip->damage_time);
1429  if(optional_string("+Attenuation Damage:")){
1430  stuff_float(&wip->atten_damage);
1431  } else if (optional_string_either("+Min Damage:", "+Max Damage:")) {
1432  Warning(LOCATION, "+Min Damage: and +Max Damage: in %s are deprecated, please change to +Attenuation Damage:.", wip->name);
1433  stuff_float(&wip->atten_damage);
1434  }
1435  }
1436 
1437  if(optional_string("$Damage Type:")) {
1438  //This is checked for validity on every armor type
1439  //If it's invalid (or -1), then armor has no effect
1443  }
1444 
1445  if(optional_string("$Arm time:")) {
1446  float flit;
1447  stuff_float(&flit);
1448  wip->arm_time = fl2f(flit);
1449  }
1450 
1451  if(optional_string("$Arm distance:")) {
1452  stuff_float(&wip->arm_dist);
1453  }
1454 
1455  if(optional_string("$Arm radius:")) {
1456  stuff_float(&wip->arm_radius);
1457  }
1458 
1459  if(optional_string("$Detonation Range:")) {
1460  stuff_float(&wip->det_range);
1461  }
1462 
1463  if(optional_string("$Detonation Radius:")) {
1464  stuff_float(&wip->det_radius);
1465  }
1466 
1467  if(optional_string("$Flak Detonation Accuracy:")) {
1469  }
1470 
1471  if(optional_string("$Flak Targeting Accuracy:")) {
1473  }
1474 
1475  if(optional_string("$Untargeted Flak Range Penalty:")) {
1477  }
1478 
1479  parse_shockwave_info(&wip->shockwave, "$");
1480 
1481  //Retain compatibility
1482  if(first_time)
1483  {
1484  wip->dinky_shockwave = wip->shockwave;
1485  wip->dinky_shockwave.damage /= 4.0f;
1486  }
1487 
1488  if(optional_string("$Dinky shockwave:"))
1489  {
1491  }
1492 
1493  if(optional_string("$Armor Factor:")) {
1494  stuff_float(&wip->armor_factor);
1495  }
1496 
1497  if(optional_string("$Shield Factor:")) {
1498  stuff_float(&wip->shield_factor);
1499  }
1500 
1501  if(optional_string("$Subsystem Factor:")) {
1503  }
1504 
1505  if(optional_string("$Lifetime Min:")) {
1506  stuff_float(&wip->life_min);
1507 
1508  if(wip->life_min < 0.0f) {
1509  wip->life_min = 0.0f;
1510  Warning(LOCATION, "Lifetime min for weapon '%s' cannot be less than 0. Setting to 0.\n", wip->name);
1511  }
1512  }
1513 
1514  if(optional_string("$Lifetime Max:")) {
1515  stuff_float(&wip->life_max);
1516 
1517  if(wip->life_max < 0.0f) {
1518  wip->life_max = 0.0f;
1519  Warning(LOCATION, "Lifetime max for weapon '%s' cannot be less than 0. Setting to 0.\n", wip->name);
1520  } else if (wip->life_max < wip->life_min) {
1521  wip->life_max = wip->life_min + 0.1f;
1522  Warning(LOCATION, "Lifetime max for weapon '%s' cannot be less than its Lifetime Min (%f) value. Setting to %f.\n", wip->name, wip->life_min, wip->life_max);
1523  } else {
1524  wip->lifetime = (wip->life_min+wip->life_max)*0.5f;
1525  }
1526  }
1527 
1528  if(wip->life_min >= 0.0f && wip->life_max < 0.0f) {
1529  wip->lifetime = wip->life_min;
1530  wip->life_min = -1.0f;
1531  Warning(LOCATION, "Lifetime min, but not lifetime max, specified for weapon %s. Assuming static lifetime of %.2f seconds.\n", wip->name, wip->lifetime);
1532  }
1533 
1534  if(optional_string("$Lifetime:")) {
1535  if(wip->life_min >= 0.0f || wip->life_max >= 0.0f) {
1536  Warning(LOCATION, "Lifetime min or max specified, but $Lifetime was also specified; min or max will be used.");
1537  }
1538  stuff_float(&wip->lifetime);
1539  if (wip->damage_time > wip->lifetime) {
1540  Warning(LOCATION, "Lifetime is lower than Damage Time, setting Damage Time to be one half the value of Lifetime.");
1541  wip->damage_time = 0.5f * wip->lifetime;
1542  }
1543  }
1544 
1545  if(optional_string("$Energy Consumed:")) {
1547  }
1548 
1549  // Goober5000: cargo size is checked for div-0 errors... see below (must parse flags first)
1550  if(optional_string("$Cargo Size:"))
1551  {
1552  stuff_float(&wip->cargo_size);
1553  }
1554 
1555  bool is_homing=false;
1556  if(optional_string("$Homing:")) {
1557  stuff_boolean(&is_homing);
1558  }
1559 
1560  if (is_homing || (wip->wi_flags & WIF_HOMING))
1561  {
1562  char temp_type[NAME_LENGTH];
1563 
1564  // the following five items only need to be recorded if the weapon is a homing weapon
1565  if(optional_string("+Type:"))
1566  {
1567  stuff_string(temp_type, F_NAME, NAME_LENGTH);
1568  if (!stricmp(temp_type, NOX("HEAT")))
1569  {
1570  if(wip->wi_flags & WIF_HOMING_ASPECT) {
1571  wip->wi_flags &= ~WIF_HOMING_ASPECT;
1572  }
1573  if(wip->wi_flags & WIF_HOMING_JAVELIN) {
1574  wip->wi_flags &= ~WIF_HOMING_JAVELIN;
1575  }
1576 
1578  wi_flags |= WIF_HOMING_HEAT | WIF_TURNS;
1579  }
1580  else if (!stricmp(temp_type, NOX("ASPECT")))
1581  {
1582  if(wip->wi_flags & WIF_HOMING_HEAT) {
1583  wip->wi_flags &= ~WIF_HOMING_HEAT;
1584  }
1585  if(wip->wi_flags & WIF_HOMING_JAVELIN) {
1586  wip->wi_flags &= ~WIF_HOMING_JAVELIN;
1587  }
1588 
1590  wi_flags |= WIF_HOMING_ASPECT | WIF_TURNS;
1591  }
1592  else if (!stricmp(temp_type, NOX("JAVELIN")))
1593  {
1594  if(wip->wi_flags & WIF_HOMING_HEAT) {
1595  wip->wi_flags &= ~WIF_HOMING_HEAT;
1596  }
1597  if(wip->wi_flags & WIF_HOMING_ASPECT) {
1598  wip->wi_flags &= ~WIF_HOMING_ASPECT;
1599  }
1600 
1602  wi_flags |= (WIF_HOMING_JAVELIN | WIF_TURNS);
1603  }
1604  //If you want to add another weapon, remember you need to reset
1605  //ALL homing flags.
1606  }
1607 
1608  if (wip->wi_flags & WIF_HOMING_HEAT)
1609  {
1610  float view_cone_angle;
1611 
1612  if(optional_string("+Turn Time:")) {
1613  stuff_float(&wip->turn_time);
1614  }
1615 
1616  if(optional_string("+View Cone:")) {
1617  stuff_float(&view_cone_angle);
1618  wip->fov = cosf(fl_radians(view_cone_angle * 0.5f));
1619  }
1620 
1621  if (optional_string("+Seeker Strength:"))
1622  {
1623  //heat default seeker strength is 3
1626  if (wip->seeker_strength <= 0)
1627  {
1628  Warning(LOCATION,"Seeker Strength for missile \'%s\' must be greater than zero\nReseting value to default.", wip->name);
1629  wip->seeker_strength = 3.0f;
1631  }
1632  }
1633  else
1634  {
1635  if(!(wip->wi_flags2 & WIF2_CUSTOM_SEEKER_STR))
1636  wip->seeker_strength = 3.0f;
1637  }
1638 
1639  if (optional_string("+Target Lead Scaler:"))
1640  {
1642  if (wip->target_lead_scaler == 0.0f)
1644  else {
1646  wi_flags2 |= WIF2_VARIABLE_LEAD_HOMING;
1647  }
1648  }
1649  }
1650  else if ((wip->wi_flags & WIF_HOMING_ASPECT) || (wip->wi_flags & WIF_HOMING_JAVELIN))
1651  {
1652  if(optional_string("+Turn Time:")) {
1653  stuff_float(&wip->turn_time);
1654  }
1655 
1656  if(optional_string("+View Cone:")) {
1657  float view_cone_angle;
1658  stuff_float(&view_cone_angle);
1659  wip->fov = (float)cos(fl_radians(view_cone_angle * 0.5f));
1660  }
1661 
1662  if(optional_string("+Min Lock Time:")) { // minimum time (in seconds) to achieve lock
1663  stuff_float(&wip->min_lock_time);
1664  }
1665 
1666  if(optional_string("+Lock Pixels/Sec:")) { // pixels/sec moved while locking
1668  }
1669 
1670  if(optional_string("+Catch-up Pixels/Sec:")) { // pixels/sec moved while catching-up for a lock
1672  }
1673 
1674  if(optional_string("+Catch-up Penalty:")) {
1675  // number of extra pixels to move while locking as a penalty for catching up for a lock
1677  }
1678 
1679  if (optional_string("+Seeker Strength:"))
1680  {
1681  //aspect default seeker strength is 2
1684  if (wip->seeker_strength <= 0)
1685  {
1686  Warning(LOCATION,"Seeker Strength for missile \'%s\' must be greater than zero\nReseting value to default.", wip->name);
1687  wip->seeker_strength = 2.0f;
1689  }
1690  }
1691  else
1692  {
1693  if(!(wip->wi_flags2 & WIF2_CUSTOM_SEEKER_STR))
1694  wip->seeker_strength = 2.0f;
1695  }
1696  if (optional_string("+Target Lead Scaler:"))
1697  {
1699  if (wip->target_lead_scaler == 1.0f)
1701  else {
1703  wi_flags2 |= WIF2_VARIABLE_LEAD_HOMING;
1704  }
1705  }
1706 
1707  if (wip->wi_flags & WIF_LOCKED_HOMING) {
1708  // locked homing missiles have a much longer lifespan than the AI think they do
1710  }
1711  }
1712  else
1713  {
1714  Error(LOCATION, "Illegal homing type = %s.\nMust be HEAT, ASPECT or JAVELIN.\n", temp_type);
1715  }
1716 
1717  }
1718 
1719  // swarm missiles
1720  int s_count;
1721 
1722  if(optional_string("$Swarm:"))
1723  {
1725  stuff_int(&s_count);
1726  wip->swarm_count = (short)s_count;
1727 
1728  // flag as being a swarm weapon
1729  wip->wi_flags |= WIF_SWARM;
1730  wi_flags |= WIF_SWARM;
1731  }
1732 
1733  // *Swarm wait token -Et1
1734  if((wip->wi_flags & WIF_SWARM) && optional_string( "+SwarmWait:" ))
1735  {
1736  float SwarmWait;
1737  stuff_float( &SwarmWait );
1738  if( SwarmWait > 0.0f && SwarmWait * wip->swarm_count < wip->fire_wait )
1739  {
1740  wip->SwarmWait = int( SwarmWait * 1000 );
1741  }
1742  }
1743 
1744  if(optional_string("$Acceleration Time:")) {
1746  }
1747 
1748  if(optional_string("$Velocity Inherit:")) {
1750  wip->vel_inherit_amount /= 100.0f; // % -> 0..1
1751  }
1752 
1753  if(optional_string("$Free Flight Time:")) {
1754  stuff_float(&(wip->free_flight_time));
1755  } else if(first_time && is_homing) {
1757  }
1758 
1759  if(optional_string("$Free Flight Speed:")) {
1760  float temp;
1761  stuff_float(&temp);
1762  nprintf(("Warning", "Ignoring free flight speed for weapon '%s'\n", wip->name));
1763  }
1764  //Optional one-shot sound to play at the beginning of firing
1765  parse_sound("$PreLaunchSnd:", &wip->pre_launch_snd, wip->name);
1766 
1767  //Optional delay for Pre-Launch sound
1768  if(optional_string("+PreLaunchSnd Min Interval:"))
1769  {
1771  }
1772 
1773  //Launch sound
1774  parse_sound("$LaunchSnd:", &wip->launch_snd, wip->name);
1775 
1776  //Impact sound
1777  parse_sound("$ImpactSnd:", &wip->impact_snd, wip->name);
1778 
1779  //Disarmed impact sound
1780  parse_sound("$Disarmed ImpactSnd:", &wip->impact_snd, wip->name);
1781 
1782  parse_sound("$FlyBySnd:", &wip->flyby_snd, wip->name);
1783 
1784  parse_sound("$TrackingSnd:", &wip->hud_tracking_snd, wip->name);
1785 
1786  parse_sound("$LockedSnd:", &wip->hud_locked_snd, wip->name);
1787 
1788  parse_sound("$InFlightSnd:", &wip->hud_in_flight_snd, wip->name);
1789 
1790  if (optional_string("+Inflight sound type:"))
1791  {
1792  SCP_string type;
1793 
1794  stuff_string(type, F_NAME);
1795 
1796  if (!stricmp(type.c_str(), "TARGETED"))
1797  {
1799  }
1800  else if (!stricmp(type.c_str(), "UNTARGETED"))
1801  {
1803  }
1804  else if (!stricmp(type.c_str(), "ALWAYS"))
1805  {
1806  wip->in_flight_play_type = ALWAYS;
1807  }
1808  else
1809  {
1810  Warning(LOCATION, "Unknown in-flight sound type \"%s\"!", type.c_str());
1811  wip->in_flight_play_type = ALWAYS;
1812  }
1813  }
1814 
1815  if(optional_string("$Model:"))
1816  {
1817  wip->render_type = WRT_POF;
1819  }
1820 
1821  // handle rearm rate - modified by Goober5000
1822  primary_rearm_rate_specified = 0;
1823  float rearm_rate;
1824  // Anticipate rearm rate for ballistic primaries
1825  if (optional_string("$Rearm Rate:"))
1826  {
1827  if (subtype != WP_MISSILE) {
1828  primary_rearm_rate_specified = 1;
1829  }
1830 
1831  stuff_float( &rearm_rate );
1832  if (rearm_rate > 0.0f)
1833  {
1834  wip->rearm_rate = 1.0f/rearm_rate;
1835  }
1836  else
1837  {
1838  Warning(LOCATION, "Rearm wait of less than 0 on weapon %s; setting to 1", wip->name);
1839  }
1840  }
1841 
1842 
1843  if (optional_string("+Weapon Range:")) {
1844  stuff_float(&wip->weapon_range);
1845  }
1846 
1847  if( optional_string( "+Weapon Min Range:" ) )
1848  {
1849  float MinRange;
1850  stuff_float( &MinRange );
1851 
1852  if( MinRange > 0.0f && MinRange < MIN( wip->max_speed * wip->lifetime, wip->weapon_range ) )
1853  {
1854  wip->WeaponMinRange = MinRange;
1855  }
1856  else
1857  {
1858  Warning(LOCATION, "Invalid minimum range on weapon %s; setting to 0", wip->name);
1859  }
1860 
1861  }
1862 
1863  parse_wi_flags(wip, wi_flags, wi_flags2, wi_flags3);
1864 
1865  // be friendly; make sure ballistic flags are synchronized - Goober5000
1866  // primary
1867  if (subtype == WP_LASER)
1868  {
1869  // ballistic
1870  if (wip->wi_flags2 & WIF2_BALLISTIC)
1871  {
1872  // rearm rate not specified
1873  if (!primary_rearm_rate_specified && first_time)
1874  {
1875  Warning(LOCATION, "$Rearm Rate for ballistic primary %s not specified. Defaulting to 100...\n", wip->name);
1876  wip->rearm_rate = 100.0f;
1877  }
1878  }
1879  // not ballistic
1880  else
1881  {
1882  // rearm rate specified
1883  if (primary_rearm_rate_specified)
1884  {
1885  Warning(LOCATION, "$Rearm Rate specified for non-ballistic primary %s\n", wip->name);
1886  }
1887  }
1888 
1889  }
1890  // secondary
1891  else
1892  {
1893  // ballistic
1894  if (wip->wi_flags2 & WIF2_BALLISTIC)
1895  {
1896  Warning(LOCATION, "Secondary weapon %s can't be ballistic. Removing this flag...\n", wip->name);
1897  wip->wi_flags2 &= ~WIF2_BALLISTIC;
1898  }
1899  }
1900 
1901  // also make sure EMP is friendly - Goober5000
1902  if (wip->wi_flags & WIF_EMP)
1903  {
1904  if (!wip->shockwave.outer_rad)
1905  {
1906  Warning(LOCATION, "Outer blast radius of weapon %s is zero - EMP will not work.\nAdd $Outer Radius to weapon table entry.\n", wip->name);
1907  }
1908  }
1909 
1910  // also make sure secondaries and ballistic primaries do not have 0 cargo size
1911  if (subtype == WP_MISSILE || wip->wi_flags2 & WIF2_BALLISTIC)
1912  {
1913  if (wip->cargo_size == 0.0f)
1914  {
1915  Warning(LOCATION, "Cargo size of weapon %s cannot be 0. Setting to 1.\n", wip->name);
1916  wip->cargo_size = 1.0f;
1917  }
1918  }
1919 
1920  if ( optional_string("$Trail:") ) {
1921  trail_info *ti = &wip->tr_info;
1922  wip->wi_flags |= WIF_TRAIL; // missile leaves a trail
1923 
1924  if ( optional_string("+Start Width:") )
1925  stuff_float(&ti->w_start);
1926 
1927  if ( optional_string("+End Width:") )
1928  stuff_float(&ti->w_end);
1929 
1930  if ( optional_string("+Start Alpha:") )
1931  stuff_float(&ti->a_start);
1932 
1933  if ( optional_string("+End Alpha:") )
1934  stuff_float(&ti->a_end);
1935 
1936  if ( optional_string("+Max Life:") ) {
1937  stuff_float(&ti->max_life);
1938  ti->stamp = fl2i(1000.0f*ti->max_life)/(NUM_TRAIL_SECTIONS+1);
1939  }
1940 
1941  if ( required_string("+Bitmap:") ) {
1942  stuff_string(fname, F_NAME, NAME_LENGTH);
1943  generic_bitmap_init(&ti->texture, fname);
1944  }
1945 
1946  if ( optional_string("+Faded Out Sections:") ) {
1948  }
1949  }
1950 
1951  // read in filename for icon that is used in weapons selection
1952  if ( optional_string("$Icon:") ) {
1954  }
1955 
1956  // read in filename for animation that is used in weapons selection
1957  if ( optional_string("$Anim:") ) {
1959  }
1960 
1961  if ( optional_string("$Impact Explosion:") ) {
1962  stuff_string(fname, F_NAME, NAME_LENGTH);
1963 
1964  if ( VALID_FNAME(fname) )
1965  wip->impact_weapon_expl_index = Weapon_explosions.Load(fname);
1966  }
1967 
1968  if ( optional_string("$Impact Explosion Radius:") )
1970 
1971  if ( optional_string("$Shield Impact Explosion Radius:") ) {
1973  } else if (first_time) {
1975  }
1976 
1977  if ( optional_string("$Dinky Impact Explosion:") ) {
1978  stuff_string(fname, F_NAME, NAME_LENGTH);
1979 
1980  if ( VALID_FNAME(fname) )
1981  wip->dinky_impact_weapon_expl_index = Weapon_explosions.Load(fname);
1982  } else if (first_time) {
1984  }
1985 
1986  if ( optional_string("$Dinky Impact Explosion Radius:") )
1988  else if (first_time)
1990 
1991  if ( optional_string("$Piercing Impact Explosion:") ) {
1992  stuff_string(fname, F_NAME, NAME_LENGTH);
1993 
1994  if ( VALID_FNAME(fname) )
1995  wip->piercing_impact_weapon_expl_index = Weapon_explosions.Load(fname);
1996  }
1997 
1998  if ( optional_string("$Piercing Impact Radius:") )
2000 
2001  if ( optional_string("$Piercing Impact Velocity:") )
2003 
2004  if ( optional_string("$Piercing Impact Splash Velocity:") )
2006 
2007  if ( optional_string("$Piercing Impact Variance:") )
2009 
2010  if ( optional_string("$Piercing Impact Life:") )
2012 
2013  if ( optional_string("$Piercing Impact Particles:") )
2015 
2016  // muzzle flash
2017  if ( optional_string("$Muzzleflash:") ) {
2018  stuff_string(fname, F_NAME, NAME_LENGTH);
2019 
2020  // look it up
2021  wip->muzzle_flash = mflash_lookup(fname);
2022  }
2023 
2024  // EMP optional stuff (if WIF_EMP is not set, none of this matters, anyway)
2025  if( optional_string("$EMP Intensity:") ){
2026  stuff_float(&wip->emp_intensity);
2027  }
2028 
2029  if( optional_string("$EMP Time:") ){
2030  stuff_float(&wip->emp_time);
2031  }
2032 
2033  // This is an optional modifier for a weapon that uses the "apply recoil" flag. recoil_force in ship.cpp line 10445 is multiplied by this if defined.
2034  if (optional_string("$Recoil Modifier:")){
2035  if (!(wip->wi_flags3 & WIF3_APPLY_RECOIL)){
2036  Warning(LOCATION, "$Recoil Modifier specified for weapon %s but this weapon does not have the \"apply recoil\" weapon flag set. Automatically setting the flag", wip->name);
2037  wip->wi_flags3 |= WIF3_APPLY_RECOIL;
2038  }
2040  }
2041 
2042  // Energy suck optional stuff (if WIF_ENERGY_SUCK is not set, none of this matters anyway)
2043  if( optional_string("$Leech Weapon:") ){
2044  stuff_float(&wip->weapon_reduce);
2045  }
2046 
2047  if( optional_string("$Leech Afterburner:") ){
2049  }
2050 
2051  if (optional_string("$Corkscrew:"))
2052  {
2053  if(optional_string("+Num Fired:")) {
2054  stuff_int(&wip->cs_num_fired);
2055  }
2056 
2057  if(optional_string("+Radius:")) {
2058  stuff_float(&wip->cs_radius);
2059  }
2060 
2061  if(optional_string("+Fire Delay:")) {
2062  stuff_int(&wip->cs_delay);
2063  }
2064 
2065  if(optional_string("+Counter rotate:")) {
2066  stuff_boolean(&wip->cs_crotate);
2067  }
2068 
2069  if(optional_string("+Twist:")) {
2070  stuff_float(&wip->cs_twist);
2071  }
2072  }
2073 
2074  //electronics tag optional stuff
2075  //Note that I made all these optional in the interest of modular tables.
2076  //TODO: Possibly add a warning on first_time define?
2077  if (optional_string("$Electronics:"))
2078  {
2079  if(optional_string("+New Style:")) {
2080  wip->elec_use_new_style=1;
2081  }
2082  else if(optional_string("+Old Style:")) {
2083  wip->elec_use_new_style=0;
2084  }
2085 
2086  if(optional_string("+Area Of Effect")) {
2088  }
2089 
2090  //New only -WMC
2091  if(optional_string("+Intensity:")) {
2092  float temp;
2093  stuff_float(&temp);
2094  Warning(LOCATION, "+Intensity is deprecated");
2095  }
2096 
2097  if(optional_string("+Lifetime:")) {
2098  stuff_int(&wip->elec_time);
2099  }
2100 
2101  //New only -WMC
2102  if(optional_string("+Engine Multiplier:")) {
2103  stuff_float(&wip->elec_eng_mult);
2104  if(!wip->elec_use_new_style)Warning(LOCATION, "+Engine multiplier may only be used with new style electronics");
2105  }
2106 
2107  //New only -WMC
2108  if(optional_string("+Weapon Multiplier:")) {
2109  stuff_float(&wip->elec_weap_mult);
2110  if(!wip->elec_use_new_style)Warning(LOCATION, "+Weapon multiplier may only be used with new style electronics");
2111  }
2112 
2113  //New only -WMC
2114  if(optional_string("+Beam Turret Multiplier:")) {
2115  stuff_float(&wip->elec_beam_mult);
2116  if(!wip->elec_use_new_style)Warning(LOCATION, "+Beam turret multiplier may only be used with new style electronics");
2117  }
2118 
2119  //New only -WMC
2120  if(optional_string("+Sensors Multiplier:")) {
2122  if(!wip->elec_use_new_style)Warning(LOCATION, "+Sensors multiplier may only be used with new style electronics");
2123  }
2124 
2125  if(optional_string("+Randomness Time:")) {
2126  stuff_int(&wip->elec_randomness);
2127  }
2128  }
2129 
2130  //read in the spawn angle info
2131  //if the weapon isn't a spawn weapon, then this is not going to be used.
2132  int num_spawn_angs_defined = 0;
2133  float dum_float;
2134 
2135  while (optional_string("$Spawn Angle:"))
2136  {
2137  stuff_float(&dum_float);
2138 
2139  if (num_spawn_angs_defined < MAX_SPAWN_TYPES_PER_WEAPON)
2140  {
2141  wip->spawn_info[num_spawn_angs_defined].spawn_angle = dum_float;
2142  num_spawn_angs_defined++;
2143  }
2144  }
2145 
2146  if (wip->wi_flags2 & WIF2_LOCAL_SSM && optional_string("$Local SSM:"))
2147  {
2148  if(optional_string("+Warpout Delay:")) {
2150  }
2151 
2152  if(optional_string("+Warpin Delay:")) {
2154  }
2155 
2156  if(optional_string("+Stage 5 Velocity:")) {
2158  }
2159 
2160  if(optional_string("+Warpin Radius:")) {
2162  }
2163 
2164  if (optional_string("+Lock Range:")) {
2166  }
2167  }
2168 
2169  if (optional_string("$Countermeasure:"))
2170  {
2171  if (!(wip->wi_flags & WIF_CMEASURE))
2172  {
2173  Warning(LOCATION,"Weapon \'%s\' has countermeasure information defined, but the \"countermeasure\" flag wasn\'t found in the \'$Flags:\' field.\n", wip->name);
2174  }
2175 
2176  if (optional_string("+Heat Effectiveness:"))
2178 
2179  if (optional_string("+Aspect Effectiveness:"))
2181 
2182  if (optional_string("+Effective Radius:"))
2184 
2185  if (optional_string("+Missile Detonation Radius:"))
2187 
2188  if (optional_string("+Single Missile Kill:"))
2190  }
2191 
2192  // beam weapon optional stuff
2193  if ( optional_string("$BeamInfo:") ) {
2194  // beam type
2195  if(optional_string("+Type:")) {
2196  stuff_int(&wip->b_info.beam_type);
2197  }
2198 
2199  // how long it lasts
2200  if(optional_string("+Life:")) {
2201  stuff_float(&wip->b_info.beam_life);
2202  }
2203 
2204  // warmup time
2205  if(optional_string("+Warmup:")) {
2206  stuff_int(&wip->b_info.beam_warmup);
2207  }
2208 
2209  // warmdowm time
2210  if(optional_string("+Warmdown:")) {
2212  }
2213 
2214  // muzzle glow radius
2215  if(optional_string("+Radius:")) {
2217  }
2218 
2219  // particle spew count
2220  if(optional_string("+PCount:")) {
2222  }
2223 
2224  // particle radius
2225  if(optional_string("+PRadius:")) {
2227  }
2228 
2229  // angle off turret normal
2230  if(optional_string("+PAngle:")) {
2232  }
2233 
2234  // particle bitmap/ani
2235  if ( optional_string("+PAni:") ) {
2236  stuff_string(fname, F_NAME, NAME_LENGTH);
2238  }
2239 
2240  // magic miss #
2241  if(optional_string("+Miss Factor:")) {
2242  for(idx=0; idx<NUM_SKILL_LEVELS; idx++) {
2243  float temp;
2244  if(!stuff_float_optional(&temp)) {
2245  break;
2246  }
2247  // an unspecified Miss Factor should apply to all IFFs
2248  for(iff=0; iff<Num_iffs; iff++) {
2249  wip->b_info.beam_iff_miss_factor[iff][idx] = temp;
2250  }
2251  }
2252  }
2253  // now check miss factors for each IFF
2254  for(iff=0; iff<Num_iffs; iff++) {
2255  char miss_factor_string[NAME_LENGTH + 15];
2256  sprintf(miss_factor_string, "+%s Miss Factor:", Iff_info[iff].iff_name);
2257  if(optional_string(miss_factor_string)) {
2258  // this Miss Factor applies only to the specified IFF
2259  for(idx=0; idx<NUM_SKILL_LEVELS; idx++) {
2260  if(!stuff_float_optional(&wip->b_info.beam_iff_miss_factor[iff][idx])) {
2261  break;
2262  }
2263  }
2264  }
2265  }
2266 
2267  // beam fire sound
2268  parse_sound("+BeamSound:", &wip->b_info.beam_loop_sound, wip->name);
2269 
2270  // warmup sound
2271  parse_sound("+WarmupSound:", &wip->b_info.beam_warmup_sound, wip->name);
2272 
2273  // warmdown sound
2274  parse_sound("+WarmdownSound:", &wip->b_info.beam_warmdown_sound, wip->name);
2275 
2276  // glow bitmap
2277  if (optional_string("+Muzzleglow:") ) {
2278  stuff_string(fname, F_NAME, NAME_LENGTH);
2279  generic_anim_init(&wip->b_info.beam_glow, fname);
2280  }
2281 
2282  if (optional_string("+Directional Glow:")) {
2284  wip->b_info.directional_glow = true;
2285  }
2286 
2287  // # of shots (only used for type D beams)
2288  if(optional_string("+Shots:")) {
2289  stuff_int(&wip->b_info.beam_shots);
2290  }
2291 
2292  // make sure that we have at least one shot so that TYPE_D beams will work
2293  if ( (wip->b_info.beam_type == BEAM_TYPE_D) && (wip->b_info.beam_shots < 1) ) {
2294  Warning( LOCATION, "Type D beam weapon, '%s', has less than one \"+Shots\" specified! It must be set to at least 1!!", wip->name);
2295  wip->b_info.beam_shots = 1;
2296  }
2297 
2298  // shrinkage
2299  if(optional_string("+ShrinkFactor:")) {
2301  }
2302 
2303  if(optional_string("+ShrinkPct:")) {
2305  }
2306 
2307  if (optional_string("+Range:")) {
2308  stuff_float(&wip->b_info.range);
2309  }
2310 
2311  if ( optional_string("+Attenuation:") )
2313 
2314  if ( optional_string("+BeamWidth:") )
2315  stuff_float(&wip->b_info.beam_width);
2316 
2317  if ( optional_string("+Beam Flash Effect:") ) {
2318  stuff_string(fname, F_NAME, NAME_LENGTH);
2319 
2320  if ( VALID_FNAME(fname) )
2321  wip->flash_impact_weapon_expl_index = Weapon_explosions.Load(fname);
2322  }
2323 
2324  if ( optional_string("+Beam Flash Radius:") )
2326 
2327  if ( optional_string("+Beam Piercing Effect:") ) {
2328  stuff_string(fname, F_NAME, NAME_LENGTH);
2329 
2330  if ( VALID_FNAME(fname) )
2331  wip->piercing_impact_weapon_expl_index = Weapon_explosions.Load(fname);
2332  }
2333 
2334  if ( optional_string("+Beam Piercing Radius:") )
2336 
2337  if ( optional_string("+Beam Piercing Effect Velocity:") )
2339 
2340  if ( optional_string("+Beam Piercing Splash Effect Velocity:") )
2342 
2343  if ( optional_string("+Beam Piercing Effect Variance:") )
2345 
2346  // beam sections
2347  while ( optional_string("$Section:") ) {
2348  beam_weapon_section_info *bsip = NULL, tbsw;
2349  bool nocreate = false, remove = false;
2350  int bsw_index_override = -1;
2351 
2352  if ( optional_string("+Index:") ) {
2353  stuff_int(&bsw_index_override);
2354 
2355  if ( optional_string("+remove") ) {
2356  nocreate = true;
2357  remove = true;
2358  }
2359 
2360  if ( (bsw_index_override < 0) || (!remove && (bsw_index_override >= wip->b_info.beam_num_sections)) )
2361  Warning(LOCATION, "Invalid +Index value of %d specified for beam section on weapon '%s'; valid values at this point are %d to %d.", bsw_index_override, wip->name, 0, wip->b_info.beam_num_sections -1);
2362  }
2363 
2364  if ( optional_string("+nocreate") )
2365  nocreate = true;
2366 
2367  // Where are we saving data?
2368  if (bsw_index_override >= 0) {
2369  if (bsw_index_override < wip->b_info.beam_num_sections) {
2370  bsip = &wip->b_info.sections[bsw_index_override];
2371  } else {
2372  if ( !nocreate ) {
2373  if ( (bsw_index_override == wip->b_info.beam_num_sections) && (bsw_index_override < MAX_BEAM_SECTIONS) ) {
2374  bsip = &wip->b_info.sections[wip->b_info.beam_num_sections++];
2375  } else {
2376  if ( !remove )
2377  Warning(LOCATION, "Invalid index for manually-indexed beam section %d (max %d) on weapon %s.", bsw_index_override, MAX_BEAM_SECTIONS, wip->name);
2378 
2379  bsip = &tbsw;
2380  memset( bsip, 0, sizeof(beam_weapon_section_info) );
2381  generic_anim_init(&bsip->texture, NULL);
2382  }
2383  } else {
2384  if ( !remove )
2385  Warning(LOCATION, "Invalid index for manually-indexed beam section %d, and +nocreate specified, on weapon %s", bsw_index_override, wip->name);
2386 
2387  bsip = &tbsw;
2388  memset( bsip, 0, sizeof(beam_weapon_section_info) );
2389  generic_anim_init(&bsip->texture, NULL);
2390  }
2391 
2392  }
2393  } else {
2395  bsip = &wip->b_info.sections[wip->b_info.beam_num_sections++];
2396  generic_anim_init(&bsip->texture, NULL);
2397  } else {
2398  Warning(LOCATION, "Too many beam sections for weapon %s - max is %d", wip->name, MAX_BEAM_SECTIONS);
2399  bsip = &tbsw;
2400  memset( bsip, 0, sizeof(beam_weapon_section_info) );
2401  generic_anim_init(&bsip->texture, NULL);
2402  }
2403  }
2404 
2405  // section width
2406  if ( optional_string("+Width:") )
2407  stuff_float(&bsip->width);
2408 
2409  // texture
2410  if ( optional_string("+Texture:") ) {
2411  stuff_string(fname, F_NAME, NAME_LENGTH);
2412 
2413  // invisible textures are okay
2414  if (!stricmp(fname, "invisible")) {
2415  generic_anim_init(&bsip->texture);
2416  } else {
2417  generic_anim_init(&bsip->texture, fname);
2418  }
2419  }
2420 
2421  // The E -- Dummied out due to not being used anywhere
2422  if ( optional_string("+RGBA Inner:") ) {
2423  ubyte dummy;
2424  stuff_ubyte(&dummy);
2425  stuff_ubyte(&dummy);
2426  stuff_ubyte(&dummy);
2427  stuff_ubyte(&dummy);
2428  }
2429 
2430  // The E -- Dummied out due to not being used anywhere
2431  if ( optional_string("+RGBA Outer:") ) {
2432  ubyte dummy;
2433  stuff_ubyte(&dummy);
2434  stuff_ubyte(&dummy);
2435  stuff_ubyte(&dummy);
2436  stuff_ubyte(&dummy);
2437  }
2438 
2439  // flicker
2440  if ( optional_string("+Flicker:") ) {
2441  stuff_float(&bsip->flicker);
2442  //Sanity
2443  if (bsip->flicker < 0.0f || bsip->flicker > 1.0f) {
2444  mprintf(("WARNING: Invalid value found for +Flicker on section %d of beam %s. Valid range is 0.0 to 1.0, values will be adjusted.\n", wip->b_info.beam_num_sections, wip->name));
2445  CLAMP(bsip->flicker, 0.0f, 1.0f);
2446  }
2447  }
2448 
2449  // zadd
2450  if ( optional_string("+Zadd:") )
2451  stuff_float(&bsip->z_add);
2452 
2453  // beam texture tileing factor -Bobboau
2454  if ( optional_string("+Tile Factor:") ) {
2455  stuff_float(&bsip->tile_factor);
2456  stuff_int(&bsip->tile_type);
2457  }
2458 
2459  // beam texture moveing stuff -Bobboau
2460  if ( optional_string("+Translation:") )
2461  stuff_float(&bsip->translation);
2462 
2463  // if we are actually removing this index then reset it and we'll
2464  // clean up the entries later
2465  if (remove) {
2466  memset( bsip, 0, sizeof(beam_weapon_section_info) );
2467  generic_anim_init(&bsip->texture, NULL);
2468  }
2469  }
2470  }
2471 
2472  while ( optional_string("$Pspew:") ) {
2473  int spew_index = -1;
2474  // check for pspew flag
2475  if (!( wip->wi_flags & WIF_PARTICLE_SPEW )) {
2476  Warning(LOCATION, "$Pspew specified for weapon %s but this weapon does not have the \"Particle Spew\" weapon flag set. Automatically setting the flag", wip->name);
2477  wip->wi_flags |= WIF_PARTICLE_SPEW;
2478  }
2479  // index for xmt edit, replace and remove support
2480  if (optional_string("+Index:")) {
2481  stuff_int(&spew_index);
2482  if (spew_index < 0 || spew_index >= MAX_PARTICLE_SPEWERS) {
2483  Warning(LOCATION, "+Index in particle spewer out of range. It must be between 0 and %i. Tag will be ignored.", MAX_PARTICLE_SPEWERS);
2484  spew_index = -1;
2485  }
2486  }
2487  // check for remove flag
2488  if (optional_string("+Remove")) {
2489  if (spew_index < 0) {
2490  Warning(LOCATION, "+Index not specified or is out of range, can not remove spewer.");
2491  } else { // restore defaults
2492  wip->particle_spewers[spew_index].particle_spew_type = PSPEW_NONE;
2493  wip->particle_spewers[spew_index].particle_spew_count = 1;
2494  wip->particle_spewers[spew_index].particle_spew_time = 25;
2495  wip->particle_spewers[spew_index].particle_spew_vel = 0.4f;
2496  wip->particle_spewers[spew_index].particle_spew_radius = 2.0f;
2497  wip->particle_spewers[spew_index].particle_spew_lifetime = 0.15f;
2498  wip->particle_spewers[spew_index].particle_spew_scale = 0.8f;
2499  wip->particle_spewers[spew_index].particle_spew_z_scale = 1.0f;
2500  wip->particle_spewers[spew_index].particle_spew_rotation_rate = 10.0f;
2503  generic_anim_init(&wip->particle_spewers[spew_index].particle_spew_anim, NULL);
2504  }
2505  } else { // were not removing the spewer
2506  if (spew_index < 0) { // index us ether not used or is invalid, so figure out where to put things
2507  //find a free slot in the pspew info array
2508  for (size_t s = 0; s < MAX_PARTICLE_SPEWERS; s++) {
2510  spew_index = s;
2511  break;
2512  }
2513  }
2514  }
2515  // no empty spot found, the modder tried to define too many spewers, or screwed up the xmts, or my code sucks
2516  if ( spew_index < 0 ) {
2517  Warning(LOCATION, "Too many particle spewers, max number of spewers is %i.", MAX_PARTICLE_SPEWERS);
2518  } else { // we have a valid index, now parse the spewer already
2519  if (optional_string("+Type:")) { // added type field for pspew types, 0 is the default for reverse compatability -nuke
2520  char temp_pspew_type[NAME_LENGTH];
2521  stuff_string(temp_pspew_type, F_NAME, NAME_LENGTH);
2522 
2523  if (!stricmp(temp_pspew_type, NOX("DEFAULT"))) {
2525  } else if (!stricmp(temp_pspew_type, NOX("HELIX"))) {
2526  wip->particle_spewers[spew_index].particle_spew_type = PSPEW_HELIX;
2527  } else if (!stricmp(temp_pspew_type, NOX("SPARKLER"))) { // new types can be added here
2529  } else if (!stricmp(temp_pspew_type, NOX("RING"))) {
2530  wip->particle_spewers[spew_index].particle_spew_type = PSPEW_RING;
2531  } else if (!stricmp(temp_pspew_type, NOX("PLUME"))) {
2532  wip->particle_spewers[spew_index].particle_spew_type = PSPEW_PLUME;
2533  } else {
2535  }
2536  // for compatibility with existing tables that don't have a type tag
2537  } else if (wip->particle_spewers[spew_index].particle_spew_type == PSPEW_NONE) { // make sure the omission of type wasn't to edit an existing entry
2539  }
2540 
2541  if (optional_string("+Count:")) {
2542  stuff_int(&wip->particle_spewers[spew_index].particle_spew_count);
2543  }
2544 
2545  if (optional_string("+Time:")) {
2546  stuff_int(&wip->particle_spewers[spew_index].particle_spew_time);
2547  }
2548 
2549  if (optional_string("+Vel:")) {
2550  stuff_float(&wip->particle_spewers[spew_index].particle_spew_vel);
2551  }
2552 
2553  if (optional_string("+Radius:")) {
2555  }
2556 
2557  if (optional_string("+Life:")) {
2559  }
2560 
2561  if (optional_string("+Scale:")) {
2563  }
2564 
2565  if (optional_string("+Z Scale:")) {
2567  }
2568 
2569  if (optional_string("+Rotation Rate:")) {
2571  }
2572 
2573  if (optional_string("+Offset:")) {
2575  }
2576 
2577  if (optional_string("+Initial Velocity:")) {
2579  }
2580 
2581  if (optional_string("+Bitmap:")) {
2583  generic_anim_init(&wip->particle_spewers[spew_index].particle_spew_anim, fname);
2584  }
2585  }
2586  }
2587  }
2588  // check to see if the pspew flag was enabled but no pspew tags were given, for compatability with retail tables
2589  if (wip->wi_flags & WIF_PARTICLE_SPEW) {
2590  bool nospew = true;
2591  for (size_t s = 0; s < MAX_PARTICLE_SPEWERS; s++)
2593  nospew = false;
2594  }
2595  if (nospew) { // set first spewer to default
2597  }
2598  }
2599 
2600  // tag weapon optional stuff
2601  if( optional_string("$Tag:")){
2602  stuff_int(&wip->tag_level);
2603  stuff_float(&wip->tag_time);
2604  wip->wi_flags |= WIF_TAG;
2605  }
2606 
2607  if( optional_string("$SSM:")){
2608  if (stuff_int_optional(&wip->SSM_index) != 2) {
2609  // We can't make an SSM lookup yet, because weapons are parsed first, but we can save the data to process later. -MageKing17
2610  stuff_string(fname, F_NAME, NAME_LENGTH);
2611  delayed_ssm_data temp_data;
2612  temp_data.filename = filename;
2613  temp_data.linenum = get_line_num();
2614  temp_data.ssm_entry = fname;
2615  if (Delayed_SSM_data.find(wip->name) == Delayed_SSM_data.end())
2616  Delayed_SSM_names.push_back(wip->name);
2617  Delayed_SSM_data[wip->name] = temp_data;
2618  } else {
2619  // We'll still want to validate the index later. -MageKing17
2620  delayed_ssm_index_data temp_data;
2621  temp_data.filename = filename;
2622  temp_data.linenum = get_line_num();
2623  if (Delayed_SSM_indices_data.find(wip->name) == Delayed_SSM_indices_data.end())
2624  Delayed_SSM_indices.push_back(wip->name);
2625  Delayed_SSM_indices_data[wip->name] = temp_data;
2626  }
2627  }// SSM index -Bobboau
2628 
2629  if(optional_string("$FOF:")){
2630  stuff_float(&wip->field_of_fire);
2631 
2632  if(optional_string("+FOF Spread Rate:")){
2634  if(required_string("+FOF Reset Rate:")){
2635  stuff_float(&wip->fof_reset_rate);
2636  }
2637 
2638  if(required_string("+Max FOF:")){
2639  float max_fof;
2640  stuff_float(&max_fof);
2641  wip->max_fof_spread = max_fof - wip->field_of_fire;
2642 
2643  if (wip->max_fof_spread <= 0.0f) {
2644  Warning(LOCATION, "WARNING: +Max FOF must be at least as big as $FOF for '%s'! Defaulting to match $FOF, no spread will occur!", wip->name);
2645  wip->max_fof_spread = 0.0f;
2646  }
2647  }
2648  }
2649  }
2650 
2651 
2652  if( optional_string("$Shots:")){
2653  stuff_int(&wip->shots);
2654  }
2655 
2656  //Left in for compatibility
2657  if ( optional_string("$decal:") ) {
2658  mprintf(("WARNING: The decal system has been deactivated in FSO builds. Entries for weapon %s will be discarded.\n", wip->name));
2659  required_string("+texture:");
2660  stuff_string(fname, F_NAME, NAME_LENGTH);
2661 
2662  if ( optional_string("+backface texture:") ) {
2663  stuff_string(fname, F_NAME, NAME_LENGTH);
2664  }
2665 
2666  float bogus;
2667 
2668  required_string("+radius:");
2669  stuff_float(&bogus);
2670 
2671  if ( optional_string("+burn time:") ) {
2672  stuff_float(&bogus);
2673  }
2674  }
2675 
2676 
2677  if (optional_string("$Transparent:")) {
2678  wip->wi_flags2 |= WIF2_TRANSPARENT;
2679 
2680  required_string("+Alpha:");
2681  stuff_float(&wip->alpha_max);
2682 
2683  if (wip->alpha_max > 1.0f)
2684  wip->alpha_max = 1.0f;
2685 
2686  if (wip->alpha_max <= 0.0f) {
2687  Warning(LOCATION, "WARNING: Alpha is set to 0 or a negative value for '%s'! Defaulting to 1.0!", wip->name);
2688  }
2689 
2690  if (optional_string("+Alpha Min:")) {
2691  stuff_float(&wip->alpha_min);
2692  CLAMP(wip->alpha_min, 0.0f, 1.0f);
2693  }
2694 
2695  if (optional_string("+Alpha Cycle:")) {
2696  stuff_float(&wip->alpha_cycle);
2697 
2698  if (wip->alpha_max == wip->alpha_min)
2699  Warning(LOCATION, "WARNING: Alpha is set to cycle for '%s', but max and min values are the same!", wip->name);
2700  }
2701  }
2702 
2703  if (optional_string("$Weapon Hitpoints:")) {
2704  stuff_int(&wip->weapon_hitpoints);
2705  } else if (first_time && (wip->wi_flags3 & (WIF3_TURRET_INTERCEPTABLE | WIF3_FIGHTER_INTERCEPTABLE))) {
2706  wip->weapon_hitpoints = 25;
2707  }
2708 
2709  // making sure bombs get their hitpoints assigned
2710  if ((wip->wi_flags & WIF_BOMB) && (wip->weapon_hitpoints == 0)) {
2711  wip->weapon_hitpoints = 50;
2712  }
2713 
2714  if(optional_string("$Armor Type:")) {
2716  wip->armor_type_idx = armor_type_get_idx(buf);
2717 
2718  if(wip->armor_type_idx == -1)
2719  Warning(LOCATION,"Invalid armor name %s specified for weapon %s", buf, wip->name);
2720  }
2721 
2722  if (optional_string("$Burst Shots:")) {
2723  stuff_int(&wip->burst_shots);
2724  if (wip->burst_shots > 0)
2725  wip->burst_shots--;
2726  }
2727 
2728  if (optional_string("$Burst Delay:")) {
2729  int temp;
2730  stuff_int(&temp);
2731  if (temp > 0) {
2732  wip->burst_delay = ((float) temp) / 1000.0f;
2733  }
2734  }
2735 
2736  if (optional_string("$Burst Flags:")) {
2737  parse_string_flag_list((int*)&wip->burst_flags, Burst_fire_flags, Num_burst_fire_flags);
2738  }
2739 
2740  if (optional_string("$Thruster Flame Effect:")) {
2741  stuff_string(fname, F_NAME, NAME_LENGTH);
2742 
2743  if (VALID_FNAME(fname))
2744  generic_anim_init( &wip->thruster_flame, fname );
2745  }
2746 
2747  if (optional_string("$Thruster Glow Effect:")) {
2748  stuff_string(fname, F_NAME, NAME_LENGTH);
2749 
2750  if (VALID_FNAME(fname))
2751  generic_anim_init( &wip->thruster_glow, fname );
2752  }
2753 
2754  if (optional_string("$Thruster Glow Radius Factor:")) {
2756  }
2757 
2758  //pretty stupid if a target must be tagged to shoot tag missiles at it
2759  if ((wip->wi_flags & WIF_TAG) && (wip->wi_flags2 & WIF2_TAGGED_ONLY))
2760  {
2761  Warning(LOCATION, "%s is a tag missile, but the target must be tagged to shoot it", wip->name);
2762  }
2763 
2764  // if burst delay is longer than firewait skip the whole burst fire option
2765  if (wip->burst_delay >= wip->fire_wait)
2766  wip->burst_shots = 0;
2767 
2768  /* Generate a substitution pattern for this weapon.
2769  This pattern is very naive such that it calculates the lowest common denominator as being all of
2770  the periods multiplied together.
2771  */
2772  while ( optional_string("$substitute:") ) {
2773  char subname[NAME_LENGTH];
2774  int period = 0;
2775  int index = 0;
2776  int offset = 0;
2777  stuff_string(subname, F_NAME, NAME_LENGTH);
2778  if ( optional_string("+period:") ) {
2779  stuff_int(&period);
2780  if ( period <= 0 ) {
2781  Warning(LOCATION, "Substitution '%s' for weapon '%s' requires a period greater than 0. Setting period to 1.", subname, wip->name);
2782  period = 1;
2783  }
2784  if ( optional_string("+offset:") ) {
2785  stuff_int(&offset);
2786  if ( offset <= 0 ) {
2787  Warning(LOCATION, "Period offset for substitution '%s' of weapon '%s' has to be greater than 0. Setting offset to 1.", subname, wip->name);
2788  offset = 1;
2789  }
2790  }
2791  } else if ( optional_string("+index:") ) {
2792  stuff_int(&index);
2793  if ( index < 0 ) {
2794  Warning(LOCATION, "Substitution '%s' for weapon '%s' requires an index greater than 0. Setting index to 0.", subname, wip->name);
2795  index = 0;
2796  }
2797  }
2798 
2799  // we are going to use weapon substition so, make sure that the pattern array has at least one element
2800  if ( wip->num_substitution_patterns == 0 ) {
2801  // pattern is empty, initialize pattern with the weapon being currently parsed.
2804  }
2805 
2806  // if tbler specifies a period then determine if we can fit the resulting pattern
2807  // neatly into the pattern array.
2808  if ( period > 0 ) {
2809  if ( (wip->num_substitution_patterns % period) > 0 ) {
2810  // not neat, need to expand the pattern so that our frequency pattern fits completly.
2811  size_t current_size = wip->num_substitution_patterns;
2812  size_t desired_size = current_size*period;
2813  if (desired_size > MAX_SUBSTITUTION_PATTERNS) {
2814  Warning(LOCATION, "The period is too large for the number of substitution patterns! desired size=" SIZE_T_ARG ", max size=%d", desired_size, MAX_SUBSTITUTION_PATTERNS);
2815  }
2816  else {
2817  wip->num_substitution_patterns = desired_size;
2818 
2819  // now duplicate the current pattern into the new area so the current pattern holds
2820  for ( size_t i = current_size; i < desired_size; i++ ) {
2822  }
2823  }
2824  }
2825 
2826  /* Apply the substituted weapon at the requested period, barrel
2827  shifted by offset if needed.*/
2828  for ( size_t pos = (period + offset - 1) % period;
2829  pos < wip->num_substitution_patterns; pos += period )
2830  {
2832  }
2833  } else {
2834  // assume that tbler wanted to specify a index for the new weapon.
2835 
2836  // make sure that there is enough room
2837  if (index >= MAX_SUBSTITUTION_PATTERNS) {
2838  Warning(LOCATION, "Substitution pattern index exceeds the maximum size! Index=%d, max size=%d", index, MAX_SUBSTITUTION_PATTERNS);
2839  } else {
2840  if ( (size_t)index >= wip->num_substitution_patterns ) {
2841  // need to make the pattern bigger by filling the extra with the current weapon.
2842  for ( size_t i = wip->num_substitution_patterns; i < (size_t)index; i++ ) {
2844  }
2845  wip->num_substitution_patterns = index+1;
2846  }
2847 
2848  strcpy_s(wip->weapon_substitution_pattern_names[index], subname);
2849  }
2850  }
2851  }
2852 
2853  //Optional score for destroying this weapon.
2854  if (optional_string("$Score:")) {
2855  stuff_int(&wip->score);
2856  }
2857 
2858  return WEAPON_INFO_INDEX(wip);
2859 }
2860 
2866 {
2867  int i, j, k;
2868 
2869  for (i = 0; i < Num_weapon_types; i++)
2870  {
2871  for (j = 0; j < Weapon_info[i].num_spawn_weapons_defined; j++)
2872  {
2873  if ( (Weapon_info[i].spawn_info[j].spawn_type > -1) && (Weapon_info[i].spawn_info[j].spawn_type < Num_spawn_types) )
2874  {
2875  int spawn_type = Weapon_info[i].spawn_info[j].spawn_type;
2876 
2877  Assert( spawn_type < Num_spawn_types );
2878 
2879  for (k = 0; k < Num_weapon_types; k++)
2880  {
2881  if ( !stricmp(Spawn_names[spawn_type], Weapon_info[k].name) )
2882  {
2883  Weapon_info[i].spawn_info[j].spawn_type = (short)k;
2884 
2885  if (i == k)
2886  Warning(LOCATION, "Weapon %s spawns itself. Infinite recursion?\n", Weapon_info[i].name);
2887 
2888  break;
2889  }
2890  }
2891  }
2892  }
2893  }
2894 }
2895 
2896 static char Default_cmeasure_name[NAME_LENGTH] = "";
2897 
2898 void parse_weaponstbl(const char *filename)
2899 {
2900  try
2901  {
2902  read_file_text(filename, CF_TYPE_TABLES);
2903  reset_parse();
2904 
2905  if (optional_string("#Primary Weapons"))
2906  {
2907  while (required_string_either("#End", "$Name:")) {
2908  // AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
2909  if (parse_weapon(WP_LASER, Parsing_modular_table, filename) < 0) {
2910  continue;
2911  }
2912  }
2913  required_string("#End");
2914  }
2915 
2916  if (optional_string("#Secondary Weapons"))
2917  {
2918  while (required_string_either("#End", "$Name:")) {
2919  // AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
2920  if (parse_weapon(WP_MISSILE, Parsing_modular_table, filename) < 0) {
2921  continue;
2922  }
2923  }
2924  required_string("#End");
2925  }
2926 
2927  if (optional_string("#Beam Weapons"))
2928  {
2929  while (required_string_either("#End", "$Name:")) {
2930  // AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
2931  if (parse_weapon(WP_BEAM, Parsing_modular_table, filename) < 0) {
2932  continue;
2933  }
2934  }
2935  required_string("#End");
2936  }
2937 
2938  if (optional_string("#Countermeasures"))
2939  {
2940  while (required_string_either("#End", "$Name:"))
2941  {
2943 
2944  if (idx < 0) {
2945  continue;
2946  }
2947 
2948  //Make sure cmeasure flag is set
2949  Weapon_info[idx].wi_flags |= WIF_CMEASURE;
2950 
2951  //Set cmeasure index
2952  if (!strlen(Default_cmeasure_name)) {
2953  //We can't be sure that index will be the same after sorting, so save the name
2954  strcpy_s(Default_cmeasure_name, Weapon_info[idx].name);
2955  }
2956  }
2957 
2958  required_string("#End");
2959  }
2960 
2961  // Read in a list of weapon_info indicies that are an ordering of the player weapon precedence.
2962  // This list is used to select an alternate weapon when a particular weapon is not available
2963  // during weapon selection.
2964  if ((!Parsing_modular_table && required_string("$Player Weapon Precedence:")) || optional_string("$Player Weapon Precedence:"))
2965  {
2966  Num_player_weapon_precedence = stuff_int_list(Player_weapon_precedence, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
2967  }
2968 
2969  // add tbl/tbm to multiplayer validation list
2970  fs2netd_add_table_validation(filename);
2971  }
2972  catch (const parse::ParseException& e)
2973  {
2974  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
2975  return;
2976  }
2977 }
2978 
2979 //uses a simple bucket sort to sort weapons, order of importance is:
2980 //Lasers
2981 //Beams
2982 //Child primary weapons
2983 //Fighter missiles and bombs
2984 //Capital missiles and bombs
2985 //Child secondary weapons
2987 {
2988  weapon_info *lasers = NULL, *big_lasers = NULL, *beams = NULL, *missiles = NULL, *big_missiles = NULL, *child_primaries = NULL, *child_secondaries = NULL;
2989  int num_lasers = 0, num_big_lasers = 0, num_beams = 0, num_missiles = 0, num_big_missiles = 0, num_child_primaries = 0, num_child_secondaries = 0;
2990  int i, weapon_index;
2991 
2992  // get the initial count of each weapon type
2993  for (i = 0; i < MAX_WEAPON_TYPES; i++) {
2994  switch (Weapon_info[i].subtype)
2995  {
2996  case WP_UNUSED:
2997  continue;
2998 
2999  case WP_LASER:
3000  if (Weapon_info[i].wi_flags & WIF_CHILD)
3001  num_child_primaries++;
3002  else if (Weapon_info[i].wi_flags & WIF_BIG_ONLY)
3003  num_big_lasers++;
3004  else
3005  num_lasers++;
3006  break;
3007 
3008  case WP_BEAM:
3009  num_beams++;
3010  break;
3011 
3012  case WP_MISSILE:
3013  if (Weapon_info[i].wi_flags & WIF_CHILD)
3014  num_child_secondaries++;
3015  else if (Weapon_info[i].wi_flags & WIF_BIG_ONLY)
3016  num_big_missiles++;
3017  else
3018  num_missiles++;
3019  break;
3020 
3021  default:
3022  continue;
3023  }
3024 
3025  }
3026 
3027  // allocate the buckets
3028  if (num_lasers) {
3029  lasers = new weapon_info[num_lasers];
3030  Verify( lasers != NULL );
3031  num_lasers = 0;
3032  }
3033 
3034  if (num_big_lasers) {
3035  big_lasers = new weapon_info[num_big_lasers];
3036  Verify( big_lasers != NULL );
3037  num_big_lasers = 0;
3038  }
3039 
3040  if (num_beams) {
3041  beams = new weapon_info[num_beams];
3042  Verify( beams != NULL );
3043  num_beams = 0;
3044  }
3045 
3046  if (num_missiles) {
3047  missiles = new weapon_info[num_missiles];
3048  Verify( missiles != NULL );
3049  num_missiles = 0;
3050  }
3051 
3052  if (num_big_missiles) {
3053  big_missiles = new weapon_info[num_big_missiles];
3054  Verify( big_missiles != NULL );
3055  num_big_missiles = 0;
3056  }
3057 
3058  if (num_child_primaries) {
3059  child_primaries = new weapon_info[num_child_primaries];
3060  Verify( child_primaries != NULL );
3061  num_child_primaries = 0;
3062  }
3063 
3064  if (num_child_secondaries) {
3065  child_secondaries = new weapon_info[num_child_secondaries];
3066  Verify( child_secondaries != NULL );
3067  num_child_secondaries = 0;
3068  }
3069 
3070  // fill the buckets
3071  for (i = 0; i < MAX_WEAPON_TYPES; i++) {
3072  switch (Weapon_info[i].subtype)
3073  {
3074  case WP_UNUSED:
3075  continue;
3076 
3077  case WP_LASER:
3078  if (Weapon_info[i].wi_flags & WIF_CHILD)
3079  child_primaries[num_child_primaries++] = Weapon_info[i];
3080  else if (Weapon_info[i].wi_flags & WIF_BIG_ONLY)
3081  big_lasers[num_big_lasers++] = Weapon_info[i];
3082  else
3083  lasers[num_lasers++] = Weapon_info[i];
3084  break;
3085 
3086  case WP_BEAM:
3087  beams[num_beams++] = Weapon_info[i];
3088  break;
3089 
3090  case WP_MISSILE:
3091  if (Weapon_info[i].wi_flags & WIF_CHILD)
3092  child_secondaries[num_child_secondaries++] = Weapon_info[i];
3093  else if (Weapon_info[i].wi_flags & WIF_BIG_ONLY)
3094  big_missiles[num_big_missiles++] = Weapon_info[i];
3095  else
3096  missiles[num_missiles++]=Weapon_info[i];
3097  break;
3098 
3099  default:
3100  continue;
3101  }
3102  }
3103 
3104  weapon_index = 0;
3105 
3106  // reorder the weapon_info structure according to our rules defined above
3107  for (i = 0; i < num_lasers; i++, weapon_index++)
3108  Weapon_info[weapon_index] = lasers[i];
3109 
3110  for (i = 0; i < num_big_lasers; i++, weapon_index++)
3111  Weapon_info[weapon_index] = big_lasers[i];
3112 
3113  for (i = 0; i < num_beams; i++, weapon_index++)
3114  Weapon_info[weapon_index] = beams[i];
3115 
3116  for (i = 0; i < num_child_primaries; i++, weapon_index++)
3117  Weapon_info[weapon_index] = child_primaries[i];
3118 
3119  // designate start of secondary weapons so that we'll have the correct offset later on
3120  First_secondary_index = weapon_index;
3121 
3122  for (i = 0; i < num_missiles; i++, weapon_index++)
3123  Weapon_info[weapon_index] = missiles[i];
3124 
3125  for (i = 0; i < num_big_missiles; i++, weapon_index++)
3126  Weapon_info[weapon_index] = big_missiles[i];
3127 
3128  for (i = 0; i < num_child_secondaries; i++, weapon_index++)
3129  Weapon_info[weapon_index] = child_secondaries[i];
3130 
3131 
3132  if (lasers) delete [] lasers;
3133  if (big_lasers) delete [] big_lasers;
3134  if (beams) delete [] beams;
3135  if (missiles) delete [] missiles;
3136  if (big_missiles) delete [] big_missiles;
3137  if (child_primaries) delete [] child_primaries;
3138  if (child_secondaries) delete [] child_secondaries;
3139 }
3140 
3145 {
3146  weapon_info *wip;
3147  int i;
3148 
3149  for (i = 0; i < Num_weapon_types; i++) {
3150  wip = &Weapon_info[i];
3151 
3152  if (wip->wi_flags & WIF_BEAM) {
3153  // clean up any beam sections which may have been deleted
3154  int removed = 0;
3155 
3156  for (int s_idx = 0; s_idx < wip->b_info.beam_num_sections; s_idx++) {
3157  if ( !strlen(wip->b_info.sections[s_idx].texture.filename) ) {
3158  int new_idx = s_idx + 1;
3159 
3160  while (new_idx < MAX_BEAM_SECTIONS) {
3161  memcpy( &wip->b_info.sections[new_idx-1], &wip->b_info.sections[new_idx], sizeof(beam_weapon_section_info) );
3162  new_idx++;
3163  }
3164 
3165  removed++;
3166  }
3167  }
3168 
3169  if (removed) {
3170  mprintf(("NOTE: weapon-cleanup is removing %i stale beam sections, out of %i original, from '%s'.\n", removed, wip->b_info.beam_num_sections, wip->name));
3171  wip->b_info.beam_num_sections -= removed;
3172  }
3173  }
3174  }
3175 }
3176 
3178 {
3179  int i, j;
3180  weapon_info *wip;
3181 
3182  // not for FRED...
3183  if (Fred_running)
3184  return;
3185 
3186  // if we are just going to load them all again any, keep everything
3188  return;
3189 
3190  for (i = 0; i < Num_weapon_types; i++) {
3191  wip = &Weapon_info[i];
3192 
3193  // go ahead and clear out models, the model paging code will actually take care of
3194  // releasing this stuff if needed, but we have to keep track of current modelnums ourselves
3195  if (wip->render_type == WRT_POF)
3196  wip->model_num = -1;
3197 
3198  // we are only interested in what we don't need for this mission
3199  if ( used_weapons[i] )
3200  continue;
3201 
3202  if (wip->render_type == WRT_LASER) {
3203  if (wip->laser_bitmap.first_frame >= 0) {
3205  wip->laser_bitmap.first_frame = -1;
3206  }
3207 
3208  // now for the glow
3209  if (wip->laser_glow_bitmap.first_frame >= 0) {
3211  wip->laser_glow_bitmap.first_frame = -1;
3212  }
3213  }
3214 
3215  if (wip->wi_flags & WIF_BEAM) {
3216  // particle animation
3217  if (wip->b_info.beam_particle_ani.first_frame >= 0) {
3220  }
3221 
3222  // muzzle glow
3223  if (wip->b_info.beam_glow.first_frame >= 0) {
3225  wip->b_info.beam_glow.first_frame = -1;
3226  }
3227 
3228  // section textures
3229  for (j = 0; j < wip->b_info.beam_num_sections; j++) {
3230  beam_weapon_section_info *bsi = &wip->b_info.sections[j];
3231 
3232  if (bsi->texture.first_frame >= 0) {
3234  bsi->texture.first_frame = -1;
3235  }
3236  }
3237  }
3238 
3239  if (wip->wi_flags & WIF_TRAIL) {
3240  if (wip->tr_info.texture.bitmap_id >= 0) {
3242  wip->tr_info.texture.bitmap_id = -1;
3243  }
3244  }
3245 
3246  if (wip->wi_flags & WIF_PARTICLE_SPEW) { // tweaked for multiple particle spews -nuke
3247  for (size_t s = 0; s < MAX_PARTICLE_SPEWERS; s++) { // just bitmaps that got loaded
3252  }
3253  }
3254  }
3255  }
3256 
3257  if (wip->thruster_flame.first_frame >= 0) {
3259  wip->thruster_flame.first_frame = -1;
3260  }
3261 
3262  if (wip->thruster_glow.first_frame >= 0) {
3264  wip->thruster_glow.first_frame = -1;
3265  }
3266  }
3267 }
3268 
3269 bool weapon_is_used(int weapon_index)
3270 {
3271  Assert( (weapon_index >= 0) || (weapon_index < Num_weapon_types) );
3272  return (used_weapons[weapon_index] > 0);
3273 }
3274 
3275 void weapon_load_bitmaps(int weapon_index)
3276 {
3277  weapon_info *wip;
3278 
3279  // not for FRED...
3280  if (Fred_running)
3281  return;
3282 
3283  if ( (weapon_index < 0) || (weapon_index >= Num_weapon_types) ) {
3284  Int3();
3285  return;
3286  }
3287 
3288  wip = &Weapon_info[weapon_index];
3289 
3290  if ( (wip->render_type == WRT_LASER) && (wip->laser_bitmap.first_frame < 0) ) {
3292 
3293  if (wip->laser_bitmap.first_frame >= 0) {
3294  wip->laser_bitmap.num_frames = 1;
3295  wip->laser_bitmap.total_time = 1;
3296  }
3297  // fall back to an animated type
3298  else if ( generic_anim_load(&wip->laser_bitmap) ) {
3299  mprintf(("Could not find a usable bitmap for '%s'!\n", wip->name));
3300  Warning(LOCATION, "Could not find a usable bitmap (%s) for weapon '%s'!\n", wip->laser_bitmap.filename, wip->name);
3301  }
3302 
3303  // now see if we also have a glow
3304  if ( strlen(wip->laser_glow_bitmap.filename) ) {
3306 
3307  if (wip->laser_glow_bitmap.first_frame >= 0) {
3308  wip->laser_glow_bitmap.num_frames = 1;
3309  wip->laser_glow_bitmap.total_time = 1;
3310  }
3311  // fall back to an animated type
3312  else if ( generic_anim_load(&wip->laser_glow_bitmap) ) {
3313  mprintf(("Could not find a usable glow bitmap for '%s'!\n", wip->name));
3314  Warning(LOCATION, "Could not find a usable glow bitmap (%s) for weapon '%s'!\n", wip->laser_glow_bitmap.filename, wip->name);
3315  }
3316  }
3317  }
3318 
3319  if (wip->wi_flags & WIF_BEAM) {
3320  // particle animation
3321  if ( (wip->b_info.beam_particle_ani.first_frame < 0) && strlen(wip->b_info.beam_particle_ani.filename) )
3323 
3324  // muzzle glow
3325  if ( (wip->b_info.beam_glow.first_frame < 0) && strlen(wip->b_info.beam_glow.filename) ) {
3326  if ( generic_anim_load(&wip->b_info.beam_glow) ) {
3327  // animated version failed to load, try static instead
3329 
3330  if (wip->b_info.beam_glow.first_frame >= 0) {
3331  wip->b_info.beam_glow.num_frames = 1;
3332  wip->b_info.beam_glow.total_time = 1;
3333  } else {
3334  mprintf(("Could not find a usable muzzle glow bitmap for '%s'!\n", wip->name));
3335  Warning(LOCATION, "Could not find a usable muzzle glow bitmap (%s) for weapon '%s'!\n", wip->b_info.beam_glow.filename, wip->name);
3336  }
3337  }
3338  }
3339 
3340  // section textures
3341  for (int i = 0; i < wip->b_info.beam_num_sections; i++) {
3342  beam_weapon_section_info *bsi = &wip->b_info.sections[i];
3343 
3344  if ( (bsi->texture.first_frame < 0) && strlen(bsi->texture.filename) ) {
3345  if ( generic_anim_load(&bsi->texture) ) {
3346  // animated version failed to load, try static instead
3348 
3349  if (bsi->texture.first_frame >= 0) {
3350  bsi->texture.num_frames = 1;
3351  bsi->texture.total_time = 1;
3352  } else {
3353  mprintf(("Could not find a usable beam section (%i) bitmap for '%s'!\n", i, wip->name));
3354  Warning(LOCATION, "Could not find a usable beam section (%i) bitmap (%s) for weapon '%s'!\n", i, bsi->texture.filename, wip->name);
3355  }
3356  }
3357  }
3358  }
3359  }
3360 
3361  if ( (wip->wi_flags & WIF_TRAIL) && (wip->tr_info.texture.bitmap_id < 0) )
3363 
3364  //WMC - Don't try to load an anim if no anim is specified, Mmkay?
3365  if (wip->wi_flags & WIF_PARTICLE_SPEW) {
3366  for (size_t s = 0; s < MAX_PARTICLE_SPEWERS; s++) { // looperfied for multiple pspewers -nuke
3368 
3370  && (wip->particle_spewers[s].particle_spew_anim.filename[0] != '\0') ) {
3371 
3373 
3377  }
3378  // fall back to an animated type
3380  mprintf(("Could not find a usable particle spew bitmap for '%s'!\n", wip->name));
3381  Warning(LOCATION, "Could not find a usable particle spew bitmap (%s) for weapon '%s'!\n", wip->particle_spewers[s].particle_spew_anim.filename, wip->name);
3382  }
3383  }
3384  }
3385  }
3386  }
3387 
3388  // load alternate thruster textures
3389  if (strlen(wip->thruster_flame.filename)) {
3391  }
3392 
3393  if (strlen(wip->thruster_glow.filename)) {
3395  if (wip->thruster_glow.first_frame >= 0) {
3396  wip->thruster_glow.num_frames = 1;
3397  wip->thruster_glow.total_time = 1;
3398  } else {
3400  }
3401  }
3402 
3403  // if this weapon isn't already marked as used, then mark it as such now
3404  // (this should really only happen if the player is cheating)
3405  if ( !used_weapons[weapon_index] )
3406  used_weapons[weapon_index]++;
3407 }
3408 
3413  for (int i = 0; i < MAX_WEAPON_TYPES; i++) {
3414  weapon_info *wip = &(Weapon_info[i]);
3415 
3416  if ( wip->num_substitution_patterns > 0 ) {
3417  for ( size_t j = 0; j < wip->num_substitution_patterns; j++ ) {
3418  int weapon_index = -1;
3419  if ( stricmp("none", wip->weapon_substitution_pattern_names[j]) != 0 ) {
3420  weapon_index = weapon_info_lookup(wip->weapon_substitution_pattern_names[j]);
3421  if ( weapon_index == -1 ) { // invalid sub weapon
3422  Warning(LOCATION, "Weapon '%s' requests substitution with '%s' which does not seem to exist",
3423  wip->name, wip->weapon_substitution_pattern_names[j]);
3424  continue;
3425  }
3426  }
3427 
3428  wip->weapon_substitution_pattern[j] = weapon_index;
3429  }
3430 
3432  }
3433  }
3434 }
3435 
3437 {
3438  weapon_info *wip;
3439  int first_cmeasure_index = -1;
3440  int i;
3441 
3442  weapon_sort_by_type(); // NOTE: This has to be first thing!
3445 
3446  Default_cmeasure_index = -1;
3447 
3448  // run through weapons list and deal with individual issues
3449  for (i = 0; i < Num_weapon_types; i++) {
3450  wip = &Weapon_info[i];
3451 
3452  // set default counter-measure index from the saved name
3453  if ( (Default_cmeasure_index < 0) && strlen(Default_cmeasure_name) ) {
3454  if ( !stricmp(wip->name, Default_cmeasure_name) ) {
3455  Default_cmeasure_index = i;
3456  }
3457  }
3458 
3459  // catch a fall back cmeasure index, just in case
3460  if ( (first_cmeasure_index < 0) && (wip->wi_flags & WIF_CMEASURE) )
3461  first_cmeasure_index = i;
3462  }
3463 
3464  // catch cmeasure fallback
3465  if (Default_cmeasure_index < 0)
3466  Default_cmeasure_index = first_cmeasure_index;
3467 
3468  // now we want to resolve the countermeasures by species
3469  for (SCP_vector<species_info>::iterator ii = Species_info.begin(); ii != Species_info.end(); ++ii)
3470  {
3471  if (*ii->cmeasure_name)
3472  {
3473  int index = weapon_info_lookup(ii->cmeasure_name);
3474  if (index < 0)
3475  Warning(LOCATION, "Could not find weapon type '%s' to use as countermeasure on species '%s'", ii->cmeasure_name, ii->species_name);
3476  else if (Weapon_info[index].wi_flags & WIF_BEAM)
3477  Warning(LOCATION, "Attempt made to set a beam weapon as a countermeasure on species '%s'", ii->species_name);
3478  else
3479  ii->cmeasure_index = index;
3480  }
3481  }
3482 
3483  // translate all spawn type weapons to referrnce the appropriate spawned weapon entry
3485 }
3486 
3488 {
3489  int i;
3490 
3491  parse_weapon_expl_tbl("weapon_expl.tbl");
3492 
3493  // check for, and load, modular tables
3495 
3496  // we've got our list so pass it off for final checking and loading
3497  for (i = 0; i < (int)LOD_checker.size(); i++) {
3498  Weapon_explosions.Load( LOD_checker[i].filename, LOD_checker[i].num_lods );
3499  }
3500 
3501  // done
3502  LOD_checker.clear();
3503 }
3504 
3506 {
3507  memset( Weapon_info, 0, sizeof(weapon_info) * MAX_WEAPON_TYPES );
3508 
3509  for (int i = 0; i < MAX_WEAPON_TYPES; i++)
3511 }
3512 
3517 {
3518  if ( !Weapons_inited ) {
3519  //Init weapon explosion info
3521 
3522  // parse weapons.tbl
3524 
3525  Num_weapon_types = 0;
3526  Num_spawn_types = 0;
3527 
3528  parse_weaponstbl("weapons.tbl");
3529 
3530  parse_modular_table(NOX("*-wep.tbm"), parse_weaponstbl);
3531 
3532  // do post-parse cleanup
3534 
3535  Weapons_inited = 1;
3536  }
3537 
3539 }
3540 
3541 
3546 {
3547  int i;
3548 
3549  for (i = 0; i<MAX_WEAPON_TYPES; i++) {
3550  if (Weapon_info[i].desc) {
3551  vm_free(Weapon_info[i].desc);
3552  Weapon_info[i].desc = NULL;
3553  }
3554 
3555  if (Weapon_info[i].tech_desc) {
3556  vm_free(Weapon_info[i].tech_desc);
3557  Weapon_info[i].tech_desc = NULL;
3558  }
3559  }
3560 
3561  if (used_weapons != NULL) {
3562  delete[] used_weapons;
3563  used_weapons = NULL;
3564  }
3565 
3566  if (Spawn_names != NULL) {
3567  for (i=0; i<Num_spawn_types; i++) {
3568  if (Spawn_names[i] != NULL) {
3569  vm_free(Spawn_names[i]);
3570  Spawn_names[i] = NULL;
3571  }
3572  }
3573 
3574  vm_free(Spawn_names);
3575  Spawn_names = NULL;
3576  }
3577 }
3578 
3583 {
3584  int i;
3585 
3586  // Reset everything between levels
3587  Num_weapons = 0;
3588  for (i=0; i<MAX_WEAPONS; i++) {
3589  Weapons[i].objnum = -1;
3590  Weapons[i].weapon_info_index = -1;
3591  }
3592 
3593  for (i=0; i<MAX_WEAPON_TYPES; i++) {
3594  Weapon_info[i].damage_type_idx = Weapon_info[i].damage_type_idx_sav;
3595  Weapon_info[i].shockwave.damage_type_idx = Weapon_info[i].shockwave.damage_type_idx_sav;
3596  }
3597 
3598  trail_level_init(); // reset all missile trails
3599 
3600  swarm_level_init();
3602 
3604 
3605  // emp effect
3606  emp_level_init();
3607 
3608  if (used_weapons == NULL)
3609  used_weapons = new int[Num_weapon_types];
3610 
3611  // clear out used_weapons between missions
3612  memset(used_weapons, 0, Num_weapon_types * sizeof(int));
3613 
3614  Weapon_flyby_sound_timer = timestamp(0);
3615  Weapon_impact_timer = 1; // inited each level, used to reduce impact sounds
3616 }
3617 
3618 MONITOR( NumWeaponsRend )
3619 
3620 const float weapon_glow_scale_f = 2.3f;
3621 const float weapon_glow_scale_r = 2.3f;
3622 const float weapon_glow_scale_l = 1.5f;
3623 const int weapon_glow_alpha = 217; // (0.85 * 255);
3624 
3626 {
3627  int num;
3628  weapon_info *wip;
3629  weapon *wp;
3630  color c;
3631 
3632  MONITOR_INC(NumWeaponsRend, 1);
3633 
3634  Assert(obj->type == OBJ_WEAPON);
3635 
3636  num = obj->instance;
3637  wp = &Weapons[num];
3638  wip = &Weapon_info[Weapons[num].weapon_info_index];
3639 
3640  if (wip->wi_flags2 & WIF2_TRANSPARENT) {
3641  if (wp->alpha_current == -1.0f) {
3642  wp->alpha_current = wip->alpha_max;
3643  } else if (wip->alpha_cycle > 0.0f) {
3644  if (wp->alpha_backward) {
3645  wp->alpha_current += wip->alpha_cycle;
3646 
3647  if (wp->alpha_current > wip->alpha_max) {
3648  wp->alpha_current = wip->alpha_max;
3649  wp->alpha_backward = 0;
3650  }
3651  } else {
3652  wp->alpha_current -= wip->alpha_cycle;
3653 
3654  if (wp->alpha_current < wip->alpha_min) {
3655  wp->alpha_current = wip->alpha_min;
3656  wp->alpha_backward = 1;
3657  }
3658  }
3659  }
3660  }
3661 
3662  switch (wip->render_type)
3663  {
3664  case WRT_LASER:
3665  {
3666  if(wip->laser_length < 0.0001f)
3667  return;
3668  // turn off fogging for good measure
3669  gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
3670  int alpha = 255;
3671  int framenum = 0;
3672 
3673  if (wip->laser_bitmap.first_frame >= 0) {
3675 
3676  if (wip->laser_bitmap.num_frames > 1) {
3678 
3679  // Sanity checks
3680  if (wp->laser_bitmap_frame < 0.0f)
3681  wp->laser_bitmap_frame = 0.0f;
3682  if (wp->laser_bitmap_frame > 100.0f)
3683  wp->laser_bitmap_frame = 0.0f;
3684 
3685  while (wp->laser_bitmap_frame > wip->laser_bitmap.total_time)
3687 
3688  framenum = fl2i( (wp->laser_bitmap_frame * wip->laser_bitmap.num_frames) / wip->laser_bitmap.total_time );
3689 
3690  CLAMP(framenum, 0, wip->laser_bitmap.num_frames-1);
3691  }
3692 
3693  if (wip->wi_flags2 & WIF2_TRANSPARENT)
3694  alpha = fl2i(wp->alpha_current * 255.0f);
3695 
3696  vec3d headp;
3697 
3698  vm_vec_scale_add(&headp, &obj->pos, &obj->orient.vec.fvec, wip->laser_length);
3700 
3701  if ( batch_add_laser(wip->laser_bitmap.first_frame + framenum, &headp, wip->laser_head_radius, &obj->pos, wip->laser_tail_radius, alpha, alpha, alpha) ) {
3703  }
3704  }
3705 
3706  // maybe draw laser glow bitmap
3707  if (wip->laser_glow_bitmap.first_frame >= 0) {
3708  // get the laser color
3709  weapon_get_laser_color(&c, obj);
3710 
3711  // *Tail point "getting bigger" as well as headpoint isn't being taken into consideration, so
3712  // it caused uneven glow between the head and tail, which really shows in big lasers. So...fixed! -Et1
3713  vec3d headp2, tailp;
3714 
3715  vm_vec_scale_add(&headp2, &obj->pos, &obj->orient.vec.fvec, wip->laser_length * weapon_glow_scale_l);
3716  vm_vec_scale_add(&tailp, &obj->pos, &obj->orient.vec.fvec, wip->laser_length * (1 - weapon_glow_scale_l) );
3717 
3718  framenum = 0;
3719 
3720  if (wip->laser_glow_bitmap.num_frames > 1) {
3722 
3723  // Sanity checks
3724  if (wp->laser_glow_bitmap_frame < 0.0f)
3725  wp->laser_glow_bitmap_frame = 0.0f;
3726  if (wp->laser_glow_bitmap_frame > 100.0f)
3727  wp->laser_glow_bitmap_frame = 0.0f;
3728 
3731 
3733 
3734  CLAMP(framenum, 0, wip->laser_glow_bitmap.num_frames-1);
3735  }
3736 
3737  if (wip->wi_flags2 & WIF2_TRANSPARENT) {
3738  alpha = fl2i(wp->alpha_current * 255.0f);
3739  alpha -= 38; // take 1.5f into account for the normal glow alpha
3740 
3741  if (alpha < 0)
3742  alpha = 0;
3743  } else {
3744  alpha = weapon_glow_alpha;
3745  }
3746 
3747  batch_add_laser(wip->laser_glow_bitmap.first_frame + framenum, &headp2, wip->laser_head_radius * weapon_glow_scale_f, &tailp, wip->laser_tail_radius * weapon_glow_scale_r, (c.red*alpha)/255, (c.green*alpha)/255, (c.blue*alpha)/255);
3748  }
3749 
3750  break;
3751  }
3752 
3753  case WRT_POF:
3754  {
3756 
3758  render_flags &= ~MR_DEPRECATED_NO_LIGHTING;
3759 
3760  if (wip->wi_flags2 & WIF2_TRANSPARENT) {
3762  render_flags |= MR_DEPRECATED_ALL_XPARENT;
3763  }
3764 
3766 
3767  if ( (wip->wi_flags & WIF_THRUSTER) && ((wp->thruster_bitmap > -1) || (wp->thruster_glow_bitmap > -1)) ) {
3768  float ft;
3769  mst_info mst;
3770 
3771  // Add noise to thruster geometry.
3772  ft = 1.0f; // Always use 1.0f for missiles
3773  ft *= (1.0f + frand()/5.0f - 1.0f/10.0f);
3774  if (ft > 1.0f)
3775  ft = 1.0f;
3776 
3777  mst.length.xyz.x = ft;
3778  mst.length.xyz.y = ft;
3779  mst.length.xyz.z = ft;
3780 
3781  mst.primary_bitmap = wp->thruster_bitmap;
3784  mst.glow_noise = wp->thruster_glow_noise;
3785 
3786  model_set_thrust(wip->model_num, &mst);
3787 
3788  render_flags |= MR_DEPRECATED_SHOW_THRUSTERS;
3789  }
3790 
3791 
3792  //don't render local ssm's when they are still in subspace
3793  if (wp->lssm_stage==3)
3794  break;
3795 
3796  int clip_plane=0;
3797 
3798  //start a clip plane
3799  if (wp->lssm_stage==2)
3800  {
3801  object *wobj=&Objects[wp->lssm_warp_idx]; //warphole object
3802  clip_plane=1;
3803 
3804  g3_start_user_clip_plane(&wobj->pos,&wobj->orient.vec.fvec);
3805  }
3806 
3807 
3808  model_render_DEPRECATED(wip->model_num, &obj->orient, &obj->pos, render_flags);
3810  if (clip_plane)
3811  {
3813  }
3814  break;
3815  }
3816 
3817  default:
3818  Warning(LOCATION, "Unknown weapon rendering type = %i for weapon %s\n", wip->render_type, wip->name);
3819  }
3820 }
3821 
3822 void weapon_delete(object *obj)
3823 {
3824  weapon *wp;
3825  int num;
3826 
3827  Script_system.SetHookObjects(2, "Weapon", obj, "Self", obj);
3829  Script_system.RemHookVars(2, "Weapon", "Self");
3830 
3831  num = obj->instance;
3832 
3833  Assert( Weapons[num].objnum == OBJ_INDEX(obj));
3834  wp = &Weapons[num];
3835 
3836  Assert(wp->weapon_info_index >= 0);
3837  wp->weapon_info_index = -1;
3838  if (wp->swarm_index >= 0) {
3840  wp->swarm_index = -1;
3841  }
3842 
3843  if(wp->cscrew_index >= 0) {
3845  wp->cscrew_index = -1;
3846  }
3847 
3848  if (wp->missile_list_index >= 0) {
3850  wp->missile_list_index = -1;
3851  }
3852 
3853  if (wp->trail_ptr != NULL) {
3855  wp->trail_ptr = NULL;
3856  }
3857 
3860 
3861  if (wp->model_instance_num >= 0)
3863 
3864  if (wp->cmeasure_ignore_list != nullptr) {
3865  delete wp->cmeasure_ignore_list;
3866  wp->cmeasure_ignore_list = nullptr;
3867  }
3868 
3869  wp->objnum = -1;
3870  Num_weapons--;
3871  Assert(Num_weapons >= 0);
3872 }
3873 
3878 {
3879  if ( wp->homing_object == Player_obj ) {
3880  if ( !(wp->weapon_flags & WF_LOCK_WARNING_PLAYED) ) {
3882  // Use heatlock-warning sound for Heat and Javelin for now
3883  // Possibly add an additional third sound later
3884  if ( (Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING_HEAT) ||
3885  (Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING_JAVELIN) ) {
3887  } else {
3888  Assert(Weapon_info[wp->weapon_info_index].wi_flags & WIF_HOMING_ASPECT);
3890  }
3891  }
3892  }
3893 }
3894 
3895 
3899 void detonate_nearby_missiles(object* killer_objp, object* missile_objp)
3900 {
3901  if(killer_objp->type != OBJ_WEAPON || missile_objp->type != OBJ_WEAPON) {
3902  Int3();
3903  return;
3904  }
3905 
3906  weapon_info* killer_infop = &Weapon_info[Weapons[killer_objp->instance].weapon_info_index];
3907 
3908  if (killer_infop->cm_kill_single) {
3909  weapon* wp = &Weapons[missile_objp->instance];
3910  if (wp->lifeleft > 0.2f) {
3911  nprintf(("Countermeasures", "Countermeasure (%s-%i) detonated missile (%s-%i) Frame: %i\n",
3912  killer_infop->name, killer_objp->signature,
3913  Weapon_info[Weapons[missile_objp->instance].weapon_info_index].name, missile_objp->signature, Framecount));
3914  wp->lifeleft = 0.2f;
3915  }
3916  return;
3917  }
3918 
3919  missile_obj* mop = GET_FIRST(&Missile_obj_list);
3920 
3921  while(mop != END_OF_LIST(&Missile_obj_list)) {
3922  object* objp = &Objects[mop->objnum];
3923  weapon* wp = &Weapons[objp->instance];
3924 
3925  if (iff_x_attacks_y(Weapons[killer_objp->instance].team, wp->team)) {
3926  if ( Missiontime - wp->creation_time > F1_0/2) {
3927  if (vm_vec_dist_quick(&killer_objp->pos, &objp->pos) < killer_infop->cm_detonation_rad) {
3928  if (wp->lifeleft > 0.2f) {
3929  nprintf(("Countermeasures", "Countermeasure (%s-%i) detonated missile (%s-%i) Frame: %i\n",
3930  killer_infop->name, killer_objp->signature,
3931  Weapon_info[Weapons[objp->instance].weapon_info_index].name, objp->signature, Framecount));
3932  wp->lifeleft = 0.2f;
3933  }
3934  }
3935  }
3936  }
3937 
3938  mop = mop->next;
3939  }
3940 }
3941 
3945 void find_homing_object(object *weapon_objp, int num)
3946 {
3947  object *objp, *old_homing_objp;
3948  weapon_info *wip;
3949  weapon *wp;
3950  ship *sp;
3951  ship_info *sip;
3952  float best_dist;
3953  int homing_object_team;
3954  float dist;
3955  float dot;
3956  vec3d vec_to_object;
3957  ship_subsys *target_engines = NULL;
3958 
3959  wp = &Weapons[num];
3960 
3961  wip = &Weapon_info[Weapons[num].weapon_info_index];
3962 
3963  best_dist = 99999.9f;
3964 
3965  // save the old homing object so that multiplayer servers can give the right information
3966  // to clients if the object changes
3967  old_homing_objp = wp->homing_object;
3968 
3970 
3971  // Scan all objects, find a weapon to home on.
3972  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3973  if ((objp->type == OBJ_SHIP) || ((objp->type == OBJ_WEAPON) && (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_CMEASURE)))
3974  {
3975  //WMC - Spawn weapons shouldn't go for protected ships
3976  // ditto for untargeted heat seekers - niffiwan
3977  if ( (objp->flags & OF_PROTECTED) &&
3979  continue;
3980 
3981  // Spawned weapons should never home in on their parent - even in multiplayer dogfights where they would pass the iff test below
3982  if ((wp->weapon_flags & WF_SPAWNED) && (objp == &Objects[weapon_objp->parent]))
3983  continue;
3984 
3985  homing_object_team = obj_team(objp);
3986  if (iff_x_attacks_y(wp->team, homing_object_team))
3987  {
3988  if ( objp->type == OBJ_SHIP )
3989  {
3990  sp = &Ships[objp->instance];
3991  sip = &Ship_info[sp->ship_info_index];
3992 
3993  //if the homing weapon is a huge weapon and the ship that is being
3994  //looked at is not huge, then don't home
3995  if ((wip->wi_flags & WIF_HUGE) &&
3997  {
3998  continue;
3999  }
4000 
4001  // AL 2-17-98: If ship is immune to sensors, can't home on it (Sandeep says so)!
4002  if ( sp->flags & SF_HIDDEN_FROM_SENSORS ) {
4003  continue;
4004  }
4005 
4006  // Goober5000: if missiles can't home on sensor-ghosted ships,
4007  // they definitely shouldn't home on stealth ships
4009  continue;
4010  }
4011 
4012  if (wip->wi_flags & WIF_HOMING_JAVELIN)
4013  {
4014  target_engines = ship_get_closest_subsys_in_sight(sp, SUBSYSTEM_ENGINE, &weapon_objp->pos);
4015 
4016  if (!target_engines)
4017  continue;
4018  }
4019 
4020  // MK, 9/4/99.
4021  // If this is a player object, make sure there aren't already too many homers.
4022  // Only in single player. In multiplayer, we don't want to restrict it in dogfight on team vs. team.
4023  // For co-op, it's probably also OK.
4024  if (!( Game_mode & GM_MULTIPLAYER )) {
4025  int num_homers = compute_num_homing_objects(objp);
4027  continue;
4028  }
4029  }
4030  else if (objp->type == OBJ_WEAPON)
4031  {
4032  //don't attempt to home on weapons if the weapon is a huge weapon or is a javelin homing weapon.
4033  if (wip->wi_flags & (WIF_HUGE | WIF_HOMING_JAVELIN))
4034  continue;
4035 
4036  //don't look for local ssms that are gone for the time being
4037  if (Weapons[objp->instance].lssm_stage == 3)
4038  continue;
4039  }
4040 
4041  dist = vm_vec_normalized_dir(&vec_to_object, &objp->pos, &weapon_objp->pos);
4042 
4043  if (objp->type == OBJ_WEAPON && (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_CMEASURE)) {
4044  dist *= 0.5f;
4045  }
4046 
4047  dot = vm_vec_dot(&vec_to_object, &weapon_objp->orient.vec.fvec);
4048 
4049  if (dot > wip->fov) {
4050  if (dist < best_dist) {
4051  best_dist = dist;
4052  wp->homing_object = objp;
4053  wp->target_sig = objp->signature;
4054  wp->homing_subsys = target_engines;
4055 
4057  }
4058  }
4059  }
4060  }
4061  }
4062 
4063  if (wp->homing_object == Player_obj)
4065 
4066  // if the old homing object is different that the new one, send a packet to clients
4067  if ( MULTIPLAYER_MASTER && (old_homing_objp != wp->homing_object) ) {
4068  send_homing_weapon_info( num );
4069  }
4070 }
4071 
4075 void find_homing_object_cmeasures_1(object *weapon_objp)
4076 {
4077  object *objp;
4078  weapon *wp, *cm_wp;
4079  weapon_info *wip, *cm_wip;
4080  float best_dot, dist, dot;
4081 
4082  wp = &Weapons[weapon_objp->instance];
4083  wip = &Weapon_info[wp->weapon_info_index];
4084 
4085  best_dot = wip->fov; // Note, setting to this avoids comparison below.
4086 
4087  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
4088  {
4089  //first check if its a weapon, then setup the pointers
4090  if (objp->type == OBJ_WEAPON)
4091  {
4092  cm_wp = &Weapons[objp->instance];
4093  cm_wip = &Weapon_info[cm_wp->weapon_info_index];
4094 
4095  if (cm_wip->wi_flags & WIF_CMEASURE)
4096  {
4097  //don't have a weapon try to home in on itself
4098  if (objp==weapon_objp)
4099  continue;
4100 
4101  //don't have a weapon try to home in on missiles fired by the same team, unless its the traitor team.
4102  if ((wp->team == cm_wp->team) && (wp->team != Iff_traitor))
4103  continue;
4104 
4105  vec3d vec_to_object;
4106  dist = vm_vec_normalized_dir(&vec_to_object, &objp->pos, &weapon_objp->pos);
4107 
4108  if (dist < cm_wip->cm_effective_rad)
4109  {
4110  float chance;
4111 
4112  if (wp->cmeasure_ignore_list == nullptr) {
4114  }
4115  else {
4116  bool found = false;
4117  for (auto ii = wp->cmeasure_ignore_list->cbegin(); ii != wp->cmeasure_ignore_list->cend(); ++ii) {
4118  if (objp->signature == *ii) {
4119  nprintf(("CounterMeasures", "Weapon (%s-%04i) already seen CounterMeasure (%s-%04i) Frame: %i\n",
4120  wip->name, weapon_objp->instance, cm_wip->name, objp->signature, Framecount));
4121  found = true;
4122  break;
4123  }
4124  }
4125  if (found) {
4126  continue;
4127  }
4128  }
4129 
4130  if (wip->wi_flags & WIF_HOMING_ASPECT) {
4131  // aspect seeker this likely to chase a countermeasure
4132  chance = cm_wip->cm_aspect_effectiveness/wip->seeker_strength;
4133  } else {
4134  // heat seeker and javelin HS this likely to chase a countermeasure
4135  chance = cm_wip->cm_heat_effectiveness/wip->seeker_strength;
4136  }
4137 
4138  // remember this cmeasure so it can be ignored in future
4139  wp->cmeasure_ignore_list->push_back(objp->signature);
4140 
4141  if (frand() >= chance) {
4142  // failed to decoy
4143  nprintf(("CounterMeasures", "Weapon (%s-%04i) ignoring CounterMeasure (%s-%04i) Frame: %i\n",
4144  wip->name, weapon_objp->instance, cm_wip->name, objp->signature, Framecount));
4145  }
4146  else {
4147  // successful decoy, maybe chase the new cm
4148  dot = vm_vec_dot(&vec_to_object, &weapon_objp->orient.vec.fvec);
4149 
4150  if (dot > best_dot)
4151  {
4152  best_dot = dot;
4153  wp->homing_object = objp;
4155  nprintf(("CounterMeasures", "Weapon (%s-%04i) chasing CounterMeasure (%s-%04i) Frame: %i\n",
4156  wip->name, weapon_objp->instance, cm_wip->name, objp->signature, Framecount));
4157  }
4158  }
4159  }
4160  }
4161  }
4162  }
4163 }
4164 
4165 
4171 {
4172  object *weapon_objp;
4173 
4174  if (Cmeasures_homing_check == 0)
4175  return;
4176 
4177  if (Cmeasures_homing_check <= 0)
4179 
4181 
4182  for (weapon_objp = GET_FIRST(&obj_used_list); weapon_objp != END_OF_LIST(&obj_used_list); weapon_objp = GET_NEXT(weapon_objp) ) {
4183  if (weapon_objp->type == OBJ_WEAPON) {
4184  weapon_info *wip = &Weapon_info[Weapons[weapon_objp->instance].weapon_info_index];
4185 
4186  if (wip->wi_flags & WIF_HOMING)
4187  find_homing_object_cmeasures_1(weapon_objp);
4188  }
4189  }
4190 
4191 }
4192 
4196 void find_homing_object_by_sig(object *weapon_objp, int sig)
4197 {
4198  ship_obj *sop;
4199  weapon *wp;
4200  object *old_homing_objp;
4201 
4202  wp = &Weapons[weapon_objp->instance];
4203 
4204  // save the old object so that multiplayer masters know whether to send a homing update packet
4205  old_homing_objp = wp->homing_object;
4206 
4207  sop = GET_FIRST(&Ship_obj_list);
4208  while(sop != END_OF_LIST(&Ship_obj_list)) {
4209  object *objp;
4210 
4211  objp = &Objects[sop->objnum];
4212  if (objp->signature == sig) {
4213  wp->homing_object = objp;
4214  wp->target_sig = objp->signature;
4215  break;
4216  }
4217 
4218  sop = sop->next;
4219  }
4220 
4221  // if the old homing object is different that the new one, send a packet to clients
4222  if ( MULTIPLAYER_MASTER && (old_homing_objp != wp->homing_object) ) {
4223  send_homing_weapon_info( weapon_objp->instance );
4224  }
4225 }
4226 
4228 {
4229  Assert(wp != NULL);
4230 
4231  if (wp->homing_object->signature != wp->target_sig) {
4232  if (wp->homing_object->type == OBJ_WEAPON)
4233  {
4234  weapon_info* target_info = &Weapon_info[Weapons[wp->homing_object->instance].weapon_info_index];
4235 
4236  if (target_info->wi_flags & WIF_CMEASURE)
4237  {
4238  // Check if we can home on this countermeasure
4240  || target_info->wi_flags3 & WIF3_CMEASURE_ASPECT_HOME_ON;
4241 
4242  if (!home_on_cmeasure)
4243  {
4244  return true;
4245  }
4246  }
4247  }
4248  }
4249 
4250  return false;
4251 }
4252 
4256 void weapon_home(object *obj, int num, float frame_time)
4257 {
4258  weapon *wp;
4259  weapon_info *wip;
4260  object *hobjp;
4261 
4262  Assert(obj->type == OBJ_WEAPON);
4263  Assert(obj->instance == num);
4264  wp = &Weapons[num];
4265  wip = &Weapon_info[wp->weapon_info_index];
4266  hobjp = Weapons[num].homing_object;
4267 
4268  //local ssms home only in stages 1 and 5
4269  if ( (wp->lssm_stage==2) || (wp->lssm_stage==3) || (wp->lssm_stage==4))
4270  return;
4271 
4272  float max_speed;
4273 
4274  if ((wip->wi_flags2 & WIF2_LOCAL_SSM) && (wp->lssm_stage==5))
4275  max_speed=wip->lssm_stage5_vel;
4276  else
4277  max_speed=wip->max_speed;
4278 
4279  // If not [free-flight-time] gone by, don't home yet.
4280  // Goober5000 - this has been fixed back to more closely follow the original logic. Remember, the retail code
4281  // had 0.5 second of free flight time, the first half of which was spent ramping up to full speed.
4282  if ((hobjp == &obj_used_list) || ( f2fl(Missiontime - wp->creation_time) < (wip->free_flight_time / 2) )) {
4283  if (f2fl(Missiontime - wp->creation_time) > wip->free_flight_time) {
4284  // If this is a heat seeking homing missile and [free-flight-time] has elapsed since firing
4285  // and we don't have a target (else we wouldn't be inside the IF), find a new target.
4286  if (wip->wi_flags & WIF_HOMING_HEAT) {
4287  find_homing_object(obj, num);
4288  }
4289  // modders may want aspect homing missiles to die if they lose their target
4290  else if (wip->wi_flags & WIF_LOCKED_HOMING && wip->wi_flags3 & WIF3_DIE_ON_LOST_LOCK) {
4291  if (wp->lifeleft > 0.5f) {
4292  wp->lifeleft = frand_range(0.1f, 0.5f); // randomise a bit to avoid multiple missiles detonating in one frame
4293  }
4294  return;
4295  }
4296  }
4300  }
4301 
4302  if (wip->acceleration_time > 0.0f) {
4303  if (Missiontime - wp->creation_time < fl2f(wip->acceleration_time)) {
4304  float t;
4305 
4306  t = f2fl(Missiontime - wp->creation_time) / wip->acceleration_time;
4307  obj->phys_info.speed = wp->launch_speed + MAX(0.0f, wp->weapon_max_vel - wp->launch_speed) * t;
4308  }
4309  }
4310  // since free_flight_time can now be 0, guard against that
4311  else if (wip->free_flight_time > 0.0f) {
4312  if (obj->phys_info.speed > max_speed) {
4313  obj->phys_info.speed -= frame_time * (2 / wip->free_flight_time);
4314  } else if ((obj->phys_info.speed < max_speed / (2 / wip->free_flight_time)) && (wip->wi_flags & WIF_HOMING_HEAT)) {
4315  obj->phys_info.speed = max_speed / (2 / wip->free_flight_time);
4316  }
4317  }
4318  // no free_flight_time, so immediately set desired speed
4319  else {
4320  obj->phys_info.speed = max_speed;
4321  }
4322 
4323  // set velocity using whatever speed we have
4324  vm_vec_copy_scale( &obj->phys_info.desired_vel, &obj->orient.vec.fvec, obj->phys_info.speed);
4325 
4326  return;
4327  }
4328 
4329  // if we've got this far, this should be valid
4330  weapon_info* hobj_infop = &Weapon_info[Weapons[hobjp->instance].weapon_info_index];
4331 
4332  if (wip->acceleration_time > 0.0f) {
4333  if (Missiontime - wp->creation_time < fl2f(wip->acceleration_time)) {
4334  float t;
4335 
4336  t = f2fl(Missiontime - wp->creation_time) / wip->acceleration_time;
4337  obj->phys_info.speed = wp->launch_speed + (wp->weapon_max_vel - wp->launch_speed) * t;
4338  vm_vec_copy_scale( &obj->phys_info.desired_vel, &obj->orient.vec.fvec, obj->phys_info.speed);
4339  }
4340  }
4341 
4342  // AL 4-8-98: If original target for aspect lock missile is lost, stop homing
4343  // WCS - or javelin
4344  if (wip->wi_flags & WIF_LOCKED_HOMING) {
4345  if ( wp->target_sig > 0 ) {
4346  if (aspect_should_lose_target(wp))
4347  {
4349  return;
4350  }
4351  }
4352  }
4353 
4354  // AL 4-13-98: Stop homing on a subsystem if parent ship has changed
4355  if (wip->wi_flags & WIF_HOMING_HEAT) {
4356  if ( wp->target_sig > 0 ) {
4357  if ( wp->homing_object->signature != wp->target_sig ) {
4358  wp->homing_subsys = NULL;
4359  }
4360  }
4361  }
4362 
4363  // If target subsys is dead make missile pick random spot on target as attack point.
4364  if (wp->homing_subsys != NULL) {
4366  if ((wp->homing_subsys->max_hits > 0) && (wp->homing_subsys->current_hits <= 0)) {
4368  return;
4369  }
4370  }
4371  }
4372 
4373  // Make sure Javelin HS missiles always home on engine subsystems if ships
4374  if ((wip->wi_flags & WIF_HOMING_JAVELIN) &&
4375  (hobjp->type == OBJ_SHIP) &&
4376  (wp->target_sig > 0) &&
4377  (wp->homing_subsys != NULL) &&
4379  int sindex = ship_get_by_signature(wp->target_sig);
4380  if (sindex >= 0) {
4381  ship *enemy = &Ships[sindex];
4383  }
4384  }
4385 
4386  // If Javelin HS missile doesn't home in on a subsystem but homing in on a
4387  // ship, lose lock alltogether
4388  // Javelins can only home in one Engines or bombs.
4389  if ((wip->wi_flags & WIF_HOMING_JAVELIN) &&
4390  (hobjp->type == OBJ_SHIP) &&
4391  (wp->target_sig > 0) &&
4392  (wp->homing_subsys == NULL)) {
4394  return;
4395  }
4396 
4397  // TODO maybe add flag to allow WF_LOCKED_HOMING to lose target when target is dead
4398 
4399  switch (hobjp->type) {
4400  case OBJ_NONE:
4401  if (wip->wi_flags & WIF_LOCKED_HOMING) {
4403  }
4404  else {
4405  find_homing_object(obj, num);
4406  }
4407  return;
4408  break;
4409  case OBJ_SHIP:
4410  if (hobjp->signature != wp->target_sig) {
4411  if (wip->wi_flags & WIF_LOCKED_HOMING) {
4413  }
4414  else {
4415  find_homing_object(obj, num);
4416  }
4417  return;
4418  }
4419  break;
4420  case OBJ_WEAPON:
4421  {
4423  || hobj_infop->wi_flags3 & WIF3_CMEASURE_ASPECT_HOME_ON;
4424 
4425  // don't home on countermeasures or non-bombs, that's handled elsewhere
4426  if (((hobj_infop->wi_flags & WIF_CMEASURE) && !home_on_cmeasure))
4427  {
4428  break;
4429  }
4430  else if (!(hobj_infop->wi_flags & WIF_BOMB))
4431  {
4432  break;
4433  }
4434 
4435  if (wip->wi_flags & WIF_LOCKED_HOMING) {
4437  }
4438  else {
4439  find_homing_object(obj, num);
4440  }
4441  break;
4442  }
4443  default:
4444  return;
4445  }
4446 
4447  // See if this weapon is the nearest homing object to the object it is homing on.
4448  // If so, update some fields in the target object's ai_info.
4449  if (hobjp != &obj_used_list) {
4450  float dist;
4451 
4452  dist = vm_vec_dist_quick(&obj->pos, &hobjp->pos);
4453 
4454  if (hobjp->type == OBJ_SHIP) {
4455  ai_info *aip;
4456 
4457  aip = &Ai_info[Ships[hobjp->instance].ai_index];
4458 
4459  if ((aip->nearest_locked_object == -1) || (dist < aip->nearest_locked_distance)) {
4460  aip->nearest_locked_object = obj-Objects;
4461  aip->nearest_locked_distance = dist;
4462  }
4463  }
4464  }
4465 
4466  // If the object it is homing on is still valid, home some more!
4467  if (hobjp != &obj_used_list) {
4468  float old_dot, vel;
4469  vec3d vec_to_goal;
4470  vec3d target_pos; // position of what the homing missile is seeking
4471 
4472  vm_vec_zero(&target_pos);
4473 
4474  // the homing missile may be seeking a subsystem on a ship. If so, we need to calculate the
4475  // world coordinates of that subsystem so the homing missile can seek it out.
4476  // For now, March 7, 1997, MK, heat seeking homing missiles will be able to home on
4477  // any subsystem. Probably makes sense for them to only home on certain kinds of subsystems.
4478  if ( (wp->homing_subsys != NULL) && !(wip->wi_flags2 & WIF2_NON_SUBSYS_HOMING) && hobjp->type == OBJ_SHIP) {
4479  get_subsystem_world_pos(hobjp, Weapons[num].homing_subsys, &target_pos);
4480  wp->homing_pos = target_pos; // store the homing position in weapon data
4481  Assert( !vm_is_vec_nan(&wp->homing_pos) );
4482  } else {
4483  float fov;
4484  float dist;
4485 
4486  dist = vm_vec_dist_quick(&obj->pos, &hobjp->pos);
4487  if (hobjp->type == OBJ_WEAPON && (hobj_infop->wi_flags & WIF_CMEASURE))
4488  {
4489  if (dist < hobj_infop->cm_detonation_rad)
4490  {
4491  // Make this missile detonate soon. Not right away, not sure why. Seems better.
4492  if (iff_x_attacks_y(Weapons[hobjp->instance].team, wp->team)) {
4493  detonate_nearby_missiles(hobjp, obj);
4494  return;
4495  }
4496  }
4497  }
4498 
4499  fov = -1.0f;
4500 
4501  int pick_homing_point = 0;
4502  if ( IS_VEC_NULL(&wp->homing_pos) ) {
4503  pick_homing_point = 1;
4504  }
4505 
4506  // Update homing position if it hasn't been set, you're within 500 meters, or every half second, approximately.
4507  // For large objects, don't lead them.
4508  if (hobjp->radius < 40.0f) {
4509  target_pos = hobjp->pos;
4510  wp->homing_pos = target_pos;
4511  } else if ( pick_homing_point || (dist < 500.0f) || (rand_chance(flFrametime, 2.0f)) ) {
4512 
4513  if (hobjp->type == OBJ_SHIP) {
4514  if ( !pick_homing_point ) {
4515  // ensure that current attack point is only updated in world coords (ie not pick a different vertex)
4517  }
4518 
4519  if ( pick_homing_point && !(wip->wi_flags2 & WIF2_NON_SUBSYS_HOMING) ) {
4520  // If *any* player is parent of homing missile, then use position where lock indicator is
4521  if ( Objects[obj->parent].flags & OF_PLAYER_SHIP ) {
4522  player *pp;
4523 
4524  // determine the player
4525  pp = Player;
4526 
4527  if ( Game_mode & GM_MULTIPLAYER ) {
4528  int pnum;
4529 
4530  pnum = multi_find_player_by_object( &Objects[obj->parent] );
4531  if ( pnum != -1 ){
4532  pp = Net_players[pnum].m_player;
4533  }
4534  }
4535 
4536  // If player has apect lock, we don't want to find a homing point on the closest
4537  // octant... setting the timestamp to 0 ensures this.
4538  if (wip->wi_flags & WIF_LOCKED_HOMING) {
4540  } else {
4542  }
4543 
4544  if ( pp && pp->locking_subsys ) {
4546  } else {
4548  }
4549  }
4550  }
4551 
4552  ai_big_pick_attack_point(hobjp, obj, &target_pos, fov);
4553 
4554  } else {
4555  target_pos = hobjp->pos;
4556  }
4557 
4558  wp->homing_pos = target_pos;
4559  Assert( !vm_is_vec_nan(&wp->homing_pos) );
4560  } else
4561  target_pos = wp->homing_pos;
4562  }
4563 
4564  // Couldn't find a lock.
4565  if (IS_VEC_NULL(&target_pos))
4566  return;
4567 
4568  // Cause aspect seeking weapon to home at target's predicted position.
4569  // But don't use predicted position if dot product small or negative.
4570  // If do this, with a ship headed towards missile, could choose a point behind missile.
4571  float dist_to_target, time_to_target;
4572 
4573  dist_to_target = vm_vec_normalized_dir(&vec_to_goal, &target_pos, &obj->pos);
4574  time_to_target = dist_to_target/max_speed;
4575 
4576  vec3d tvec;
4577  tvec = obj->phys_info.vel;
4578  vm_vec_normalize(&tvec);
4579 
4580  old_dot = vm_vec_dot(&tvec, &vec_to_goal);
4581 
4582  // If a weapon has missed its target, detonate it.
4583  // This solves the problem of a weapon circling the center of a subsystem that has been blown away.
4584  // Problem: It does not do impact damage, just proximity damage.
4585  if ((dist_to_target < flFrametime * obj->phys_info.speed * 4.0f + 10.0f) &&
4586  (old_dot < wip->fov) &&
4587  (wp->lifeleft > 0.01f) &&
4588  (wp->homing_object != &obj_used_list) &&
4589  (wp->homing_object->type == OBJ_SHIP))
4590  {
4591  wp->lifeleft = 0.01f;
4592  }
4593 
4594  // Only lead target if more than one second away. Otherwise can miss target. I think this
4595  // is what's causing Harbingers to miss the super destroyer. -- MK, 4/15/98
4596  if ((old_dot > 0.1f) && (time_to_target > 0.1f)) {
4597  if (wip->wi_flags2 & WIF2_VARIABLE_LEAD_HOMING) {
4598  vm_vec_scale_add2(&target_pos, &hobjp->phys_info.vel, (0.33f * wip->target_lead_scaler * MIN(time_to_target, 6.0f)));
4599  } else if (wip->wi_flags & WIF_LOCKED_HOMING) {
4600  vm_vec_scale_add2(&target_pos, &hobjp->phys_info.vel, MIN(time_to_target, 2.0f));
4601  }
4602  }
4603 
4604  // If a HEAT seeking (rather than ASPECT seeking) homing missile, verify that target is in viewcone.
4605  if (wip->wi_flags & WIF_HOMING_HEAT) {
4606  if ((old_dot < wip->fov) && (dist_to_target > wip->shockwave.inner_rad*1.1f)) { // Delay finding new target one frame to allow detonation.
4607  find_homing_object(obj, num);
4608  return; // Maybe found a new homing object. Return, process more next frame.
4609  } else // Subtract out life based on how far from target this missile points.
4610  if ((wip->fov < 0.95f) && !(wip->wi_flags2 & WIF2_NO_LIFE_LOST_IF_MISSED)) {
4611  wp->lifeleft -= flFrametime * (0.95f - old_dot);
4612  }
4613  } else if (wip->wi_flags & WIF_LOCKED_HOMING) { // subtract life as if max turn is 90 degrees.
4614  if ((wip->fov < 0.95f) && !(wip->wi_flags2 & WIF2_NO_LIFE_LOST_IF_MISSED))
4615  wp->lifeleft -= flFrametime * (0.95f - old_dot);
4616  } else {
4617  Warning(LOCATION, "Tried to make weapon '%s' home, but found it wasn't aspect-seeking or heat-seeking or a Javelin!", wip->name);
4618  }
4619 
4620 
4621  // Control speed based on dot product to goal. If close to straight ahead, move
4622  // at max speed, else move slower based on how far from ahead.
4623  if (old_dot < 0.90f) {
4624  obj->phys_info.speed = MAX(0.2f, old_dot* (float) fabs(old_dot));
4625  if (obj->phys_info.speed < max_speed*0.75f)
4626  obj->phys_info.speed = max_speed*0.75f;
4627  } else
4628  obj->phys_info.speed = max_speed;
4629 
4630 
4631  if (wip->acceleration_time > 0.0f) {
4632  // Ramp up speed linearly for the given duration
4633  if (Missiontime - wp->creation_time < fl2f(wip->acceleration_time)) {
4634  float t;
4635 
4636  t = f2fl(Missiontime - wp->creation_time) / wip->acceleration_time;
4637  obj->phys_info.speed = wp->launch_speed + MAX(0.0f, wp->weapon_max_vel - wp->launch_speed) * t;
4638  }
4639  } else if (!(wip->wi_flags3 & WIF3_NO_HOMING_SPEED_RAMP) && Missiontime - wp->creation_time < i2f(1)) {
4640  // Default behavior:
4641  // For first second of weapon's life, it doesn't fly at top speed. It ramps up.
4642  float t;
4643 
4644  t = f2fl(Missiontime - wp->creation_time);
4645  obj->phys_info.speed *= t*t;
4646  }
4647 
4648  Assert( obj->phys_info.speed > 0.0f );
4649 
4650  vm_vec_copy_scale( &obj->phys_info.desired_vel, &obj->orient.vec.fvec, obj->phys_info.speed);
4651 
4652  // turn the missile towards the target only if non-swarm. Homing swarm missiles choose
4653  // a different vector to turn towards, this is done in swarm_update_direction().
4654  if ( wp->swarm_index < 0 ) {
4655  ai_turn_towards_vector(&target_pos, obj, frame_time, wip->turn_time, NULL, NULL, 0.0f, 0, NULL);
4656  vel = vm_vec_mag(&obj->phys_info.desired_vel);
4657 
4658  vm_vec_copy_scale(&obj->phys_info.desired_vel, &obj->orient.vec.fvec, vel);
4659 
4660  }
4661  }
4662 }
4663 
4664 // as Mike K did with ships -- break weapon into process_pre and process_post for code to execute
4665 // before and after physics movement
4666 
4667 void weapon_process_pre( object *obj, float frame_time)
4668 {
4669  if(obj->type != OBJ_WEAPON)
4670  return;
4671 
4672  weapon *wp = &Weapons[obj->instance];
4673  weapon_info *wip = &Weapon_info[wp->weapon_info_index];
4674 
4675  // if the object is a corkscrew style weapon, process it now
4676  if((obj->type == OBJ_WEAPON) && (Weapons[obj->instance].cscrew_index >= 0)){
4677  cscrew_process_pre(obj);
4678  }
4679 
4680  //WMC - Originally flak_maybe_detonate, moved here.
4681  if(wp->det_range > 0.0f)
4682  {
4683  vec3d temp;
4684  vm_vec_sub(&temp, &obj->pos, &wp->start_pos);
4685  if(vm_vec_mag(&temp) >= wp->det_range){
4686  weapon_detonate(obj);
4687  }
4688  }
4689 
4690  //WMC - Maybe detonate weapon anyway!
4691  if(wip->det_radius > 0.0f)
4692  {
4693  if((wp->homing_object != &obj_used_list) && (wp->homing_object->type != 0))
4694  {
4695  if(!IS_VEC_NULL(&wp->homing_pos) && vm_vec_dist(&wp->homing_pos, &obj->pos) <= wip->det_radius)
4696  {
4697  weapon_detonate(obj);
4698  }
4699  } else if(wp->target_num > -1)
4700  {
4701  if(vm_vec_dist(&obj->pos, &Objects[wp->target_num].pos) <= wip->det_radius)
4702  {
4703  weapon_detonate(obj);
4704  }
4705  }
4706  }
4707 }
4708 
4710 
4711 
4712 MONITOR( NumWeapons )
4713 
4714 
4718 {
4719  // don't play flyby sounds too close together
4720  if ( !timestamp_elapsed(Weapon_flyby_sound_timer) ) {
4721  return;
4722  }
4723 
4724  if ( !(wp->weapon_flags & WF_PLAYED_FLYBY_SOUND) && (wp->weapon_flags & WF_CONSIDER_FOR_FLYBY_SOUND) ) {
4725  float dist, dot, radius;
4726 
4727  if ( (Weapon_info[wp->weapon_info_index].wi_flags & WIF_CORKSCREW) ) {
4728  dist = vm_vec_dist_quick(&weapon_objp->last_pos, &Eye_position);
4729  } else {
4730  dist = vm_vec_dist_quick(&weapon_objp->pos, &Eye_position);
4731  }
4732 
4733  if ( Viewer_obj ) {
4734  radius = Viewer_obj->radius;
4735  } else {
4736  radius = 0.0f;
4737  }
4738 
4739  if ( (dist > radius) && (dist < 55) ) {
4740  vec3d vec_to_weapon;
4741 
4742  vm_vec_sub(&vec_to_weapon, &weapon_objp->pos, &Eye_position);
4743  vm_vec_normalize(&vec_to_weapon);
4744 
4745  // ensure laser is in front of eye
4746  dot = vm_vec_dot(&vec_to_weapon, &Eye_matrix.vec.fvec);
4747  if ( dot < 0.1 ) {
4748  return;
4749  }
4750 
4751  // ensure that laser is moving in similar direction to fvec
4752  dot = vm_vec_dot(&vec_to_weapon, &weapon_objp->orient.vec.fvec);
4753 
4754  if ( (dot < -0.80) && (dot > -0.98) ) {
4755  if(Weapon_info[wp->weapon_info_index].flyby_snd != -1) {
4756  snd_play_3d( &Snds[Weapon_info[wp->weapon_info_index].flyby_snd], &weapon_objp->pos, &Eye_position );
4757  } else {
4758  if ( Weapon_info[wp->weapon_info_index].subtype == WP_LASER ) {
4759  snd_play_3d( &Snds[SND_WEAPON_FLYBY], &weapon_objp->pos, &Eye_position );
4760  }
4761  }
4762  Weapon_flyby_sound_timer = timestamp(200);
4763  wp->weapon_flags |= WF_PLAYED_FLYBY_SOUND;
4764  }
4765  }
4766  }
4767 }
4768 
4769 // process a weapon after physics movement. MWA reorders some of the code on 8/13 for multiplayer. When
4770 // adding something to this function, decide whether or not a client in a multiplayer game needs to do
4771 // what is normally done in a single player game. Things like plotting an object on a radar, effect
4772 // for exhaust are things that are done on all machines. Things which calculate weapon targets, new
4773 // velocities, etc, are server only functions and should go after the if ( !MULTIPLAYER_MASTER ) statement
4774 // See Allender if you cannot decide what to do.
4775 void weapon_process_post(object * obj, float frame_time)
4776 {
4777  int num;
4778  weapon_info *wip;
4779  weapon *wp;
4780 
4781  MONITOR_INC( NumWeapons, 1 );
4782 
4783  Assert(obj->type == OBJ_WEAPON);
4784 
4785  num = obj->instance;
4786 
4787 #ifndef NDEBUG
4788  int objnum;
4789  objnum = OBJ_INDEX(obj);
4790  Assert( Weapons[num].objnum == objnum );
4791 #endif
4792 
4793  wp = &Weapons[num];
4794 
4795  wp->lifeleft -= frame_time;
4796 
4797  wip = &Weapon_info[wp->weapon_info_index];
4798 
4799 
4800  if (wip->wi_flags2 & WIF2_LOCAL_SSM)
4801  {
4802  if ((wp->lssm_stage != 5) && (wp->lssm_stage != 0))
4803  {
4804  wp->lifeleft += frame_time;
4805  }
4806  }
4807 
4808 
4809  // check life left. Multiplayer client code will go through here as well. We must be careful in weapon_hit
4810  // when killing a missile that spawn child weapons!!!!
4811  if ( wp->lifeleft < 0.0f ) {
4812  if ( wip->subtype & WP_MISSILE ) {
4813  if(Game_mode & GM_MULTIPLAYER){
4814  if ( !MULTIPLAYER_CLIENT || (MULTIPLAYER_CLIENT && (wp->lifeleft < -2.0f)) || (MULTIPLAYER_CLIENT && (wip->wi_flags & WIF_CHILD))) { // don't call this function multiplayer client -- host will send this packet to us
4815  weapon_detonate(obj);
4816  }
4817  } else {
4818  weapon_detonate(obj);
4819  }
4820  if (wip->wi_flags & WIF_HOMING) {
4821  Homing_misses++;
4822  }
4823  } else {
4824  obj->flags |= OF_SHOULD_BE_DEAD;
4825  }
4826 
4827  return;
4828  }
4829 
4830  // plot homing missiles on the radar
4831  if (((wip->wi_flags & WIF_BOMB) || (wip->wi_flags2 & WIF2_SHOWN_ON_RADAR)) && !(wip->wi_flags2 & WIF2_DONT_SHOW_ON_RADAR)) {
4832  if ( hud_gauge_active(HUD_RADAR) ) {
4833  radar_plot_object( obj );
4834  }
4835  }
4836 
4837  // trail missiles
4838  if ((wip->wi_flags & WIF_TRAIL) && !(wip->wi_flags & WIF_CORKSCREW)) {
4839  if ( (wp->trail_ptr != NULL ) && (wp->lssm_stage!=3)) {
4840  vec3d pos;
4841 
4842  if (wip->render_type == WRT_LASER) {
4843  // place tail origin in center of the bolt
4844  vm_vec_scale_add(&pos, &obj->pos, &obj->orient.vec.fvec, (wip->laser_length / 2));
4845  } else {
4846  pos = obj->pos;
4847  }
4848 
4849  if (trail_stamp_elapsed(wp->trail_ptr)) {
4850 
4851  trail_add_segment( wp->trail_ptr, &pos );
4852 
4854  } else {
4855  trail_set_segment( wp->trail_ptr, &pos );
4856  }
4857 
4858  }
4859  }
4860 
4861  if ( wip->wi_flags & WIF_THRUSTER ) {
4863  }
4864 
4865  // maybe play a "whizz sound" if close enough to view position
4866  #ifndef NDEBUG
4869  }
4870  #else
4872  #endif
4873 
4874  // If our target is still valid, then update some info.
4875  if (wp->target_num != -1) {
4876  if (Objects[wp->target_num].signature == wp->target_sig) {
4877  float cur_dist;
4878  vec3d v0;
4879 
4880  vm_vec_avg(&v0, &obj->pos, &obj->last_pos);
4881 
4882  cur_dist = vm_vec_dist_quick(&v0, &Objects[wp->target_num].pos);
4883 
4884  if (cur_dist < wp->nearest_dist) {
4885  wp->nearest_dist = cur_dist;
4886  } else if (cur_dist > wp->nearest_dist + 1.0f) {
4887  float dot;
4888  vec3d tvec;
4889  ai_info *parent_aip;
4890 
4891  parent_aip = NULL;
4892  if (obj->parent != Player_obj-Objects) {
4893  parent_aip = &Ai_info[Ships[Objects[obj->parent].instance].ai_index];
4894  }
4895 
4896  vm_vec_normalized_dir(&tvec, &v0, &Objects[wp->target_num].pos);
4897  dot = vm_vec_dot(&tvec, &Objects[wp->target_num].orient.vec.fvec);
4898  wp->target_num = -1;
4899 
4900  // Learn! If over-shooting or under-shooting, compensate.
4901  // Really need to compensate for left/right errors. This does no good against someone circling
4902  // in a plane perpendicular to the attacker's forward vector.
4903  if (parent_aip != NULL) {
4904  if (cur_dist > 100.0f)
4905  parent_aip->lead_scale = 0.0f;
4906 
4907  if (dot < -0.1f){
4908  parent_aip->lead_scale += cur_dist/2000.0f;
4909  } else if (dot > 0.1f) {
4910  parent_aip->lead_scale -= cur_dist/2000.0f;
4911  }
4912 
4913  if (fl_abs(parent_aip->lead_scale) > 1.0f){
4914  parent_aip->lead_scale *= 0.9f;
4915  }
4916  }
4917  }
4918  }
4919  }
4920 
4921  if(wip->wi_flags & WIF_PARTICLE_SPEW){
4923  }
4924 
4925  // a single player or multiplayer server function -- it affects actual weapon movement.
4926  if (wip->wi_flags & WIF_HOMING && !(wp->weapon_flags & WF_NO_HOMING)) {
4927  weapon_home(obj, num, frame_time);
4928 
4929  // If this is a swarm type missile,
4930  if ( wp->swarm_index >= 0 ) {
4931  swarm_update_direction(obj, frame_time);
4932  }
4933 
4934  if( wp->cscrew_index >= 0) {
4935  cscrew_process_post(obj);
4936  }
4937  } else if (wip->acceleration_time > 0.0f) {
4938  if (Missiontime - wp->creation_time < fl2f(wip->acceleration_time)) {
4939  float t;
4940 
4941  t = f2fl(Missiontime - wp->creation_time) / wip->acceleration_time;
4942  obj->phys_info.speed = wp->launch_speed + MAX(0.0f, wp->weapon_max_vel - wp->launch_speed) * t;
4943  } else {
4944  obj->phys_info.speed = wip->max_speed;
4945  obj->phys_info.flags |= PF_CONST_VEL; // Max speed reached, can use simpler physics calculations now
4946  }
4947 
4948  vm_vec_copy_scale( &obj->phys_info.desired_vel, &obj->orient.vec.fvec, obj->phys_info.speed);
4949  }
4950 
4951  //local ssm stuff
4952  if (wip->wi_flags2 & WIF2_LOCAL_SSM)
4953  {
4954  //go into subspace if the missile is locked and its time to warpout
4955  if ((wp->lssm_stage==1) && (timestamp_elapsed(wp->lssm_warpout_time)))
4956  {
4957  //if we don't have a lock at this point, just stay in normal space
4958  if (wp->homing_object == &obj_used_list)
4959  {
4960  wp->lssm_stage=0;
4961  return;
4962  }
4963 
4964  //point where to warpout
4965  vec3d warpout;
4966 
4967  //create a warp effect
4968  vm_vec_copy_scale(&warpout,&obj->phys_info.vel,3.0f);
4969 
4970  //set the time the warphole stays open, minimum of 7 seconds
4971  wp->lssm_warp_time = ((obj->radius * 2) / (obj->phys_info.speed)) +1.5f;
4972  wp->lssm_warp_time = MAX(wp->lssm_warp_time,7.0f);
4973 
4974  //calculate the percerentage of the warpholes life at which the missile is fully in subspace.
4975  wp->lssm_warp_pct = 1.0f - (3.0f/wp->lssm_warp_time);
4976 
4977  //create the warphole
4978  vm_vec_add2(&warpout,&obj->pos);
4980 
4981  if (wp->lssm_warp_idx < 0) {
4982  mprintf(("LSSM: Failed to create warp effect! Please report if this happens frequently.\n"));
4983  // Abort warping
4984  wp->lssm_stage = 0;
4985  } else {
4986  wp->lssm_stage = 2;
4987  }
4988  }
4989 
4990  //its just entered subspace subspace. don't collide or render
4992  {
4993  uint flags=obj->flags & ~(OF_RENDERS | OF_COLLIDES);
4994 
4995  obj_set_flags(obj, flags);
4996 
4997  //get the position of the target, and estimate its position when it warps out
4998  //so we have an idea of where it will be.
4999  if (wp->target_num >= 0)
5000  {
5002  }
5003  else
5004  {
5005  // Our target is invalid, just jump to our position
5006  wp->lssm_target_pos = obj->pos;
5007  }
5008 
5009  wp->lssm_stage=3;
5010 
5011  }
5012 
5013  //time to warp in.
5014  if ((wp->lssm_stage==3) && (timestamp_elapsed(wp->lssm_warpin_time)))
5015  {
5016 
5017  vec3d warpin;
5018  object* target_objp=wp->homing_object;
5019  vec3d fvec;
5020  matrix orient;
5021 
5022  //spawn the ssm at a random point in a circle around the target
5023  vm_vec_random_in_circle(&warpin, &wp->lssm_target_pos, &target_objp->orient, wip->lssm_warpin_radius + target_objp->radius,1);
5024 
5025  //orient the missile properly
5026  vm_vec_sub(&fvec,&wp->lssm_target_pos, &warpin);
5027  vm_vector_2_matrix(&orient,&fvec,NULL,NULL);
5028 
5029  //create a warpin effect
5031 
5032  if (wp->lssm_warp_idx < 0) {
5033  mprintf(("LSSM: Failed to create warp effect! Please report if this happens frequently.\n"));
5034  }
5035 
5036  obj->orient=orient;
5037  obj->pos=warpin;
5038  obj->phys_info.speed=0;
5040  obj->phys_info.vel = obj->phys_info.desired_vel;
5041 
5042  wp->lssm_stage = 4;
5043  }
5044 
5045  //done warping in. render and collide it. let the fun begin
5046  // If the previous fireball creation failed just put it into normal space now
5047  if ((wp->lssm_stage==4) && (wp->lssm_warp_idx < 0 || fireball_lifeleft_percent(&Objects[wp->lssm_warp_idx]) <=0.5f))
5048  {
5050  obj->phys_info.vel = obj->phys_info.desired_vel;
5052 
5053  wp->lssm_stage=5;
5054 
5056 
5057  obj_set_flags(obj,flags);
5058  }
5059  }
5060 
5061  if (wip->hud_in_flight_snd >= 0 && obj->parent_sig == Player_obj->signature)
5062  {
5063  bool play_sound = false;
5064  switch (wip->in_flight_play_type)
5065  {
5066  case TARGETED:
5067  play_sound = wp->homing_object != &obj_used_list;
5068  break;
5069  case UNTARGETED:
5070  play_sound = wp->homing_object == &obj_used_list;
5071  break;
5072  case ALWAYS:
5073  play_sound = true;
5074  break;
5075  default:
5076  Error(LOCATION, "Unknown in-flight sound status %d!", (int) wip->in_flight_play_type);
5077  break;
5078  }
5079 
5080  if (play_sound)
5081  {
5083  {
5085  }
5086  }
5087  }
5088 }
5089 
5093 void weapon_set_tracking_info(int weapon_objnum, int parent_objnum, int target_objnum, int target_is_locked, ship_subsys *target_subsys)
5094 {
5095  object *parent_objp;
5096  weapon *wp;
5097  weapon_info *wip;
5098  int targeting_same = 0;
5099 
5100  if ( weapon_objnum < 0 ) {
5101  return;
5102  }
5103 
5104  Assert(Objects[weapon_objnum].type == OBJ_WEAPON);
5105 
5106  wp = &Weapons[Objects[weapon_objnum].instance];
5107  wip = &Weapon_info[wp->weapon_info_index];
5108 
5109  if (wp->weapon_flags & WF_NO_HOMING) {
5110  return;
5111  }
5112 
5113  if (parent_objnum >= 0) {
5114  parent_objp = &Objects[parent_objnum];
5115  Assert(parent_objp->type == OBJ_SHIP);
5116  } else {
5117  parent_objp = NULL;
5118  }
5119 
5120  if (parent_objp != NULL && (Ships[parent_objp->instance].flags2 & SF2_NO_SECONDARY_LOCKON)) {
5121  wp->weapon_flags |= WF_NO_HOMING;
5123  wp->homing_subsys = NULL;
5124  wp->target_num = -1;
5125  wp->target_sig = -1;
5126 
5127  return;
5128  }
5129 
5130  if ( parent_objp == NULL || Ships[parent_objp->instance].ai_index >= 0 ) {
5131  int target_team = -1;
5132  if ( target_objnum >= 0 ) {
5133  int obj_type = Objects[target_objnum].type;
5134  if ( (obj_type == OBJ_SHIP) || (obj_type == OBJ_WEAPON) ) {
5135  target_team = obj_team(&Objects[target_objnum]);
5136  }
5137  }
5138 
5139  // determining if we're targeting the same team
5140  if (parent_objp != NULL && Ships[parent_objp->instance].team == target_team){
5141  targeting_same = 1;
5142 
5143  // Goober5000 - if we're going bonkers, pretend we're not targeting our own team
5144  ai_info *parent_aip = &Ai_info[Ships[parent_objp->instance].ai_index];
5145  if (parent_aip->active_goal != AI_GOAL_NONE && parent_aip->active_goal != AI_ACTIVE_GOAL_DYNAMIC) {
5146  if (parent_aip->goals[parent_aip->active_goal].flags & AIGF_TARGET_OWN_TEAM) {
5147  targeting_same = 0;
5148  }
5149  }
5150  } else {
5151  targeting_same = 0;
5152  }
5153 
5154  if ((target_objnum != -1) && (!targeting_same || (MULTI_DOGFIGHT && (target_team == Iff_traitor))) ) {
5155  wp->target_num = target_objnum;
5156  wp->target_sig = Objects[target_objnum].signature;
5157  wp->nearest_dist = 99999.0f;
5158  if ( (wip->wi_flags & WIF_HOMING_ASPECT) && target_is_locked) {
5159  wp->homing_object = &Objects[target_objnum];
5160  wp->homing_subsys = target_subsys;
5162  } else if ( (wip->wi_flags & WIF_HOMING_JAVELIN) && target_is_locked) {
5163  if ((Objects[target_objnum].type == OBJ_SHIP) &&
5164  ( (wp->homing_subsys == NULL) ||
5166  ship *target_ship = &Ships[Objects[target_objnum].instance];
5167  wp->homing_subsys = ship_get_closest_subsys_in_sight(target_ship, SUBSYSTEM_ENGINE, &Objects[weapon_objnum].pos);
5168  if (wp->homing_subsys == NULL) {
5170  } else {
5171  Assert(wp->homing_subsys->parent_objnum == target_objnum);
5172  wp->homing_object = &Objects[target_objnum];
5174  }
5175  } else {
5176  wp->homing_object = &Objects[target_objnum];
5177  wp->homing_subsys = target_subsys;
5179  }
5180  } else if ( wip->wi_flags & WIF_HOMING_HEAT ) {
5181  // Make a heat seeking missile try to home. If the target is outside the view cone, it will
5182  // immediately drop it and try to find one in its view cone.
5183  if ((target_objnum != -1) && !(wip->wi_flags2 & WIF2_UNTARGETED_HEAT_SEEKER)) {
5184  wp->homing_object = &Objects[target_objnum];
5185  wp->homing_subsys = target_subsys;
5187  } else {
5189  wp->homing_subsys = NULL;
5190  }
5191  }
5192  } else {
5193  wp->target_num = -1;
5194  wp->target_sig = -1;
5195  }
5196 
5197  // If missile is locked on target, increase its lifetime by 20% since missiles can be fired at limit of range
5198  // as defined by velocity*lifeleft, but missiles often slow down a bit, plus can be fired at a moving away target.
5199  // Confusing to many players when their missiles run out of gas before getting to target.
5200  // DB - removed 7:14 pm 9/6/99. was totally messing up lifetimes for all weapons.
5201  // MK, 7:11 am, 9/7/99. Put it back in, but with a proper check here to make sure it's an aspect seeker and
5202  // put a sanity check in the color changing laser code that was broken by this code.
5203  if (target_is_locked && (wp->target_num != -1) && (wip->wi_flags & WIF_LOCKED_HOMING) ) {
5205  if (MULTIPLAYER_MASTER) {
5207  }
5208  }
5209 
5210  ai_update_danger_weapon(target_objnum, weapon_objnum);
5211  }
5212 }
5213 
5214 size_t* get_pointer_to_weapon_fire_pattern_index(int weapon_type, ship* shipp, ship_subsys * src_turret)
5215 {
5216  Assert( shipp != NULL );
5217  ship_weapon* ship_weapon_p = &(shipp->weapons);
5218  if(src_turret)
5219  {
5220  ship_weapon_p = &src_turret->weapons;
5221  }
5222  Assert( ship_weapon_p != NULL );
5223 
5224  // search for the corresponding bank pattern index for the weapon_type that is being fired.
5225  // Note: Because a weapon_type may not be unique to a weapon bank per ship this search may attribute
5226  // the weapon to the wrong bank. Hopefully this isn't a problem.
5227  for ( int pi = 0; pi < MAX_SHIP_PRIMARY_BANKS; pi++ ) {
5228  if ( ship_weapon_p->primary_bank_weapons[pi] == weapon_type ) {
5229  return &(ship_weapon_p->primary_bank_pattern_index[pi]);
5230  }
5231  }
5232  for ( int si = 0; si < MAX_SHIP_SECONDARY_BANKS; si++ ) {
5233  if ( ship_weapon_p->secondary_bank_weapons[si] == weapon_type ) {
5234  return &(ship_weapon_p->secondary_bank_pattern_index[si]);
5235  }
5236  }
5237  return NULL;
5238 }
5239 
5246 int weapon_create( vec3d * pos, matrix * porient, int weapon_type, int parent_objnum, int group_id, int is_locked, int is_spawned, float fof_cooldown, ship_subsys * src_turret)
5247 {
5248  int n, objnum;
5249  int num_deleted;
5250  object *objp, *parent_objp=NULL;
5251  weapon *wp;
5252  weapon_info *wip;
5253 
5254  Assert(weapon_type >= 0 && weapon_type < Num_weapon_types);
5255 
5256  wip = &Weapon_info[weapon_type];
5257 
5258  // beam weapons should never come through here!
5259  if(wip->wi_flags & WIF_BEAM)
5260  {
5261  Warning(LOCATION, "An attempt to fire a beam ('%s') through weapon_create() was made.\n", wip->name);
5262  return -1;
5263  }
5264 
5265  parent_objp = NULL;
5266  if(parent_objnum >= 0){
5267  parent_objp = &Objects[parent_objnum];
5268  }
5269 
5270  if ( (wip->num_substitution_patterns > 0) && (parent_objp != NULL)) {
5271  // using substitution
5272 
5273  // get to the instance of the gun
5274  Assertion( parent_objp->type == OBJ_SHIP, "Expected type OBJ_SHIP, got %d", parent_objp->type );
5275  Assertion( (parent_objp->instance < MAX_SHIPS) && (parent_objp->instance >= 0),
5276  "Ship index is %d, which is out of range [%d,%d)", parent_objp->instance, 0, MAX_SHIPS);
5277  ship* parent_shipp = &(Ships[parent_objp->instance]);
5278  Assert( parent_shipp != NULL );
5279 
5280  size_t *position = get_pointer_to_weapon_fire_pattern_index(weapon_type, parent_shipp, src_turret);
5281  Assertion( position != NULL, "'%s' is trying to fire a weapon that is not selected", Ships[parent_objp->instance].ship_name );
5282 
5283  ++(*position);
5284  *position = (*position) % wip->num_substitution_patterns;
5285 
5286  if ( wip->weapon_substitution_pattern[*position] == -1 ) {
5287  // weapon doesn't want any sub
5288  return -1;
5289  } else if ( wip->weapon_substitution_pattern[*position] != weapon_type ) {
5290  // weapon wants to sub with weapon other than me
5291  return weapon_create(pos, porient, wip->weapon_substitution_pattern[*position], parent_objnum, group_id, is_locked, is_spawned, fof_cooldown);
5292  }
5293  }
5294 
5295  num_deleted = 0;
5296  if (Num_weapons >= MAX_WEAPONS-5) {
5297 
5298  //No, do remove for AI ships -- MK, 3/12/98 // don't need to try and delete weapons for ai ships
5299  //if ( !(Objects[parent_objnum].flags & OF_PLAYER_SHIP) )
5300  // return -1;
5301 
5302  num_deleted = collide_remove_weapons();
5303 
5304  nprintf(("WARNING", "Deleted %d weapons because of lack of slots\n", num_deleted));
5305  if (num_deleted == 0){
5306  return -1;
5307  }
5308  }
5309 
5310  for (n=0; n<MAX_WEAPONS; n++ ){
5311  if (Weapons[n].weapon_info_index < 0){
5312  break;
5313  }
5314  }
5315 
5316  if (n == MAX_WEAPONS) {
5317  // if we supposedly deleted weapons above, what happened here!!!!
5318  if (num_deleted){
5319  Int3(); // get allender -- something funny is going on!!!
5320  }
5321 
5322  return -1;
5323  }
5324 
5325  // make sure we are loaded and useable
5326  if ( (wip->render_type == WRT_POF) && (wip->model_num < 0) ) {
5327  wip->model_num = model_load(wip->pofbitmap_name, 0, NULL);
5328 
5329  if (wip->model_num < 0) {
5330  Int3();
5331  return -1;
5332  }
5333  }
5334 
5335  // make sure that our textures are loaded as well
5336  if ( !used_weapons[weapon_type] )
5337  weapon_load_bitmaps(weapon_type);
5338 
5339  //I am hopeing that this way does not alter the input orient matrix
5340  //Feild of Fire code -Bobboau
5341  matrix morient;
5342  matrix *orient;
5343 
5344  if(porient != NULL) {
5345  morient = *porient;
5346  } else {
5347  morient = vmd_identity_matrix;
5348  }
5349 
5350  orient = &morient;
5351 
5352  float combined_fof = wip->field_of_fire;
5353  // If there is a fof_cooldown value, increase the spread linearly
5354  if (fof_cooldown != 0.0f) {
5355  combined_fof = wip->field_of_fire + (fof_cooldown * wip->max_fof_spread);
5356  }
5357 
5358  if(combined_fof > 0.0f){
5359  vec3d f;
5360  vm_vec_random_cone(&f, &orient->vec.fvec, combined_fof);
5361  vm_vec_normalize(&f);
5362  vm_vector_2_matrix( orient, &f, NULL, NULL);
5363  }
5364 
5365  Weapons_created++;
5366  objnum = obj_create( OBJ_WEAPON, parent_objnum, n, orient, pos, 2.0f, OF_RENDERS | OF_COLLIDES | OF_PHYSICS );
5367  Assert(objnum >= 0);
5368  objp = &Objects[objnum];
5369 
5370  // Create laser n!
5371  wp = &Weapons[n];
5372 
5373  // check if laser or dumbfire missile
5374  // set physics flag to allow optimization
5375  if ((wip->subtype == WP_LASER) || ((wip->subtype == WP_MISSILE) && !(wip->wi_flags & WIF_HOMING) && wip->acceleration_time == 0.0f)) {
5376  // set physics flag
5377  objp->phys_info.flags |= PF_CONST_VEL;
5378  }
5379 
5380  wp->start_pos = *pos;
5381  wp->objnum = objnum;
5382  wp->model_instance_num = -1;
5383  wp->homing_object = &obj_used_list; // Assume not homing on anything.
5384  wp->homing_subsys = NULL;
5385  wp->creation_time = Missiontime;
5386  wp->group_id = group_id;
5387 
5388  // we don't necessarily need a parent
5389  if(parent_objp != NULL){
5390  Assert(parent_objp->type == OBJ_SHIP); // Get Mike, a non-ship has fired a weapon!
5391  Assert((parent_objp->instance >= 0) && (parent_objp->instance < MAX_SHIPS));
5392  wp->team = Ships[parent_objp->instance].team;
5393  wp->species = Ship_info[Ships[parent_objp->instance].ship_info_index].species;
5394  } else {
5395  // ugh - we need to prevent bad array accesses
5396  wp->team = Iff_traitor;
5397  wp->species = 0;
5398  }
5399  wp->turret_subsys = NULL;
5400  vm_vec_zero(&wp->homing_pos);
5401  wp->weapon_flags = 0;
5402  wp->target_sig = -1;
5403  wp->cmeasure_ignore_list = nullptr;
5404  wp->det_range = wip->det_range;
5405 
5406  // Init the thruster info
5407  wp->thruster_bitmap = -1;
5408  wp->thruster_frame = 0.0f;
5409  wp->thruster_glow_bitmap = -1;
5410  wp->thruster_glow_noise = 1.0f;
5411  wp->thruster_glow_frame = 0.0f;
5412 
5413  // init the laser info
5414  wp->laser_bitmap_frame = 0.0f;
5415  wp->laser_glow_bitmap_frame = 0.0f;
5416 
5417  if ( wip->wi_flags & WIF_SWARM ) {
5418  wp->swarm_index = (short)swarm_create();
5419  } else {
5420  wp->swarm_index = -1;
5421  }
5422 
5423  // if this is a particle spewing weapon, setup some stuff
5424  if (wip->wi_flags & WIF_PARTICLE_SPEW) {
5425  for (size_t s = 0; s < MAX_PARTICLE_SPEWERS; s++) { // allow for multiple time values
5427  wp->particle_spew_time[s] = -1;
5428  wp->particle_spew_rand = frand_range(0, PI2); // per weapon randomness
5429  }
5430  }
5431  }
5432 
5433  // assign the network signature. The starting sig is sent to all clients, so this call should
5434  // result in the same net signature numbers getting assigned to every player in the game
5435  if ( Game_mode & GM_MULTIPLAYER ) {
5436  if(wip->subtype == WP_MISSILE){
5438 
5439  // for weapons that respawn, add the number of respawnable weapons to the net signature pool
5440  // to reserve N signatures for the spawned weapons
5441  if ( wip->wi_flags & WIF_SPAWN ){
5443  }
5444  } else {
5446  }
5447  // for multiplayer clients, when creating lasers, add some more life to the lasers. This helps
5448  // to overcome some problems associated with lasers dying on client machine before they get message
5449  // from server saying it hit something.
5450  }
5451 
5452  //Check if we want to gen a random number
5453  //This is used for lifetime min/max
5454  float rand_val;
5455  if ( Game_mode & GM_NORMAL ){
5456  rand_val = frand();
5457  } else {
5458  rand_val = static_randf(Objects[objnum].net_signature);
5459  }
5460 
5461  wp->weapon_info_index = weapon_type;
5462  if(wip->life_min < 0.0f && wip->life_max < 0.0f) {
5463  wp->lifeleft = wip->lifetime;
5464  } else {
5465  wp->lifeleft = (rand_val) * (wip->life_max - wip->life_min) / wip->life_min;
5466  if((wip->wi_flags & WIF_CMEASURE) && (parent_objp != NULL) && (parent_objp->flags & OF_PLAYER_SHIP)) {
5468  }
5469  wp->lifeleft = wip->life_min + wp->lifeleft * (wip->life_max - wip->life_min);
5470  }
5471 
5472  if(wip->wi_flags & WIF_CMEASURE) {
5473  //2-frame homing check, to fend off sync errors
5475  }
5476 
5477  // Make remote detonate missiles look like they're getting detonated by firer simply by giving them variable lifetimes.
5478  if (parent_objp != NULL && !(parent_objp->flags & OF_PLAYER_SHIP) && (wip->wi_flags & WIF_REMOTE)) {
5479  wp->lifeleft = wp->lifeleft/2.0f + rand_val * wp->lifeleft/2.0f;
5480  }
5481 
5482  objp->phys_info.mass = wip->mass;
5483  objp->phys_info.side_slip_time_const = 0.0f;
5484  objp->phys_info.rotdamp = 0.0f;
5485  vm_vec_zero(&objp->phys_info.max_vel);
5486  objp->phys_info.max_vel.xyz.z = wip->max_speed;
5488  objp->shield_quadrant[0] = wip->damage;
5489  if (wip->weapon_hitpoints > 0){
5490  objp->hull_strength = (float) wip->weapon_hitpoints;
5491  } else {
5492  objp->hull_strength = 0.0f;
5493  }
5494 
5495  if ( wip->render_type == WRT_POF ) {
5496  // this should have been checked above, but let's be extra sure
5497  Assert(wip->model_num >= 0);
5498 
5499  objp->radius = model_get_radius(wip->model_num);
5500 
5501  // if we intrinsic-rotate, make sure we have a model instance
5504  }
5505  } else if ( wip->render_type == WRT_LASER ) {
5506  objp->radius = wip->laser_head_radius;
5507  }
5508 
5509  // Set desired velocity and initial velocity.
5510  // For lasers, velocity is always the same.
5511  // For missiles, it is a small amount plus the firing ship's velocity.
5512  // For missiles, the velocity trends towards some goal.
5513  // Note: If you change how speed works here, such as adding in speed of parent ship, you'll need to change the AI code
5514  // that predicts collision points. See Mike Kulas or Dave Andsager. (Or see ai_get_weapon_speed().)
5515  if (wip->acceleration_time > 0.0f) {
5516  vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, 0.01f ); // Tiny initial velocity to avoid possible null vec issues
5517  objp->phys_info.vel = objp->phys_info.desired_vel;
5518  objp->phys_info.speed = 0.0f;
5519  wp->launch_speed = 0.0f;
5520  } else if (!(wip->wi_flags & WIF_HOMING)) {
5521  vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
5522  objp->phys_info.vel = objp->phys_info.desired_vel;
5524  } else {
5525  // For weapons that home, set velocity to sum of forward component of parent's velocity and 1/4 weapon's max speed.
5526  // Note that it is important to extract the forward component of the parent's velocity to factor out sliding, else
5527  // the missile will not be moving forward.
5528  if(parent_objp != NULL){
5529  if (wip->free_flight_time > 0.0)
5530  vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, vm_vec_dot(&parent_objp->phys_info.vel, &parent_objp->orient.vec.fvec) + objp->phys_info.max_vel.xyz.z/4 );
5531  else
5532  vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
5533  } else {
5534  if (!is_locked && wip->free_flight_time > 0.0)
5535  {
5536  vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z/4 );
5537  }
5538  else
5539  {
5540  vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, objp->phys_info.max_vel.xyz.z );
5541  }
5542  }
5543  objp->phys_info.vel = objp->phys_info.desired_vel;
5544  objp->phys_info.speed = vm_vec_mag(&objp->phys_info.vel);
5545  }
5546 
5547  wp->weapon_max_vel = objp->phys_info.max_vel.xyz.z;
5548 
5549  // Turey - maybe make the initial speed of the weapon take into account the velocity of the parent.
5550  // Improves aiming during gliding.
5551  if ((parent_objp != NULL) && (The_mission.ai_profile->flags & AIPF_USE_ADDITIVE_WEAPON_VELOCITY)) {
5552  float pspeed = vm_vec_mag( &parent_objp->phys_info.vel );
5553  vm_vec_scale_add2( &objp->phys_info.vel, &parent_objp->phys_info.vel, wip->vel_inherit_amount );
5554  wp->weapon_max_vel += pspeed * wip->vel_inherit_amount;
5555  objp->phys_info.speed = vm_vec_mag(&objp->phys_info.vel);
5556 
5557  if (wip->acceleration_time > 0.0f)
5558  wp->launch_speed += pspeed;
5559  }
5560 
5561  // create the corkscrew
5562  if ( wip->wi_flags & WIF_CORKSCREW ) {
5563  wp->cscrew_index = (short)cscrew_create(objp);
5564  } else {
5565  wp->cscrew_index = -1;
5566  }
5567 
5568  if (wip->wi_flags2 & WIF2_LOCAL_SSM)
5569  {
5570 
5571  Assert(parent_objp); //local ssms must have a parent
5572 
5575  wp->lssm_stage=1;
5576  }
5577  else{
5578  wp->lssm_stage=-1;
5579  }
5580 
5581 
5582  // if this is a flak weapon shell, make it so
5583  // NOTE : this function will change some fundamental things about the weapon object
5584  if ( (wip->wi_flags & WIF_FLAK) && !(wip->wi_flags2 & WIF2_RENDER_FLAK) ) {
5586  }
5587 
5588  wp->missile_list_index = -1;
5589  // If this is a missile, then add it to the Missile_obj_list
5590  if ( wip->subtype == WP_MISSILE ) {
5592  }
5593 
5594  if (wip->wi_flags & WIF_TRAIL /*&& !(wip->wi_flags & WIF_CORKSCREW) */) {
5595  wp->trail_ptr = trail_create(&wip->tr_info);
5596 
5597  if ( wp->trail_ptr != NULL ) {
5598  // Add two segments. One to stay at launch pos, one to move.
5599  trail_add_segment( wp->trail_ptr, &objp->pos );
5600  trail_add_segment( wp->trail_ptr, &objp->pos );
5601  }
5602  }
5603  else
5604  {
5605  //If a weapon has no trails, make sure we don't try to do anything with them.
5606  wp->trail_ptr = NULL;
5607  }
5608 
5609  // Ensure weapon flyby sound doesn't get played for player lasers
5610  if ( parent_objp != NULL && parent_objp == Player_obj ) {
5612  }
5613 
5615 
5616  // Set detail levels for POF-type weapons.
5617  if (Weapon_info[wp->weapon_info_index].model_num != -1) {
5618  polymodel * pm;
5619  int i;
5620  pm = model_get(Weapon_info[wp->weapon_info_index].model_num);
5621 
5622  for (i=0; i<pm->n_detail_levels; i++){
5623  // for weapons, detail levels are all preset to -1
5624  if (wip->detail_distance[i] >= 0)
5625  pm->detail_depth[i] = i2fl(wip->detail_distance[i]);
5626  else
5627  pm->detail_depth[i] = (objp->radius*20.0f + 20.0f) * i;
5628  }
5629 
5630 #ifndef NDEBUG
5631  // since debug builds always have cheats enabled, we don't necessarily get the chance
5632  // to enable thrusters for previously non-loaded weapons (ie, weapons_page_in_cheats())
5633  // when using cheat-keys, so we need to make sure and enable thrusters here if needed
5634  if (pm->n_thrusters > 0) {
5635  wip->wi_flags |= WIF_THRUSTER;
5636  }
5637 #endif
5638  }
5639 
5640  // if the weapon was fired locked
5641  if(is_locked){
5643  }
5644 
5645  //if the weapon was spawned from a spawning type weapon
5646  if(is_spawned){
5647  wp->weapon_flags |= WF_SPAWNED;
5648  }
5649 
5650  wp->alpha_current = -1.0f;
5651  wp->alpha_backward = 0;
5652 
5653  wp->collisionOccured = false;
5654  wp->hud_in_flight_snd_sig = -1;
5655 
5656  Num_weapons++;
5657 
5658  // reset the damage record fields (for scoring purposes)
5659  wp->total_damage_received = 0.0f;
5660  for(int i=0;i<MAX_WEP_DAMAGE_SLOTS;i++)
5661  {
5662  wp->damage_ship[i] = 0.0f;
5663  wp->damage_ship_id[i] = -1;
5664  }
5665 
5667  Objects[objnum].collision_group_id = Objects[parent_objnum].collision_group_id;
5668  }
5669 
5670  return objnum;
5671 }
5672 
5677 {
5678  int i, j;
5679  int child_id;
5680  int parent_num;
5681  ushort starting_sig;
5682  weapon *wp = NULL;
5683  beam *bp = NULL;
5684  weapon_info *wip, *child_wip;
5685  vec3d *opos, *fvec;
5686 
5687  Assertion(objp->type == OBJ_WEAPON || objp->type == OBJ_BEAM, "spawn_child_weapons() doesn't make sense for non-weapon non-beam objects; get a coder!\n");
5688  Assertion(objp->instance >= 0, "spawn_child_weapons() called with an object with an instance of %d; get a coder!\n", objp->instance);
5689  Assertion(!(objp->type == OBJ_WEAPON) || (objp->instance < MAX_WEAPONS), "spawn_child_weapons() called with a weapon with an instance of %d while MAX_WEAPONS is %d; get a coder!\n", objp->instance, MAX_WEAPONS);
5690  Assertion(!(objp->type == OBJ_BEAM) || (objp->instance < MAX_BEAMS), "spawn_child_weapons() called with a beam with an instance of %d while MAX_BEAMS is %d; get a coder!\n", objp->instance, MAX_BEAMS);
5691 
5692  if (objp->type == OBJ_WEAPON) {
5693  wp = &Weapons[objp->instance];
5694  Assertion((wp->weapon_info_index >= 0) && (wp->weapon_info_index < Num_weapon_types), "Invalid weapon_info_index of %d; get a coder!\n", wp->weapon_info_index);
5695  wip = &Weapon_info[wp->weapon_info_index];
5696  } else if (objp->type == OBJ_BEAM) {
5697  bp = &Beams[objp->instance];
5698  Assertion((bp->weapon_info_index >= 0) && (bp->weapon_info_index < Num_weapon_types), "Invalid weapon_info_index of %d; get a coder!\n", bp->weapon_info_index);
5699  wip = &Weapon_info[bp->weapon_info_index];
5700  } else { // Let's make sure we don't do screwball things in a release build if this gets called with a non-weapon non-beam.
5701  return;
5702  }
5703 
5704  parent_num = objp->parent;
5705 
5706  if (parent_num >= 0) {
5707  if ((Objects[parent_num].type != objp->parent_type) || (Objects[parent_num].signature != objp->parent_sig)) {
5708  mprintf(("Warning: Parent of spawn weapon does not exist. Not spawning.\n"));
5709  return;
5710  }
5711  }
5712 
5713  starting_sig = 0;
5714 
5715  if ( Game_mode & GM_MULTIPLAYER ) {
5716  // get the next network signature and save it. Set the next usable network signature to be
5717  // the passed in objects signature + 1. We "reserved" N of these slots when we created objp
5718  // for it's spawned children.
5721  }
5722 
5723  opos = &objp->pos;
5724  fvec = &objp->orient.vec.fvec;
5725 
5726  for (i = 0; i < wip->num_spawn_weapons_defined; i++)
5727  {
5728  for (j = 0; j < wip->spawn_info[i].spawn_count; j++)
5729  {
5730  int weapon_objnum;
5731  vec3d tvec, pos;
5732  matrix orient;
5733 
5734  child_id = wip->spawn_info[i].spawn_type;
5735  child_wip = &Weapon_info[child_id];
5736 
5737  // for multiplayer, use the static randvec functions based on the network signatures to provide
5738  // the randomness so that it is the same on all machines.
5739  if ( Game_mode & GM_MULTIPLAYER ) {
5740  static_rand_cone(objp->net_signature + j, &tvec, fvec, wip->spawn_info[i].spawn_angle);
5741  } else {
5742  vm_vec_random_cone(&tvec, fvec, wip->spawn_info[i].spawn_angle);
5743  }
5744  vm_vec_scale_add(&pos, opos, &tvec, objp->radius);
5745 
5746  // Let's allow beam-spawn! -MageKing17
5747  if (child_wip->wi_flags & WIF_BEAM) {
5748  beam_fire_info fire_info;
5749  memset(&fire_info, 0, sizeof(beam_fire_info));
5750 
5751  fire_info.accuracy = 0.000001f; // this will guarantee a hit
5752  fire_info.shooter = &Objects[parent_num];
5753  fire_info.turret = NULL;
5754  fire_info.target = NULL;
5755  fire_info.target_subsys = NULL;
5756  fire_info.target_pos1 = fire_info.target_pos2 = pos;
5758  fire_info.starting_pos = *opos;
5759  fire_info.beam_info_index = child_id;
5760  fire_info.team = static_cast<char>(obj_team(&Objects[parent_num]));
5761 
5762  // fire the beam
5763  beam_fire(&fire_info);
5764  } else {
5765  vm_vector_2_matrix(&orient, &tvec, NULL, NULL);
5766  weapon_objnum = weapon_create(&pos, &orient, child_id, parent_num, -1, wp->weapon_flags & WF_LOCKED_WHEN_FIRED, 1);
5767 
5768  //if the child inherits parent target, do it only if the parent weapon was locked to begin with
5769  if ((child_wip->wi_flags2 & WIF2_INHERIT_PARENT_TARGET) && (wp->homing_object != &obj_used_list))
5770  {
5771  //Deal with swarm weapons
5772  if (wp->swarm_index >= 0) {
5773  swarm_info *swarmp;
5774  swarmp = &Swarm_missiles[wp->swarm_index];
5775 
5776  weapon_set_tracking_info(weapon_objnum, parent_num, swarmp->homing_objnum, 1, wp->homing_subsys);
5777  } else {
5778  weapon_set_tracking_info(weapon_objnum, parent_num, wp->target_num, 1, wp->homing_subsys);
5779  }
5780  }
5781 
5782  // Assign a little randomness to lifeleft so they don't all disappear at the same time.
5783  if (weapon_objnum != -1) {
5784  float rand_val;
5785 
5786  if ( Game_mode & GM_NORMAL ){
5787  rand_val = frand();
5788  } else {
5789  rand_val = static_randf(objp->net_signature + j);
5790  }
5791 
5792  Weapons[Objects[weapon_objnum].instance].lifeleft *= rand_val*0.4f + 0.8f;
5793  }
5794  }
5795  }
5796 
5797  }
5798 
5799  // in multiplayer, reset the next network signature to the one that was saved.
5800  if ( Game_mode & GM_MULTIPLAYER ){
5802  }
5803 }
5804 
5809 void weapon_play_impact_sound(weapon_info *wip, vec3d *hitpos, bool is_armed)
5810 {
5811  if(is_armed)
5812  {
5813  if(wip->impact_snd != -1) {
5814  snd_play_3d( &Snds[wip->impact_snd], hitpos, &Eye_position );
5815  }
5816  }
5817  else
5818  {
5819  if(wip->disarmed_impact_snd != -1) {
5821  }
5822  }
5823 }
5824 
5834 void weapon_hit_do_sound(object *hit_obj, weapon_info *wip, vec3d *hitpos, bool is_armed)
5835 {
5836  int is_hull_hit;
5837  float shield_str;
5838 
5839  // If non-missiles (namely lasers) expire without hitting a ship, don't play impact sound
5840  if ( wip->subtype != WP_MISSILE ) {
5841  if ( !hit_obj ) {
5842  // flak weapons make sounds
5843  if(wip->wi_flags & WIF_FLAK)
5844  {
5845  weapon_play_impact_sound(wip, hitpos, is_armed);
5846  }
5847  return;
5848  }
5849 
5850  switch(hit_obj->type) {
5851  case OBJ_SHIP:
5852  // do nothing
5853  break;
5854 
5855  case OBJ_ASTEROID:
5856  if ( timestamp_elapsed(Weapon_impact_timer) ) {
5857  weapon_play_impact_sound(wip, hitpos, is_armed);
5858  Weapon_impact_timer = timestamp(IMPACT_SOUND_DELTA);
5859  }
5860  return;
5861  break;
5862 
5863  default:
5864  return;
5865  }
5866  }
5867 
5868  if ( hit_obj == NULL ) {
5869  weapon_play_impact_sound(wip, hitpos, is_armed);
5870  return;
5871  }
5872 
5873  if ( timestamp_elapsed(Weapon_impact_timer) ) {
5874 
5875  is_hull_hit = 1;
5876  if ( hit_obj->type == OBJ_SHIP ) {
5877  shield_str = ship_quadrant_shield_strength(hit_obj, hitpos);
5878  } else {
5879  shield_str = 0.0f;
5880  }
5881 
5882  // play a shield hit if shields are above 10% max in this quadrant
5883  if ( shield_str > 0.1f ) {
5884  is_hull_hit = 0;
5885  }
5886 
5887  if ( !is_hull_hit ) {
5888  // Play a shield impact sound effect
5889  if ( hit_obj == Player_obj ) {
5891  // AL 12-15-97: Add missile impact sound even when shield is hit
5892  if ( wip->subtype == WP_MISSILE ) {
5894  }
5895  } else {
5897  }
5898  } else {
5899  // Play a hull impact sound effect
5900  switch ( wip->subtype ) {
5901  case WP_LASER:
5902  if ( hit_obj == Player_obj )
5904  else {
5905  weapon_play_impact_sound(wip, hitpos, is_armed);
5906  }
5907  break;
5908  case WP_MISSILE:
5909  if ( hit_obj == Player_obj )
5911  else {
5912  weapon_play_impact_sound(wip, hitpos, is_armed);
5913  }
5914  break;
5915  default:
5916  nprintf(("Warning","WARNING ==> Cannot determine sound to play for weapon impact\n"));
5917  break;
5918  } // end switch
5919  }
5920 
5921  Weapon_impact_timer = timestamp(IMPACT_SOUND_DELTA);
5922  }
5923 }
5924 
5925 extern bool turret_weapon_has_flags(ship_weapon *swp, int flags);
5926 
5934 void weapon_do_electronics_effect(object *ship_objp, vec3d *blast_pos, int wi_index)
5935 {
5936  weapon_info *wip;
5937  ship *shipp;
5938  ship_subsys *ss;
5939  model_subsystem *psub;
5940  vec3d subsys_world_pos;
5941  float dist;
5942 
5943  shipp = &Ships[ship_objp->instance];
5944  wip = &Weapon_info[wi_index];
5945 
5946  for ( ss = GET_FIRST(&shipp->subsys_list); ss != END_OF_LIST(&shipp->subsys_list); ss = GET_NEXT(ss) )
5947  {
5948  psub = ss->system_info;
5949 
5950  // convert subsys point to world coords
5951  vm_vec_unrotate(&subsys_world_pos, &psub->pnt, &ship_objp->orient);
5952  vm_vec_add2(&subsys_world_pos, &ship_objp->pos);
5953 
5954  // see if subsys point is within damage sphere
5955  dist = vm_vec_dist_quick(blast_pos, &subsys_world_pos);
5956  if ( dist < wip->shockwave.outer_rad )
5957  {
5958  float disrupt_time = (float)wip->elec_time;
5959 
5960  //use new style electronics disruption
5961  if (wip->elec_use_new_style)
5962  {
5963  //if its an engine subsytem, take the multiplier into account
5964  if (psub->type==SUBSYSTEM_ENGINE)
5965  {
5966  disrupt_time*=wip->elec_eng_mult;
5967  }
5968 
5969  //if its a turret or weapon subsytem, take the multiplier into account
5970  if ((psub->type==SUBSYSTEM_TURRET) || (psub->type==SUBSYSTEM_WEAPONS))
5971  {
5972  //disrupt beams
5973  //WMC - do this even if there are other types of weapons on the turret.
5974  //I figure, the big fancy electronics on beams will be used for the other
5975  //weapons as well. No reason having two targeting computers on a turret.
5976  //Plus, it's easy and fast to code. :)
5978  {
5979  disrupt_time*=wip->elec_beam_mult;
5980  }
5981  //disrupt other weapons
5982  else
5983  {
5984  disrupt_time*=wip->elec_weap_mult;
5985  }
5986  }
5987 
5988  //disrupt sensor and awacs systems.
5989  if ((psub->type==SUBSYSTEM_SENSORS) || (psub->flags & MSS_FLAG_AWACS))
5990  {
5991  disrupt_time*=wip->elec_sensors_mult;
5992  }
5993  }
5994 
5995  //add a little randomness to the disruption time
5996  disrupt_time += frand_range(-1.0f, 1.0f) * wip->elec_randomness;
5997 
5998  //disrupt this subsystem for the calculated time
5999  //if it turns out to be less than 0 seconds, don't bother
6000  if (disrupt_time > 0)
6001  {
6002  ship_subsys_set_disrupted(ss, fl2i(disrupt_time));
6003  }
6004  }
6005  }
6006 }
6007 
6025 int weapon_area_calc_damage(object *objp, vec3d *pos, float inner_rad, float outer_rad, float max_blast, float max_damage, float *blast, float *damage, float limit)
6026 {
6027  float dist;
6028  vec3d box_pt;
6029 
6030  // if object receiving the blast is a ship, use the bbox for distances
6031  // otherwise use the objects radius
6032  // could possibly exclude SIF_SMALL_SHIP (& other small objects) from using the bbox
6033  if (objp->type == OBJ_SHIP) {
6034  int inside = get_nearest_bbox_point(objp, pos, &box_pt);
6035  if (inside) {
6036  dist = 0.0001f;
6037  } else {
6038  dist = vm_vec_dist_quick(pos, &box_pt);
6039  }
6040  } else {
6041  dist = vm_vec_dist_quick(&objp->pos, pos) - objp->radius;
6042  }
6043 
6044  if ( (dist > outer_rad) || (dist > limit) ) {
6045  return -1; // spheres don't intersect at all
6046  }
6047 
6048  if ( dist < inner_rad ) {
6049  // damage is maximum within inner radius
6050  *damage = max_damage;
6051  *blast = max_blast;
6052  } else {
6053  float dist_to_outer_rad_squared = (outer_rad-dist)*(outer_rad-dist);
6054  float total_dist_squared = (inner_rad-outer_rad)*(inner_rad-outer_rad);
6055 
6056  // this means the inner and outer radii are basically equal... and since we aren't within the inner radius,
6057  // we fudge the law of excluded middle to place ourselves outside the outer radius
6058  if (total_dist_squared < 0.0001f) {
6059  return -1; // avoid divide-by-zero; we won't take damage anyway
6060  }
6061 
6062  // AL 2-24-98: drop off damage relative to square of distance
6063  Assert(dist_to_outer_rad_squared <= total_dist_squared);
6064  *damage = max_damage * dist_to_outer_rad_squared/total_dist_squared;
6065  *blast = (dist - outer_rad) * max_blast /(inner_rad - outer_rad);
6066  }
6067 
6068  return 0;
6069 }
6070 
6080 void weapon_area_apply_blast(vec3d *force_apply_pos, object *ship_objp, vec3d *blast_pos, float blast, int make_shockwave)
6081 {
6082  #define SHAKE_CONST 3000
6083  vec3d force, vec_blast_to_ship, vec_ship_to_impact;
6084  polymodel *pm;
6085 
6086  // don't waste time here if there is no blast force
6087  if ( blast == 0.0f )
6088  return;
6089 
6090  // apply blast force based on distance from center of explosion
6091  vm_vec_sub(&vec_blast_to_ship, &ship_objp->pos, blast_pos);
6092  vm_vec_normalize_safe(&vec_blast_to_ship);
6093  vm_vec_copy_scale(&force, &vec_blast_to_ship, blast );
6094 
6095  vm_vec_sub(&vec_ship_to_impact, blast_pos, &ship_objp->pos);
6096 
6097  pm = model_get(Ship_info[Ships[ship_objp->instance].ship_info_index].model_num);
6098  Assert ( pm != NULL );
6099 
6100  if (make_shockwave) {
6101  physics_apply_shock (&force, blast, &ship_objp->phys_info, &ship_objp->orient, &pm->mins, &pm->maxs, pm->rad);
6102  if (ship_objp == Player_obj) {
6103  joy_ff_play_vector_effect(&vec_blast_to_ship, blast * 2.0f);
6104  }
6105  } else {
6106  ship_apply_whack( &force, &vec_ship_to_impact, ship_objp);
6107  }
6108 }
6109 
6118 void weapon_do_area_effect(object *wobjp, shockwave_create_info *sci, vec3d *pos, object *other_obj)
6119 {
6120  weapon_info *wip;
6121  object *objp;
6122  float damage, blast;
6123 
6124  wip = &Weapon_info[Weapons[wobjp->instance].weapon_info_index];
6125 
6126  // only blast ships and asteroids
6127  // And (some) weapons
6128  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
6129  if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_ASTEROID) && (objp->type != OBJ_WEAPON) ) {
6130  continue;
6131  }
6132 
6133  if (objp->type == OBJ_WEAPON) {
6134  // only apply to missiles with hitpoints
6135  weapon_info* wip2 = &Weapon_info[Weapons[objp->instance].weapon_info_index];
6136  if (wip2->weapon_hitpoints <= 0)
6137  continue;
6138  if (!((wip2->wi_flags2 & WIF2_TAKES_BLAST_DAMAGE) || (wip->wi_flags2 & WIF2_CIWS)))
6139  continue;
6140  }
6141 
6142  if ( objp->type == OBJ_SHIP ) {
6143  // don't blast navbuoys
6144  if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
6145  continue;
6146  }
6147  }
6148 
6149  if ( weapon_area_calc_damage(objp, pos, sci->inner_rad, sci->outer_rad, sci->blast, sci->damage, &blast, &damage, sci->outer_rad) == -1 ){
6150  continue;
6151  }
6152 
6153  // scale damage
6154  damage *= weapon_get_damage_scale(wip, wobjp, other_obj);
6155 
6156  weapon_info* target_wip;
6157 
6158  switch ( objp->type ) {
6159  case OBJ_SHIP:
6160  // If we're doing an AoE Electronics blast, do the electronics stuff (unless it also has the regular "electronics"
6161  // flag and this is the ship the missile directly impacted; then leave it for the regular code below) -MageKing17
6162  if ( (wip->wi_flags3 & WIF3_AOE_ELECTRONICS) && !((objp->flags & OF_INVULNERABLE) || ((objp == other_obj) && (wip->wi_flags & WIF_ELECTRONICS))) ) {
6163  weapon_do_electronics_effect(objp, pos, Weapons[wobjp->instance].weapon_info_index);
6164  }
6165  ship_apply_global_damage(objp, wobjp, pos, damage);
6166  weapon_area_apply_blast(NULL, objp, pos, blast, 0);
6167  break;
6168  case OBJ_ASTEROID:
6169  asteroid_hit(objp, NULL, NULL, damage);
6170  break;
6171  case OBJ_WEAPON:
6172  target_wip = &Weapon_info[Weapons[objp->instance].weapon_info_index];
6173  if (target_wip->armor_type_idx >= 0)
6174  damage = Armor_types[target_wip->armor_type_idx].GetDamage(damage, wip->damage_type_idx, 1.0f);
6175 
6176  objp->hull_strength -= damage;
6177  if (objp->hull_strength < 0.0f) {
6178  Weapons[objp->instance].lifeleft = 0.01f;
6179  Weapons[objp->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON;
6180  }
6181  break;
6182  default:
6183  Int3();
6184  break;
6185  }
6186 
6187  } // end for
6188 
6189  // if this weapon has the "Electronics" flag set, then disrupt subsystems in sphere
6190  if ( (other_obj != NULL) && (wip->wi_flags & WIF_ELECTRONICS) ) {
6191  if ( other_obj->type == OBJ_SHIP ) {
6192  weapon_do_electronics_effect(other_obj, pos, Weapons[wobjp->instance].weapon_info_index);
6193  }
6194  }
6195 }
6196 
6197 // ----------------------------------------------------------------------
6198 // weapon_armed(weapon)
6199 //
6200 // Call to figure out if a weapon is armed or not
6201 //
6202 //Weapon is armed when...
6203 //1: Weapon is shot down by weapon
6204 //OR
6205 //1: weapon is destroyed before arm time
6206 //2: weapon is destroyed before arm distance from ship
6207 //3: weapon is outside arm radius from target ship
6208 bool weapon_armed(weapon *wp, bool hit_target)
6209 {
6210  Assert(wp != NULL);
6211 
6212  weapon_info *wip = &Weapon_info[wp->weapon_info_index];
6213 
6215  && !wip->arm_time
6216  && wip->arm_dist == 0.0f
6217  && wip->arm_radius == 0.0f)
6218  {
6219  return false;
6220  }
6221  else
6222  {
6223  object *wobj = &Objects[wp->objnum];
6224  object *pobj;
6225 
6226  if(wobj->parent > -1) {
6227  pobj = &Objects[wobj->parent];
6228  } else {
6229  pobj = NULL;
6230  }
6231 
6232  if( ((wip->arm_time) && ((Missiontime - wp->creation_time) < wip->arm_time))
6233  || ((wip->arm_dist) && (pobj != NULL && pobj->type != OBJ_NONE && (vm_vec_dist(&wobj->pos, &pobj->pos) < wip->arm_dist))))
6234  {
6235  return false;
6236  }
6237  if(wip->arm_radius && (!hit_target)) {
6238  if(wp->homing_object == &obj_used_list)
6239  return false;
6240  if(IS_VEC_NULL(&wp->homing_pos) || vm_vec_dist(&wobj->pos, &wp->homing_pos) > wip->arm_radius)
6241  return false;
6242  }
6243  }
6244 
6245  return true;
6246 }
6247 
6248 
6253 void weapon_hit( object * weapon_obj, object * other_obj, vec3d * hitpos, int quadrant )
6254 {
6255  Assert(weapon_obj != NULL);
6256  if(weapon_obj == NULL){
6257  return;
6258  }
6259  Assert((weapon_obj->type == OBJ_WEAPON) && (weapon_obj->instance >= 0) && (weapon_obj->instance < MAX_WEAPONS));
6260  if((weapon_obj->type != OBJ_WEAPON) || (weapon_obj->instance < 0) || (weapon_obj->instance >= MAX_WEAPONS)){
6261  return;
6262  }
6263 
6264  int num = weapon_obj->instance;
6265  int weapon_type = Weapons[num].weapon_info_index;
6266  int expl_ani_handle;
6267  weapon_info *wip;
6268  weapon *wp;
6269  bool hit_target = false;
6270 
6271  object *other_objp;
6272  ship_obj *so;
6273  ship *shipp;
6274  int objnum;
6275 
6276  Assert((weapon_type >= 0) && (weapon_type < MAX_WEAPON_TYPES));
6277  if((weapon_type < 0) || (weapon_type >= MAX_WEAPON_TYPES)){
6278  return;
6279  }
6280  wp = &Weapons[weapon_obj->instance];
6281  wip = &Weapon_info[weapon_type];
6282  objnum = wp->objnum;
6283 
6284  // check if the weapon actually hit the intended target
6285  if (wp->homing_object != &obj_used_list)
6286  if (wp->homing_object == other_obj)
6287  hit_target = true;
6288 
6289  //This is an expensive check
6290  bool armed_weapon = weapon_armed(&Weapons[num], hit_target);
6291 
6292  // if this is the player ship, and is a laser hit, skip it. wait for player "pain" to take care of it
6293  if ((other_obj != Player_obj) || (wip->subtype != WP_LASER) || !MULTIPLAYER_CLIENT) {
6294  weapon_hit_do_sound(other_obj, wip, hitpos, armed_weapon);
6295  }
6296 
6297  if ( wip->impact_weapon_expl_index > -1 && armed_weapon)
6298  {
6299  expl_ani_handle = Weapon_explosions.GetAnim(wip->impact_weapon_expl_index, hitpos, wip->impact_explosion_radius);
6301  }
6302  else if(wip->dinky_impact_weapon_expl_index > -1 && !armed_weapon)
6303  {
6304  expl_ani_handle = Weapon_explosions.GetAnim(wip->dinky_impact_weapon_expl_index, hitpos, wip->dinky_impact_explosion_radius);
6306  }
6307 
6308  if((other_obj != NULL) && (quadrant == -1) && (wip->piercing_impact_weapon_expl_index > -1 && armed_weapon)) {
6309  if ((other_obj->type == OBJ_SHIP) || (other_obj->type == OBJ_DEBRIS)) {
6310 
6311  int ok_to_draw = 1;
6312 
6313  if (other_obj->type == OBJ_SHIP) {
6314  float draw_limit, hull_pct;
6315  int dmg_type_idx, piercing_type;
6316 
6317  shipp = &Ships[other_obj->instance];
6318 
6319  hull_pct = other_obj->hull_strength / shipp->ship_max_hull_strength;
6320  dmg_type_idx = wip->damage_type_idx;
6321  draw_limit = Ship_info[shipp->ship_info_index].piercing_damage_draw_limit;
6322 
6323  if (shipp->armor_type_idx != -1) {
6324  piercing_type = Armor_types[shipp->armor_type_idx].GetPiercingType(dmg_type_idx);
6325  if (piercing_type == SADTF_PIERCING_DEFAULT) {
6326  draw_limit = Armor_types[shipp->armor_type_idx].GetPiercingLimit(dmg_type_idx);
6327  } else if ((piercing_type == SADTF_PIERCING_NONE) || (piercing_type == SADTF_PIERCING_RETAIL)) {
6328  ok_to_draw = 0;
6329  }
6330  }
6331 
6332  if (hull_pct > draw_limit)
6333  ok_to_draw = 0;
6334  }
6335 
6336  if (ok_to_draw) {
6337  particle_emitter pe;
6338  vec3d null_v;
6339 
6340  vm_vec_zero(&null_v);
6341  expl_ani_handle = Weapon_explosions.GetAnim(wip->piercing_impact_weapon_expl_index, hitpos, wip->piercing_impact_explosion_radius);
6342 
6343  pe.max_vel = 2.0f * wip->piercing_impact_particle_velocity;
6344  pe.min_vel = 0.5f * wip->piercing_impact_particle_velocity;
6345  pe.max_life = 2.0f * wip->piercing_impact_particle_life;
6346  pe.min_life = 0.25f * wip->piercing_impact_particle_life;
6349  pe.pos = weapon_obj->pos;
6350  pe.normal = weapon_obj->last_orient.vec.fvec;
6352  pe.max_rad = 2.0f * wip->piercing_impact_explosion_radius;
6353  pe.min_rad = 0.5f * wip->piercing_impact_explosion_radius;
6354  pe.vel = null_v;
6355 
6356  particle_emit(&pe, PARTICLE_BITMAP, expl_ani_handle, 10.0f);
6357 
6358  if (wip->piercing_impact_particle_back_velocity != 0.0f) {
6359 
6362  pe.num_high /= 2;
6363  pe.num_low /= 2;
6364 
6365  particle_emit(&pe, PARTICLE_BITMAP, expl_ani_handle, 10.0f);
6366  }
6367  }
6368  }
6369  }
6370 
6371  // For all objects that had this weapon as a target, wipe it out, forcing find of a new enemy
6372  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
6373  other_objp = &Objects[so->objnum];
6374  Assert(other_objp->instance != -1);
6375 
6376  shipp = &Ships[other_objp->instance];
6377  Assert(shipp->ai_index != -1);
6378 
6379  ai_info *aip = &Ai_info[shipp->ai_index];
6380 
6381  if (aip->target_objnum == objnum) {
6382  set_target_objnum(aip, -1);
6383  // If this ship had a dynamic goal of chasing this weapon, clear the dynamic goal.
6384  if (aip->resume_goal_time != -1)
6385  aip->active_goal = AI_GOAL_NONE;
6386  }
6387 
6388  if (aip->goal_objnum == objnum) {
6389  aip->goal_objnum = -1;
6390  aip->goal_signature = -1;
6391  }
6392 
6393  if (aip->guard_objnum == objnum) {
6394  aip->guard_objnum = -1;
6395  aip->guard_signature = -1;
6396  }
6397 
6398  if (aip->hitter_objnum == objnum) {
6399  aip->hitter_objnum = -1;
6400  }
6401  }
6402 
6403  // single player and multiplayer masters evaluate the scoring and kill stuff
6404  if (!MULTIPLAYER_CLIENT) {
6405  //If this is a bomb, set it up for scoring. -Halleck
6406  if (wip->wi_flags & WIF_BOMB) {
6407  scoring_eval_kill_on_weapon(weapon_obj, other_obj);
6408  }
6409  }
6410 
6411  weapon_obj->flags |= OF_SHOULD_BE_DEAD;
6412 
6413  //Set shockwaves flag
6414  int sw_flag = SW_WEAPON;
6415 
6416  if ( ((other_obj) && (other_obj->type == OBJ_WEAPON)) || (Weapons[num].weapon_flags & WF_DESTROYED_BY_WEAPON)) {
6417  sw_flag |= SW_WEAPON_KILL;
6418  }
6419 
6420  //Which shockwave?
6421  shockwave_create_info *sci = &wip->shockwave;
6422  if(!armed_weapon) {
6423  sci = &wip->dinky_shockwave;
6424  }
6425 
6426  // check if this is an area effect weapon (i.e. has a blast radius)
6427  if (sci->inner_rad != 0.0f || sci->outer_rad != 0.0f)
6428  {
6429  if(sci->speed > 0.0f) {
6430  shockwave_create(OBJ_INDEX(weapon_obj), hitpos, sci, sw_flag, -1);
6431  }
6432  else {
6433  weapon_do_area_effect(weapon_obj, sci, hitpos, other_obj);
6434  }
6435  }
6436 
6437  // check if this is an EMP weapon
6438  if(wip->wi_flags & WIF_EMP){
6440  }
6441 
6442  // spawn weapons - note the change from FS 1 multiplayer.
6443  if (wip->wi_flags & WIF_SPAWN){
6444  if (!((wip->wi_flags3 & WIF3_DONT_SPAWN_IF_SHOT) && (sw_flag == SW_WEAPON_KILL))){ // prevent spawning of children if shot down and the dont spawn if shot flag is set (DahBlount)
6445  spawn_child_weapons(weapon_obj);
6446  }
6447  }
6448 }
6449 
6450 void weapon_detonate(object *objp)
6451 {
6452  Assert(objp != NULL);
6453  if(objp == NULL){
6454  return;
6455  }
6456  Assert((objp->type == OBJ_WEAPON) && (objp->instance >= 0));
6457  if((objp->type != OBJ_WEAPON) || (objp->instance < 0)){
6458  return;
6459  }
6460 
6461  // send a detonate packet in multiplayer
6462  if(MULTIPLAYER_MASTER){
6464  }
6465 
6466  // call weapon hit
6467  // Wanderer - use last frame pos for the corkscrew missiles
6468  if ( (Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_CORKSCREW) ) {
6469  weapon_hit(objp, NULL, &objp->last_pos);
6470  } else {
6471  weapon_hit(objp, NULL, &objp->pos);
6472  }
6473 }
6474 
6475 
6476 // Group_id: If you should quad lasers, they should all have the same group id.
6477 // This will be used to optimize lighting, since each group only needs to cast one light.
6478 // Call this to get a new group id, then pass it to each weapon_create call for all the
6479 // weapons in the group. Number will be between 0 and WEAPON_MAX_GROUP_IDS and will
6480 // get reused.
6482 {
6483  static int current_id = 0;
6484 
6485  int n = current_id;
6486 
6487  current_id++;
6488  if ( current_id >= WEAPON_MAX_GROUP_IDS ) {
6489  current_id = 0;
6490  }
6491  return n;
6492 }
6493 
6497 void weapon_mark_as_used(int weapon_type)
6498 {
6499  if (weapon_type < 0)
6500  return;
6501 
6502  if ( used_weapons == NULL )
6503  return;
6504 
6505  Assert( weapon_type < MAX_WEAPON_TYPES );
6506 
6507  if (weapon_type < Num_weapon_types) {
6508  used_weapons[weapon_type]++;
6509  }
6510 }
6511 
6513 {
6514  int i, j, idx;
6515 
6516  Assert( used_weapons != NULL );
6517 
6518  // for weapons in weaponry pool
6519  for (i = 0; i < Num_teams; i++) {
6520  for (j = 0; j < Team_data[i].num_weapon_choices; j++) {
6521  used_weapons[Team_data[i].weaponry_pool[j]] += Team_data[i].weaponry_count[j];
6522  }
6523  }
6524 
6525  // this grabs all spawn weapon types (Cluster Baby, etc.) which can't be
6526  // assigned directly to a ship
6527  for (i = 0; i < Num_weapon_types; i++) {
6528  // we only want entries that already exist
6529  if ( !used_weapons[i] )
6530  continue;
6531 
6532  // if it's got a spawn type then grab it
6533  for (j = 0; j < Weapon_info[i].num_spawn_weapons_defined; j++)
6534  {
6535  used_weapons[(int)Weapon_info[i].spawn_info[j].spawn_type]++;
6536  }
6537  }
6538 
6539  // release anything loaded that we don't have marked as used for this mission
6540  if ( !Cmdline_load_all_weapons )
6542 
6543  // Page in bitmaps for all used weapons
6544  for (i = 0; i < Num_weapon_types; i++) {
6545  if ( !Cmdline_load_all_weapons ) {
6546  if ( !used_weapons[i] ) {
6547  nprintf(("Weapons", "Not loading weapon id %d (%s)\n", i, Weapon_info[i].name));
6548  continue;
6549  }
6550  }
6551 
6553 
6554  weapon_info *wip = &Weapon_info[i];
6555 
6556  wip->wi_flags &= (~WIF_THRUSTER); // Assume no thrusters
6557 
6558  switch (wip->render_type)
6559  {
6560  case WRT_POF:
6561  {
6562  wip->model_num = model_load( wip->pofbitmap_name, 0, NULL );
6563 
6564  polymodel *pm = model_get( wip->model_num );
6565 
6566  // If it has a model, and the model pof has thrusters, then set
6567  // the flags
6568  if (pm->n_thrusters > 0) {
6569  wip->wi_flags |= WIF_THRUSTER;
6570  }
6571 
6572  for (j = 0; j < pm->n_textures; j++)
6573  pm->maps[j].PageIn();
6574 
6575  break;
6576  }
6577 
6578  case WRT_LASER:
6579  {
6582 
6583  break;
6584  }
6585 
6586  default:
6587  Assertion(wip->render_type != WRT_POF && wip->render_type != WRT_LASER, "Weapon %s does not have a valid rendering type. Type passed: %d\n", wip->name, wip->render_type); // Invalid weapon rendering type.
6588  }
6589 
6590  wip->external_model_num = -1;
6591 
6592  if ( strlen(wip->external_model_name) )
6593  wip->external_model_num = model_load( wip->external_model_name, 0, NULL );
6594 
6595  if (wip->external_model_num == -1)
6596  wip->external_model_num = wip->model_num;
6597 
6598 
6599  //Load shockwaves
6602 
6603  //Explosions
6604  Weapon_explosions.PageIn(wip->impact_weapon_expl_index);
6605  Weapon_explosions.PageIn(wip->dinky_impact_weapon_expl_index);
6606  Weapon_explosions.PageIn(wip->flash_impact_weapon_expl_index);
6607  Weapon_explosions.PageIn(wip->piercing_impact_weapon_expl_index);
6608 
6609  // trail bitmaps
6610  if ( (wip->wi_flags & WIF_TRAIL) && (wip->tr_info.texture.bitmap_id > -1) )
6612 
6613  // if this is a beam weapon, page in its stuff
6614  if (wip->wi_flags & WIF_BEAM) {
6615  // all beam sections
6616  for (idx = 0; idx < wip->b_info.beam_num_sections; idx++)
6618 
6619  // muzzle glow
6621 
6622  // particle ani
6624  }
6625 
6626  if (wip->wi_flags & WIF_PARTICLE_SPEW) {
6627  for (size_t s = 0; s < MAX_PARTICLE_SPEWERS; s++) { // looped, multi particle spew -nuke
6630  }
6631  }
6632  }
6633 
6634  // muzzle flashes
6635  if (wip->muzzle_flash >= 0)
6637 
6640  }
6641 }
6642 
6651 {
6652  int i;
6653 
6654  // don't bother if they are all loaded already
6656  return;
6657 
6658  Assert( used_weapons != NULL );
6659 
6660  // force a page in of all muzzle flashes
6661  mflash_page_in(true);
6662 
6663  // page in models for all weapon types that aren't already loaded
6664  for (i = 0; i < Num_weapon_types; i++) {
6665  // skip over anything that's already loaded
6666  if (used_weapons[i])
6667  continue;
6668 
6670 
6671  weapon_info *wip = &Weapon_info[i];
6672 
6673  wip->wi_flags &= (~WIF_THRUSTER); // Assume no thrusters
6674 
6675  if ( wip->render_type == WRT_POF ) {
6676  wip->model_num = model_load( wip->pofbitmap_name, 0, NULL );
6677 
6678  polymodel *pm = model_get( wip->model_num );
6679 
6680  // If it has a model, and the model pof has thrusters, then set
6681  // the flags
6682  if ( pm->n_thrusters > 0 ) {
6683  wip->wi_flags |= WIF_THRUSTER;
6684  }
6685  }
6686 
6687  wip->external_model_num = -1;
6688 
6689  if ( strlen(wip->external_model_name) )
6690  wip->external_model_num = model_load( wip->external_model_name, 0, NULL );
6691 
6692  if (wip->external_model_num == -1)
6693  wip->external_model_num = wip->model_num;
6694 
6695 
6696  //Load shockwaves
6699 
6700  used_weapons[i]++;
6701  }
6702 }
6703 
6708 {
6709  weapon *wep;
6710  weapon_info *winfo;
6711  float pct;
6712 
6713  // sanity
6714  if (c == NULL)
6715  return;
6716 
6717  // sanity
6718  Assert(objp != NULL);
6719  Assert(objp->type == OBJ_WEAPON);
6720  Assert(objp->instance >= 0);
6721  Assert(Weapons[objp->instance].weapon_info_index >= 0);
6722 
6723  if ( (objp == NULL) || (objp->type != OBJ_WEAPON) || (objp->instance < 0) || (Weapons[objp->instance].weapon_info_index < 0) )
6724  return;
6725 
6726  wep = &Weapons[objp->instance];
6727  winfo = &Weapon_info[wep->weapon_info_index];
6728 
6729  // if we're a one-color laser
6730  if ( (winfo->laser_color_2.red == winfo->laser_color_1.red) && (winfo->laser_color_2.green == winfo->laser_color_1.green) && (winfo->laser_color_2.blue == winfo->laser_color_1.blue) ) {
6731  *c = winfo->laser_color_1;
6732  return;
6733  }
6734 
6735  int r = winfo->laser_color_1.red;
6736  int g = winfo->laser_color_1.green;
6737  int b = winfo->laser_color_1.blue;
6738 
6739  // lifetime pct
6740  pct = 1.0f - (wep->lifeleft / winfo->lifetime);
6741  CLAMP(pct, 0.0f, 0.5f);
6742 
6743  if (pct > 0.0f) {
6744  pct *= 2.0f;
6745 
6746  r += fl2i((winfo->laser_color_2.red - winfo->laser_color_1.red) * pct);
6747  g += fl2i((winfo->laser_color_2.green - winfo->laser_color_1.green) * pct);
6748  b += fl2i((winfo->laser_color_2.blue - winfo->laser_color_1.blue) * pct);
6749  }
6750 
6751  // otherwise interpolate between the colors
6752  gr_init_color( c, r, g, b );
6753 }
6754 
6755 // default weapon particle spew data
6756 
6763 
6768 {
6769  weapon *wp;
6770  weapon_info *wip;
6771  int idx;
6772 
6773  // check some stuff
6774  Assert(obj->type == OBJ_WEAPON);
6775  Assert(obj->instance >= 0);
6776  Assert(Weapons[obj->instance].weapon_info_index >= 0);
6777  Assert(Weapon_info[Weapons[obj->instance].weapon_info_index].wi_flags & WIF_PARTICLE_SPEW);
6778 
6779  wp = &Weapons[obj->instance];
6780  wip = &Weapon_info[wp->weapon_info_index];
6781  vec3d spawn_pos, spawn_vel, output_pos, output_vel, input_pos, input_vel;
6782 
6783  for (int psi = 0; psi < MAX_PARTICLE_SPEWERS; psi++) { // iterate through spewers -nuke
6784  if (wip->particle_spewers[psi].particle_spew_type != PSPEW_NONE) {
6785  // if the weapon's particle timestamp has elapsed
6786  if ((wp->particle_spew_time[psi] == -1) || timestamp_elapsed(wp->particle_spew_time[psi])) {
6787  // reset the timestamp
6789 
6790  // turn normals and origins to world space if we need to
6791  if (!vm_vec_same(&wip->particle_spewers[psi].particle_spew_offset, &vmd_zero_vector)) { // don't xform unused vectors
6792  vm_vec_unrotate(&spawn_pos, &wip->particle_spewers[psi].particle_spew_offset, &obj->orient);
6793  } else {
6794  spawn_pos = vmd_zero_vector;
6795  }
6796 
6798  vm_vec_unrotate(&spawn_vel, &wip->particle_spewers[psi].particle_spew_velocity, &obj->orient);
6799  } else {
6800  spawn_vel = vmd_zero_vector;
6801  }
6802 
6803  // spew some particles
6804  if (wip->particle_spewers[psi].particle_spew_type == PSPEW_DEFAULT) // default pspew type
6805  { // do the default pspew
6806  vec3d direct, direct_temp, particle_pos;
6807  vec3d null_vec = ZERO_VECTOR;
6808  vec3d vel;
6809  float ang;
6810 
6811  for (idx = 0; idx < wip->particle_spewers[psi].particle_spew_count; idx++) {
6812  // get the backward vector of the weapon
6813  direct = obj->orient.vec.fvec;
6814  vm_vec_negate(&direct);
6815 
6816  // randomly perturb x, y and z
6817 
6818  // uvec
6819  ang = frand_range(-PI_2,PI_2); // fl_radian(frand_range(-90.0f, 90.0f)); -optimized by nuke
6820  vm_rot_point_around_line(&direct_temp, &direct, ang, &null_vec, &obj->orient.vec.fvec);
6821  direct = direct_temp;
6823 
6824  // rvec
6825  ang = frand_range(-PI_2,PI_2); // fl_radian(frand_range(-90.0f, 90.0f)); -optimized by nuke
6826  vm_rot_point_around_line(&direct_temp, &direct, ang, &null_vec, &obj->orient.vec.rvec);
6827  direct = direct_temp;
6829 
6830  // fvec
6831  ang = frand_range(-PI_2,PI_2); // fl_radian(frand_range(-90.0f, 90.0f)); -optimized by nuke
6832  vm_rot_point_around_line(&direct_temp, &direct, ang, &null_vec, &obj->orient.vec.uvec);
6833  direct = direct_temp;
6835 
6836  // get a velocity vector of some percentage of the weapon's velocity
6837  vel = obj->phys_info.vel;
6839 
6840  // maybe add in offset and initial velocity
6841  if (!vm_vec_same(&spawn_vel, &vmd_zero_vector)) { // add in particle velocity if its available
6842  vm_vec_add2(&vel, &spawn_vel);
6843  }
6844  if (!vm_vec_same(&spawn_pos, &vmd_zero_vector)) { // add offset if available
6845  vm_vec_add2(&direct, &spawn_pos);
6846  }
6847 
6848  if (wip->wi_flags & WIF_CORKSCREW) {
6849  vm_vec_add(&particle_pos, &obj->last_pos, &direct);
6850  } else {
6851  vm_vec_add(&particle_pos, &obj->pos, &direct);
6852  }
6853 
6854  // emit the particle
6855  if (wip->particle_spewers[psi].particle_spew_anim.first_frame < 0) {
6857  } else {
6859  }
6860  }
6861  } else if (wip->particle_spewers[psi].particle_spew_type == PSPEW_HELIX) { // helix
6862  float segment_length = wip->max_speed * flFrametime; // determine how long the segment is
6863  float segment_angular_length = PI2 * wip->particle_spewers[psi].particle_spew_rotation_rate * flFrametime; // determine how much the segment rotates
6864  float rotation_value = (wp->lifeleft * PI2 * wip->particle_spewers[psi].particle_spew_rotation_rate) + wp->particle_spew_rand; // calculate a rotational start point based on remaining life
6865  float inc = 1.0f / wip->particle_spewers[psi].particle_spew_count; // determine our incriment
6866  float particle_rot;
6867  vec3d input_pos_l = ZERO_VECTOR;
6868 
6869  for (float is = 0; is < 1; is += inc ) { // use iterator as a scaler
6870  particle_rot = rotation_value + (segment_angular_length * is); // find what point of the rotation were at
6871  input_vel.xyz.x = sinf(particle_rot) * wip->particle_spewers[psi].particle_spew_scale; // determine x/y velocity based on scale and rotation
6872  input_vel.xyz.y = cosf(particle_rot) * wip->particle_spewers[psi].particle_spew_scale;
6873  input_vel.xyz.z = wip->max_speed * wip->particle_spewers[psi].particle_spew_vel; // velocity inheritance
6874  vm_vec_unrotate(&output_vel, &input_vel, &obj->orient); // orient velocity to weapon
6875  input_pos_l.xyz.x = input_vel.xyz.x * flFrametime * (1.0f - is); // interpolate particle motion
6876  input_pos_l.xyz.y = input_vel.xyz.y * flFrametime * (1.0f - is);
6877  input_pos_l.xyz.z = segment_length * is; // position particle correctly on the z axis
6878  vm_vec_unrotate(&input_pos, &input_pos_l, &obj->orient); // orient to weapon
6879  vm_vec_sub(&output_pos, &obj->pos, &input_pos); // translate to world space
6880 
6881  //maybe add in offset and initial velocity
6882  if (!vm_vec_same(&spawn_vel, &vmd_zero_vector)) { // add particle velocity if needed
6883  vm_vec_add2(&output_vel, &spawn_vel);
6884  }
6885  if (!vm_vec_same(&spawn_pos, &vmd_zero_vector)) { // add offset if needed
6886  vm_vec_add2(&output_pos, &spawn_pos);
6887  }
6888 
6889  //emit particles
6890  if (wip->particle_spewers[psi].particle_spew_anim.first_frame < 0) {
6892  } else {
6894  }
6895  }
6896  } else if (wip->particle_spewers[psi].particle_spew_type == PSPEW_SPARKLER) { // sparkler
6897  vec3d temp_vel;
6898  output_vel = obj->phys_info.vel;
6899  vm_vec_scale(&output_vel, wip->particle_spewers[psi].particle_spew_vel);
6900 
6901  for (idx = 0; idx < wip->particle_spewers[psi].particle_spew_count; idx++) {
6902  // create a random unit vector and scale it
6903  vm_vec_rand_vec_quick(&input_vel);
6904  vm_vec_scale(&input_vel, wip->particle_spewers[psi].particle_spew_scale);
6905 
6906  if (wip->particle_spewers[psi].particle_spew_z_scale != 1.0f) { // don't do the extra math for spherical effect
6907  temp_vel = input_vel;
6908  temp_vel.xyz.z *= wip->particle_spewers[psi].particle_spew_z_scale; // for an ovoid particle effect to better combine with laser effects
6909  vm_vec_unrotate(&input_vel, &temp_vel, &obj->orient); // so it has to be rotated
6910  }
6911 
6912  vm_vec_add2(&output_vel, &input_vel); // add to weapon velocity
6913  output_pos = obj->pos;
6914 
6915  // maybe add in offset and initial velocity
6916  if (!vm_vec_same(&spawn_vel, &vmd_zero_vector)) { // add particle velocity if needed
6917  vm_vec_add2(&output_vel, &spawn_vel);
6918  }
6919  if (!vm_vec_same(&spawn_pos, &vmd_zero_vector)) { // add offset if needed
6920  vm_vec_add2(&output_pos, &spawn_pos);
6921  }
6922 
6923  // emit particles
6924  if (wip->particle_spewers[psi].particle_spew_anim.first_frame < 0) {
6926  } else {
6928  }
6929  }
6930  } else if (wip->particle_spewers[psi].particle_spew_type == PSPEW_RING) {
6931  float inc = PI2 / wip->particle_spewers[psi].particle_spew_count;
6932 
6933  for (float ir = 0; ir < PI2; ir += inc) { // use iterator for rotation
6934  input_vel.xyz.x = sinf(ir) * wip->particle_spewers[psi].particle_spew_scale; // generate velocity from rotation data
6935  input_vel.xyz.y = cosf(ir) * wip->particle_spewers[psi].particle_spew_scale;
6936  input_vel.xyz.z = obj->phys_info.fspeed * wip->particle_spewers[psi].particle_spew_vel;
6937  vm_vec_unrotate(&output_vel, &input_vel, &obj->orient); // rotate it to model
6938 
6939  output_pos = obj->pos;
6940 
6941  // maybe add in offset amd iitial velocity
6942  if (!vm_vec_same(&spawn_vel, &vmd_zero_vector)) { // add particle velocity if needed
6943  vm_vec_add2(&output_vel, &spawn_vel);
6944  }
6945  if (!vm_vec_same(&spawn_pos, &vmd_zero_vector)) { // add offset if needed
6946  vm_vec_add2(&output_pos, &spawn_pos);
6947  }
6948 
6949  // emit particles
6950  if (wip->particle_spewers[psi].particle_spew_anim.first_frame < 0) {
6952  } else {
6954  }
6955  }
6956  } else if (wip->particle_spewers[psi].particle_spew_type == PSPEW_PLUME) {
6957  float ang_rand, len_rand, sin_ang, cos_ang;
6958  vec3d input_pos_l = ZERO_VECTOR;
6959 
6960  for (int i = 0; i < wip->particle_spewers[psi].particle_spew_count; i++) {
6961  // use polar coordinates to ensure a disk shaped spew plane
6962  ang_rand = frand_range(-PI,PI);
6963  len_rand = frand() * wip->particle_spewers[psi].particle_spew_scale;
6964  sin_ang = sinf(ang_rand);
6965  cos_ang = cosf(ang_rand);
6966  // compute velocity
6967  input_vel.xyz.x = wip->particle_spewers[psi].particle_spew_z_scale * -sin_ang;
6968  input_vel.xyz.y = wip->particle_spewers[psi].particle_spew_z_scale * -cos_ang;
6969  input_vel.xyz.z = obj->phys_info.fspeed * wip->particle_spewers[psi].particle_spew_vel;
6970  vm_vec_unrotate(&output_vel, &input_vel, &obj->orient); // rotate it to model
6971  // place particle on a disk prependicular to the weapon normal and rotate to model space
6972  input_pos_l.xyz.x = sin_ang * len_rand;
6973  input_pos_l.xyz.y = cos_ang * len_rand;
6974  vm_vec_unrotate(&input_pos, &input_pos_l, &obj->orient); // rotate to world
6975  vm_vec_sub(&output_pos, &obj->pos, &input_pos); // translate to world
6976 
6977  // maybe add in offset amd iitial velocity
6978  if (!vm_vec_same(&spawn_vel, &vmd_zero_vector)) { // add particle velocity if needed
6979  vm_vec_add2(&output_vel, &spawn_vel);
6980  }
6981  if (!vm_vec_same(&spawn_pos, &vmd_zero_vector)) { // add offset if needed
6982  vm_vec_add2(&output_pos, &spawn_pos);
6983  }
6984 
6985  //emit particles
6986  if (wip->particle_spewers[psi].particle_spew_anim.first_frame < 0) {
6988  } else {
6990  }
6991  }
6992  }
6993  }
6994  }
6995  }
6996 }
6997 
7001 void dcf_pspew();
7002 DCF(pspew_count, "Number of particles spewed at a time")
7003 {
7004  if (dc_optional_string_either("help", "--help")) {
7005  dcf_pspew();
7006  return;
7007  }
7008 
7009  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
7010  dc_printf("Partical count is %i\n", Weapon_particle_spew_count);
7011  return;
7012  }
7013 
7014  dc_stuff_int(&Weapon_particle_spew_count);
7015 
7016  dc_printf("Partical count set to %i\n", Weapon_particle_spew_count);
7017 }
7018 
7019 DCF(pspew_time, "Time between particle spews")
7020 {
7021  if (dc_optional_string_either("help", "--help")) {
7022  dcf_pspew();
7023  return;
7024  }
7025 
7026  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
7027  dc_printf("Particle spawn period is %i\n", Weapon_particle_spew_time);
7028  return;
7029  }
7030 
7031  dc_stuff_int(&Weapon_particle_spew_time);
7032 
7033  dc_printf("Particle spawn period set to %i\n", Weapon_particle_spew_time);
7034 }
7035 
7036 DCF(pspew_vel, "Relative velocity of particles (0.0 - 1.0)")
7037 {
7038  if (dc_optional_string_either("help", "--help")) {
7039  dcf_pspew();
7040  return;
7041  }
7042 
7043  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
7044  dc_printf("Particle relative velocity is %f\n", Weapon_particle_spew_vel);
7045  return;
7046  }
7047 
7048  dc_stuff_float(&Weapon_particle_spew_vel);
7049 
7050  dc_printf("Particle relative velocity set to %f\n", Weapon_particle_spew_vel);
7051 }
7052 
7053 DCF(pspew_size, "Size of spewed particles")
7054 {
7055  if (dc_optional_string_either("help", "--help")) {
7056  dcf_pspew();
7057  return;
7058  }
7059 
7060  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
7061  dc_printf("Particle size is %f\n", Weapon_particle_spew_radius);
7062  return;
7063  }
7064 
7065  dc_stuff_float(&Weapon_particle_spew_radius);
7066 
7067  dc_printf("Particle size set to %f\n", Weapon_particle_spew_radius);
7068 }
7069 
7070 DCF(pspew_life, "Lifetime of spewed particles")
7071 {
7072  if (dc_optional_string_either("help", "--help")) {
7073  dcf_pspew();
7074  return;
7075  }
7076 
7077  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
7078  dc_printf("Particle lifetime is %f\n", Weapon_particle_spew_lifetime);
7079  return;
7080  }
7081 
7082  dc_stuff_float(&Weapon_particle_spew_lifetime);
7083 
7084  dc_printf("Particle lifetime set to %f\n", Weapon_particle_spew_lifetime);
7085 }
7086 
7087 DCF(pspew_scale, "How far away particles are from the weapon path")
7088 {
7089  if (dc_optional_string_either("help", "--help")) {
7090  dcf_pspew();
7091  return;
7092  }
7093 
7094  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
7095  dc_printf("Particle scale is %f\n", Weapon_particle_spew_scale);
7096  }
7097 
7098  dc_stuff_float(&Weapon_particle_spew_scale);
7099 
7100  dc_printf("Particle scale set to %f\n", Weapon_particle_spew_scale);
7101 }
7102 
7103 // Help and Status provider
7104 DCF(pspew, "Particle spew help and status provider")
7105 {
7106  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
7107  dc_printf("Particle spew settings\n\n");
7108 
7109  dc_printf(" Count (pspew_count) : %d\n", Weapon_particle_spew_count);
7110  dc_printf(" Time (pspew_time) : %d\n", Weapon_particle_spew_time);
7111  dc_printf(" Velocity (pspew_vel) : %f\n", Weapon_particle_spew_vel);
7112  dc_printf(" Size (pspew_size) : %f\n", Weapon_particle_spew_radius);
7113  dc_printf(" Lifetime (pspew_life) : %f\n", Weapon_particle_spew_lifetime);
7114  dc_printf(" Scale (psnew_scale) : %f\n", Weapon_particle_spew_scale);
7115  return;
7116  }
7117 
7118  dc_printf("Available particlar spew commands:\n");
7119  dc_printf("pspew_count : %s\n", dcmd_pspew_count.help);
7120  dc_printf("pspew_time : %s\n", dcmd_pspew_time.help);
7121  dc_printf("pspew_vel : %s\n", dcmd_pspew_vel.help);
7122  dc_printf("pspew_size : %s\n", dcmd_pspew_size.help);
7123  dc_printf("pspew_life : %s\n", dcmd_pspew_life.help);
7124  dc_printf("pspew_scale : %s\n\n", dcmd_pspew_scale.help);
7125 
7126  dc_printf("To view status of all pspew settings, type in 'pspew --status'.\n");
7127  dc_printf("Passing '--status' as an argument to any of the individual spew commands will show the status of that variable only.\n\n");
7128 
7129  dc_printf("These commands adjust the various properties of the particle spew system, which is used by weapons when they are fired, are in-flight, and die (either by impact or by end of life time.\n");
7130  dc_printf("Generally, a large particle count with small size and scale will result in a nice dense particle spew.\n");
7131  dc_printf("Be advised, this effect is applied to _ALL_ weapons, and as such may drastically reduce framerates on lower powered platforms.\n");
7132 }
7133 
7137 float weapon_get_damage_scale(weapon_info *wip, object *wep, object *target)
7138 {
7139  weapon *wp;
7140  int from_player = 0;
7141  float total_scale = 1.0f;
7142  float hull_pct;
7143  int is_big_damage_ship = 0;
7144 
7145  // Goober5000 - additional sanity (target can be NULL)
7146  Assert(wip);
7147  Assert(wep);
7148 
7149  // sanity
7150  if((wip == NULL) || (wep == NULL) || (target == NULL)){
7151  return 1.0f;
7152  }
7153 
7154  // don't scale any damage if its not a weapon
7155  if((wep->type != OBJ_WEAPON) || (wep->instance < 0) || (wep->instance >= MAX_WEAPONS)){
7156  return 1.0f;
7157  }
7158  wp = &Weapons[wep->instance];
7159 
7160  // was the weapon fired by the player
7161  from_player = 0;
7162  if((wep->parent >= 0) && (wep->parent < MAX_OBJECTS) && (Objects[wep->parent].flags & OF_PLAYER_SHIP)){
7163  from_player = 1;
7164  }
7165 
7166  // if this is a lockarm weapon, and it was fired unlocked
7167  if((wip->wi_flags & WIF_LOCKARM) && !(wp->weapon_flags & WF_LOCKED_WHEN_FIRED)){
7168  total_scale *= 0.1f;
7169  }
7170 
7171  // if the hit object was a ship and we're doing damage scaling
7172  if ( (target->type == OBJ_SHIP) &&
7175  ) {
7176  ship_info *sip;
7177 
7178  // get some info on the ship
7179  Assert((target->instance >= 0) && (target->instance < MAX_SHIPS));
7180  if((target->instance < 0) || (target->instance >= MAX_SHIPS)){
7181  return total_scale;
7182  }
7183  sip = &Ship_info[Ships[target->instance].ship_info_index];
7184 
7185  // get hull pct of the ship currently
7186  hull_pct = get_hull_pct(target);
7187 
7188  // if it has hit a supercap ship and is not a supercap class weapon
7189  if((sip->flags & SIF_SUPERCAP) && !(wip->wi_flags & WIF_SUPERCAP)){
7190  // if the supercap is around 3/4 damage, apply nothing
7191  if(hull_pct <= 0.75f){
7192  return 0.0f;
7193  } else {
7194  total_scale *= SUPERCAP_DAMAGE_SCALE;
7195  }
7196  }
7197 
7198  // determine if this is a big damage ship
7199  is_big_damage_ship = (sip->flags & SIF_BIG_DAMAGE);
7200 
7201  // if this is a large ship, and is being hit by flak
7202  if(is_big_damage_ship && (wip->wi_flags & WIF_FLAK)){
7203  total_scale *= FLAK_DAMAGE_SCALE;
7204  }
7205 
7206  // if the weapon is a small weapon being fired at a big ship
7207  if( is_big_damage_ship && !(wip->wi_flags & (WIF_HURTS_BIG_SHIPS)) ){
7208 
7209  // if the player is firing it
7210  if ( from_player && !(The_mission.ai_profile->flags2 & AIPF2_PLAYER_WEAPON_SCALE_FIX)) {
7211  // if it's a laser weapon
7212  if(wip->subtype == WP_LASER){
7213  total_scale *= 0.01f;
7214  } else {
7215  total_scale *= 0.05f;
7216  }
7217  }
7218 
7219  // scale based on hull
7220  if(hull_pct > 0.1f){
7221  total_scale *= hull_pct;
7222  } else {
7223  return 0.0f;
7224  }
7225  }
7226  }
7227 
7228  return total_scale;
7229 }
7230 
7232 {
7233  for (int i = 0; i < MAX_WEAPONS; i++)
7234  {
7235  if (Weapons[i].objnum != -1)
7236  {
7237  weapon* wp = &Weapons[i];
7238 
7240  {
7241  // Stop sound, it will be restarted in the first frame after the game is unpaused
7243  }
7244  }
7245  }
7246 }
7247 
7249 {
7250  // Pause all beam sounds
7252 
7253  // Pause in-flight sounds
7255 }
7256 
7258 {
7259  // Pause all beam sounds
7261 }
7262 
7263 void shield_impact_explosion(vec3d *hitpos, object *objp, float radius, int idx) {
7264  int expl_ani_handle = Weapon_explosions.GetAnim(idx, hitpos, radius);
7265  particle_create( hitpos, &vmd_zero_vector, 0.0f, radius, PARTICLE_BITMAP_PERSISTENT, expl_ani_handle, -1.0f, objp );
7266 }
7267 
7268 void weapon_render(object* obj, draw_list *scene)
7269 {
7270  int num;
7271  weapon_info *wip;
7272  weapon *wp;
7273  color c;
7274 
7275  MONITOR_INC(NumWeaponsRend, 1);
7276 
7277  Assert(obj->type == OBJ_WEAPON);
7278 
7279  num = obj->instance;
7280  wp = &Weapons[num];
7281  wip = &Weapon_info[Weapons[num].weapon_info_index];
7282 
7283  if (wip->wi_flags2 & WIF2_TRANSPARENT) {
7284  if (wp->alpha_current == -1.0f) {
7285  wp->alpha_current = wip->alpha_max;
7286  } else if (wip->alpha_cycle > 0.0f) {
7287  if (wp->alpha_backward) {
7288  wp->alpha_current += wip->alpha_cycle;
7289 
7290  if (wp->alpha_current > wip->alpha_max) {
7291  wp->alpha_current = wip->alpha_max;
7292  wp->alpha_backward = 0;
7293  }
7294  } else {
7295  wp->alpha_current -= wip->alpha_cycle;
7296 
7297  if (wp->alpha_current < wip->alpha_min) {
7298  wp->alpha_current = wip->alpha_min;
7299  wp->alpha_backward = 1;
7300  }
7301  }
7302  }
7303  }
7304 
7305  switch (wip->render_type)
7306  {
7307  case WRT_LASER:
7308  {
7309  if(wip->laser_length < 0.0001f)
7310  return;
7311 
7312  int alpha = 255;
7313  int framenum = 0;
7314 
7315  if (wip->laser_bitmap.first_frame >= 0) {
7317 
7318  if (wip->laser_bitmap.num_frames > 1) {
7320 
7321  // Sanity checks
7322  if (wp->laser_bitmap_frame < 0.0f)
7323  wp->laser_bitmap_frame = 0.0f;
7324  if (wp->laser_bitmap_frame > 100.0f)
7325  wp->laser_bitmap_frame = 0.0f;
7326 
7327  while (wp->laser_bitmap_frame > wip->laser_bitmap.total_time)
7329 
7330  framenum = fl2i( (wp->laser_bitmap_frame * wip->laser_bitmap.num_frames) / wip->laser_bitmap.total_time );
7331 
7332  CLAMP(framenum, 0, wip->laser_bitmap.num_frames-1);
7333  }
7334 
7335  if (wip->wi_flags2 & WIF2_TRANSPARENT)
7336  alpha = fl2i(wp->alpha_current * 255.0f);
7337 
7338  vec3d headp;
7339 
7340  vm_vec_scale_add(&headp, &obj->pos, &obj->orient.vec.fvec, wip->laser_length);
7342 
7343  if ( batch_add_laser(wip->laser_bitmap.first_frame + framenum, &headp, wip->laser_head_radius, &obj->pos, wip->laser_tail_radius, alpha, alpha, alpha) ) {
7345  }
7346  }
7347 
7348  // maybe draw laser glow bitmap
7349  if (wip->laser_glow_bitmap.first_frame >= 0) {
7350  // get the laser color
7351  weapon_get_laser_color(&c, obj);
7352 
7353  // *Tail point "getting bigger" as well as headpoint isn't being taken into consideration, so
7354  // it caused uneven glow between the head and tail, which really shows in big lasers. So...fixed! -Et1
7355  vec3d headp2, tailp;
7356 
7357  vm_vec_scale_add(&headp2, &obj->pos, &obj->orient.vec.fvec, wip->laser_length * weapon_glow_scale_l);
7358  vm_vec_scale_add(&tailp, &obj->pos, &obj->orient.vec.fvec, wip->laser_length * (1 - weapon_glow_scale_l) );
7359 
7360  framenum = 0;
7361 
7362  if (wip->laser_glow_bitmap.num_frames > 1) {
7364 
7365  // Sanity checks
7366  if (wp->laser_glow_bitmap_frame < 0.0f)
7367  wp->laser_glow_bitmap_frame = 0.0f;
7368  if (wp->laser_glow_bitmap_frame > 100.0f)
7369  wp->laser_glow_bitmap_frame = 0.0f;
7370 
7373 
7375 
7376  CLAMP(framenum, 0, wip->laser_glow_bitmap.num_frames-1);
7377  }
7378 
7379  if (wip->wi_flags2 & WIF2_TRANSPARENT) {
7380  alpha = fl2i(wp->alpha_current * 255.0f);
7381  alpha -= 38; // take 1.5f into account for the normal glow alpha
7382 
7383  if (alpha < 0)
7384  alpha = 0;
7385  } else {
7386  alpha = weapon_glow_alpha;
7387  }
7388 
7389  batch_add_laser(wip->laser_glow_bitmap.first_frame + framenum, &headp2, wip->laser_head_radius * weapon_glow_scale_f, &tailp, wip->laser_tail_radius * weapon_glow_scale_r, (c.red*alpha)/255, (c.green*alpha)/255, (c.blue*alpha)/255);
7390  }
7391 
7392  break;
7393  }
7394 
7395  case WRT_POF:
7396  {
7397  model_render_params render_info;
7398 
7400 
7402  render_flags &= ~MR_NO_LIGHTING;
7403 
7404  if (wip->wi_flags2 & WIF2_TRANSPARENT) {
7405  render_info.set_alpha(wp->alpha_current);
7406  render_flags |= MR_ALL_XPARENT;
7407  }
7408 
7410 
7411  if ( (wip->wi_flags & WIF_THRUSTER) && ((wp->thruster_bitmap > -1) || (wp->thruster_glow_bitmap > -1)) ) {
7412  float ft;
7413  mst_info mst;
7414 
7415  // Add noise to thruster geometry.
7416  ft = 1.0f; // Always use 1.0f for missiles
7417  ft *= (1.0f + frand()/5.0f - 1.0f/10.0f);
7418  if (ft > 1.0f)
7419  ft = 1.0f;
7420 
7421  mst.length.xyz.x = ft;
7422  mst.length.xyz.y = ft;
7423  mst.length.xyz.z = ft;
7424 
7425  mst.primary_bitmap = wp->thruster_bitmap;
7428  mst.glow_noise = wp->thruster_glow_noise;
7429 
7430  render_info.set_thruster_info(mst);
7431 
7432  render_flags |= MR_SHOW_THRUSTERS;
7433  }
7434 
7435 
7436  //don't render local ssm's when they are still in subspace
7437  if (wp->lssm_stage==3)
7438  break;
7439 
7440  // start a clip plane
7441  if ( wp->lssm_stage == 2 ) {
7442  object *wobj=&Objects[wp->lssm_warp_idx]; //warphole object
7443 
7444  render_info.set_clip_plane(wobj->pos, wobj->orient.vec.fvec);
7445  }
7446 
7447  render_info.set_flags(render_flags);
7448 
7449  model_render_queue(&render_info, scene, wip->model_num, &obj->orient, &obj->pos);
7451 
7452  break;
7453  }
7454 
7455  default:
7456  Warning(LOCATION, "Unknown weapon rendering type = %i for weapon %s\n", wip->render_type, wip->name);
7457  }
7458 }
7459 
7460 // Called by hudartillery.cpp after SSMs have been parsed to make sure that $SSM: entries defined in weapons are valid.
7462 {
7463  int wi;
7465  weapon_info *wip;
7466 
7467  for (it = Delayed_SSM_names.begin(); it != Delayed_SSM_names.end(); ++it) {
7468  delayed_ssm_data *dat = &Delayed_SSM_data[*it];
7469  wi = weapon_info_lookup(it->c_str());
7470  Assertion(wi >= 0, "Trying to validate non-existant weapon '%s'; get a coder!\n", it->c_str());
7471  wip = &Weapon_info[wi];
7472  nprintf(("parse", "Starting validation of '%s' [wip->name is '%s'], currently has an SSM_index of %d.\n", it->c_str(), wip->name, wip->SSM_index));
7473  wip->SSM_index = ssm_info_lookup(dat->ssm_entry.c_str());
7474  if (wip->SSM_index < 0) {
7475  Warning(LOCATION, "Unknown SSM entry '%s' in specification for %s (%s:line %d).\n", dat->ssm_entry.c_str(), it->c_str(), dat->filename.c_str(), dat->linenum);
7476  }
7477  nprintf(("parse", "Validation complete, SSM_index is %d.\n", wip->SSM_index));
7478  }
7479 
7480  // This information is no longer relevant, so might as well clear it out.
7481  Delayed_SSM_data.clear();
7482  Delayed_SSM_names.clear();
7483 
7484  for (it = Delayed_SSM_indices.begin(); it != Delayed_SSM_indices.end(); ++it) {
7485  delayed_ssm_index_data *dat = &Delayed_SSM_indices_data[*it];
7486  wi = weapon_info_lookup(it->c_str());
7487  Assertion(wi >= 0, "Trying to validate non-existant weapon '%s'; get a coder!\n", it->c_str());
7488  wip = &Weapon_info[wi];
7489  nprintf(("parse", "Starting validation of '%s' [wip->name is '%s'], currently has an SSM_index of %d.\n", it->c_str(), wip->name, wip->SSM_index));
7490  if (wip->SSM_index < -1 || wip->SSM_index >= static_cast<int>(Ssm_info.size())) {
7491  Warning(LOCATION, "Invalid SSM index '%d' (should be 0-" SIZE_T_ARG ") in specification for %s (%s:line %d).\n", wip->SSM_index, Ssm_info.size() - 1, it->c_str(), dat->filename.c_str(), dat->linenum);
7492  wip->SSM_index = -1;
7493  }
7494  nprintf(("parse", "Validation complete, SSM-index is %d.\n", wip->SSM_index));
7495  }
7496 }
void cscrew_delete(int i)
Definition: corkscrew.cpp:167
#define SSF_MISSILES_IGNORE_IF_DEAD
Definition: ship.h:291
#define WIF_EMP
Definition: weapon.h:73
int target_num
Definition: weapon.h:172
#define OF_INVULNERABLE
Definition: object.h:107
#define WIF3_USE_EMP_TIME_FOR_CAPSHIP_TURRETS
Definition: weapon.h:118
#define WIF3_CMEASURE_ASPECT_HOME_ON
Definition: weapon.h:121
short cscrew_index
Definition: weapon.h:204
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
#define WIF2_VARIABLE_LEAD_HOMING
Definition: weapon.h:98
void radar_plot_object(object *objp)
Definition: radarsetup.cpp:146
int muzzle_flash
Definition: weapon.h:463
int particle_spew_type
Definition: weapon.h:281
#define WIF_NO_DUMBFIRE
Definition: weapon.h:65
#define WEAPON_LIST_TYPE
Definition: parselo.h:51
int timestamp(int delta_ms)
Definition: timer.cpp:226
void ai_update_danger_weapon(int objnum, int weapon_objnum)
Definition: aicode.cpp:1056
int stamp
Definition: trails.h:29
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
int launch_snd
Definition: weapon.h:414
vec3d target_pos2
Definition: beam.h:65
fix creation_time
Definition: weapon.h:175
#define WIF2_TAKES_BLAST_DAMAGE
Definition: weapon.h:110
char tech_model[MAX_FILENAME_LEN]
Definition: weapon.h:338
void obj_set_flags(object *obj, uint new_flags)
Definition: object.cpp:1000
int Framecount
Definition: systemvars.cpp:22
int i
Definition: multi_pxo.cpp:466
float nearest_dist
Definition: weapon.h:174
fix Missiontime
Definition: systemvars.cpp:19
#define WP_UNUSED
Definition: weapon.h:26
int lock_pixels_per_sec
Definition: weapon.h:402
#define WIF_BOMBER_PLUS
Definition: weapon.h:69
void weapon_pause_sounds()
Definition: weapons.cpp:7248
int mflash_lookup(char *name)
#define vm_free(ptr)
Definition: pstypes.h:548
int n_textures
Definition: model.h:761
float p
Definition: pstypes.h:111
#define WEAPONS_MULTITEXT_LENGTH
Definition: weapons.cpp:1126
int stuff_string_list(SCP_vector< SCP_string > &slp)
Definition: parselo.cpp:2689
model_subsystem * system_info
Definition: ship.h:314
#define WIF_CMEASURE
Definition: weapon.h:51
char * tech_desc
Definition: weapon.h:335
#define Verify(x)
Definition: pstypes.h:272
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:103
SCP_vector< ArmorType > Armor_types
Definition: ship.cpp:170
float cm_aspect_effectiveness
Definition: weapon.h:503
#define MIN(a, b)
Definition: pstypes.h:296
#define MAX_SHIP_PRIMARY_BANKS
Definition: globals.h:62
int elec_time
Definition: weapon.h:479
float fof_spread_rate
Definition: weapon.h:495
void weapon_init()
Definition: weapons.cpp:3516
float min_lock_time
Definition: weapon.h:401
int group_id
Definition: weapon.h:184
int team
Definition: ship.h:606
#define PSPEW_SPARKLER
Definition: weapon.h:156
#define PSPEW_DEFAULT
Definition: weapon.h:154
float particle_spew_scale
Definition: weapon.h:287
int beam_info_index
Definition: beam.h:57
char name[NAME_LENGTH]
Definition: weapon.h:322
void weapon_do_electronics_effect(object *ship_objp, vec3d *blast_pos, int wi_index)
Definition: weapons.cpp:5934
void validate_SSM_entries()
Definition: weapons.cpp:7461
#define MR_NORMAL
Definition: model.h:858
object * homing_object
Definition: weapon.h:177
void weapon_load_bitmaps(int weapon_index)
Definition: weapons.cpp:3275
int parse_string_flag_list(int *dest, flag_def_list defs[], int defs_size)
Definition: parselo.cpp:2665
int Game_mode
Definition: systemvars.cpp:24
int SwarmWait
Definition: weapon.h:511
#define F1_0
Definition: fix.h:15
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
int Num_burst_fire_flags
Definition: weapons.cpp:99
int flyby_snd
Definition: weapon.h:417
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
vec3d mins
Definition: model.h:746
void trail_level_init()
Definition: trails.cpp:26
float arm_radius
Definition: weapon.h:371
size_t num_substitution_patterns
Definition: weapon.h:546
float laser_glow_bitmap_frame
Definition: weapon.h:196
int weapon_create_group_id()
Definition: weapons.cpp:6481
void missile_obj_list_rebuild()
Definition: weapons.cpp:441
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
int total_children_spawned
Definition: weapon.h:394
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
int external_model_num
Definition: weapon.h:331
int obj_team(object *objp)
Definition: object.cpp:1843
#define SIF_SUPERCAP
Definition: ship.h:901
float nearest_locked_distance
Definition: ai.h:487
#define MAX_BEAMS
Definition: beam.h:40
float thruster_glow_noise
Definition: weapon.h:192
int weapon_info_lookup(const char *name)
Definition: weapons.cpp:467
int stuff_int_optional(int *i, bool raw)
Definition: parselo.cpp:2387
ship_weapon weapons
Definition: ship.h:658
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
object * target
Definition: beam.h:62
float fire_wait
Definition: weapon.h:359
#define WIF2_RENDER_FLAK
Definition: weapon.h:113
void g3_stop_user_clip_plane()
Definition: 3dsetup.cpp:408
int species
Definition: weapon.h:168
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
generic_anim laser_bitmap
Definition: weapon.h:346
vec3d closeup_pos
Definition: weapon.h:340
char parent_type
Definition: object.h:149
#define WIF_LOCKED_HOMING
Definition: weapon.h:130
char * Weapon_subtype_names[]
Definition: weapons.cpp:87
int Cmeasures_homing_check
Definition: cmeasure.cpp:22
#define WIF_HURTS_BIG_SHIPS
Definition: weapon.h:131
float flFrametime
Definition: fredstubs.cpp:22
#define ESUCK_DEFAULT_WEAPON_REDUCE
Definition: weapons.cpp:134
#define WIF2_CYCLE
Definition: weapon.h:89
int beam_loop_sound
Definition: weapon.h:263
fix arm_time
Definition: weapon.h:369
#define MR_ALL_XPARENT
Definition: model.h:877
vec3d desired_vel
Definition: physics.h:70
GLuint index
Definition: Glext.h:5608
Definition: weapon.h:163
#define WIF_BIG_ONLY
Definition: weapon.h:61
ushort multi_get_next_network_signature(int what_kind)
Definition: multiutil.cpp:168
int active_goal
Definition: ai.h:413
void set_thruster_info(mst_info &info)
physics_info phys_info
Definition: object.h:157
player * m_player
Definition: multi.h:459
int Fred_running
Definition: fred.cpp:44
int trail_stamp_elapsed(trail *trailp)
Definition: trails.cpp:572
void weapon_set_tracking_info(int weapon_objnum, int parent_objnum, int target_objnum, int target_is_locked, ship_subsys *target_subsys)
Definition: weapons.cpp:5093
generic_anim beam_glow
Definition: weapon.h:267
#define WIF_HUGE
Definition: weapon.h:64
#define MAX_SHIPS
Definition: globals.h:37
void weapon_close()
Definition: weapons.cpp:3545
#define WF_PLAYED_FLYBY_SOUND
Definition: weapon.h:139
SCP_vector< ssm_info > Ssm_info
#define WIF_TURNS
Definition: weapon.h:56
char weapon_substitution_pattern_names[MAX_SUBSTITUTION_PATTERNS][NAME_LENGTH]
Definition: weapon.h:548
int pick_big_attack_point_timestamp
Definition: weapon.h:198
vec3d target_pos1
Definition: beam.h:64
float elec_eng_mult
Definition: weapon.h:480
void cscrew_level_init()
Definition: corkscrew.cpp:58
#define WIF2_NON_SUBSYS_HOMING
Definition: weapon.h:101
int missile_list_index
Definition: weapon.h:181
#define BEAM_FAR_LENGTH
Definition: weapon.h:305
float max_hits
Definition: ship.h:320
int scoring_eval_kill_on_weapon(object *weapon_obj, object *other_obj)
Definition: scoring.cpp:858
void stuff_malloc_string(char **dest, int type, char *terminators)
Definition: parselo.cpp:1419
int Cmdline_missile_lighting
Definition: cmdline.cpp:325
float glow_length
Definition: weapon.h:268
void mflash_mark_as_used(int index)
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
int generic_anim_load(generic_anim *ga)
Definition: generic.cpp:138
int pre_launch_snd
Definition: weapon.h:412
float piercing_impact_particle_life
Definition: weapon.h:439
float alpha_cycle
Definition: weapon.h:528
Assert(pm!=NULL)
int target_objnum
Definition: ai.h:339
float weapon_reduce
Definition: weapon.h:452
ship_obj * next
Definition: ship.h:1482
#define SWARM_MISSILE_DELAY
Definition: weapons.cpp:147
int Cmdline_load_all_weapons
Definition: cmdline.cpp:437
#define DEFAULT_WEAPON_SPAWN_COUNT
Definition: weapons.cpp:480
#define WIF2_DEFAULT_IN_TECH_DATABASE
Definition: weapon.h:86
float det_range
Definition: weapon.h:185
void static_rand_cone(int num, vec3d *out, vec3d *in, float max_angle, matrix *orient)
Randomly perturb a vector around a given (normalized vector) or optional orientation matrix...
Definition: staticrand.cpp:129
int bfi_flags
Definition: beam.h:71
#define WIF2_TAKES_SHOCKWAVE_DAMAGE
Definition: weapon.h:111
Definition: pstypes.h:88
float detail_depth[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:739
void emp_level_init()
Definition: emp.cpp:88
InFlightSoundType in_flight_play_type
Definition: weapon.h:555
void generic_bitmap_init(generic_bitmap *gb, const char *filename)
Definition: generic.cpp:124
#define mprintf(args)
Definition: pstypes.h:238
#define WIF_CORKSCREW
Definition: weapon.h:71
SCP_map< SCP_string, delayed_ssm_data > Delayed_SSM_data
Definition: weapons.cpp:60
int ai_index
Definition: ship.h:538
ship_weapon weapons
Definition: ship.h:362
ushort net_signature
Definition: object.h:163
struct delayed_ssm_data delayed_ssm_data
#define NUM_SKILL_LEVELS
Definition: systemvars.h:150
float side_slip_time_const
Definition: physics.h:44
#define OBJ_ASTEROID
Definition: object.h:44
void ship_subsys_set_disrupted(ship_subsys *ss, int time)
Definition: ship.cpp:9053
float weapon_max_vel
Definition: weapon.h:226
#define WIF_STREAM
Definition: weapon.h:80
#define OF_RENDERS
Definition: object.h:103
short spawn_type
Definition: weapon.h:297
Definition: 2d.h:95
int stuff_float_optional(float *f, bool raw)
Definition: parselo.cpp:2343
int shockwave_create(int parent_objnum, vec3d *pos, shockwave_create_info *sci, int flag, int delay)
Definition: shockwave.cpp:64
char anim_filename[MAX_FILENAME_LEN]
Definition: weapon.h:423
matrix Eye_matrix
Definition: 3dsetup.cpp:26
char filename[MAX_FILENAME_LEN]
Definition: pstypes.h:408
void shockwave_create_info_load(shockwave_create_info *sci)
Definition: shockwave.cpp:825
#define WIF2_MR_NO_LIGHTING
Definition: weapon.h:92
float laser_head_radius
Definition: weapon.h:352
#define PF_CONST_VEL
Definition: physics.h:26
float total_time
Definition: generic.h:27
float untargeted_flak_range_penalty
Definition: weapon.h:376
char name[MAX_FILENAME_LEN]
Definition: shockwave.h:74
ship_subsys * turret
Definition: beam.h:60
void set_flags(uint flags)
void model_set_alpha(float alpha)
#define MR_NO_LIGHTING
Definition: model.h:867
int get_nearest_bbox_point(object *ship_objp, vec3d *start, vec3d *box_pt)
Definition: ship.cpp:18664
void cscrew_process_post(object *objp)
Definition: corkscrew.cpp:198
int hud_gauge_active(int gauge_index)
Determine if the specified HUD gauge should be displayed.
Definition: hud.cpp:3006
struct vec3d::@225::@227 xyz
#define WIF3_DONT_SPAWN_IF_SHOT
Definition: weapon.h:126
int Num_weapon_subtypes
Definition: weapons.cpp:92
float piercing_impact_particle_variance
Definition: weapon.h:442
void trail_object_died(trail *trailp)
Definition: trails.cpp:551
int generic_bitmap_load(generic_bitmap *gb)
Definition: generic.cpp:278
float max_fof_spread
Definition: weapon.h:497
ship_subsys * target_subsys
Definition: beam.h:63
short swarm_count
Definition: weapon.h:398
char external_model_name[MAX_FILENAME_LEN]
Definition: weapon.h:330
vec3d max_vel
Definition: physics.h:49
int shots
Definition: weapon.h:498
float particle_spew_rand
Definition: weapon.h:208
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
#define SIZE_T_ARG
Definition: clang.h:61
int GetAnim(int weapon_expl_index, vec3d *pos, float size)
Definition: weapons.cpp:253
#define BFIF_TARGETING_COORDS
Definition: beam.h:52
float fof_reset_rate
Definition: weapon.h:496
#define WIF2_SAME_TURRET_COOLDOWN
Definition: weapon.h:91
void weapon_do_area_effect(object *wobjp, shockwave_create_info *sci, vec3d *pos, object *other_obj)
Definition: weapons.cpp:6118
void init_weapon_entry(int weap_info_index)
Definition: weapons.cpp:833
#define WIF2_EXTERNAL_WEAPON_LNCH
Definition: weapon.h:109
float thruster_glow_factor
Definition: weapon.h:539
#define SW_WEAPON_KILL
Definition: shockwave.h:24
int snd_is_playing(int sig)
Definition: sound.cpp:1047
void weapon_expl_info_init()
Definition: weapons.cpp:3487
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
void weapon_mark_as_used(int weapon_type)
Definition: weapons.cpp:6497
#define SIF_BIG_DAMAGE
Definition: ship.h:905
#define Assertion(expr, msg,...)
Definition: clang.h:41
vec3d starting_pos
Definition: beam.h:66
#define WIF2_TAGGED_ONLY
Definition: weapon.h:88
#define WEAPON_INFO_INDEX(wip)
Definition: weapon.h:613
float lead_scale
Definition: ai.h:468
object obj_used_list
Definition: object.cpp:53
float Eye_fov
Definition: 3dsetup.cpp:28
#define f2fl(fx)
Definition: floating.h:37
int cs_crotate
Definition: weapon.h:475
void translate_spawn_types()
Definition: weapons.cpp:2865
void find_homing_object_by_sig(object *weapon_objp, int sig)
Definition: weapons.cpp:4196
vec3d maxs
Definition: model.h:746
int compute_num_homing_objects(object *target_objp)
Definition: aicode.cpp:5919
int Homing_misses
Definition: weapons.cpp:4709
void vm_vec_random_cone(vec3d *out, const vec3d *in, float max_angle, const matrix *orient)
Definition: vecmat.cpp:2418
SCP_string filename
Definition: weapons.cpp:64
float ship_quadrant_shield_strength(object *hit_objp, vec3d *hitpos)
Definition: ship.cpp:15030
#define WIF_THRUSTER
Definition: weapon.h:66
float max_speed
Definition: weapon.h:354
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
int bitmap_id
Definition: generic.h:53
ship_subsys * homing_subsys
Definition: weapon.h:178
#define OF_COLLIDES
Definition: object.h:104
#define MAX_WEP_DAMAGE_SLOTS
Definition: weapon.h:161
int burst_flags
Definition: weapon.h:534
float emp_intensity
Definition: weapon.h:445
Definition: ai.h:329
void gr_set_color_fast(color *dst)
Definition: 2d.cpp:1197
float beam_life
Definition: weapon.h:254
float batch_add_laser(int texture, vec3d *p0, float width1, vec3d *p1, float width2, int r, int g, int b)
Definition: grbatch.cpp:698
missile_obj Missile_objs[MAX_MISSILE_OBJS]
Definition: weapons.cpp:83
uint flags
Definition: ship.h:644
vec3d big_attack_point
Definition: weapon.h:199
#define WIF2_NO_LIFE_LOST_IF_MISSED
Definition: weapon.h:102
ubyte blue
Definition: 2d.h:102
#define WIF_HOMING_ASPECT
Definition: weapon.h:45
void missle_obj_list_remove(int index)
Definition: weapons.cpp:431
float weapon_range
Definition: weapon.h:390
hull_check orient
Definition: lua.cpp:5049
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
#define OF_PLAYER_SHIP
Definition: object.h:109
float piercing_impact_particle_back_velocity
Definition: weapon.h:441
#define AIPF_USE_ADDITIVE_WEAPON_VELOCITY
Definition: ai_profiles.h:34
weapon_expl_lod lod[MAX_WEAPON_EXPL_LOD]
Definition: weapon.h:583
object * objp
Definition: lua.cpp:3105
#define WRT_NONE
Definition: weapon.h:33
float lifeleft
Definition: weapon.h:169
int hud_in_flight_snd
Definition: weapon.h:554
int cs_delay
Definition: weapon.h:476
void weapon_render_DEPRECATED(object *obj)
Definition: weapons.cpp:3625
#define PARTICLE_BITMAP
Definition: particle.h:49
int beam_particle_count
Definition: weapon.h:258
GLsizeiptr size
Definition: Glext.h:5496
int disarmed_impact_snd
Definition: weapon.h:416
int subtype
Definition: weapon.h:326
#define Int3()
Definition: pstypes.h:292
weapon flyby sound
Definition: gamesnd.h:135
float weapon_get_damage_scale(weapon_info *wip, object *wep, object *target)
Definition: weapons.cpp:7137
vec3d max_rotvel
Definition: physics.h:52
int num_spawn_weapons_defined
Definition: weapon.h:393
int collide_remove_weapons()
void physics_apply_shock(vec3d *direction_vec, float pressure, physics_info *pi, matrix *orient, vec3d *min, vec3d *max, float radius)
Definition: physics.cpp:907
int beam_warmdown
Definition: weapon.h:256
#define WIF3_DIE_ON_LOST_LOCK
Definition: weapon.h:127
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
#define AI_GOAL_NONE
Definition: ai.h:194
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov)
Definition: aibig.cpp:228
ship * shipp
Definition: lua.cpp:9162
int n_thrusters
Definition: model.h:771
vec3d pos
Definition: object.h:152
float subsystem_factor
Definition: weapon.h:378
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
char pof_name[MAX_FILENAME_LEN]
Definition: shockwave.h:75
void bm_page_in_xparent_texture(int bitmapnum, int nframes)
Marks a textures as being used for level and is transparant.
Definition: bmpman.cpp:2514
void ship_apply_whack(vec3d *force, vec3d *hit_pos, object *objp)
Definition: shiphit.cpp:1740
int damage_type_idx_sav
Definition: weapon.h:520
fix resume_goal_time
Definition: ai.h:425
#define AIPF2_ASPECT_LOCK_COUNTERMEASURE
Definition: ai_profiles.h:65
int bm_release(int handle, int clear_render_targets)
Frees both a bitmap's data and it's associated slot.
Definition: bmpman.cpp:2603
int render_type
Definition: weapon.h:327
#define IS_VEC_NULL(v)
Definition: vecmat.h:28
void particle_emit(particle_emitter *pe, int type, int optional_data, float range)
Definition: particle.cpp:495
float particle_spew_z_scale
Definition: weapon.h:288
script_state Script_system("FS2_Open Scripting")
int piercing_impact_weapon_expl_index
Definition: weapon.h:436
int signature
Definition: object.h:145
#define WIF_LOCKARM
Definition: weapon.h:79
#define BEAM_TYPE_D
Definition: beam.h:35
#define WP_BEAM
Definition: weapon.h:29
GLenum type
Definition: Gl.h:1492
void stuff_float(float *f)
Definition: parselo.cpp:2328
flag_def_list Burst_fire_flags[]
Definition: weapons.cpp:94
int get_line_num()
Definition: parselo.cpp:261
float beam_iff_miss_factor[MAX_IFFS][NUM_SKILL_LEVELS]
Definition: weapon.h:262
#define MSS_FLAG_AWACS
Definition: model.h:111
float laser_length
Definition: weapon.h:349
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
#define LOCKED_HOMING_EXTENDED_LIFE_FACTOR
Definition: weapons.cpp:151
#define WIF2_CAPITAL_PLUS
Definition: weapon.h:107
#define CLAMP(x, min, max)
Definition: pstypes.h:488
void weapon_maybe_play_warning(weapon *wp)
Definition: weapons.cpp:3877
int Load(char *filename=NULL, int specified_lods=MAX_WEAPON_EXPL_LOD)
Definition: weapons.cpp:179
float laser_tail_radius
Definition: weapon.h:352
#define WIF2_TRANSPARENT
Definition: weapon.h:93
short spawn_count
Definition: weapon.h:298
iff_info Iff_info[MAX_IFFS]
Definition: iff_defs.cpp:20
ubyte green
Definition: 2d.h:101
#define SW_WEAPON
Definition: shockwave.h:22
void backspace(char *src)
Definition: parselo.cpp:4069
int weapon_info_index
Definition: weapon.h:164
void g3_start_user_clip_plane(const vec3d *plane_point, const vec3d *plane_normal)
Definition: 3dsetup.cpp:381
int weapon_substitution_pattern[MAX_SUBSTITUTION_PATTERNS]
Definition: weapon.h:547
float lifetime
Definition: weapon.h:382
int weapon_info_index
Definition: beam.h:117
float damage_threshold
Definition: weapon.h:275
#define MISSILE_OBJ_USED
Definition: weapons.cpp:81
float launch_speed
Definition: weapon.h:227
int cs_num_fired
Definition: weapon.h:472
#define AIPF_DISABLE_WEAPON_DAMAGE_SCALING
Definition: ai_profiles.h:33
#define AI_ACTIVE_GOAL_DYNAMIC
Definition: ai.h:196
int damage_ship_id[MAX_WEP_DAMAGE_SLOTS]
Definition: weapon.h:235
bool directional_glow
Definition: weapon.h:269
int objnum
Definition: ship.h:1483
int elec_randomness
Definition: weapon.h:484
int weapon_area_calc_damage(object *objp, vec3d *pos, float inner_rad, float outer_rad, float max_blast, float max_damage, float *blast, float *damage, float limit)
Definition: weapons.cpp:6025
ship_subsys subsys_list
Definition: ship.h:630
const float weapon_glow_scale_r
Definition: weapons.cpp:3621
#define WIF2_TRAINING
Definition: weapon.h:94
struct delayed_ssm_index_data delayed_ssm_index_data
int laser_model_inner
Definition: weapons.cpp:111
int objnum
Definition: weapon.h:561
#define WRT_POF
Definition: weapon.h:35
float beam_particle_radius
Definition: weapon.h:259
void set_alpha(float alpha)
vec3d homing_pos
Definition: weapon.h:179
#define WIF_CHILD
Definition: weapon.h:62
#define PM_FLAG_HAS_INTRINSIC_ROTATE
Definition: model.h:624
#define WIF2_DEFAULT_VALUE
Definition: weapon.h:41
int flash_impact_weapon_expl_index
Definition: weapon.h:433
void model_render_queue(model_render_params *interp, draw_list *scene, int model_num, matrix *orient, vec3d *pos)
int num_frames
Definition: generic.h:20
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define MAX_SHIP_SECONDARY_BANKS
Definition: globals.h:63
#define MAX_WEAPON_EXPL_LOD
Definition: weapon.h:566
Definition: beam.h:114
void ship_do_weapon_thruster_frame(weapon *weaponp, object *objp, float frametime)
Definition: ship.cpp:8680
int instance
Definition: object.h:150
beam_weapon_info b_info
Definition: weapon.h:456
int elec_use_new_style
Definition: weapon.h:485
int weapon_hitpoints
Definition: weapon.h:530
int thruster_glow_bitmap
Definition: weapon.h:190
#define WF_SPAWNED
Definition: weapon.h:144
int lssm_warpout_delay
Definition: weapon.h:488
#define WIF_FLAK
Definition: weapon.h:75
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
GLintptr offset
Definition: Glext.h:5497
Definition: player.h:85
void parse_sound(const char *tag, int *idx_dest, const char *object_name, parse_sound_flags flags)
Definition: gamesnd.cpp:445
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
const float PI2
Definition: pstypes.h:305
vec3d start_pos
Definition: weapon.h:170
vec3d last_pos
Definition: object.h:155
char * desc
Definition: weapon.h:325
int weapon_flags
Definition: weapon.h:176
void model_delete_instance(int model_instance_num)
Definition: modelread.cpp:2907
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
int Weapon_expl_initted
Definition: weapons.cpp:109
SCP_vector< SCP_string > Delayed_SSM_names
Definition: weapons.cpp:61
int flags
Definition: ship.h:322
ship_subsys * turret_subsys
Definition: weapon.h:183
struct matrix::@228::@230 vec
int num_detail_levels
Definition: weapon.h:333
#define SIF_NAVBUOY
Definition: ship.h:891
SCP_vector< int > * cmeasure_ignore_list
Definition: weapon.h:201
unsigned int uint
Definition: pstypes.h:64
float mass
Definition: weapon.h:358
#define WIF_REMOTE
Definition: weapon.h:48
void weapon_clean_entries()
Definition: weapons.cpp:3144
int armor_type_idx
Definition: weapon.h:522
#define WIF2_CIWS
Definition: weapon.h:114
int subtype
Definition: lua.cpp:9763
#define NUM_TRAIL_SECTIONS
Definition: trails.h:18
float ship_max_hull_strength
Definition: ship.h:597
GLboolean GLboolean g
Definition: Glext.h:5781
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
float beam_particle_angle
Definition: weapon.h:260
uint flags
Definition: model.h:169
#define nprintf(args)
Definition: pstypes.h:239
void swarm_level_init()
Definition: swarm.cpp:52
#define GM_MULTIPLAYER
Definition: systemvars.h:18
float life_min
Definition: weapon.h:379
float cargo_size
Definition: weapon.h:388
detail_levels Detail
Definition: systemvars.cpp:478
int first_frame
Definition: generic.h:19
#define AIPF2_PLAYER_WEAPON_SCALE_FIX
Definition: ai_profiles.h:63
int team
Definition: weapon.h:167
char hud_filename[MAX_FILENAME_LEN]
Definition: weapon.h:343
float rotdamp
Definition: physics.h:43
float glow_noise
Definition: model.h:1298
float max_life
Definition: trails.h:28
char filename[MAX_FILENAME_LEN]
Definition: weapon.h:569
#define WIF_IN_TECH_DATABASE
Definition: weapon.h:67
trail * trail_ptr
Definition: weapon.h:182
float beam_shrink_pct
Definition: weapon.h:272
#define WIF_SWARM
Definition: weapon.h:59
#define PARTICLE_SMOKE
Definition: particle.h:52
particle_spew_info particle_spewers[MAX_PARTICLE_SPEWERS]
Definition: weapon.h:469
int pre_launch_snd_min_interval
Definition: weapon.h:413
int objnum
Definition: weapon.h:165
int Num_spawn_types
Definition: weapons.cpp:121
int obj_create(ubyte type, int parent_obj, int instance, matrix *orient, vec3d *pos, float radius, uint flags)
Definition: object.cpp:467
int armor_type_get_idx(char *name)
Definition: ship.cpp:18332
float flash_impact_explosion_radius
Definition: weapon.h:434
int flags
Definition: ship.h:1227
#define SADTF_PIERCING_DEFAULT
Definition: ship.h:246
void g3_set_view_matrix(const vec3d *view_pos, const matrix *view_matrix, float zoom)
Definition: 3dsetup.cpp:152
ai_profile_t * ai_profile
Definition: missionparse.h:168
#define PSPEW_HELIX
Definition: weapon.h:155
float get_hull_pct(object *objp)
Definition: object.cpp:271
void model_clear_instance(int model_num)
Definition: modelread.cpp:4624
#define SIF_SMALL_SHIP
Definition: ship.h:943
char * filename
ubyte alpha_backward
Definition: weapon.h:223
void weapon_process_pre(object *obj, float frame_time)
Definition: weapons.cpp:4667
#define strnicmp(s1, s2, n)
Definition: config.h:272
int clip_plane(int plane_flag, vertex **src, vertex **dest, int *nv, ccodes *cc, uint flags)
Clips a plane to the viewing pyramid.
Definition: 3dclipper.cpp:222
generic_anim beam_particle_ani
Definition: weapon.h:261
size_t * get_pointer_to_weapon_fire_pattern_index(int weapon_type, ship *shipp, ship_subsys *src_turret)
Definition: weapons.cpp:5214
int ship_get_sound(object *objp, GameSoundsIndex id)
Returns a ship-specific sound index.
Definition: ship.cpp:18614
float speed
Definition: physics.h:79
int hud_target_lod
Definition: weapon.h:332
float lssm_stage5_vel
Definition: weapon.h:490
float lssm_warp_time
Definition: weapon.h:218
float free_flight_time
Definition: weapon.h:357
int damage_type_idx
Definition: weapon.h:519
ai_goal goals[MAX_AI_GOALS]
Definition: ai.h:412
#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
int rand_chance(float frametime, float chance)
Call this in the frame interval to get TRUE chance times per second.
Definition: floating.cpp:66
texture_map maps[MAX_MODEL_TEXTURES]
Definition: model.h:762
heat-seeker launch warning
Definition: gamesnd.h:93
int SSM_index
Definition: weapon.h:466
float target_lead_scaler
Definition: weapon.h:541
generic_anim thruster_glow
Definition: weapon.h:538
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
#define WP_LASER
Definition: weapon.h:27
int ship_get_SIF(ship *shipp)
Definition: ship.cpp:16096
#define MAX_WEAPON_TYPES
Definition: globals.h:73
int num_weapon_choices
Definition: missionparse.h:539
#define MULTI_SIG_NON_PERMANENT
Definition: multiutil.h:34
float WeaponMinRange
Definition: weapon.h:513
float hull_strength
Definition: object.h:160
GLfloat v0
Definition: Glext.h:5638
int dinky_impact_weapon_expl_index
Definition: weapon.h:430
#define MAX_SPAWN_TYPES_PER_WEAPON
Definition: weapon.h:302
#define WIF2_DONT_SHOW_ON_RADAR
Definition: weapon.h:112
#define OBJ_DEBRIS
Definition: object.h:37
#define WRT_LASER
Definition: weapon.h:34
int parent
Definition: object.h:147
#define w(p)
Definition: modelsinc.h:68
#define CF_TYPE_TABLES
Definition: cfile.h:50
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
#define WIF3_TURRET_INTERCEPTABLE
Definition: weapon.h:122
float shield_impact_explosion_radius
Definition: weapon.h:428
#define WIF3_APPLY_RECOIL
Definition: weapon.h:125
void vm_rot_point_around_line(vec3d *out, const vec3d *in, float angle, const vec3d *line_point, const vec3d *line_dir)
Definition: vecmat.cpp:1395
int tag_level
Definition: weapon.h:460
#define BFIF_FLOATING_BEAM
Definition: beam.h:53
int weaponry_pool[MAX_WEAPON_TYPES]
Definition: missionparse.h:540
char tech_anim_filename[MAX_FILENAME_LEN]
Definition: weapon.h:336
#define SF_HIDDEN_FROM_SENSORS
Definition: ship.h:464
ubyte red
Definition: 2d.h:100
#define OF_PROTECTED
Definition: object.h:108
#define vm_vec_negate(v)
Definition: vecmat.h:70
#define SUBSYSTEM_TURRET
Definition: model.h:54
float cmeasure_life_scale[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:103
beam_weapon_section_info sections[MAX_BEAM_SECTIONS]
Definition: weapon.h:273
object * Viewer_obj
Definition: object.cpp:57
float weapon_submodel_rotate_accell
Definition: weapon.h:516
#define PSPEW_NONE
Definition: weapon.h:153
vec3d pt
Definition: trails.h:23
#define MAX_BEAM_SECTIONS
Definition: globals.h:89
ubyte g3_rotate_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:97
int hardware_textures
Definition: systemvars.h:169
float cs_twist
Definition: weapon.h:474
uint flags
Definition: model.h:736
int First_secondary_index
Definition: weapons.cpp:116
int homing_objnum
Definition: swarm.h:43
int required_string(const char *pstr)
Definition: parselo.cpp:468
int snd_play(game_snd *gs, float pan, float vol_scale, int priority, bool is_voice_msg)
Definition: sound.cpp:517
#define fl_abs(fl)
Definition: floating.h:31
void weapon_area_apply_blast(vec3d *force_apply_pos, object *ship_objp, vec3d *blast_pos, float blast, int make_shockwave)
Definition: weapons.cpp:6080
#define WIF_PARTICLE_SPEW
Definition: weapon.h:72
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:104
int Num_teams
bool collisionOccured
Definition: weapon.h:230
#define WEAPON_MAX_GROUP_IDS
Definition: weapon.h:637
GLdouble s
Definition: Glext.h:5321
#define WF_NO_HOMING
Definition: weapon.h:146
float vm_vec_normalized_dir(vec3d *dest, const vec3d *end, const vec3d *start)
Definition: vecmat.cpp:591
int Default_cmeasure_index
Definition: weapons.cpp:117
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
#define WIF2_CAN_BE_TARGETED
Definition: weapon.h:104
int optional_string(const char *pstr)
Definition: parselo.cpp:539
int primary_glow_bitmap
Definition: model.h:1292
int lssm_warpin_delay
Definition: weapon.h:489
int detail_distance[MAX_MODEL_DETAIL_LEVELS]
Definition: weapon.h:334
int lssm_stage
Definition: weapon.h:216
void PageIn(int idx)
Definition: weapons.cpp:237
#define MULTI_DOGFIGHT
Definition: multi.h:656
float life_max
Definition: weapon.h:380
float a_start
Definition: trails.h:26
missile_obj * missile_obj_return_address(int index)
Definition: weapons.cpp:458
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
#define MONITOR(function_name)
Definition: pstypes.h:454
#define MR_DEPRECATED_ALL_XPARENT
Definition: model.h:911
float fireball_lifeleft_percent(object *obj)
Definition: fireballs.cpp:686
float fov
Definition: weapon.h:407
#define vm_strndup(ptr, size)
Definition: pstypes.h:550
char tech_title[NAME_LENGTH]
Definition: weapon.h:337
float current_hits
Definition: ship.h:319
#define SADTF_PIERCING_RETAIL
Definition: ship.h:247
void weapon_detonate(object *objp)
Definition: weapons.cpp:6450
Definition: ship.h:534
int wi_flags3
Definition: weapon.h:386
fix lssm_warpout_time
Definition: weapon.h:214
int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, int ferror=1, int duplicate=0)
Definition: modelread.cpp:2573
void emp_apply(vec3d *pos, float inner_radius, float outer_radius, float emp_intensity, float emp_time, bool use_emp_time_for_capship_turrets)
Definition: emp.cpp:103
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
#define WIF2_SHOWN_ON_RADAR
Definition: weapon.h:105
int skip_to_start_of_string_either(char *pstr1, char *pstr2, char *end)
Definition: parselo.cpp:433
int max_allowed_player_homers[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:87
#define MAX_SUBSTITUTION_PATTERNS
Definition: weapon.h:319
vec3d particle_spew_offset
Definition: weapon.h:290
float det_radius
Definition: weapon.h:373
int beam_fire(beam_fire_info *fire_info)
Definition: beam.cpp:281
bool Parsing_modular_table
Definition: parselo.cpp:34
float piercing_impact_explosion_radius
Definition: weapon.h:437
float vm_vec_normalize_safe(vec3d *v)
Definition: vecmat.cpp:471
int idx
Definition: multiui.cpp:761
#define FIREBALL_WARP
Definition: fireballs.h:29
float alpha_current
Definition: weapon.h:224
float elec_weap_mult
Definition: weapon.h:481
void weapon_unpause_sounds()
Definition: weapons.cpp:7257
GLdouble GLdouble t
Definition: Glext.h:5329
generic_anim laser_glow_bitmap
Definition: weapon.h:347
#define WIF_DEFAULT_VALUE
Definition: weapon.h:40
#define SUBSYSTEM_WEAPONS
Definition: model.h:58
void weapon_do_post_parse()
Definition: weapons.cpp:3436
#define ESUCK_DEFAULT_AFTERBURNER_REDUCE
Definition: weapons.cpp:135
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
#define WIF2_EXTERNAL_WEAPON_FP
Definition: weapon.h:108
float piercing_impact_particle_velocity
Definition: weapon.h:440
beam Beams[MAX_BEAMS]
Definition: beam.cpp:60
#define WIF2_UNTARGETED_HEAT_SEEKER
Definition: weapon.h:99
float cm_effective_rad
Definition: weapon.h:505
void ship_apply_global_damage(object *ship_objp, object *other_obj, vec3d *force_center, float damage)
Definition: shiphit.cpp:2476
float lssm_warp_pct
Definition: weapon.h:219
int Weapon_particle_spew_time
Definition: weapons.cpp:6758
int iff_x_attacks_y(int team_x, int team_y)
Definition: iff_defs.cpp:605
float Weapon_particle_spew_vel
Definition: weapons.cpp:6759
float alpha_max
Definition: weapon.h:526
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
for(int idx=0;idx< i;idx++)
Definition: multi_pxo.cpp:472
bool weapon_is_used(int weapon_index)
Definition: weapons.cpp:3269
#define WIF2_SMALL_ONLY
Definition: weapon.h:90
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
void weapon_hit_do_sound(object *hit_obj, weapon_info *wip, vec3d *hitpos, bool is_armed)
Definition: weapons.cpp:5834
bool weapon_armed(weapon *wp, bool hit_target)
Definition: weapons.cpp:6208
int model_instance_num
Definition: weapon.h:166
GLclampd n
Definition: Glext.h:7286
int ssm_info_lookup(const char *name)
#define MR_SHOW_THRUSTERS
Definition: model.h:864
unsigned char ubyte
Definition: pstypes.h:62
#define MONITOR_INC(function_name, inc)
Definition: pstypes.h:457
missile_obj * next
Definition: weapon.h:560
void stuff_vec3d(vec3d *vp)
Definition: parselo.cpp:3082
int wi_flags
Definition: weapon.h:384
#define vm_vec_zero(v)
Definition: vecmat.h:37
#define AIPF_FIX_HEAT_SEEKER_STEALTH_BUG
Definition: ai_profiles.h:44
uint flags
Definition: physics.h:37
#define FLAK_DAMAGE_SCALE
Definition: weapons.cpp:141
#define WF_CONSIDER_FOR_FLYBY_SOUND
Definition: weapon.h:140
float emp_time
Definition: weapon.h:446
dc_printf("Particle relative velocity set to %f\n", Weapon_particle_spew_vel)
void trail_add_segment(trail *trailp, vec3d *pos)
Definition: trails.cpp:480
#define ZERO_VECTOR
Definition: vecmat.h:60
float laser_bitmap_frame
Definition: weapon.h:195
#define OBJ_INDEX(objp)
Definition: object.h:235
#define IMPACT_SOUND_DELTA
Definition: weapons.cpp:130
void weapon_hit(object *weapon_obj, object *other_obj, vec3d *hitpos, int quadrant)
Definition: weapons.cpp:6253
int g3_get_bitmap_dims(int bitmap, vertex *pos, float radius, int *x, int *y, int *w, int *h, int *size)
Definition: 3ddraw.cpp:740
aspect launch warning
Definition: gamesnd.h:110
void stuff_boolean(int *i, bool a_to_eol)
Definition: parselo.cpp:2519
matrix orient
Definition: object.h:153
#define WIF_HOMING_HEAT
Definition: weapon.h:44
int wi_flags2
Definition: weapon.h:385
int catchup_pixels_per_sec
Definition: weapon.h:403
char icon_filename[MAX_FILENAME_LEN]
Definition: weapon.h:422
#define NOX(s)
Definition: pstypes.h:473
char ** Spawn_names
Definition: weapons.cpp:122
int Weapon_flyby_sound_enabled
Definition: weapons.cpp:72
int particle_spew_count
Definition: weapon.h:282
float Weapon_particle_spew_scale
Definition: weapons.cpp:6762
float total_damage_received
Definition: weapon.h:233
int piercing_impact_particle_count
Definition: weapon.h:438
#define SIF_HARMLESS
Definition: ship.h:947
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
Definition: weapon.h:316
#define SADTF_PIERCING_NONE
Definition: ship.h:245
#define WIF_BOMB
Definition: weapon.h:63
void weapon_generate_indexes_for_substitution()
Definition: weapons.cpp:3412
#define OBJ_SHIP
Definition: object.h:32
#define WBF_FAST_FIRING
Definition: weapon.h:149
void shield_impact_explosion(vec3d *hitpos, object *objp, float radius, int idx)
Definition: weapons.cpp:7263
float glow_rad_factor
Definition: model.h:1302
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
int target_sig
Definition: weapon.h:173
int catchup_pixel_penalty
Definition: weapon.h:404
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
GLbitfield flags
Definition: Glext.h:6722
void vm_vec_rand_vec_quick(vec3d *rvec)
Definition: vecmat.cpp:1379
bool turret_weapon_has_flags(ship_weapon *swp, int flags)
Definition: aiturret.cpp:306
SCP_string ssm_entry
Definition: weapons.cpp:58
void swarm_update_direction(object *objp, float frametime)
Definition: swarm.cpp:184
#define WIF3_NO_LINKED_PENALTY
Definition: weapon.h:119
float Weapon_particle_spew_radius
Definition: weapons.cpp:6760
#define WBF_RANDOM_LENGTH
Definition: weapon.h:150
color laser_color_1
Definition: weapon.h:350
#define WIF2_PIERCE_SHIELDS
Definition: weapon.h:85
typedef void(APIENTRY *PFNGLARRAYELEMENTEXTPROC)(GLint i)
void reset_parse(char *text)
Definition: parselo.cpp:3305
void dc_stuff_int(int *i)
Stuffs an int to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats...
void weapon_play_impact_sound(weapon_info *wip, vec3d *hitpos, bool is_armed)
Definition: weapons.cpp:5809
GLuint const GLchar * name
Definition: Glext.h:5608
int parse_weapon(int subtype, bool replace, const char *filename)
Definition: weapons.cpp:1128
trail * trail_create(trail_info *info)
Definition: trails.cpp:52
int RunCondition(int condition, char format='\0', void *data=NULL, class object *objp=NULL, int more_data=0)
Definition: scripting.cpp:924
int weaponry_count[MAX_WEAPON_TYPES]
Definition: missionparse.h:541
#define WIF_ELECTRONICS
Definition: weapon.h:46
void cmeasure_maybe_alert_success(object *objp)
If this is a player countermeasure, let the player know they evaded a missile.
Definition: cmeasure.cpp:84
int weapon_create(vec3d *pos, matrix *porient, int weapon_type, int parent_objnum, int group_id, int is_locked, int is_spawned, float fof_cooldown, ship_subsys *src_turret)
Definition: weapons.cpp:5246
void SetHookObjects(int num,...)
Definition: scripting.cpp:556
void find_homing_object_cmeasures()
Definition: weapons.cpp:4170
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
int cscrew_create(object *obj)
Definition: corkscrew.cpp:115
#define SUBSYSTEM_ENGINE
Definition: model.h:53
vec3d vel
Definition: physics.h:77
#define vm_realloc(ptr, size)
Definition: pstypes.h:551
float fspeed
Definition: physics.h:80
#define WIF2_SHOW_FRIENDLY
Definition: weapon.h:106
int primary_bitmap
Definition: model.h:1291
vec3d Eye_position
Definition: 3dsetup.cpp:27
#define WIF_SHUDDER
Definition: weapon.h:78
int bm_load(const char *real_filename)
Loads a bitmap so we can draw with it later.
Definition: bmpman.cpp:1119
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
int score
Definition: weapon.h:550
void stuff_int(int *i)
Definition: parselo.cpp:2372
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
void weapon_get_laser_color(color *c, object *objp)
Definition: weapons.cpp:6707
int stuff_int_list(int *ilp, int max_ints, int lookup_type)
Definition: parselo.cpp:2782
__inline void gr_fog_set(int fog_mode, int r, int g, int b, float fog_near=-1.0f, float fog_far=-1.0f)
Definition: 2d.h:833
float particle_spew_vel
Definition: weapon.h:284
vec3d particle_spew_velocity
Definition: weapon.h:291
shockwave_create_info dinky_shockwave
Definition: weapon.h:368
#define CC_BEHIND
Definition: 3d.h:31
float Weapon_particle_spew_lifetime
Definition: weapons.cpp:6761
float particle_spew_rotation_rate
Definition: weapon.h:289
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
int selection_effect
Definition: weapon.h:424
int parent_objnum
Definition: ship.h:316
int ship_get_by_signature(int signature)
Definition: ship.cpp:16106
int hud_in_flight_snd_sig
Definition: weapon.h:237
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
void fs2netd_add_table_validation(const char *tblname)
float cs_radius
Definition: weapon.h:473
GLuint GLuint num
Definition: Glext.h:9089
#define SIF2_DISABLE_WEAPON_DAMAGE_SCALING
Definition: ship.h:924
void shockwave_create_info_init(shockwave_create_info *sci)
Definition: shockwave.cpp:811
void weapons_page_in_cheats()
Definition: weapons.cpp:6650
#define WIF_PLAYER_ALLOWED
Definition: weapon.h:68
int Homing_hits
Definition: weapons.cpp:4709
#define MR_DEPRECATED_NORMAL
Definition: model.h:892
#define DCF_BOOL(function_name, bool_variable)
Definition: console.h:71
void parse_weaponstbl(const char *filename)
Definition: weapons.cpp:2898
int flags
Definition: weapon.h:561
SCP_vector< lod_checker > LOD_checker
Definition: weapons.cpp:103
vec3d pnt
Definition: model.h:178
void weapon_reset_info()
Definition: weapons.cpp:3505
int vm_vec_same(const vec3d *v1, const vec3d *v2)
Definition: vecmat.cpp:1526
float frame_time
Definition: multi.cpp:1426
int goal_signature
Definition: ai.h:356
void find_homing_object_cmeasures_1(object *weapon_objp)
Definition: weapons.cpp:4075
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
void model_render_DEPRECATED(int model_num, matrix *orient, vec3d *pos, uint flags=MR_DEPRECATED_NORMAL, int objnum=-1, int lighting_skip=-1, int *replacement_textures=NULL, int render=MODEL_RENDER_ALL, const bool is_skybox=false)
int hud_tracking_snd
Definition: weapon.h:552
int laser_model_outer
Definition: weapons.cpp:112
float cm_detonation_rad
Definition: weapon.h:506
#define NAME_LENGTH
Definition: globals.h:15
float frand()
Return random value in range 0.0..1.0- (1.0- means the closest number less than 1.0)
Definition: floating.cpp:35
shield hit
Definition: gamesnd.h:107
swarm_info Swarm_missiles[MAX_SWARM_MISSILES]
Definition: swarm.cpp:41
int lssm_warp_idx
Definition: weapon.h:217
#define WP_MISSILE
Definition: weapon.h:28
float particle_spew_radius
Definition: weapon.h:285
#define WF_LOCKED_WHEN_FIRED
Definition: weapon.h:142
float rad
Definition: model.h:757
float lssm_lock_range
Definition: weapon.h:492
int set_target_objnum(ai_info *aip, int objnum)
Definition: aicode.cpp:1250
int optional_string_either(char *str1, char *str2)
Definition: parselo.cpp:551
#define SUBSYSTEM_SENSORS
Definition: model.h:59
#define fl2i(fl)
Definition: floating.h:33
fix lssm_warpin_time
Definition: weapon.h:215
void spawn_child_weapons(object *objp)
Definition: weapons.cpp:5676
void bm_page_in_texture(int bitmapnum, int nframes)
Marks a texture as being used for this level.
Definition: bmpman.cpp:2462
#define PARTICLE_BITMAP_PERSISTENT
Definition: particle.h:54
void weapon_release_bitmaps()
Definition: weapons.cpp:3177
player * Player
DCF(pspew_count,"Number of particles spewed at a time")
Definition: weapons.cpp:7002
#define WIF2_CUSTOM_SEEKER_STR
Definition: weapon.h:103
GLenum target
Definition: Glext.h:6872
#define g3_end_frame()
Definition: 3d.h:49
void trail_set_stamp(trail *trailp)
Definition: trails.cpp:577
float flak_detonation_accuracy
Definition: weapon.h:374
#define WIF_BEAM
Definition: weapon.h:76
int missile_obj_list_add(int objnum)
Definition: weapons.cpp:406
void generic_anim_init(generic_anim *ga)
Definition: generic.cpp:80
#define WIF3_NO_HOMING_SPEED_RAMP
Definition: weapon.h:120
bool aspect_should_lose_target(weapon *wp)
Definition: weapons.cpp:4227
int snd_play_looping(game_snd *gs, float pan, int start_loop, int stop_loop, float vol_scale, int scriptingUpdateVolume)
Definition: sound.cpp:822
ship_subsys * ship_get_closest_subsys_in_sight(ship *sp, int subsys_type, vec3d *attacker_pos)
Definition: ship.cpp:14963
float beam_shrink_factor
Definition: weapon.h:271
int guard_signature
Definition: ai.h:359
float lssm_warpin_radius
Definition: weapon.h:491
weapon_explosions Weapon_explosions
Definition: weapons.cpp:101
unsigned short ushort
Definition: pstypes.h:63
#define WIF2_NO_EMP_KILL
Definition: weapon.h:97
#define WIF_ENERGY_SUCK
Definition: weapon.h:74
float cm_heat_effectiveness
Definition: weapon.h:504
void weapon_delete(object *obj)
Definition: weapons.cpp:3822
float model_get_radius(int modelnum)
Definition: modelread.cpp:3105
ship_subsys * locking_subsys
Definition: player.h:176
void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec=NULL, int sexp_flags=0)
Definition: aicode.cpp:1131
#define WIF_SUPERCAP
Definition: weapon.h:50
ship_obj Ship_obj_list
Definition: ship.cpp:162
object * shooter
Definition: beam.h:58
float thruster_glow_frame
Definition: weapon.h:191
void parse_wi_flags(weapon_info *weaponp, int wi_flags, int wi_flags2, int wi_flags3)
Definition: weapons.cpp:483
spawn_weapon_info spawn_info[MAX_SPAWN_TYPES_PER_WEAPON]
Definition: weapon.h:395
void RemHookVars(unsigned int num,...)
Definition: scripting.cpp:754
#define vm_is_vec_nan(v)
Definition: vecmat.h:19
int hud_locked_snd
Definition: weapon.h:553
#define OF_PHYSICS
Definition: object.h:105
float thruster_frame
Definition: weapon.h:189
float elec_beam_mult
Definition: weapon.h:482
void cscrew_process_pre(object *objp)
Definition: corkscrew.cpp:177
int ship_info_index
Definition: ship.h:539
#define MULTIPLAYER_MASTER
Definition: multi.h:130
int impact_snd
Definition: weapon.h:415
#define HOMING_DEFAULT_FREE_FLIGHT_TIME
Definition: weapons.cpp:144
#define MR_IS_MISSILE
Definition: model.h:872
#define F_NAME
Definition: parselo.h:34
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
int thruster_bitmap
Definition: weapon.h:188
int num_lods
Definition: pstypes.h:409
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
float shield_factor
Definition: weapon.h:378
vec3d length
Definition: model.h:1300
vec3d * vm_vec_avg(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:217
#define WIF_SPAWN
Definition: weapon.h:47
void weapon_maybe_play_flyby_sound(object *weapon_objp, weapon *wp)
Definition: weapons.cpp:4717
float burst_delay
Definition: weapon.h:533
float spawn_angle
Definition: weapon.h:299
void model_set_thrust(int model_num=-1, mst_info *mst=NULL)
int nearest_locked_object
Definition: ai.h:486
#define WIF_HOMING
Definition: weapon.h:129
#define timestamp_elapsed(stamp)
Definition: timer.h:102
#define MAX_MISSILE_OBJS
Definition: weapons.cpp:82
SCP_vector< float > shield_quadrant
Definition: object.h:159
SCP_vector< species_info > Species_info
player ship is hit by laser fire
Definition: gamesnd.h:104
float normal_variance
Definition: particle.h:114
SCP_vector< SCP_string > Delayed_SSM_indices
Definition: weapons.cpp:68
#define MAX_MODEL_DETAIL_LEVELS
Definition: model.h:27
const float weapon_glow_scale_l
Definition: weapons.cpp:3622
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
vec3d * get_subsystem_world_pos(object *parent_obj, ship_subsys *subsys, vec3d *world_pos)
Definition: hudtarget.cpp:4395
#define WIF3_DEFAULT_VALUE
Definition: weapon.h:42
void weapons_page_in()
Definition: weapons.cpp:6512
#define HUD_RADAR
Definition: hudgauges.h:25
int beam_warmdown_sound
Definition: weapon.h:265
#define PI
Definition: pstypes.h:303
#define WIF2_HARD_TARGET_BOMB
Definition: weapon.h:100
#define WIF_PUNCTURE
Definition: weapon.h:49
#define MAX_WEAPONS
Definition: globals.h:71
hull_check pos
Definition: lua.cpp:5050
float alpha_min
Definition: weapon.h:527
int Game_skill_level
Definition: fredstubs.cpp:170
void detonate_nearby_missiles(object *killer_objp, object *missile_objp)
Definition: weapons.cpp:3899
#define SUPERCAP_DAMAGE_SCALE
Definition: weapons.cpp:138
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
void weapon_process_post(object *obj, float frame_time)
Definition: weapons.cpp:4775
void send_weapon_detonate_packet(object *objp)
Definition: multimsgs.cpp:8229
#define WIF_TRAIL
Definition: weapon.h:60
#define VALID_FNAME(x)
Definition: pstypes.h:418
int armor_type_idx
Definition: ship.h:796
int Iff_traitor
Definition: iff_defs.cpp:22
float damage_time
Definition: weapon.h:364
#define SWARM_DEFAULT_NUM_MISSILES_FIRED
Definition: swarm.h:49
#define MR_DEPRECATED_IS_MISSILE
Definition: model.h:906
int particle_spew_time[MAX_PARTICLE_SPEWERS]
Definition: weapon.h:207
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
float fov
Definition: lua.cpp:9155
void weapon_render(object *obj, draw_list *scene)
Definition: weapons.cpp:7268
void trail_set_segment(trail *trailp, vec3d *pos)
Definition: trails.cpp:498
int Player_weapon_precedence[MAX_WEAPON_TYPES]
Definition: weapons.cpp:125
bool cm_kill_single
Definition: weapon.h:507
int model_num
Definition: weapon.h:329
float accuracy
Definition: beam.h:61
#define SIF_NOT_FLYABLE
Definition: ship.h:946
#define i2fl(i)
Definition: floating.h:32
void asteroid_hit(object *pasteroid_obj, object *other_obj, vec3d *hitpos, float damage)
Definition: asteroid.cpp:1368
void mflash_page_in(bool)
void find_homing_object(object *weapon_objp, int num)
Definition: weapons.cpp:3945
void set_clip_plane(vec3d &pos, vec3d &normal)
int guard_objnum
Definition: ai.h:358
int Num_player_weapon_precedence
Definition: weapons.cpp:124
int parse_modular_table(const char *name_check, void(*parse_callback)(const char *filename), int path_type, int sort_type)
Definition: parselo.cpp:4205
void send_homing_weapon_info(int weapon_num)
Definition: multimsgs.cpp:7312
#define EMP_DEFAULT_TIME
Definition: emp.h:25
float rearm_rate
Definition: weapon.h:389
float energy_consumed
Definition: weapon.h:383
float acceleration_time
Definition: weapon.h:355
float impact_explosion_radius
Definition: weapon.h:427
const float PI_2
Definition: pstypes.h:307
#define i2f(a)
Definition: fix.h:23
float seeker_strength
Definition: weapon.h:410
team_data Team_data[MAX_TVT_TEAMS]
void parse_weapon_expl_tbl(const char *filename)
Definition: weapons.cpp:339
char pofbitmap_name[MAX_FILENAME_LEN]
Definition: weapon.h:328
object * Player_obj
Definition: object.cpp:56
float elec_sensors_mult
Definition: weapon.h:483
void swarm_delete(int i)
Definition: swarm.cpp:165
#define WIF_HOMING_JAVELIN
Definition: weapon.h:55
uint flags2
Definition: ship.h:645
#define MAX_IFFS
Definition: globals.h:34
float recoil_modifier
Definition: weapon.h:449
int temp
Definition: lua.cpp:4996
int beam_warmup_sound
Definition: weapon.h:264
#define CHA_ONWEAPONDELETE
Definition: scripting.h:64
int Num_weapon_types
Definition: weapons.cpp:105
int particle_spew_time
Definition: weapon.h:283
void weapon_home(object *obj, int num, float frame_time)
Definition: weapons.cpp:4256
void stuff_ubyte(ubyte *i)
Definition: parselo.cpp:2646
float w_start
Definition: trails.h:24
int goal_objnum
Definition: ai.h:355
trail_info tr_info
Definition: weapon.h:420
#define WIF2_BALLISTIC
Definition: weapon.h:84
polymodel * pm
Definition: lua.cpp:1598
#define WIF2_ANTISUBSYSBEAM
Definition: weapon.h:115
float max_delay
Definition: weapon.h:360
void multi_set_network_signature(ushort signature, int what_kind)
Definition: multiutil.cpp:198
float dinky_impact_explosion_radius
Definition: weapon.h:431
#define MAX(a, b)
Definition: pstypes.h:299
#define PSPEW_RING
Definition: weapon.h:157
#define MR_DEPRECATED_NO_LIGHTING
Definition: model.h:901
int Weapons_inited
Definition: weapons.cpp:108
int Num_iffs
Definition: iff_defs.cpp:19
int G3_count
Definition: 3dsetup.cpp:59
float particle_spew_lifetime
Definition: weapon.h:286
float det_range
Definition: weapon.h:372
char filename[MAX_FILENAME_LEN]
Definition: generic.h:18
ushort multi_assign_network_signature(int what_kind)
Definition: multiutil.cpp:105
int swarm_create()
Definition: swarm.cpp:136
float mass
Definition: physics.h:39
#define OBJ_NONE
Definition: object.h:31
#define OBJ_BEAM
Definition: object.h:46
float afterburner_reduce
Definition: weapon.h:453
#define AIGF_TARGET_OWN_TEAM
Definition: ai.h:112
#define WIF3_NOLINK
Definition: weapon.h:117
#define MAX_WEAPON_FLAGS
Definition: weapon.h:38
ubyte codes
Definition: pstypes.h:177
int collision_group_id
Definition: object.h:169
GLboolean reset
Definition: Glext.h:5243
float vel_inherit_amount
Definition: weapon.h:356
#define GM_NORMAL
Definition: systemvars.h:19
float a_end
Definition: trails.h:27
int num_frames
Definition: weapon.h:571
#define SF2_STEALTH
Definition: ship.h:485
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
particle * particle_create(particle_info *pinfo)
Definition: particle.cpp:105
char alt_name[NAME_LENGTH]
Definition: weapon.h:323
void snd_stop(int sig)
Definition: sound.cpp:875
int model_create_instance(bool is_ship, int model_num)
Definition: modelread.cpp:2855
#define MAX_PARTICLE_SPEWERS
Definition: weapon.h:160
float min_delay
Definition: weapon.h:361
float w_end
Definition: trails.h:25
mission The_mission
#define MR_NO_BATCH
Definition: model.h:881
#define FIREBALL_WARP_EFFECT
Definition: fireballs.h:25
int beam_num_sections
Definition: weapon.h:266
matrix last_orient
Definition: object.h:156
#define WF_DESTROYED_BY_WEAPON
Definition: weapon.h:143
#define WIF2_SMART_SPAWN
Definition: weapon.h:95
#define WEAPON_TITLE_LEN
Definition: weapon.h:310
GLint lod
Definition: Glext.h:7352
float closeup_zoom
Definition: weapon.h:341
#define WIF2_INHERIT_PARENT_TARGET
Definition: weapon.h:96
#define EMP_DEFAULT_INTENSITY
Definition: emp.h:24
void beam_pause_sounds()
Definition: beam.cpp:682
float h
Definition: pstypes.h:111
#define WIF2_LOCAL_SSM
Definition: weapon.h:87
char team
Definition: beam.h:72
GLclampf GLclampf GLclampf alpha
Definition: Glext.h:5177
const float CMEASURE_DETONATE_DISTANCE
Definition: cmeasure.cpp:24
void weapon_level_init()
Definition: weapons.cpp:3582
int stuff_float_list(float *flp, int max_floats)
Definition: parselo.cpp:2988
char type
Definition: object.h:146
int Num_weapons
Definition: weapons.cpp:107
generic_anim texture
Definition: weapon.h:249
vec3d vmd_zero_vector
Definition: vecmat.cpp:24
void diag_printf(char *format,...)
Definition: parselo.cpp:229
GLint limit
Definition: Glext.h:9797
shockwave_create_info shockwave
Definition: weapon.h:367
generic_bitmap texture
Definition: trails.h:30
float damage
Definition: weapon.h:363
color laser_color_2
Definition: weapon.h:351
int hitter_objnum
Definition: ai.h:423
#define WIF3_FIGHTER_INTERCEPTABLE
Definition: weapon.h:123
short swarm_index
Definition: weapon.h:180
int missile_model
Definition: weapons.cpp:114
player ship is hit by missile
Definition: gamesnd.h:105
int multi_find_player_by_object(object *objp)
Definition: multiutil.cpp:500
void parse_shockwave_info(shockwave_create_info *sci, char *pre_char)
Definition: weapons.cpp:760
#define wp(p)
Definition: modelsinc.h:69
float flak_targeting_accuracy
Definition: weapon.h:375
net_player Net_players[MAX_PLAYERS]
Definition: multi.cpp:93
float armor_factor
Definition: weapon.h:378
float damage_ship[MAX_WEP_DAMAGE_SLOTS]
Definition: weapon.h:234
int n_fade_out_sections
Definition: trails.h:31
SCP_string filename
Definition: weapons.cpp:56
missile_obj Missile_obj_list
Definition: weapons.cpp:84
void weapon_maybe_spew_particle(object *obj)
Definition: weapons.cpp:6767
#define F_MULTITEXT
Definition: parselo.h:43
#define stricmp(s1, s2)
Definition: config.h:271
int Weapon_impact_timer
Definition: weapons.cpp:131
#define WF_LOCK_WARNING_PLAYED
Definition: weapon.h:135
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
const GLdouble * v
Definition: Glext.h:5322
void gr_init_color(color *c, int r, int g, int b)
Definition: 2d.cpp:1155
int impact_weapon_expl_index
Definition: weapon.h:426
matrix vmd_identity_matrix
Definition: vecmat.cpp:28
char title[WEAPON_TITLE_LEN]
Definition: weapon.h:324
float turn_time
Definition: weapon.h:387
void dcf_pspew()
void joy_ff_play_vector_effect(vec3d *v, float scaler)
Definition: joy-unix.cpp:635
int Weapons_created
Definition: weapons.cpp:5245
float weapon_submodel_rotate_vel
Definition: weapon.h:517
int flags
Definition: ai.h:139
#define MAX_CMEASURE_TRACK_DIST
Definition: cmeasure.h:24
float static_randf(int num)
Return a random float in 0.0f .. 1.0f- (ie, it will never return 1.0f).
Definition: staticrand.cpp:61
int parent_sig
Definition: object.h:148
int damage_type_add(char *name)
Definition: ship.cpp:17749
char ship_name[NAME_LENGTH]
Definition: ship.h:604
#define PSPEW_PLUME
Definition: weapon.h:158
#define MR_DEPRECATED_SHOW_THRUSTERS
Definition: model.h:898
float atten_damage
Definition: weapon.h:365
#define SF2_NO_SECONDARY_LOCKON
Definition: ship.h:510
generic_anim thruster_flame
Definition: weapon.h:537
void beam_unpause_sounds()
Definition: beam.cpp:703
void weapon_sort_by_type()
Definition: weapons.cpp:2986
size_t primary_bank_pattern_index[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:159
float arm_dist
Definition: weapon.h:370
const GLubyte * c
Definition: Glext.h:8376
#define WIF3_AOE_ELECTRONICS
Definition: weapon.h:124
float beam_muzzle_radius
Definition: weapon.h:257
float beam_width
Definition: weapon.h:276
player shield is hit
Definition: gamesnd.h:108
bool Weapons_inherit_parent_collision_group
Definition: mod_table.cpp:30
generic_anim particle_spew_anim
Definition: weapon.h:292
#define fl2f(fl)
Definition: floating.h:38
int n_detail_levels
Definition: model.h:737
const int weapon_glow_alpha
Definition: weapons.cpp:3623
const float weapon_glow_scale_f
Definition: weapons.cpp:3620
int burst_shots
Definition: weapon.h:532
float b
Definition: pstypes.h:111
size_t secondary_bank_pattern_index[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:160
GLint y
Definition: Gl.h:1505
void missile_obj_list_init()
Definition: weapons.cpp:392
int Default_weapon_select_effect
Definition: mod_table.cpp:25
void pause_in_flight_sounds()
Definition: weapons.cpp:7231
float tag_time
Definition: weapon.h:459
#define RAW_INTEGER_TYPE
Definition: parselo.h:52
#define g3_start_frame(zbuffer_flag)
Definition: 3d.h:39
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_obj, float size, int reverse, vec3d *velocity, float warp_lifetime, int ship_class, matrix *orient_override, int low_res, int extra_flags, int warp_open_sound, int warp_close_sound)
Definition: fireballs.cpp:788
#define fl_radians(fl)
Definition: floating.h:42
#define GR_FOGMODE_NONE
Definition: 2d.h:355
#define strcpy_s(...)
Definition: safe_strings.h:67
#define WIF_TAG
Definition: weapon.h:77
vec3d lssm_target_pos
Definition: weapon.h:220
float max_lifetime
Definition: weapon.h:381
#define WF_HOMING_UPDATE_NEEDED
Definition: weapon.h:145
int hud_image_index
Definition: weapon.h:344
float field_of_fire
Definition: weapon.h:494
weapon Weapons[MAX_WEAPONS]
Definition: weapons.cpp:78
int Weapon_particle_spew_count
Definition: weapons.cpp:6757
SCP_map< SCP_string, delayed_ssm_index_data > Delayed_SSM_indices_data
Definition: weapons.cpp:67