FS2_Open
Open source remastering of the Freespace 2 engine
ship.cpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Volition, Inc. 1999. All rights reserved.
4  *
5  * All source code herein is the property of Volition, Inc. You may not sell
6  * or otherwise commercially exploit the source or things you created based on the
7  * source.
8  *
9 */
10 
11 
12 
13 #include <setjmp.h>
14 
15 #include "ai/aigoals.h"
16 #include "asteroid/asteroid.h"
17 #include "autopilot/autopilot.h"
18 #include "cmdline/cmdline.h"
19 #include "cmeasure/cmeasure.h"
20 #include "debugconsole/console.h"
21 #include "fireball/fireballs.h"
22 #include "freespace2/freespace.h"
24 #include "gamesnd/eventmusic.h"
25 #include "gamesnd/gamesnd.h"
26 #include "globalincs/alphacolors.h"
27 #include "globalincs/def_files.h"
28 #include "globalincs/linklist.h"
30 #include "hud/hud.h"
31 #include "hud/hudartillery.h"
32 #include "hud/hudets.h"
33 #include "hud/hudmessage.h"
34 #include "hud/hudshield.h"
35 #include "hud/hudsquadmsg.h"
36 #include "hud/hudtargetbox.h"
37 #include "hud/hudwingmanstatus.h"
38 #include "iff_defs/iff_defs.h"
39 #include "io/joy_ff.h"
40 #include "io/timer.h"
41 #include "jumpnode/jumpnode.h"
42 #include "lighting/lighting.h"
43 #include "localization/localize.h"
44 #include "math/fvi.h"
45 #include "math/staticrand.h"
46 #include "math/vecmat.h"
48 #include "mission/missionlog.h"
49 #include "mission/missionmessage.h"
51 #include "missionui/redalert.h"
52 #include "mod_table/mod_table.h"
53 #include "model/model.h"
54 #include "model/modelrender.h"
55 #include "nebula/neb.h"
56 #include "network/multimsgs.h"
57 #include "network/multiutil.h"
58 #include "object/deadobjectdock.h"
59 #include "object/objcollide.h"
60 #include "object/object.h"
61 #include "object/objectdock.h"
62 #include "object/objectshield.h"
63 #include "object/objectsnd.h"
64 #include "object/waypoint.h"
65 #include "parse/parselo.h"
66 #include "parse/scripting.h"
67 #include "particle/particle.h"
68 #include "playerman/player.h"
69 #include "radar/radar.h"
70 #include "radar/radarsetup.h"
71 #include "render/3d.h"
72 #include "ship/afterburner.h"
73 #include "ship/ship.h"
74 #include "ship/shipcontrails.h"
75 #include "ship/shipfx.h"
76 #include "ship/shiphit.h"
77 #include "ship/subsysdamage.h"
79 #include "weapon/beam.h"
80 #include "weapon/corkscrew.h"
81 #include "weapon/emp.h"
82 #include "weapon/flak.h" //phreak addded 11/05/02 for flak primaries
83 #include "weapon/shockwave.h"
84 #include "weapon/swarm.h"
85 #include "weapon/weapon.h"
86 
87 #define NUM_SHIP_SUBSYSTEM_SETS 20 // number of subobject sets to use (because of the fact that it's a linked list,
88  // we can't easily go fully dynamic)
89 
90 #define NUM_SHIP_SUBSYSTEMS_PER_SET 200 // Reduced from 1000 to 400 by MK on 4/1/98. DTP; bumped from 700 to 2100
91  // Reduced to 200 by taylor on 3/13/07 -- it's managed in dynamically allocated sets now
92  // Highest I saw was 164 in sm2-03a which Sandeep says has a lot of ships.
93  // JAS: sm3-01 needs 460. You cannot know this number until *all* ships
94  // have warped in. So I put code in the paging code which knows all ships
95  // that will warp in.
96 
97 static int Num_ship_subsystems = 0;
98 static int Num_ship_subsystems_allocated = 0;
99 
100 static ship_subsys *Ship_subsystems[NUM_SHIP_SUBSYSTEM_SETS] = { NULL };
102 
103 extern bool splodeing;
104 extern float splode_level;
105 extern int splodeingtexture;
106 
107 extern int Cmdline_nohtl;
108 
109 extern void fs2netd_add_table_validation(const char *tblname);
110 
111 #define SHIP_REPAIR_SUBSYSTEM_RATE 0.01f
112 
114 #ifndef NDEBUG
116 int Ship_auto_repair = 1; // flag to indicate auto-repair of subsystem should occur
117 extern void render_path_points(object *objp);
118 #endif
119 
120 int Num_wings = 0;
123 
127 
129 int ships_inited = 0;
130 int armor_inited = 0;
131 
132 int Starting_wings[MAX_STARTING_WINGS]; // wings player starts a mission with (-1 = none)
133 
134 // Goober5000
137 
138 // Goober5000
142 
144 engine_wash_info *get_engine_wash_pointer(char* engine_wash_name);
145 
146 void ship_reset_disabled_physics(object *objp, int ship_class);
147 
148 // forward declaring for parse_ship()
149 int ship_info_lookup_sub(const char *token);
150 
151 // information for ships which have exited the game
153 
157 int Player_ship_class; // needs to be player specific, move to player structure
158 
159 #define SHIP_OBJ_USED (1<<0) // flag used in ship_obj struct
160 #define MAX_SHIP_OBJS MAX_SHIPS // max number of ships tracked in ship list
161 ship_obj Ship_objs[MAX_SHIP_OBJS]; // array used to store ship object indexes
162 ship_obj Ship_obj_list; // head of linked list of ship_obj structs
163 
167 
169 
172 
174  { "ignore subsystem armor", SAF_IGNORE_SS_ARMOR, 0 }
175 };
176 
177 const int Num_armor_flags = sizeof(Armor_flags)/sizeof(flag_def_list);
178 
180  { "Bank right", MT_BANK_RIGHT, 0 },
181  { "Bank left", MT_BANK_LEFT, 0 },
182  { "Pitch up", MT_PITCH_UP, 0 },
183  { "Pitch down", MT_PITCH_DOWN, 0 },
184  { "Roll right", MT_ROLL_RIGHT, 0 },
185  { "Roll left", MT_ROLL_LEFT, 0 },
186  { "Slide right", MT_SLIDE_RIGHT, 0 },
187  { "Slide left", MT_SLIDE_LEFT, 0 },
188  { "Slide up", MT_SLIDE_UP, 0 },
189  { "Slide down", MT_SLIDE_DOWN, 0 },
190  { "Forward", MT_FORWARD, 0 },
191  { "Reverse", MT_REVERSE, 0 }
192 };
193 
194 const int Num_man_types = sizeof(Man_types)/sizeof(flag_def_list);
195 
196 // Goober5000 - I figured we should keep this separate
197 // from Comm_orders, considering how I redid it :p
198 // (and also because we may want to change either
199 // the order text or the flag text in the future)
201  // common stuff
202  { "attack ship", ATTACK_TARGET_ITEM, 0 },
203  { "disable ship", DISABLE_TARGET_ITEM, 0 },
204  { "disarm ship", DISARM_TARGET_ITEM, 0 },
205  { "disable subsys", DISABLE_SUBSYSTEM_ITEM, 0 },
206  { "guard ship", PROTECT_TARGET_ITEM, 0 },
207  { "ignore ship", IGNORE_TARGET_ITEM, 0 },
208  { "form on wing", FORMATION_ITEM, 0 },
209  { "cover me", COVER_ME_ITEM, 0 },
210  { "attack any", ENGAGE_ENEMY_ITEM, 0 },
211 
212  // transports mostly
213  { "dock", CAPTURE_TARGET_ITEM, 0 },
214 
215  // support ships
216  { "rearm me", REARM_REPAIR_ME_ITEM, 0 },
217  { "abort rearm", ABORT_REARM_REPAIR_ITEM, 0 },
218 
219  // all ships
220  { "depart", DEPART_ITEM, 0 },
221 
222  // extra stuff for support
223  { "stay near me", STAY_NEAR_ME_ITEM, 0 },
224  { "stay near ship", STAY_NEAR_TARGET_ITEM, 0 },
225  { "keep safe dist", KEEP_SAFE_DIST_ITEM, 0 }
226 };
227 
228 const int Num_player_orders = sizeof(Player_orders)/sizeof(flag_def_list);
229 
230 // Use the last parameter here to tell the parser whether to stuff the flag into flags or flags2
232  { "untargetable", MSS_FLAG_UNTARGETABLE, 0 },
233  { "carry no damage", MSS_FLAG_CARRY_NO_DAMAGE, 0 },
234  { "use multiple guns", MSS_FLAG_USE_MULTIPLE_GUNS, 0 },
235  { "fire down normals", MSS_FLAG_FIRE_ON_NORMAL, 0 },
236  { "check hull", MSS_FLAG_TURRET_HULL_CHECK, 0 },
237  { "fixed firingpoints", MSS_FLAG_TURRET_FIXED_FP, 0 },
238  { "salvo mode", MSS_FLAG_TURRET_SALVO, 0 },
239  { "no subsystem targeting", MSS_FLAG_NO_SS_TARGETING, 0 },
240  { "fire on target", MSS_FLAG_FIRE_ON_TARGET, 0 },
241  { "reset when idle", MSS_FLAG_TURRET_RESET_IDLE, 0 },
242  { "carry shockwave", MSS_FLAG_CARRY_SHOCKWAVE, 0 },
243  { "allow landing", MSS_FLAG_ALLOW_LANDING, 0 },
244  { "target requires fov", MSS_FLAG_FOV_REQUIRED, 0 },
245  { "fov edge checks", MSS_FLAG_FOV_EDGE_CHECK, 0 },
246  { "no replace", MSS_FLAG_NO_REPLACE, 0 },
247  { "no live debris", MSS_FLAG_NO_LIVE_DEBRIS, 0 },
248  { "ignore if dead", MSS_FLAG_IGNORE_IF_DEAD, 0 },
249  { "allow vanishing", MSS_FLAG_ALLOW_VANISHING, 0 },
250  { "damage as hull", MSS_FLAG_DAMAGE_AS_HULL, 0 },
251  { "starts locked", MSS_FLAG_TURRET_LOCKED, 0 },
252  { "no aggregate", MSS_FLAG_NO_AGGREGATE, 0 },
253  { "wait for animation", MSS_FLAG_TURRET_ANIM_WAIT, 0 },
254  { "play fire sound for player", MSS_FLAG2_PLAYER_TURRET_SOUND, 1},
255  { "only target if can fire", MSS_FLAG2_TURRET_ONLY_TARGET_IF_CAN_FIRE, 1},
256  { "no disappear", MSS_FLAG2_NO_DISAPPEAR, 1},
257  { "collide submodel", MSS_FLAG2_COLLIDE_SUBMODEL, 1},
258  { "allow destroyed rotation", MSS_FLAG2_DESTROYED_ROTATION, 1},
259  { "turret use ammo", MSS_FLAG2_TURRET_USE_AMMO, 1},
260  { "autorepair if disabled", MSS_FLAG2_AUTOREPAIR_IF_DISABLED, 1},
261  { "don't autorepair if disabled", MSS_FLAG2_NO_AUTOREPAIR_IF_DISABLED, 1},
262  { "share fire direction", MSS_FLAG2_SHARE_FIRE_DIRECTION, 1 }
263 };
264 
266 
267 
268 // NOTE: a var of:
269 // "0" means that it's a SIF_* flag
270 // "1" means that it's a SIF2_* flag
271 // "255" means that the option is obsolete and a warning should be generated
273  { "no_collide", SIF_NO_COLLIDE, 0 },
274  { "player_ship", SIF_PLAYER_SHIP, 0 },
275  { "default_player_ship", SIF_DEFAULT_PLAYER_SHIP, 0 },
276  { "repair_rearm", SIF_SUPPORT, 0 },
277  { "cargo", SIF_CARGO, 0 },
278  { "fighter", SIF_FIGHTER, 0 },
279  { "bomber", SIF_BOMBER, 0 },
280  { "transport", SIF_TRANSPORT, 0 },
281  { "freighter", SIF_FREIGHTER, 0 },
282  { "capital", SIF_CAPITAL, 0 },
283  { "supercap", SIF_SUPERCAP, 0 },
284  { "drydock", SIF_DRYDOCK, 0 },
285  { "cruiser", SIF_CRUISER, 0 },
286  { "navbuoy", SIF_NAVBUOY, 0 },
287  { "sentrygun", SIF_SENTRYGUN, 0 },
288  { "escapepod", SIF_ESCAPEPOD, 0 },
289  { "stealth", SIF_STEALTH, 0 },
290  { "no type", SIF_NO_SHIP_TYPE, 0 },
291  { "ship copy", SIF_SHIP_COPY, 0 },
292  { "in tech database", SIF_IN_TECH_DATABASE | SIF_IN_TECH_DATABASE_M, 0 },
293  { "in tech database multi", SIF_IN_TECH_DATABASE_M, 0 },
294  { "dont collide invisible", SIF_SHIP_CLASS_DONT_COLLIDE_INVIS, 0 },
295  { "big damage", SIF_BIG_DAMAGE, 0 },
296  { "corvette", SIF_CORVETTE, 0 },
297  { "gas miner", SIF_GAS_MINER, 0 },
298  { "awacs", SIF_AWACS, 0 },
299  { "knossos", SIF_KNOSSOS_DEVICE, 0 },
300  { "no_fred", SIF_NO_FRED, 0 },
301  { "flash", SIF2_FLASH, 1 },
302  { "surface shields", SIF2_SURFACE_SHIELDS, 1 },
303  { "show ship", SIF2_SHOW_SHIP_MODEL, 1 },
304  { "generate icon", SIF2_GENERATE_HUD_ICON, 1 },
305  { "no weapon damage scaling", SIF2_DISABLE_WEAPON_DAMAGE_SCALING, 1 },
306  { "gun convergence", SIF2_GUN_CONVERGENCE, 1 },
307  { "no thruster geometry noise", SIF2_NO_THRUSTER_GEO_NOISE, 1 },
308  { "intrinsic no shields", SIF2_INTRINSIC_NO_SHIELDS, 1 },
309  { "dynamic primary linking", SIF2_DYN_PRIMARY_LINKING, 1 },
310  { "no primary linking", SIF2_NO_PRIMARY_LINKING, 1 },
311  { "no pain flash", SIF2_NO_PAIN_FLASH, 1 },
312  { "no ets", SIF2_NO_ETS, 1 },
313  { "no lighting", SIF2_NO_LIGHTING, 1 },
314  { "auto spread shields", SIF2_AUTO_SPREAD_SHIELDS, 1 },
315  { "model point shields", SIF2_MODEL_POINT_SHIELDS, 1 },
316  { "repair disabled subsystems", SIF2_SUBSYS_REPAIR_WHEN_DISABLED, 1},
317 
318  // to keep things clean, obsolete options go last
319  { "ballistic primaries", -1, 255 }
320 };
321 
322 const int Num_ship_flags = sizeof(Ship_flags) / sizeof(flag_def_list);
323 
324 /*
325 ++Here be dragons.. err.. begins the section for the ai targeting revision
326 ++ First flag_def_list (& its size) for object types (ship/asteroid/weapon)
327 ++ List of reasonable object flags (from object.h)
328 ++ List of potentially useful ship class flags
329 ++ List of potentially useful weapon class flags
330 */
332  { "ship", OBJ_SHIP, 0 },
333  { "asteroid", OBJ_ASTEROID, 0 },
334  { "weapon", OBJ_WEAPON, 0 }
335 };
336 
337 const int num_ai_tgt_objects = sizeof(ai_tgt_objects) / sizeof(flag_def_list);
338 
340  { "no shields", OF_NO_SHIELDS, 0 },
341  { "targetable as bomb", OF_TARGETABLE_AS_BOMB, 0 }
342 };
343 
345 
347  { "afterburners", SIF_AFTERBURNER, 0 },
348  { "big damage", SIF_BIG_DAMAGE, 0 },
349  { "has awacs", SIF_HAS_AWACS, 0 }
350 };
351 
353 
355  { "bomb", WIF_BOMB, 0 },
356  { "huge damage", WIF_HUGE, 0 },
357  { "supercap damage", WIF_SUPERCAP, 0 },
358  { "bomber+", WIF_BOMBER_PLUS, 0 },
359  { "electronics", WIF_ELECTRONICS, 0 },
360  { "puncture", WIF_PUNCTURE, 0 },
361  { "emp", WIF_EMP, 0 },
362  { "heat seeking", WIF_HOMING_HEAT, 0 },
363  { "aspect seeking", WIF_HOMING_ASPECT, 0 },
364  { "engine seeking", WIF_HOMING_JAVELIN, 0 },
365  { "pierce shields", WIF2_PIERCE_SHIELDS, 1 },
366  { "local ssm", WIF2_LOCAL_SSM, 1 },
367  { "capital+", WIF2_CAPITAL_PLUS, 1 }
368 };
369 
370 // Constant for flag, Name of flag, In flags or flags2
371 // When adding new flags remember to bump MAX_SHIP_FLAG_NAMES in ship.h
373  {SF_VAPORIZE, "vaporize", 1, },
374  {SF_WARP_BROKEN, "break-warp", 1, },
375  {SF_WARP_NEVER, "never-warp", 1, },
376  {SF_SCANNABLE, "scannable", 1, },
377  {SF_CARGO_REVEALED, "cargo-known", 1, },
378  {SF_HIDDEN_FROM_SENSORS, "hidden-from-sensors", 1, },
379  {SF2_STEALTH, "stealth", 2, },
380  {SF2_FRIENDLY_STEALTH_INVIS, "friendly-stealth-invisible", 2, },
381  {SF2_HIDE_SHIP_NAME, "hide-ship-name", 2, },
382  {SF2_PRIMITIVE_SENSORS, "primitive-sensors", 2, },
383  {SF2_AFTERBURNER_LOCKED, "afterburners-locked", 2, },
384  {SF2_PRIMARIES_LOCKED, "primaries-locked", 2, },
385  {SF2_SECONDARIES_LOCKED, "secondaries-locked", 2, },
386  {SF2_NO_SUBSPACE_DRIVE, "no-subspace-drive", 2, },
387  {SF2_DONT_COLLIDE_INVIS, "don't-collide-invisible", 2, },
388  {SF2_NO_ETS, "no-ets", 2, },
389  {SF2_TOGGLE_SUBSYSTEM_SCANNING, "toggle-subsystem-scanning", 2, },
390  {SF2_NO_SECONDARY_LOCKON, "no-secondary-lock-on", 2, },
391  {SF2_NO_DISABLED_SELF_DESTRUCT, "no-disabled-self-destruct", 2, },
392 };
393 
395 
397 
398 static int Laser_energy_out_snd_timer; // timer so we play out of laser sound effect periodically
399 static int Missile_out_snd_timer; // timer so we play out of laser sound effect periodically
400 
402 
403 // I don't want to do an AI cargo check every frame, so I made a global timer to limit check to
404 // every SHIP_CARGO_CHECK_INTERVAL ms. Didn't want to make a timer in each ship struct. Ensure
405 // inited to 1 at mission start.
406 static int Ship_cargo_check_timer;
407 
408 static int Thrust_anim_inited = 0;
409 
410 int ship_get_subobj_model_num(ship_info* sip, char* subobj_name);
411 
413 
419 {
420  Ship_objs[index].flags = 0;
421  Ship_objs[index].next = NULL;
422  Ship_objs[index].prev = (ship_obj*)-1;
423 }
424 
429 {
430  int i;
431 
432  for (i=0; i<MAX_STARTING_WINGS; i++)
433  {
434  if (shipp->wingnum == Starting_wings[i])
435  return 1;
436  }
437 
438  for (i=0; i<MAX_TVT_WINGS; i++)
439  {
440  if (shipp->wingnum == TVT_wings[i])
441  return 1;
442  }
443 
444  // not in
445  return 0;
446 }
447 
452 {
453  int i;
454 
455  list_init(&Ship_obj_list);
456  for ( i = 0; i < MAX_SHIP_OBJS; i++ ) {
458  }
459 }
460 
465 int ship_obj_list_add(int objnum)
466 {
467  int i;
468 
469  for ( i = 0; i < MAX_SHIP_OBJS; i++ ) {
470  if ( !(Ship_objs[i].flags & SHIP_OBJ_USED) )
471  break;
472  }
473  if ( i == MAX_SHIP_OBJS ) {
474  Error(LOCATION, "Fatal Error: Ran out of ship object nodes\n");
475  return -1;
476  }
477 
478  Ship_objs[i].flags = 0;
479  Ship_objs[i].objnum = objnum;
480  list_append(&Ship_obj_list, &Ship_objs[i]);
481  Ship_objs[i].flags |= SHIP_OBJ_USED;
482 
483  return i;
484 }
485 
491 {
492  Assert(index >= 0 && index < MAX_SHIP_OBJS);
493  list_remove( Ship_obj_list, &Ship_objs[index]);
495 }
496 
501 {
502  object *objp;
503 
505 
506  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
507  if ( objp->type == OBJ_SHIP ) {
508  Ships[objp->instance].ship_list_index = ship_obj_list_add(OBJ_INDEX(objp));
509  }
510  }
511 }
512 
514 {
515  Assert(index >= 0 && index < MAX_SHIP_OBJS);
516  return &Ship_objs[index];
517 }
518 
523 {
524  int count;
525  ship_obj *so;
526 
527  count = 0;
528  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) )
529  count++;
530 
531  return count;
532 }
533 
535 {
536  ewi->name[0] = '\0';
537  ewi->angle = PI / 10.0f;
538  ewi->radius_mult = 1.0f;
539  ewi->length = 500.0f;
540  ewi->intensity = 1.0f;
541 }
542 
546 void parse_engine_wash(bool replace)
547 {
548  engine_wash_info ewt;
549  engine_wash_info_init(&ewt);
550 
551  engine_wash_info *ewp;
552  bool create_if_not_found = true;
553 
554  // name of engine wash info
555  required_string("$Name:");
557 
558  if(optional_string("+nocreate")) {
559  if(!replace) {
560  Warning(LOCATION, "+nocreate flag used for engine wash in non-modular table");
561  }
562  create_if_not_found = false;
563  }
564 
565  //Does this engine wash exist already?
566  //If so, load this new info into it
567  //Otherwise, increment Num_engine_wash_types
568  ewp = get_engine_wash_pointer(ewt.name);
569  if(ewp != NULL)
570  {
571  if(replace)
572  {
573  nprintf(("Warning", "More than one version of engine wash %s exists; using newer version.", ewt.name));
574  }
575  else
576  {
577  Error(LOCATION, "Error: Engine wash %s already exists. All engine wash names must be unique.", ewt.name);
578  }
579  }
580  else
581  {
582  //Don't create engine wash if it has +nocreate and is in a modular table.
583  if(!create_if_not_found && replace)
584  {
585  if ( !skip_to_start_of_string_either("$Name:", "#End")) {
586  Int3();
587  }
588  return;
589  }
590  Engine_wash_info.push_back(ewt);
591  ewp = &Engine_wash_info[Num_engine_wash_types++];
592  }
593 
594 
595  // half angle of cone of wash from thruster
596  if(optional_string("$Angle:"))
597  {
598  stuff_float(&ewp->angle);
599  ewp->angle *= (PI / 180.0f);
600  }
601 
602  // radius multiplier for hemisphere around thruster pt
603  if(optional_string("$Radius Mult:")) {
604  stuff_float(&ewp->radius_mult);
605  }
606 
607  // length of cone
608  if(optional_string("$Length:")) {
609  stuff_float(&ewp->length);
610  }
611 
612  // intensity inside hemisphere (or at 0 distance from frustated cone)
613  if(optional_string("$Intensity:")) {
614  stuff_float(&ewp->intensity);
615  }
616 }
617 
618 char *Warp_types[] = {
619  "Default",
620  "Knossos",
621  "Babylon5",
622  "Galactica",
623  "Homeworld",
624  "Hyperspace",
625 };
626 
627 int Num_warp_types = sizeof(Warp_types)/sizeof(char*);
628 
629 int warptype_match(char *p)
630 {
631  int i;
632  for(i = 0; i < Num_warp_types; i++)
633  {
634  if(!stricmp(Warp_types[i], p))
635  return i;
636  }
637 
638  return -1;
639 }
640 
641 char *Lightning_types[] = {
642  "None",
643  "Default",
644 };
645 
646 int Num_lightning_types = sizeof(Lightning_types)/sizeof(char*);
647 
649 {
650  int i;
651  for(i = 0; i < Num_lightning_types; i++)
652  {
653  if(!stricmp(Lightning_types[i], p))
654  return i;
655  }
656 
657  return -1;
658 }
659 
660 // Kazan -- Volition had this set to 1500, Set it to 4K for WC Saga
661 #define SHIP_MULTITEXT_LENGTH 4096
662 #define DEFAULT_DELTA_BANK_CONST 0.5f
663 
664 #define CHECK_THEN_COPY(attribute) \
665 do {\
666  if (other.attribute != NULL)\
667  attribute = vm_strdup( other.attribute );\
668 } while(false)
669 
670 void ship_info::clone(const ship_info& other)
671 {
672  strcpy_s(name, other.name);
673  strcpy_s(alt_name, other.alt_name);
675  species = other.species;
676  class_type = other.class_type;
677 
684 
686 
690 
693  strcpy_s(pof_file, other.pof_file);
696  memcpy(detail_distance, other.detail_distance, sizeof(int) * MAX_SHIP_DETAIL_LEVELS);
698 
699  // I'm not sure if these three are A) a good idea or B) relevant at all. -MageKing17
701  model_num = other.model_num;
703 
705  density = other.density;
706  damp = other.damp;
707  rotdamp = other.rotdamp;
709  max_vel = other.max_vel;
710  max_rotvel = other.max_rotvel;
713  max_rear_vel = other.max_rear_vel;
716  slide_accel = other.slide_accel;
717  slide_decel = other.slide_decel;
718 
723  warpin_speed = other.warpin_speed;
724  warpin_time = other.warpin_time;
726  warpin_type = other.warpin_type;
727 
734  warpout_time = other.warpout_time;
736  warpout_type = other.warpout_type;
737 
739 
740  flags = other.flags;
741  flags2 = other.flags2;
742  ai_class = other.ai_class;
743  max_speed = other.max_speed;
744  min_speed = other.min_speed;
745  max_accel = other.max_accel;
746 
749 
750  memcpy(&shockwave, &other.shockwave, sizeof(shockwave_create_info));
762 
763  impact_spew = other.impact_spew;
764  damage_spew = other.damage_spew;
768 
780 
781  if ( other.n_subsystems > 0 ) {
782  if( n_subsystems < 1 ) {
784  } else {
785  for ( int i = 0; i < n_subsystems; i++ ) {
786  for ( int j = 0; j < subsystems[i].n_triggers; j++ ) {
787  if ( i < other.n_subsystems ) {
789  } else {
790  vm_free(subsystems[i].triggers);
791  }
792  }
793  }
795  }
796  Assert( subsystems != NULL );
797  for ( int i = n_subsystems; i < other.n_subsystems; i++ ) {
799  }
800 
801  for ( int i = 0; i < other.n_subsystems; i++ ) {
802  queued_animation* triggers = subsystems[i].triggers;
803  subsystems[i] = other.subsystems[i];
804  subsystems[i].triggers = triggers;
805  memcpy(subsystems[i].triggers, other.subsystems[i].triggers, sizeof(queued_animation) * (subsystems[i].n_triggers));
806  }
807  }
808  n_subsystems = other.n_subsystems;
809 
810  power_output = other.power_output;
815 
823 
825  cmeasure_max = other.cmeasure_max;
826 
829  memcpy(primary_bank_ammo_capacity, other.primary_bank_ammo_capacity, sizeof(int) * MAX_SHIP_PRIMARY_BANKS);
830 
833  memcpy(secondary_bank_ammo_capacity, other.secondary_bank_ammo_capacity, sizeof(int) * MAX_SHIP_SECONDARY_BANKS);
834 
835  memcpy(draw_primary_models, other.draw_primary_models, sizeof(bool) * MAX_SHIP_PRIMARY_BANKS);
836  memcpy(draw_secondary_models, other.draw_secondary_models, sizeof(bool) * MAX_SHIP_SECONDARY_BANKS);
838 
846 
847  // ...Hmm. A memcpy() seems slightly overkill here, but I've settled into the pattern of "array gets memcpy'd", so... -MageKing17
848  memcpy(shield_point_augment_ctrls, other.shield_point_augment_ctrls, sizeof(int) * 4);
849 
852 
856 
857  closeup_pos = other.closeup_pos;
858  closeup_zoom = other.closeup_zoom;
859 
860  memcpy(allowed_weapons, other.allowed_weapons, sizeof(int) * MAX_WEAPON_TYPES);
861 
863  memcpy(allowed_bank_restricted_weapons, other.allowed_bank_restricted_weapons, sizeof(int) * MAX_SHIP_WEAPONS * MAX_WEAPON_TYPES);
864 
871 
876 
877  score = other.score;
878 
879  scan_time = other.scan_time;
880 
881  memcpy(ct_info, other.ct_info, sizeof(trail_info) * MAX_SHIP_CONTRAILS);
882  ct_count = other.ct_count;
883 
885  memcpy(nondark_colors, other.nondark_colors, sizeof(ubyte) * MAX_NONDARK_COLORS * 3);
886 
887  memcpy(shield_color, other.shield_color, sizeof(ubyte) * 3);
888 
891 
897 
900 
901  memcpy(&thruster_flame_info, &other.thruster_flame_info, sizeof(thrust_pair));
902  memcpy(&thruster_glow_info, &other.thruster_glow_info, sizeof(thrust_pair));
906 
914 
916 
919 
921 
924 
925  can_glide = other.can_glide;
926  glide_cap = other.glide_cap;
931 
932  autoaim_fov = other.autoaim_fov;
933 
936 
937  engine_snd = other.engine_snd;
941 
942  ship_sounds = other.ship_sounds;
943 
945  memcpy(maneuvering, other.maneuvering, sizeof(man_thruster) * MAX_MAN_THRUSTERS);
946 
951 
952  memcpy(ship_iff_info, other.ship_iff_info, sizeof(int) * MAX_IFFS * MAX_IFFS);
953 
954  aiming_flags = other.aiming_flags;
958 
960 
962 
964 
966  hud_gauges = other.hud_gauges;
967  hud_enabled = other.hud_enabled;
968  hud_retail = other.hud_retail;
969 
970  displays = other.displays;
971 
972  pathMetadata = other.pathMetadata;
973 
975 }
976 
977 void ship_info::move(ship_info&& other)
978 {
979  std::swap(name, other.name);
980  std::swap(alt_name, other.alt_name);
981  std::swap(short_name, other.short_name);
982  species = other.species;
983  class_type = other.class_type;
984 
985  std::swap(type_str, other.type_str);
986  std::swap(maneuverability_str, other.maneuverability_str);
987  std::swap(armor_str, other.armor_str);
988  std::swap(manufacturer_str, other.manufacturer_str);
989  std::swap(desc, other.desc);
990  std::swap(tech_desc, other.tech_desc);
991 
992  std::swap(tech_title, other.tech_title);
993 
994  std::swap(ship_length, other.ship_length);
995  std::swap(gun_mounts, other.gun_mounts);
996  std::swap(missile_banks, other.missile_banks);
997 
998  std::swap(cockpit_pof_file, other.cockpit_pof_file);
999  std::swap(cockpit_offset, other.cockpit_offset);
1000  std::swap(pof_file, other.pof_file);
1001  std::swap(pof_file_hud, other.pof_file_hud);
1002  num_detail_levels = other.num_detail_levels;
1003  std::swap(detail_distance, other.detail_distance);
1004  collision_lod = other.collision_lod;
1005 
1006  cockpit_model_num = other.cockpit_model_num;
1007  model_num = other.model_num;
1008  model_num_hud = other.model_num_hud;
1009 
1010  hud_target_lod = other.hud_target_lod;
1011  density = other.density;
1012  damp = other.damp;
1013  rotdamp = other.rotdamp;
1014  delta_bank_const = other.delta_bank_const;
1015  std::swap(max_vel, other.max_vel);
1016  std::swap(max_rotvel, other.max_rotvel);
1017  std::swap(rotation_time, other.rotation_time);
1018  srotation_time = other.srotation_time;
1019  max_rear_vel = other.max_rear_vel;
1020  forward_accel = other.forward_accel;
1021  forward_decel = other.forward_decel;
1022  slide_accel = other.slide_accel;
1023  slide_decel = other.slide_decel;
1024 
1025  std::swap(warpin_anim, other.warpin_anim);
1026  warpin_radius = other.warpin_radius;
1027  warpin_snd_start = other.warpin_snd_start;
1028  warpin_snd_end = other.warpin_snd_end;
1029  warpin_speed = other.warpin_speed;
1030  warpin_time = other.warpin_time;
1031  warpin_decel_exp = other.warpin_decel_exp;
1032  warpin_type = other.warpin_type;
1033 
1034  std::swap(warpout_anim, other.warpout_anim);
1035  warpout_radius = other.warpout_radius;
1036  warpout_snd_start = other.warpout_snd_start;
1037  warpout_snd_end = other.warpout_snd_end;
1038  warpout_engage_time = other.warpout_engage_time;
1039  warpout_speed = other.warpout_speed;
1040  warpout_time = other.warpout_time;
1041  warpout_accel_exp = other.warpout_accel_exp;
1042  warpout_type = other.warpout_type;
1043 
1044  warpout_player_speed = other.warpout_player_speed;
1045 
1046  flags = other.flags;
1047  flags2 = other.flags2;
1048  ai_class = other.ai_class;
1049  max_speed = other.max_speed;
1050  min_speed = other.min_speed;
1051  max_accel = other.max_accel;
1052 
1053  collision_damage_type_idx = other.collision_damage_type_idx;
1054  std::swap(collision_physics, other.collision_physics);
1055 
1056  std::swap(shockwave, other.shockwave);
1057  explosion_propagates = other.explosion_propagates;
1058  big_exp_visual_rad = other.big_exp_visual_rad;
1059  prop_exp_rad_mult = other.prop_exp_rad_mult;
1060  death_roll_r_mult = other.death_roll_r_mult;
1061  death_fx_r_mult = other.death_fx_r_mult;
1062  death_roll_time_mult = other.death_roll_time_mult;
1063  death_roll_base_time = other.death_roll_base_time;
1064  death_fx_count = other.death_fx_count;
1065  shockwave_count = other.shockwave_count;
1066  std::swap(explosion_bitmap_anims, other.explosion_bitmap_anims);
1067  vaporize_chance = other.vaporize_chance;
1068 
1069  std::swap(impact_spew, other.impact_spew);
1070  std::swap(damage_spew, other.damage_spew);
1071  std::swap(split_particles, other.split_particles);
1072  std::swap(knossos_end_particles, other.knossos_end_particles);
1073  std::swap(regular_end_particles, other.regular_end_particles);
1074 
1075  debris_min_lifetime = other.debris_min_lifetime;
1076  debris_max_lifetime = other.debris_max_lifetime;
1077  debris_min_speed = other.debris_min_speed;
1078  debris_max_speed = other.debris_max_speed;
1079  debris_min_rotspeed = other.debris_min_rotspeed;
1080  debris_max_rotspeed = other.debris_max_rotspeed;
1081  debris_damage_type_idx = other.debris_damage_type_idx;
1082  debris_min_hitpoints = other.debris_min_hitpoints;
1083  debris_max_hitpoints = other.debris_max_hitpoints;
1084  debris_damage_mult = other.debris_damage_mult;
1085  debris_arc_percent = other.debris_arc_percent;
1086 
1087  std::swap(subsystems, other.subsystems);
1088  std::swap(n_subsystems, other.n_subsystems);
1089 
1090  power_output = other.power_output;
1091  max_overclocked_speed = other.max_overclocked_speed;
1092  max_weapon_reserve = other.max_weapon_reserve;
1093  max_shield_regen_per_second = other.max_shield_regen_per_second;
1094  max_weapon_regen_per_second = other.max_weapon_regen_per_second;
1095 
1096  std::swap(afterburner_max_vel, other.afterburner_max_vel);
1097  afterburner_forward_accel = other.afterburner_forward_accel;
1098  afterburner_fuel_capacity = other.afterburner_fuel_capacity;
1099  afterburner_burn_rate = other.afterburner_burn_rate;
1100  afterburner_recover_rate = other.afterburner_recover_rate;
1101  afterburner_max_reverse_vel = other.afterburner_max_reverse_vel;
1102  afterburner_reverse_accel = other.afterburner_reverse_accel;
1103 
1104  cmeasure_type = other.cmeasure_type;
1105  cmeasure_max = other.cmeasure_max;
1106 
1107  num_primary_banks = other.num_primary_banks;
1108  std::swap(primary_bank_weapons, other.primary_bank_weapons);
1109  std::swap(primary_bank_ammo_capacity, other.primary_bank_ammo_capacity);
1110 
1111  num_secondary_banks = other.num_secondary_banks;
1112  std::swap(secondary_bank_weapons, other.secondary_bank_weapons);
1113  std::swap(secondary_bank_ammo_capacity, other.secondary_bank_ammo_capacity);
1114 
1115  std::swap(draw_primary_models, other.draw_primary_models);
1116  std::swap(draw_secondary_models, other.draw_secondary_models);
1117  weapon_model_draw_distance = other.weapon_model_draw_distance;
1118 
1119  max_hull_strength = other.max_hull_strength;
1120  max_shield_strength = other.max_shield_strength;
1121  max_shield_recharge = other.max_shield_recharge;
1122  auto_shield_spread = other.auto_shield_spread;
1123  auto_shield_spread_bypass = other.auto_shield_spread_bypass;
1124  auto_shield_spread_from_lod = other.auto_shield_spread_from_lod;
1125  auto_shield_spread_min_span = other.auto_shield_spread_min_span;
1126 
1127  std::swap(shield_point_augment_ctrls, other.shield_point_augment_ctrls);
1128 
1129  hull_repair_rate = other.hull_repair_rate;
1130  subsys_repair_rate = other.subsys_repair_rate;
1131 
1132  sup_hull_repair_rate = other.sup_hull_repair_rate;
1133  sup_shield_repair_rate = other.sup_shield_repair_rate;
1134  sup_subsys_repair_rate = other.sup_subsys_repair_rate;
1135 
1136  std::swap(closeup_pos, other.closeup_pos);
1137  closeup_zoom = other.closeup_zoom;
1138 
1139  std::swap(allowed_weapons, other.allowed_weapons);
1140 
1141  std::swap(restricted_loadout_flag, other.restricted_loadout_flag);
1142  memcpy(allowed_bank_restricted_weapons, other.allowed_bank_restricted_weapons, sizeof(int) * MAX_SHIP_WEAPONS * MAX_WEAPON_TYPES);
1143 
1144  shield_icon_index = other.shield_icon_index;
1145  std::swap(icon_filename, other.icon_filename);
1146  model_icon_angles = other.model_icon_angles;
1147  std::swap(anim_filename, other.anim_filename);
1148  std::swap(overhead_filename, other.overhead_filename);
1149  selection_effect = other.selection_effect;
1150 
1151  bii_index_ship = other.bii_index_ship;
1152  bii_index_ship_with_cargo = other.bii_index_ship_with_cargo;
1153  bii_index_wing = other.bii_index_wing;
1154  bii_index_wing_with_cargo = other.bii_index_wing_with_cargo;
1155 
1156  score = other.score;
1157 
1158  scan_time = other.scan_time;
1159 
1160  std::swap(ct_info, other.ct_info);
1161  ct_count = other.ct_count;
1162 
1163  num_nondark_colors = other.num_nondark_colors;
1164  memcpy(nondark_colors, other.nondark_colors, sizeof(ubyte) * MAX_NONDARK_COLORS * 3);
1165 
1166  std::swap(shield_color, other.shield_color);
1167 
1168  uses_team_colors = other.uses_team_colors;
1169  std::swap(default_team_name, other.default_team_name);
1170 
1171  std::swap(afterburner_trail, other.afterburner_trail);
1172  afterburner_trail_width_factor = other.afterburner_trail_width_factor;
1173  afterburner_trail_alpha_factor = other.afterburner_trail_alpha_factor;
1174  afterburner_trail_life = other.afterburner_trail_life;
1175  afterburner_trail_faded_out_sections = other.afterburner_trail_faded_out_sections;
1176 
1177  std::swap(normal_thruster_particles, other.normal_thruster_particles);
1178  std::swap(afterburner_thruster_particles, other.afterburner_thruster_particles);
1179 
1180  std::swap(thruster_flame_info, other.thruster_flame_info);
1181  std::swap(thruster_glow_info, other.thruster_glow_info);
1182  std::swap(thruster_secondary_glow_info, other.thruster_secondary_glow_info);
1183  std::swap(thruster_tertiary_glow_info, other.thruster_tertiary_glow_info);
1184  std::swap(thruster_distortion_info, other.thruster_distortion_info);
1185 
1186  thruster01_glow_rad_factor = other.thruster01_glow_rad_factor;
1187  thruster02_glow_rad_factor = other.thruster02_glow_rad_factor;
1188  thruster03_glow_rad_factor = other.thruster03_glow_rad_factor;
1189  thruster02_glow_len_factor = other.thruster02_glow_len_factor;
1190  thruster_dist_rad_factor = other.thruster_dist_rad_factor;
1191  thruster_dist_len_factor = other.thruster_dist_len_factor;
1192  thruster_glow_noise_mult = other.thruster_glow_noise_mult;
1193 
1194  draw_distortion = other.draw_distortion;
1195 
1196  splodeing_texture = other.splodeing_texture;
1197  std::swap(splodeing_texture_name, other.splodeing_texture_name);
1198 
1199  std::swap(replacement_textures, other.replacement_textures);
1200 
1201  armor_type_idx = other.armor_type_idx;
1202  shield_armor_type_idx = other.shield_armor_type_idx;
1203 
1204  can_glide = other.can_glide;
1205  glide_cap = other.glide_cap;
1206  glide_dynamic_cap = other.glide_dynamic_cap;
1207  glide_accel_mult = other.glide_accel_mult;
1208  use_newtonian_damp = other.use_newtonian_damp;
1209  newtonian_damp_override = other.newtonian_damp_override;
1210 
1211  autoaim_fov = other.autoaim_fov;
1212 
1213  topdown_offset_def = other.topdown_offset_def;
1214  std::swap(topdown_offset, other.topdown_offset);
1215 
1216  engine_snd = other.engine_snd;
1217  min_engine_vol = other.min_engine_vol;
1218  glide_start_snd = other.glide_start_snd;
1219  glide_end_snd = other.glide_end_snd;
1220 
1221  std::swap(ship_sounds, other.ship_sounds);
1222 
1223  num_maneuvering = other.num_maneuvering;
1224  std::swap(maneuvering, other.maneuvering);
1225 
1226  radar_image_2d_idx = other.radar_image_2d_idx;
1227  radar_color_image_2d_idx = other.radar_color_image_2d_idx;
1228  radar_image_size = other.radar_image_size;
1229  radar_projection_size_mult = other.radar_projection_size_mult;
1230 
1231  memcpy(ship_iff_info, other.ship_iff_info, sizeof(int) * MAX_IFFS * MAX_IFFS);
1232 
1233  aiming_flags = other.aiming_flags;
1234  minimum_convergence_distance = other.minimum_convergence_distance;
1235  convergence_distance = other.convergence_distance;
1236  std::swap(convergence_offset, other.convergence_offset);
1237 
1238  emp_resistance_mod = other.emp_resistance_mod;
1239 
1240  piercing_damage_draw_limit = other.piercing_damage_draw_limit;
1241 
1242  damage_lightning_type = other.damage_lightning_type;
1243 
1244  shield_impact_explosion_anim = other.shield_impact_explosion_anim;
1245  std::swap(hud_gauges, other.hud_gauges);
1246  hud_enabled = other.hud_enabled;
1247  hud_retail = other.hud_retail;
1248 
1249  std::swap(displays, other.displays);
1250 
1251  std::swap(pathMetadata, other.pathMetadata);
1252 
1253  std::swap(glowpoint_bank_override_map, other.glowpoint_bank_override_map);
1254 }
1255 
1256 #define CHECK_THEN_FREE(attribute) \
1257 do {\
1258  if (attribute != NULL) {\
1259  vm_free(attribute);\
1260  attribute = NULL;\
1261  }\
1262 } while(false)
1263 
1265 {
1275 }
1276 
1278 {
1279  if (this != &other) {
1280  move(std::move(other));
1281  }
1282  return *this;
1283 }
1284 
1286 {
1287  // MageKing17 - Initialize these pointers to NULL because otherwise move() will leave them uninitialized.
1288  type_str = NULL;
1289  maneuverability_str = NULL;
1290  armor_str = NULL;
1291  manufacturer_str = NULL;
1292  desc = NULL;
1293  tech_desc = NULL;
1294  ship_length = NULL;
1295  gun_mounts = NULL;
1296  missile_banks = NULL;
1297  subsystems = NULL;
1298  n_subsystems = 0;
1299 
1300  // Then we swap everything (well, everything that matters to the deconstructor).
1301  move(std::move(other));
1302 }
1303 
1305 {
1306  int i,j;
1307 
1308  name[0] = '\0';
1309  alt_name[0] = '\0';
1310  sprintf(short_name, "ShipClass%d", static_cast<int>(Ship_info.size()));
1311  species = 0;
1312  class_type = -1;
1313 
1315  desc = tech_desc = NULL;
1316  tech_title[0] = 0;
1317 
1318  ship_length = NULL;
1319  gun_mounts = NULL;
1320  missile_banks = NULL;
1321 
1322  cockpit_pof_file[0] = '\0';
1324  pof_file[0] = '\0';
1325  pof_file_hud[0] = '\0';
1326  num_detail_levels = 1;
1327  detail_distance[0] = 0;
1328  collision_lod = -1;
1329  cockpit_model_num = -1;
1330  model_num = -1;
1331  model_num_hud = -1;
1332  hud_target_lod = -1;
1333 
1334  density = 1.0f;
1335  damp = 0.0f;
1336  rotdamp = 0.0f;
1338  vm_vec_zero(&max_vel);
1341  srotation_time = 0.0f;
1342  max_rear_vel = 0.0f;
1343  forward_accel = 0.0f;
1344  forward_decel = 0.0f;
1345  slide_accel = 0.0f;
1346  slide_decel = 0.0f;
1347 
1348  warpin_anim[0] = '\0';
1349  warpin_radius = 0.0f;
1350  warpin_snd_start = -1;
1351  warpin_snd_end = -1;
1352  warpin_speed = 0.0f;
1353  warpin_time = 0;
1354  warpin_decel_exp = 1;
1356 
1357  warpout_anim[0] = '\0';
1358  warpout_radius = 0.0f;
1359  warpout_snd_start = -1;
1360  warpout_snd_end = -1;
1361  warpout_engage_time = -1;
1362  warpout_speed = 0.0f;
1363  warpout_time = 0;
1364  warpout_accel_exp = 1;
1366 
1367  warpout_player_speed = 0.0f;
1368 
1371  ai_class = 0;
1372  max_speed = 0.0f;
1373  min_speed = 0.0f;
1374  max_accel = 0.0f;
1375 
1377  // Retail default collision physics and default landing parameters
1378  memset(&collision_physics, 0, sizeof(ship_collision_physics));
1380  collision_physics.bounce = 5.0;
1385 
1388  big_exp_visual_rad = -1.0f;
1389  prop_exp_rad_mult = 1.0f;
1390  death_roll_r_mult = 1.0f;
1391  death_fx_r_mult = 1.0f;
1392  death_roll_time_mult = 1.0f;
1393  death_roll_base_time = 3000;
1394  death_fx_count = 6;
1395  shockwave_count = 1;
1396  explosion_bitmap_anims.clear();
1397  vaporize_chance = 0;
1398 
1399  // default values from shipfx.cpp
1400  impact_spew.n_high = 30;
1401  impact_spew.n_low = 25;
1402  impact_spew.max_rad = 0.5f;
1403  impact_spew.min_rad = 0.2f;
1404  impact_spew.max_life = 0.55f;
1405  impact_spew.min_life = 0.05f;
1406  impact_spew.max_vel = 12.0f;
1407  impact_spew.min_vel = 2.0f;
1408  impact_spew.variance = 1.0f;
1409 
1410  // default values from shipfx.cpp
1411  damage_spew.n_high = 1; // 1 is used here to trigger retail behaviour
1412  damage_spew.n_low = 0;
1413  damage_spew.max_rad = 1.3f;
1414  damage_spew.min_rad = 0.7f;
1415  damage_spew.max_life = 0.0f;
1416  damage_spew.min_life = 0.0f;
1417  damage_spew.max_vel = 12.0f;
1418  damage_spew.min_vel = 3.0f;
1419  damage_spew.variance = 0.0f;
1420 
1421  split_particles.n_high = 80;
1422  split_particles.n_low = 40;
1423  split_particles.max_rad = 0.0f;
1424  split_particles.min_rad = 0.0f;
1425  split_particles.max_life = 0.0f;
1426  split_particles.min_life = 0.0f;
1427  split_particles.max_vel = 0.0f;
1428  split_particles.min_vel = 0.0f;
1429  split_particles.variance = 2.0f;
1430 
1433  knossos_end_particles.max_rad = 100.0f;
1437  knossos_end_particles.max_vel = 350.0f;
1440 
1450 
1451  debris_min_lifetime = -1.0f;
1452  debris_max_lifetime = -1.0f;
1453  debris_min_speed = -1.0f;
1454  debris_max_speed = -1.0f;
1455  debris_min_rotspeed = -1.0f;
1456  debris_max_rotspeed = -1.0f;
1458  debris_min_hitpoints = -1.0f;
1459  debris_max_hitpoints = -1.0f;
1460  debris_damage_mult = 1.0f;
1461  debris_arc_percent = 0.5f;
1462 
1463  n_subsystems = 0;
1464  subsystems = NULL;
1465 
1466  power_output = 0.0f;
1467  max_overclocked_speed = 0.0f;
1468  max_weapon_reserve = 0.0f;
1471 
1475  afterburner_burn_rate = 0.0f;
1476  afterburner_recover_rate = 0.0f;
1479 
1481  cmeasure_max = 0;
1482 
1483  num_primary_banks = 0;
1484  for ( i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++ )
1485  {
1486  primary_bank_weapons[i] = -1;
1487  draw_primary_models[i] = false;
1489  }
1490 
1491  num_secondary_banks = 0;
1492  for ( i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++ )
1493  {
1494  secondary_bank_weapons[i] = -1;
1495  draw_secondary_models[i] = false;
1497  }
1498 
1499  weapon_model_draw_distance = 200.0f;
1500 
1501  ship_recoil_modifier = 1.0f;
1502 
1503  max_hull_strength = 100.0f;
1504  max_shield_strength = 0.0f;
1505 
1506  max_shield_recharge = 1.0f;
1507 
1508  auto_shield_spread = 0.0f;
1509  auto_shield_spread_bypass = false;
1512 
1513  for (i = 0; i < 4; i++)
1514  {
1516  }
1517 
1518  hull_repair_rate = 0.0f;
1519  //-2 represents not set, in which case the default is used for the ship (if it is small)
1520  subsys_repair_rate = -2.0f;
1521 
1522  sup_hull_repair_rate = 0.15f;
1523  sup_shield_repair_rate = 0.20f;
1524  sup_subsys_repair_rate = 0.15f;
1525 
1527  closeup_zoom = 0.5f;
1528 
1529  memset(allowed_weapons, 0, sizeof(int) * MAX_WEAPON_TYPES);
1530 
1531  memset(restricted_loadout_flag, 0, sizeof(int) * MAX_SHIP_WEAPONS);
1532  memset(allowed_bank_restricted_weapons, 0, sizeof(int) * MAX_SHIP_WEAPONS * MAX_WEAPON_TYPES);
1533 
1534  shield_icon_index = 255; // stored as ubyte
1535  icon_filename[0] = '\0';
1536  memset(&model_icon_angles, 0, sizeof(angles));
1537  anim_filename[0] = '\0';
1538  overhead_filename[0] = '\0';
1539 
1541 
1542  bii_index_ship = -1;
1544  bii_index_wing = -1;
1546 
1547  score = 0;
1548 
1549  scan_time = 2000;
1550 
1551  memset(&ct_info, 0, sizeof(trail_info) * MAX_SHIP_CONTRAILS);
1552  ct_count = 0;
1553 
1554  num_nondark_colors = 0;
1555  memset(nondark_colors, 0, sizeof(ubyte) * MAX_NONDARK_COLORS * 3);
1556 
1557  shield_color[0] = 255;
1558  shield_color[1] = 255;
1559  shield_color[2] = 255;
1560 
1561  // Team colors
1562  uses_team_colors = false;
1563  default_team_name = "";
1564 
1568  afterburner_trail_life = 5.0f;
1570 
1571  normal_thruster_particles.clear();
1573 
1574  // Bobboau's thruster stuff
1585 
1586  // Bobboau's thruster stuff
1591  thruster_dist_rad_factor = 2.0f;
1592  thruster_dist_len_factor = 2.0f;
1593  thruster_glow_noise_mult = 1.0f;
1594 
1595  draw_distortion = true;
1596 
1597  splodeing_texture = -1;
1599 
1600  replacement_textures.clear();
1601 
1602  armor_type_idx = -1;
1603  shield_armor_type_idx = -1;
1604 
1605  can_glide = false;
1606  glide_cap = 0.0f;
1607  glide_dynamic_cap = false;
1608  glide_accel_mult = 0.0f;
1609  use_newtonian_damp = false;
1610  newtonian_damp_override = false;
1611 
1612  autoaim_fov = 0.0f;
1613 
1614  topdown_offset_def = false;
1616 
1617  engine_snd = -1;
1618  min_engine_vol = -1.0f;
1619  glide_start_snd = -1;
1620  glide_end_snd = -1;
1621 
1622  ship_sounds.clear();
1623 
1624  num_maneuvering = 0;
1625  memset(maneuvering, 0, MAX_MAN_THRUSTERS * sizeof(man_thruster));
1626  for (i = 0; i < MAX_MAN_THRUSTERS; i++)
1627  {
1628  maneuvering[i].start_snd = -1;
1629  maneuvering[i].loop_snd = -1;
1630  maneuvering[i].stop_snd = -1;
1631  maneuvering[i].tex_id = -1;
1632  }
1633 
1634  radar_image_2d_idx = -1;
1636  radar_image_size = -1;
1638 
1639  for (i=0;i<MAX_IFFS;i++)
1640  {
1641  for (j=0;j<MAX_IFFS;j++)
1642  ship_iff_info[i][j] = -1;
1643  }
1644 
1645  aiming_flags = 0;
1647  convergence_distance = 100.0f;
1649 
1650  emp_resistance_mod = 0.0f;
1651 
1653 
1655 
1657  hud_gauges.clear();
1658  hud_enabled = false;
1659  hud_retail = false;
1660 
1661  displays.clear();
1662 
1663  pathMetadata.clear();
1664 
1666 }
1667 
1669 {
1670  if ( subsystems != NULL ) {
1671  for(int n = 0; n < n_subsystems; n++) {
1672  if (subsystems[n].triggers != NULL) {
1673  vm_free(subsystems[n].triggers);
1674  subsystems[n].triggers = NULL;
1675  }
1676  }
1677 
1679  subsystems = NULL;
1680  }
1681 
1682  free_strings();
1683 }
1684 
1688 int parse_ship(const char *filename, bool replace)
1689 {
1690  char buf[SHIP_MULTITEXT_LENGTH];
1691  ship_info *sip;
1692  bool create_if_not_found = true;
1693  int rtn = 0;
1694 
1695  required_string("$Name:");
1697 
1698  if(optional_string("+nocreate")) {
1699  if(!replace) {
1700  Warning(LOCATION, "+nocreate flag used for ship in non-modular table");
1701  }
1702  create_if_not_found = false;
1703  }
1704 
1705 #ifdef NDEBUG
1707  rtn = 1;
1708 #endif
1709 
1710  //Remove @ symbol
1711  //these used to be used to denote weapons that would
1712  //only be parsed in demo builds
1713  if ( buf[0] == '@' ) {
1714  backspace(buf);
1715  }
1716 
1717  diag_printf ("Ship name -- %s\n", buf);
1718  //Check if ship exists already
1719  int ship_id;
1720  bool first_time = false;
1721  ship_id = ship_info_lookup_sub( buf );
1722 
1723  if(ship_id != -1)
1724  {
1725  sip = &Ship_info[ship_id];
1726  if(!replace)
1727  {
1728  Warning(LOCATION, "Error: Ship name %s already exists in %s. All ship class names must be unique.", sip->name, filename);
1729  if ( !skip_to_start_of_string_either("$Name:", "#End")) {
1730  Int3();
1731  }
1732  return -1;
1733  }
1734  }
1735  else
1736  {
1737  //Don't create ship if it has +nocreate and is in a modular table.
1738  if(!create_if_not_found && replace)
1739  {
1740  if ( !skip_to_start_of_string_either("$Name:", "#End")) {
1741  Int3();
1742  }
1743 
1744  return -1;
1745  }
1746 
1747  //Check if there are too many ship classes
1748  if(Ship_info.size() >= MAX_SHIP_CLASSES) {
1749  Error(LOCATION, "Too many ship classes before '%s'; maximum is %d.\n", buf, MAX_SHIP_CLASSES);
1750  }
1751 
1752  //Init vars
1753  Ship_info.push_back(ship_info());
1754  sip = &Ship_info.back();
1755  first_time = true;
1756 
1757  strcpy_s(sip->name, buf);
1758  }
1759 
1760  // Use a template for this ship.
1761  if( optional_string( "+Use Template:" ) ) {
1762  if ( !create_if_not_found ) {
1763  Warning(LOCATION, "Both '+nocreate' and '+Use Template:' were specified for ship class '%s', ignoring '+Use Template:'\n", buf);
1764  }
1765  else {
1766  char template_name[SHIP_MULTITEXT_LENGTH];
1767  stuff_string(template_name, F_NAME, SHIP_MULTITEXT_LENGTH);
1768  int template_id = ship_template_lookup(template_name);
1769  if ( template_id != -1 ) {
1770  first_time = false;
1771  sip->clone(Ship_templates[template_id]);
1772  strcpy_s(sip->name, buf);
1773  }
1774  else {
1775  Warning(LOCATION, "Unable to find ship template '%s' requested by ship class '%s', ignoring template request...", template_name, buf);
1776  }
1777  }
1778  }
1779 
1780  rtn = parse_ship_values(sip, false, first_time, replace);
1781 
1782  return rtn; //0 for success
1783 }
1784 
1789 {
1790  char buf[SHIP_MULTITEXT_LENGTH];
1791  ship_info *sip;
1792  int rtn = 0;
1793  bool first_time = true;
1794 
1795  required_string("$Template:");
1797 
1798  if( optional_string("+nocreate") ) {
1799  Warning(LOCATION, "+nocreate flag used on ship template. Ship templates can not be modified. Ignoring +nocreate.");
1800  }
1801 
1802  diag_printf ("Ship template name -- %s\n", buf);
1803  //Check if the template exists already
1804  int template_id;
1805  template_id = ship_template_lookup( buf );
1806 
1807  if( template_id != -1 ) {
1808  sip = &Ship_templates[template_id];
1809  Warning(LOCATION, "WARNING: Ship template %s already exists. All ship template names must be unique.", sip->name);
1810  if ( !skip_to_start_of_string_either("$Template:", "#End")) {
1811  error_display(1, "Missing [#End] or [$Template] after duplicate entry for %s", sip->name);
1812  }
1813  return -1;
1814  }
1815  else {
1816 
1817  Ship_templates.push_back(ship_info());
1818  sip = &Ship_templates.back();
1819 
1820  strcpy_s(sip->name, buf);
1821  //Use another template for this template. This allows for template hierarchies. - Turey
1822  if( optional_string("+Use Template:") ) {
1823  char template_name[SHIP_MULTITEXT_LENGTH];
1824  stuff_string(template_name, F_NAME, SHIP_MULTITEXT_LENGTH);
1825  template_id = ship_template_lookup( template_name);
1826 
1827  if ( template_id != -1 ) {
1828  first_time = false;
1829  sip->clone(Ship_templates[template_id]);
1830  strcpy_s(sip->name, buf);
1831  }
1832  else {
1833  Warning(LOCATION, "Unable to find ship template '%s' requested by ship template '%s', ignoring template request...", template_name, buf);
1834  }
1835  }
1836  }
1837 
1838  rtn = parse_ship_values( sip, true, first_time, false );
1839 
1840  return rtn;
1841 }
1842 
1844 {
1845  Assert( name != NULL );
1846 
1847  int temp_index = -1;
1848 
1849  parse_sound(name, &temp_index, sip->name);
1850 
1851  if (temp_index >= 0)
1852  sip->ship_sounds.insert(std::pair<GameSoundsIndex, int>(id, temp_index));
1853 }
1854 
1856 {
1857  parse_ship_sound("$CockpitEngineSnd:", SND_ENGINE, sip);
1858  parse_ship_sound("$FullThrottleSnd:", SND_FULL_THROTTLE, sip);
1859  parse_ship_sound("$ZeroThrottleSnd:", SND_ZERO_THROTTLE, sip);
1860  parse_ship_sound("$ThrottleUpSnd:", SND_THROTTLE_UP, sip);
1861  parse_ship_sound("$ThrottleDownSnd:", SND_THROTTLE_DOWN, sip);
1862  parse_ship_sound("$AfterburnerSnd:", SND_ABURN_LOOP, sip);
1863  parse_ship_sound("$AfterburnerEngageSnd:", SND_ABURN_ENGAGE, sip);
1864  parse_ship_sound("$AfterburnerFailedSnd:", SND_ABURN_FAIL, sip);
1865  parse_ship_sound("$MissileTrackingSnd:", SND_MISSILE_TRACKING, sip);
1866  parse_ship_sound("$MissileLockedSnd:", SND_MISSILE_LOCK, sip);
1867  parse_ship_sound("$PrimaryCycleSnd:", SND_PRIMARY_CYCLE, sip);
1868  parse_ship_sound("$SecondaryCycleSnd:", SND_SECONDARY_CYCLE, sip);
1869  parse_ship_sound("$TargetAcquiredSnd:", SND_TARGET_ACQUIRE, sip);
1870  parse_ship_sound("$PrimaryFireFailedSnd:", SND_OUT_OF_WEAPON_ENERGY, sip);
1871  parse_ship_sound("$SecondaryFireFailedSnd:", SND_OUT_OF_MISSLES, sip);
1872  parse_ship_sound("$HeatSeekerLaunchWarningSnd:", SND_HEATLOCK_WARN, sip);
1873  parse_ship_sound("$AspectSeekerLaunchWarningSnd:", SND_ASPECTLOCK_WARN, sip);
1874  parse_ship_sound("$MissileLockWarningSnd:", SND_THREAT_FLASH, sip);
1875  parse_ship_sound("$HeatSeekerProximityWarningSnd:", SND_PROXIMITY_WARNING, sip);
1876  parse_ship_sound("$AspectSeekerProximityWarningSnd:", SND_PROXIMITY_ASPECT_WARNING, sip);
1877  parse_ship_sound("$MissileEvadedSnd:", SND_MISSILE_EVADED_POPUP, sip);
1878  parse_ship_sound("$CargoScanningSnd:", SND_CARGO_SCAN, sip);
1879 
1880  // Use SND_SHIP_EXPLODE_1 for custom explosion sounds
1881  parse_ship_sound("$ExplosionSnd:", SND_SHIP_EXPLODE_1, sip);
1882 }
1883 
1884 void parse_ship_particle_effect(ship_info* sip, particle_effect* pe, char *id_string)
1885 {
1886  float tempf;
1887  int temp;
1888  if(optional_string("+Max particles:"))
1889  {
1890  stuff_int(&temp);
1891  if (temp < 0) {
1892  Warning(LOCATION,"Bad value %i, defined as %s particle number (max) in ship '%s'.\nValue should be a non-negative integer.\n", temp, id_string, sip->name);
1893  } else {
1894  pe->n_high = temp;
1895  if (pe->n_high == 0) {
1896  // notification for disabling the particles
1897  mprintf(("Particle effect for %s disabled on ship '%s'.\n", id_string, sip->name));
1898  }
1899  }
1900  }
1901  if(optional_string("+Min particles:"))
1902  {
1903  stuff_int(&temp);
1904  if (temp < 0) {
1905  Warning(LOCATION,"Bad value %i, defined as %s particle number (min) in ship '%s'.\nValue should be a non-negative integer.\n", temp, id_string, sip->name);
1906  } else {
1907  pe->n_low = temp;
1908  }
1909  }
1910  if (pe->n_low > pe->n_high)
1911  pe->n_low = pe->n_high;
1912 
1913  if(optional_string("+Max Radius:"))
1914  {
1915  stuff_float(&tempf);
1916  if (tempf <= 0.0f) {
1917  Warning(LOCATION,"Bad value %f, defined as %s particle radius (max) in ship '%s'.\nValue should be a positive float.\n", tempf, id_string, sip->name);
1918  } else {
1919  pe->max_rad = tempf;
1920  }
1921  }
1922  if(optional_string("+Min Radius:"))
1923  {
1924  stuff_float(&tempf);
1925  if (tempf < 0.0f) {
1926  Warning(LOCATION,"Bad value %f, defined as %s particle radius (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, id_string, sip->name);
1927  } else {
1928  pe->min_rad = tempf;
1929  }
1930  }
1931  if (pe->min_rad > pe->max_rad)
1932  pe->min_rad = pe->max_rad;
1933 
1934  if(optional_string("+Max Lifetime:"))
1935  {
1936  stuff_float(&tempf);
1937  if (tempf <= 0.0f) {
1938  Warning(LOCATION,"Bad value %f, defined as %s particle lifetime (max) in ship '%s'.\nValue should be a positive float.\n", tempf, id_string, sip->name);
1939  } else {
1940  pe->max_life = tempf;
1941  }
1942  }
1943  if(optional_string("+Min Lifetime:"))
1944  {
1945  stuff_float(&tempf);
1946  if (tempf < 0.0f) {
1947  Warning(LOCATION,"Bad value %f, defined as %s particle lifetime (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, id_string, sip->name);
1948  } else {
1949  pe->min_life = tempf;
1950  }
1951  }
1952  if (pe->min_life > pe->max_life)
1953  pe->min_life = pe->max_life;
1954 
1955  if(optional_string("+Max Velocity:"))
1956  {
1957  stuff_float(&tempf);
1958  if (tempf < 0.0f) {
1959  Warning(LOCATION,"Bad value %f, defined as %s particle velocity (max) in ship '%s'.\nValue should be a non-negative float.\n", tempf, id_string, sip->name);
1960  } else {
1961  pe->max_vel = tempf;
1962  }
1963  }
1964  if(optional_string("+Min Velocity:"))
1965  {
1966  stuff_float(&tempf);
1967  if (tempf < 0.0f) {
1968  Warning(LOCATION,"Bad value %f, defined as %s particle velocity (min) in ship '%s'.\nValue should be a non-negative float.\n", tempf, id_string, sip->name);
1969  } else {
1970  pe->min_vel = tempf;
1971  }
1972  }
1973  if (pe->min_vel > pe->max_vel)
1974  pe->min_vel = pe->max_vel;
1975 
1976  if(optional_string("+Normal Variance:"))
1977  {
1978  stuff_float(&tempf);
1979  if ((tempf >= 0.0f) && (tempf <= 2.0f)) {
1980  pe->variance = tempf;
1981  } else {
1982  Warning(LOCATION,"Bad value %f, defined as %s particle normal variance in ship '%s'.\nValue should be a float from 0.0 to 2.0.\n", tempf, id_string, sip->name);
1983  }
1984  }
1985 }
1986 
1987 void parse_allowed_weapons(ship_info *sip, const bool is_primary, const bool is_dogfight, const bool first_time)
1988 {
1989  int i, num_allowed;
1990  int allowed_weapons[MAX_WEAPON_TYPES];
1991  const int max_banks = (is_primary ? MAX_SHIP_PRIMARY_BANKS : MAX_SHIP_SECONDARY_BANKS);
1992  const int weapon_type = (is_dogfight ? DOGFIGHT_WEAPON : REGULAR_WEAPON);
1993  const int offset = (is_primary ? 0 : MAX_SHIP_PRIMARY_BANKS);
1994  const char *allowed_banks_str = is_primary ? (is_dogfight ? "$Allowed Dogfight PBanks:" : "$Allowed PBanks:")
1995  : (is_dogfight ? "$Allowed Dogfight SBanks:" : "$Allowed SBanks:");
1996  const char *bank_type_str = is_primary ? "primary" : "secondary";
1997 
1998  // Goober5000 - fixed Bobboau's implementation of restricted banks
1999  int bank;
2000 
2001  // Set the weapons filter used in weapons loadout (for primary weapons)
2002  if (optional_string(allowed_banks_str))
2003  {
2004  // MageKing17 - We need to make modular tables replace bank restrictions by default, instead of adding to them.
2005  if (!first_time && !(optional_string("+noreplace"))) { // Only makes sense for modular tables.
2006  // clear allowed weapons so the modular table can define new ones
2007  for (bank = 0; bank < max_banks; bank++) {
2008  for (i = 0; i < Num_weapon_types; i++) {
2009  sip->allowed_bank_restricted_weapons[offset+bank][i] &= ~weapon_type;
2010  }
2011  sip->restricted_loadout_flag[offset+bank] &= ~weapon_type;
2012  }
2013  }
2014 
2015  bank = -1;
2016 
2017  while (check_for_string("("))
2018  {
2019  bank++;
2020 
2021  // make sure we don't specify more than we have banks for
2022  if (bank >= max_banks)
2023  {
2024  Warning(LOCATION, "%s bank-specific loadout for %s exceeds permissible number of %s banks. Ignoring the rest...", allowed_banks_str, sip->name, bank_type_str);
2025  bank--;
2026  break;
2027  }
2028 
2029  num_allowed = stuff_int_list(allowed_weapons, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
2030 
2031  // actually say which weapons are allowed
2032  for ( i = 0; i < num_allowed; i++ )
2033  {
2034  if ( allowed_weapons[i] >= 0 ) // MK, Bug fix, 9/6/99. Used to be "allowed_weapons" not "allowed_weapons[i]".
2035  {
2036  sip->allowed_bank_restricted_weapons[offset+bank][allowed_weapons[i]] |= weapon_type;
2037  }
2038  }
2039  }
2040 
2041  // set flags if need be
2042  if (bank > 0) // meaning there was a restricted bank table entry
2043  {
2044  for (i=0; i<=bank; i++)
2045  {
2046  sip->restricted_loadout_flag[offset+i] |= weapon_type;
2047  }
2048  }
2049  }
2050 }
2051 
2056 void parse_weapon_bank(ship_info *sip, bool is_primary, int *num_banks, int *bank_default_weapons, int *bank_capacities)
2057 {
2058  Assert(sip != NULL);
2059  Assert(bank_default_weapons != NULL);
2060  Assert(bank_capacities != NULL);
2061  const int max_banks = is_primary ? MAX_SHIP_PRIMARY_BANKS : MAX_SHIP_SECONDARY_BANKS;
2062  const char *default_banks_str = is_primary ? "$Default PBanks:" : "$Default SBanks:";
2063  const char *bank_capacities_str = is_primary ? "$PBank Capacity:" : "$SBank Capacity:";
2064 
2065  // we initialize to the previous parse, which presumably worked
2066  int num_bank_capacities = num_banks != NULL ? *num_banks : 0;
2067 
2068  if (optional_string(default_banks_str))
2069  {
2070  // get weapon list
2071  if (num_banks != NULL)
2072  *num_banks = stuff_int_list(bank_default_weapons, max_banks, WEAPON_LIST_TYPE);
2073  else
2074  stuff_int_list(bank_default_weapons, max_banks, WEAPON_LIST_TYPE);
2075  }
2076 
2077  if (optional_string(bank_capacities_str))
2078  {
2079  // get capacity list
2080  num_bank_capacities = stuff_int_list(bank_capacities, max_banks, RAW_INTEGER_TYPE);
2081  }
2082 
2083  // num_banks can be null if we're parsing weapons for a turret
2084  if ((num_banks != NULL) && (*num_banks != num_bank_capacities))
2085  {
2086  // okay for a ship to have 0 primary capacities, since it won't be ammo-enabled
2087  if (is_primary && num_bank_capacities != 0)
2088  {
2089  Warning(LOCATION, "Ship class '%s' has %d primary banks, but %d primary capacities... fix this!!", sip->name, *num_banks, num_bank_capacities);
2090  }
2091 
2092  // secondaries have no excuse!
2093  if (!is_primary)
2094  {
2095  Warning(LOCATION, "Ship class '%s' has %d secondary banks, but %d secondary capacities... fix this!!", sip->name, *num_banks, num_bank_capacities);
2096  }
2097  }
2098 }
2099 
2104 {
2105  int bii_index = -1;
2106  size_t icon;
2107  char regular_temp[MAX_FILENAME_LEN];
2108  char fade_temp[MAX_FILENAME_LEN];
2109  char highlight_temp[MAX_FILENAME_LEN];
2110 
2111  required_string("+Regular:");
2112  stuff_string(regular_temp, F_NAME, MAX_FILENAME_LEN);
2113  required_string("+Fade:");
2114  stuff_string(fade_temp, F_NAME, MAX_FILENAME_LEN);
2115  required_string("+Highlight:");
2116  stuff_string(highlight_temp, F_NAME, MAX_FILENAME_LEN);
2117 
2118  // search among our existing icons
2119  for (icon = 0; icon < Briefing_icon_info.size(); icon++)
2120  {
2121  if ( !stricmp(regular_temp, Briefing_icon_info[icon].regular.filename)
2122  && !stricmp(fade_temp, Briefing_icon_info[icon].fade.filename)
2123  && !stricmp(highlight_temp, Briefing_icon_info[icon].highlight.filename) )
2124  {
2125  bii_index = (int) icon;
2126  break;
2127  }
2128  }
2129 
2130  // icon not found: create new one
2131  if (bii_index < 0)
2132  {
2133  briefing_icon_info bii;
2134  generic_anim_init(&bii.regular, regular_temp);
2135  hud_anim_init(&bii.fade, 0, 0, fade_temp);
2136  hud_anim_init(&bii.highlight, 0, 0, highlight_temp);
2137 
2138  bii_index = (int) Briefing_icon_info.size();
2139  Briefing_icon_info.push_back(bii);
2140  }
2141 
2142  return bii_index;
2143 }
2144 
2148 int parse_ship_values(ship_info* sip, const bool is_template, const bool first_time, const bool replace)
2149 {
2150  char buf[SHIP_MULTITEXT_LENGTH];
2151  char* info_type_name;
2152  char* type_name;
2153  int i, j;
2154  int rtn = 0;
2155  char name_tmp[NAME_LENGTH];
2156 
2157  if ( ! is_template ) {
2158  info_type_name = "Ship Class";
2159  type_name = "$Name";
2160  }
2161  else {
2162  info_type_name = "Ship Template";
2163  type_name = "$Template";
2164  }
2165 
2166  if(optional_string("$Alt name:"))
2168 
2169  if(optional_string("$Short name:"))
2171  else if (first_time)
2172  {
2173  char *srcpos, *srcend, *destpos;
2174  srcpos = sip->name;
2175  destpos = sip->short_name;
2176  srcend = srcpos + strlen(sip->name);
2177  while(srcpos <= srcend)
2178  {
2179  if(*srcpos != ' ')
2180  *destpos++ = *srcpos++;
2181  else
2182  srcpos++;
2183  }
2184  }
2185  diag_printf ("Ship short name -- %s\n", sip->short_name);
2186 
2187  if (optional_string("$Species:")) {
2188  char temp[NAME_LENGTH];
2190  int i_species = 0;
2191 
2192  bool found = false;
2193  for (SCP_vector<species_info>::iterator sii = Species_info.begin(); sii != Species_info.end(); ++sii, ++i_species) {
2194  if (!stricmp(temp, sii->species_name)) {
2195  sip->species = i_species;
2196  found = true;
2197  break;
2198  }
2199  }
2200 
2201  if (!found) {
2202  Error(LOCATION, "Invalid Species %s defined in table entry for ship %s.\n", temp, sip->name);
2203  }
2204  }
2205 
2206  diag_printf ("Ship species -- %s\n", Species_info[sip->species].species_name);
2207 
2208  if (optional_string("+Type:")) {
2210  }
2211 
2212  if (optional_string("+Maneuverability:")) {
2214  }
2215 
2216  if (optional_string("+Armor:")) {
2218  }
2219 
2220  if (optional_string("+Manufacturer:")) {
2222  }
2223 
2224  if (optional_string("+Description:")) {
2225  stuff_malloc_string(&sip->desc, F_MULTITEXT, NULL);
2226  }
2227 
2228  if (optional_string("+Tech Title:")) {
2230  }
2231 
2232  if (optional_string("+Tech Description:")) {
2234  }
2235 
2236  if (optional_string("+Length:")) {
2238  }
2239 
2240  if (optional_string("+Gun Mounts:")) {
2242  }
2243 
2244  if (optional_string("+Missile Banks:")) {
2246  }
2247 
2248  // Ship fadein effect, used when no ani is specified or ship_select_3d is active
2249  sip->selection_effect = Default_ship_select_effect; //By default, use the FS2 effect
2250  if(optional_string("$Selection Effect:")) {
2251  char effect[NAME_LENGTH];
2252  stuff_string(effect, F_NAME, NAME_LENGTH);
2253  if (!stricmp(effect, "FS2"))
2254  sip->selection_effect = 2;
2255  else if (!stricmp(effect, "FS1"))
2256  sip->selection_effect = 1;
2257  else if (!stricmp(effect, "off"))
2258  sip->selection_effect = 0;
2259  }
2260 
2261  if(optional_string( "$Cockpit POF file:" ))
2262  {
2263  char temp[MAX_FILENAME_LEN];
2265 
2266  // assume we're using this file name
2267  bool valid = true;
2268 
2269  // Goober5000 - if this is a modular table, and we're replacing an existing file name, and the file doesn't exist, don't replace it
2270  if (replace)
2271  if (sip->cockpit_pof_file[0] != '\0')
2272  if (!cf_exists_full(temp, CF_TYPE_MODELS))
2273  valid = false;
2274 
2275  if (valid)
2276  strcpy_s(sip->cockpit_pof_file, temp);
2277  else
2278  WarningEx(LOCATION, "Ship %s\nCockpit POF file \"%s\" invalid!", sip->name, temp);
2279  }
2280  if(optional_string( "+Cockpit offset:" ))
2281  {
2282  stuff_vec3d(&sip->cockpit_offset);
2283  }
2284  while(optional_string( "$Cockpit Display:" ))
2285  {
2286  cockpit_display_info display;
2287 
2288  display.bg_filename[0] = 0;
2289  display.fg_filename[0] = 0;
2290  display.filename[0] = 0;
2291  display.name[0] = 0;
2292  display.offset[0] = 0;
2293  display.offset[1] = 0;
2294 
2295  required_string("+Texture:");
2297 
2298  if ( optional_string("+Offsets:") ) {
2299  stuff_int_list(display.offset, 2);
2300  }
2301 
2302  required_string("+Size:");
2303  stuff_int_list(display.size, 2);
2304 
2305  if ( optional_string("+Background:") ) {
2307  }
2308  if ( optional_string("+Foreground:") ) {
2310  }
2311 
2312  required_string("+Display Name:");
2314 
2315  if ( display.offset[0] < 0 || display.offset[1] < 0 ) {
2316  Warning(LOCATION, "Negative display offsets given for cockpit display on %s, skipping entry", sip->name);
2317  continue;
2318  }
2319 
2320  if( display.size[0] <= 0 || display.size[1] <= 0 ) {
2321  Warning(LOCATION, "Negative or zero display size given for cockpit display on %s, skipping entry", sip->name);
2322  continue;
2323  }
2324 
2325  sip->displays.push_back(display);
2326  }
2327 
2328  if(optional_string( "$POF file:" ))
2329  {
2330  char temp[MAX_FILENAME_LEN];
2332 
2333  // assume we're using this file name
2334  bool valid = true;
2335 
2336  // Goober5000 - if this is a modular table, and we're replacing an existing file name, and the file doesn't exist, don't replace it
2337  if (replace)
2338  if (sip->pof_file[0] != '\0')
2339  if (!cf_exists_full(temp, CF_TYPE_MODELS))
2340  valid = false;
2341 
2342  if (valid)
2343  strcpy_s(sip->pof_file, temp);
2344  else
2345  WarningEx(LOCATION, "Ship %s\nPOF file \"%s\" invalid!", sip->name, temp);
2346  }
2347 
2348  // ship class texture replacement - Goober5000
2349  // don't clear the vector because we could be parsing a TBM
2350  if (optional_string("$Texture Replace:"))
2351  {
2352  texture_replace tr;
2353  char *p;
2354 
2355  while (optional_string("+old:"))
2356  {
2357  strcpy_s(tr.ship_name, sip->name);
2358  tr.new_texture_id = -1;
2359 
2361  required_string("+new:");
2363 
2364  // get rid of extensions
2365  p = strchr(tr.old_texture, '.');
2366  if (p)
2367  {
2368  mprintf(("Extraneous extension found on replacement texture %s!\n", tr.old_texture));
2369  *p = 0;
2370  }
2371  p = strchr(tr.new_texture, '.');
2372  if (p)
2373  {
2374  mprintf(("Extraneous extension found on replacement texture %s!\n", tr.new_texture));
2375  *p = 0;
2376  }
2377 
2378  // add it if we aren't over the limit
2379  if (sip->replacement_textures.size() < MAX_MODEL_TEXTURES)
2380  sip->replacement_textures.push_back(tr);
2381  else
2382  mprintf(("Too many replacement textures specified for ship '%s'!\n", sip->name));
2383  }
2384  }
2385 
2386  // optional hud targeting model
2387  if(optional_string( "$POF target file:"))
2388  {
2389  char temp[MAX_FILENAME_LEN];
2391 
2392  // assume we're using this file name
2393  bool valid = true;
2394 
2395  // Goober5000 - if this is a modular table, and we're replacing an existing file name, and the file doesn't exist, don't replace it
2396  if (replace)
2397  if (sip->pof_file_hud[0] != '\0')
2398  if (!cf_exists_full(temp, CF_TYPE_MODELS))
2399  valid = false;
2400 
2401  if (valid)
2402  strcpy_s(sip->pof_file_hud, temp);
2403  else
2404  WarningEx(LOCATION, "Ship \"%s\" POF target file \"%s\" invalid!", sip->name, temp);
2405  }
2406 
2407  // optional hud target LOD if not using special hud model
2408  if (optional_string( "$POF target LOD:" )) {
2409  stuff_int(&sip->hud_target_lod);
2410  }
2411 
2412  if(optional_string("$Detail distance:")) {
2414  }
2415 
2416  if(optional_string("$Collision LOD:")) {
2417  stuff_int(&sip->collision_lod);
2418 
2419  // Cap to sane values, just in case
2420  sip->collision_lod = MAX(0, MIN(sip->collision_lod, sip->num_detail_levels));
2421  }
2422 
2423  // check for optional pixel colors
2424  while(optional_string("$ND:")){
2425  ubyte nr, ng, nb;
2426  stuff_ubyte(&nr);
2427  stuff_ubyte(&ng);
2428  stuff_ubyte(&nb);
2429 
2431  sip->nondark_colors[sip->num_nondark_colors][0] = nr;
2432  sip->nondark_colors[sip->num_nondark_colors][1] = ng;
2433  sip->nondark_colors[sip->num_nondark_colors++][2] = nb;
2434  }
2435  }
2436 
2437  if (optional_string("$Enable Team Colors:")) {
2439  sip->default_team_name = "None";
2440  }
2441 
2442  if (optional_string("$Default Team:")) {
2443  char temp[NAME_LENGTH];
2445  SCP_string name = temp;
2446  if (!stricmp(temp, "none")) {
2447  sip->uses_team_colors = true;
2448  } else {
2449  if (Team_Colors.find(name) != Team_Colors.end()) {
2450  sip->default_team_name = name;
2451  sip->uses_team_colors = true;
2452  } else {
2453  Warning(LOCATION, "Team name %s is invalid. Teams must be defined in colors.tbl.\n", temp);
2454  }
2455  }
2456  }
2457 
2458  if(optional_string("$Show damage:"))
2459  {
2460  int bogus_bool;
2461  stuff_boolean(&bogus_bool);
2462  }
2463 
2464  if(optional_string("$Damage Lightning Type:"))
2465  {
2467  j = lightningtype_match(buf);
2468  if(j >= 0) {
2469  sip->damage_lightning_type = j;
2470  } else {
2471  Warning(LOCATION, "Invalid lightning type '%s' specified for ship '%s'", buf, sip->name);
2473  }
2474  }
2475 
2476  if(optional_string("$Impact:"))
2477  {
2478  if(optional_string("+Damage Type:"))
2479  {
2482  }
2483  }
2484 
2485  //HACK -
2486  //This should really be reworked so that all particle fields
2487  //are settable, but erg, just not happening right now -C
2488  if(optional_string("$Impact Spew:"))
2489  {
2490  parse_ship_particle_effect(sip, &sip->impact_spew, "impact spew");
2491  }
2492  if(optional_string("$Damage Spew:"))
2493  {
2494  parse_ship_particle_effect(sip, &sip->damage_spew, "damage spew");
2495  }
2496 
2497  if(optional_string("$Collision Physics:"))
2498  {
2499  if(optional_string("+Bounce:")) {
2501  }
2502  if(optional_string("+Both Small Bounce:")) {
2504  }
2505  if(optional_string("+Friction:")) {
2507  }
2508  if(optional_string("+Rotation Factor:")) {
2510  }
2511  if(optional_string("+Landing Max Forward Vel:")) {
2513  }
2514  if(optional_string("+Landing Min Forward Vel:")) {
2516  }
2517  if(optional_string("+Landing Max Descent Vel:")) {
2519  sip->collision_physics.landing_min_y *= -1;
2520  }
2521  if(optional_string("+Landing Max Horizontal Vel:")) {
2523  }
2524  if(optional_string("+Landing Max Angle:")) {
2525  float degrees;
2526  stuff_float(&degrees);
2527  sip->collision_physics.landing_max_angle = cosf(fl_radians(90.0f - degrees));
2528  }
2529  if(optional_string("+Landing Min Angle:")) {
2530  float degrees;
2531  stuff_float(&degrees);
2532  sip->collision_physics.landing_min_angle = cosf(fl_radians(90.0f - degrees));
2533  }
2534  if(optional_string("+Landing Max Rotate Angle:")) {
2535  float degrees;
2536  stuff_float(&degrees);
2537  sip->collision_physics.landing_max_rot_angle = cosf(fl_radians(90.0f - degrees));
2538  }
2539  if(optional_string("+Reorient Max Forward Vel:")) {
2541  }
2542  if(optional_string("+Reorient Min Forward Vel:")) {
2544  }
2545  if(optional_string("+Reorient Max Descent Vel:")) {
2547  sip->collision_physics.reorient_min_y *= -1;
2548  }
2549  if(optional_string("+Reorient Max Horizontal Vel:")) {
2551  }
2552  if(optional_string("+Reorient Max Angle:")) {
2553  float degrees;
2554  stuff_float(&degrees);
2555  sip->collision_physics.reorient_max_angle = cosf(fl_radians(90.0f - degrees));
2556  }
2557  if(optional_string("+Reorient Min Angle:")) {
2558  float degrees;
2559  stuff_float(&degrees);
2560  sip->collision_physics.reorient_min_angle = cosf(fl_radians(90.0f - degrees));
2561  }
2562  if(optional_string("+Reorient Max Rotate Angle:")) {
2563  float degrees;
2564  stuff_float(&degrees);
2565  sip->collision_physics.reorient_max_rot_angle = cosf(fl_radians(90.0f - degrees));
2566  }
2567  if(optional_string("+Reorient Speed Mult:")) {
2569  }
2570  if(optional_string("+Landing Rest Angle:")) {
2571  float degrees;
2572  stuff_float(&degrees);
2573  sip->collision_physics.landing_rest_angle = cosf(fl_radians(90.0f - degrees));
2574  }
2575  parse_sound("+Landing Sound:", &sip->collision_physics.landing_sound_idx, sip->name);
2576  }
2577 
2578 
2579  if(optional_string("$Debris:"))
2580  {
2581  if(optional_string("+Min Lifetime:")) {
2583  if(sip->debris_min_lifetime < 0.0f)
2584  Warning(LOCATION, "Debris min lifetime on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2585  }
2586  if(optional_string("+Max Lifetime:")) {
2588  if(sip->debris_max_lifetime < 0.0f)
2589  Warning(LOCATION, "Debris max lifetime on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2590  }
2591  if(optional_string("+Min Speed:")) {
2593  if(sip->debris_min_speed < 0.0f)
2594  Warning(LOCATION, "Debris min speed on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2595  }
2596  if(optional_string("+Max Speed:")) {
2598  if(sip->debris_max_speed < 0.0f)
2599  Warning(LOCATION, "Debris max speed on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2600  }
2601  if(optional_string("+Min Rotation speed:")) {
2603  if(sip->debris_min_rotspeed < 0.0f)
2604  Warning(LOCATION, "Debris min speed on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2605  }
2606  if(optional_string("+Max Rotation speed:")) {
2608  if(sip->debris_max_rotspeed < 0.0f)
2609  Warning(LOCATION, "Debris max speed on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2610  }
2611  if(optional_string("+Damage Type:")) {
2614  }
2615  if(optional_string("+Min Hitpoints:")) {
2617  if(sip->debris_min_hitpoints < 0.0f)
2618  Warning(LOCATION, "Debris min hitpoints on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2619  }
2620  if(optional_string("+Max Hitpoints:")) {
2622  if(sip->debris_max_hitpoints < 0.0f)
2623  Warning(LOCATION, "Debris max hitpoints on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2624  }
2625  if(optional_string("+Damage Multiplier:")) {
2627  if(sip->debris_damage_mult < 0.0f)
2628  Warning(LOCATION, "Debris damage multiplier on %s '%s' is below 0 and will be ignored", info_type_name, sip->name);
2629  }
2630  if(optional_string("+Lightning Arc Percent:")) {
2632  if(sip->debris_arc_percent < 0.0f || sip->debris_arc_percent > 100.0f) {
2633  Warning(LOCATION, "Lightning Arc Percent on %s '%s' should be between 0 and 100.0 (read %f). Entry will be ignored.", info_type_name, sip->name, sip->debris_arc_percent);
2634  sip->debris_arc_percent = 50.0;
2635  }
2636  //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
2637  sip->debris_arc_percent /= 100.0;
2638  }
2639 
2640  }
2641  //WMC - sanity checking
2642  if(sip->debris_min_speed > sip->debris_max_speed && sip->debris_max_speed >= 0.0f) {
2643  Warning(LOCATION, "Debris min speed (%f) on %s '%s' is greater than debris max speed (%f), and will be set to debris max speed.", sip->debris_min_speed, info_type_name, sip->name, sip->debris_max_speed);
2644  sip->debris_min_speed = sip->debris_max_speed;
2645  }
2646  if(sip->debris_min_rotspeed > sip->debris_max_rotspeed && sip->debris_max_rotspeed >= 0.0f) {
2647  Warning(LOCATION, "Debris min rotation speed (%f) on %s '%s' is greater than debris max rotation speed (%f), and will be set to debris max rotation speed.", sip->debris_min_rotspeed, info_type_name, sip->name, sip->debris_max_rotspeed);
2649  }
2650  if(sip->debris_min_lifetime > sip->debris_max_lifetime && sip->debris_max_lifetime >= 0.0f) {
2651  Warning(LOCATION, "Debris min lifetime (%f) on %s '%s' is greater than debris max lifetime (%f), and will be set to debris max lifetime.", sip->debris_min_lifetime, info_type_name, sip->name, sip->debris_max_lifetime);
2653  }
2654  if(sip->debris_min_hitpoints > sip->debris_max_hitpoints && sip->debris_max_hitpoints >= 0.0f) {
2655  Warning(LOCATION, "Debris min hitpoints (%f) on %s '%s' is greater than debris max hitpoints (%f), and will be set to debris max hitpoints.", sip->debris_min_hitpoints, info_type_name, sip->name, sip->debris_max_hitpoints);
2657  }
2658 
2659  if(optional_string("$Density:"))
2660  stuff_float( &(sip->density) );
2661  diag_printf ("Ship density -- %7.3f\n", sip->density);
2662 
2663  if(optional_string("$Damp:"))
2664  stuff_float( &(sip->damp) );
2665  diag_printf ("Ship damp -- %7.3f\n", sip->damp);
2666 
2667  if(optional_string("$Rotdamp:"))
2668  stuff_float( &(sip->rotdamp) );
2669  diag_printf ("Ship rotdamp -- %7.3f\n", sip->rotdamp);
2670 
2671  if(optional_string("$Banking Constant:"))
2672  stuff_float( &(sip->delta_bank_const) );
2673  diag_printf ("%s '%s' delta_bank_const -- %7.3f\n", info_type_name, sip->name, sip->delta_bank_const);
2674 
2675  if(optional_string("$Max Velocity:"))
2676  {
2677  stuff_vec3d(&sip->max_vel);
2678  sip->max_accel = sip->max_vel.xyz.z;
2679  }
2680 
2681  // calculate the max speed from max_velocity
2682  sip->max_speed = sip->max_vel.xyz.z;
2683 
2684  if(optional_string("$Rotation Time:"))
2685  {
2686  stuff_vec3d(&sip->rotation_time);
2687 
2688  // div/0 safety check.
2689  if ((sip->rotation_time.xyz.x == 0) || (sip->rotation_time.xyz.y == 0) || (sip->rotation_time.xyz.z == 0))
2690  Warning(LOCATION, "Rotation time must have non-zero values in each of the three variables.\nFix this in %s %s\n", info_type_name, sip->name);
2691 
2692  sip->srotation_time = (sip->rotation_time.xyz.x + sip->rotation_time.xyz.y)/2.0f;
2693 
2694  sip->max_rotvel.xyz.x = (2 * PI) / sip->rotation_time.xyz.x;
2695  sip->max_rotvel.xyz.y = (2 * PI) / sip->rotation_time.xyz.y;
2696  sip->max_rotvel.xyz.z = (2 * PI) / sip->rotation_time.xyz.z;
2697  }
2698 
2699  // get the backwards velocity;
2700  if(optional_string("$Rear Velocity:"))
2701  {
2702  stuff_float(&sip->max_rear_vel);
2703  sip->min_speed = -sip->max_rear_vel;
2704  }
2705 
2706  // get the accelerations
2707  if(optional_string("$Forward accel:"))
2708  stuff_float(&sip->forward_accel );
2709 
2710  if(optional_string("$Forward decel:"))
2711  stuff_float(&sip->forward_decel );
2712 
2713  if(optional_string("$Slide accel:"))
2714  stuff_float(&sip->slide_accel );
2715 
2716  if(optional_string("$Slide decel:"))
2717  stuff_float(&sip->slide_decel );
2718 
2719  if(optional_string("$Glide:"))
2720  {
2721  stuff_boolean(&sip->can_glide);
2722  }
2723 
2724  if(sip->can_glide == true)
2725  {
2726  if(optional_string("+Dynamic Glide Cap:"))
2728  if(optional_string("+Max Glide Speed:"))
2729  stuff_float(&sip->glide_cap );
2730  if(optional_string("+Glide Accel Mult:"))
2732  }
2733 
2734  if(optional_string("$Use Newtonian Dampening:")) {
2735  sip->newtonian_damp_override = true;
2737  }
2738 
2739  if(optional_string("$Autoaim FOV:"))
2740  {
2741  float fov_temp;
2742  stuff_float(&fov_temp);
2743 
2744  // Make sure it is a reasonable value
2745  if (fov_temp < 0.0f)
2746  fov_temp = 0.0f;
2747 
2748  if (fov_temp > 180.0f)
2749  fov_temp = 180.0f;
2750 
2752  sip->autoaim_fov = fov_temp * PI / 180.0f;
2753 
2754  if(optional_string("+Converging Autoaim"))
2756 
2757  if(optional_string("+Minimum Distance:"))
2759  }
2760 
2761  if(optional_string("$Convergence:"))
2762  {
2763  if(optional_string("+Automatic"))
2764  {
2766  if(optional_string("+Minimum Distance:"))
2768  }
2769  if(optional_string("+Standard"))
2770  {
2772  if(required_string("+Distance:"))
2774  }
2775  if(optional_string("+Offset:")) {
2777 
2778  if (IS_VEC_NULL(&sip->convergence_offset))
2780  else
2782  }
2783  }
2784 
2785  if(optional_string("$Warpin type:"))
2786  {
2788  j = warptype_match(buf);
2789  if(j >= 0) {
2790  sip->warpin_type = j;
2791  } else {
2792  Warning(LOCATION, "Invalid warpin type '%s' specified for %s '%s'", buf, info_type_name, sip->name);
2793  sip->warpin_type = WT_DEFAULT;
2794  }
2795  }
2796 
2797  parse_sound("$Warpin Start Sound:", &sip->warpin_snd_start, sip->name);
2798  parse_sound("$Warpin End Sound:", &sip->warpin_snd_end, sip->name);
2799 
2800  if(optional_string("$Warpin speed:"))
2801  {
2802  stuff_float(&sip->warpin_speed);
2803  }
2804 
2805  if(optional_string("$Warpin time:"))
2806  {
2807  float t_time;
2808  stuff_float(&t_time);
2809  sip->warpin_time = fl2i(t_time*1000.0f);
2810  if(sip->warpin_time <= 0) {
2811  Warning(LOCATION, "Warp-in time specified as 0 or less on %s '%s'; value ignored", info_type_name, sip->name);
2812  }
2813  }
2814 
2815  if(optional_string("$Warpin decel exp:"))
2816  {
2818  if (sip->warpin_decel_exp < 0.0f) {
2819  Warning(LOCATION, "Warp-in deceleration exponent specified as less than 0 on %s '%s'; value ignored", info_type_name, sip->name);
2820  sip->warpin_decel_exp = 1.0f;
2821  }
2822  }
2823 
2824  if(optional_string("$Warpin radius:"))
2825  {
2826  stuff_float(&sip->warpin_radius);
2827  if(sip->warpin_radius <= 0.0f) {
2828  Warning(LOCATION, "Warp-in radius specified as 0 or less on %s '%s'; value ignored", info_type_name, sip->name);
2829  }
2830  }
2831 
2832  if(optional_string("$Warpin animation:"))
2833  {
2835  }
2836 
2837  if(optional_string("$Warpout type:"))
2838  {
2840  j = warptype_match(buf);
2841  if(j >= 0) {
2842  sip->warpout_type = j;
2843  } else {
2844  Warning(LOCATION, "Invalid warpout type '%s' specified for %s '%s'", buf, info_type_name, sip->name);
2845  sip->warpout_type = WT_DEFAULT;
2846  }
2847  }
2848 
2849  parse_sound("$Warpout Start Sound:", &sip->warpout_snd_start, sip->name);
2850  parse_sound("$Warpout End Sound:", &sip->warpout_snd_end, sip->name);
2851 
2852  if(optional_string("$Warpout engage time:"))
2853  {
2854  float t_time;
2855  stuff_float(&t_time);
2856  if (t_time >= 0)
2857  sip->warpout_engage_time = fl2i(t_time*1000.0f);
2858  else
2859  Warning(LOCATION, "Warp-out engage time specified as 0 or less on %s '%s'; value ignored", info_type_name, sip->name);
2860  } else {
2861  sip->warpout_engage_time = -1;
2862  }
2863 
2864  if(optional_string("$Warpout speed:"))
2865  {
2866  stuff_float(&sip->warpout_speed);
2867  }
2868 
2869  if(optional_string("$Warpout time:"))
2870  {
2871  float t_time;
2872  stuff_float(&t_time);
2873  sip->warpout_time = fl2i(t_time*1000.0f);
2874  if(sip->warpout_time <= 0) {
2875  Warning(LOCATION, "Warp-out time specified as 0 or less on %s '%s'; value ignored", info_type_name, sip->name);
2876  }
2877  }
2878 
2879  if(optional_string("$Warpout accel exp:"))
2880  {
2882  if (sip->warpout_accel_exp < 0.0f) {
2883  Warning(LOCATION, "Warp-out acceleration exponent specified as less than 0 on %s '%s'; value ignored", info_type_name, sip->name);
2884  sip->warpout_accel_exp = 1.0f;
2885  }
2886  }
2887 
2888  if(optional_string("$Warpout radius:"))
2889  {
2890  stuff_float(&sip->warpout_radius);
2891  if(sip->warpout_radius <= 0.0f) {
2892  Warning(LOCATION, "Warp-out radius specified as 0 or less on %s '%s'; value ignored", info_type_name, sip->name);
2893  }
2894  }
2895 
2896  if(optional_string("$Warpout animation:"))
2897  {
2899  }
2900 
2901 
2902  if(optional_string("$Player warpout speed:"))
2903  {
2905  if(sip->warpout_player_speed == 0.0f) {
2906  Warning(LOCATION, "Player warp-out speed cannot be 0; value ignored.");
2907  }
2908  }
2909 
2910  // get ship explosion info
2911  shockwave_create_info *sci = &sip->shockwave;
2912  if(optional_string("$Expl inner rad:")){
2913  stuff_float(&sci->inner_rad);
2914  }
2915 
2916  if(optional_string("$Expl outer rad:")){
2917  stuff_float(&sci->outer_rad);
2918  }
2919 
2920  if(optional_string("$Expl damage:")){
2921  stuff_float(&sci->damage);
2922  }
2923 
2924  if(optional_string("$Expl blast:")){
2925  stuff_float(&sci->blast);
2926  }
2927 
2928  if(optional_string("$Expl Propagates:")){
2930  }
2931 
2932  if(optional_string("$Propagating Expl Radius Multiplier:")){
2934  if(sip->prop_exp_rad_mult <= 0) {
2935  // on invalid value return to default setting
2936  Warning(LOCATION, "Propagating explosion radius multiplier was set to non-positive value.\nDefaulting multiplier to 1.0 on %s '%s'.\n", info_type_name, sip->name);
2937  sip->prop_exp_rad_mult = 1.0f;
2938  }
2939  }
2940 
2941  if(optional_string("$Expl Visual Rad:")){
2943  }
2944 
2945  if(optional_string("$Base Death-Roll Time:")){
2947  if (sip->death_roll_base_time < 2)
2948  sip->death_roll_base_time = 2;
2949  }
2950 
2951  if(optional_string("$Death-Roll Explosion Radius Mult:")){
2953  if (sip->death_roll_r_mult < 0)
2954  sip->death_roll_r_mult = 0;
2955  }
2956 
2957  if(optional_string("$Death-Roll Explosion Intensity Mult:")){
2959  if (sip->death_roll_time_mult <= 0)
2960  sip->death_roll_time_mult = 1.0f;
2961  }
2962 
2963  if(optional_string("$Death FX Explosion Radius Mult:")){
2965  if (sip->death_fx_r_mult < 0)
2966  sip->death_fx_r_mult = 0;
2967  }
2968 
2969  if(optional_string("$Death FX Explosion Count:")){
2970  stuff_int(&sip->death_fx_count);
2971  if (sip->death_fx_count < 0)
2972  sip->death_fx_count = 0;
2973  }
2974 
2975  if(optional_string("$Ship Splitting Particles:"))
2976  {
2977  parse_ship_particle_effect(sip, &sip->split_particles, "ship split spew");
2978  }
2979 
2980  if(optional_string("$Ship Death Particles:"))
2981  {
2982  parse_ship_particle_effect(sip, &sip->regular_end_particles, "normal death spew");
2983  }
2984 
2985  if(optional_string("$Alternate Death Particles:"))
2986  {
2987  parse_ship_particle_effect(sip, &sip->knossos_end_particles, "knossos death spew");
2988  }
2989 
2990  if(optional_string("$Vaporize Percent Chance:")){
2992  if (sip->vaporize_chance < 0.0f || sip->vaporize_chance > 100.0f) {
2993  sip->vaporize_chance = 0.0f;
2994  Warning(LOCATION, "$Vaporize Percent Chance should be between 0 and 100.0 (read %f). Setting to 0.", sip->vaporize_chance);
2995  }
2996  //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
2997  sip->vaporize_chance /= 100.0;
2998  }
2999 
3000  if(optional_string("$Shockwave Damage Type:")) {
3004  }
3005 
3006  if(optional_string("$Shockwave Speed:")){
3007  stuff_float( &sci->speed );
3008  }
3009 
3010  if(optional_string("$Shockwave Count:")){
3011  stuff_int(&sip->shockwave_count);
3012  }
3013 
3014  if(optional_string("$Shockwave model:")){
3016  }
3017 
3018  if(optional_string("$Shockwave name:")) {
3020  }
3021 
3022  if(optional_string("$Explosion Animations:")){
3023  int temp[MAX_FIREBALL_TYPES];
3024  int parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
3025  sip->explosion_bitmap_anims.clear();
3026  sip->explosion_bitmap_anims.insert(sip->explosion_bitmap_anims.begin(), temp, temp+parsed_ints);
3027  }
3028 
3029  if (optional_string("$Weapon Model Draw Distance:")) {
3031  }
3032 
3033  // Set the weapons filter used in weapons loadout (for primary weapons)
3034  parse_allowed_weapons(sip, true, false, first_time);
3035  parse_allowed_weapons(sip, true, true, first_time);
3036 
3037  // Get primary bank weapons
3039 
3040  if(optional_string("$Show Primary Models:"))
3041  {
3044  }
3045 
3046  // Set the weapons filter used in weapons loadout (for secondary weapons)
3047  parse_allowed_weapons(sip, false, false, first_time);
3048  parse_allowed_weapons(sip, false, true, first_time);
3049 
3050  // Get secondary bank weapons
3052 
3053  if(optional_string("$Show Secondary Models:"))
3054  {
3057  }
3058 
3059  if (optional_string("$Ship Recoil Modifier:")){
3061  }
3062 
3063  if(optional_string("$Shields:")) {
3065 
3066  if(optional_string("+Auto Spread:")) {
3068  }
3069  if(optional_string("+Minimum Weapon Span:")) {
3071  }
3072  if(optional_string("+Allow Bypass:")) {
3074  }
3075  if(optional_string("+Spread From LOD:")) {
3076  int temp;
3077  stuff_int(&temp);
3078 
3079  if (temp > sip->num_detail_levels)
3080  Warning(LOCATION, "+Spread From LOD for %s was %i whereas ship only has %i detail levels, ignoring...", sip->name, temp, sip->num_detail_levels);
3081  else
3083  }
3084  }
3085 
3086  if(optional_string("$Model Point Shield Controls:")) {
3087  SCP_vector<SCP_string> ctrl_strings;
3088  int num_strings = stuff_string_list(ctrl_strings);
3089 
3090  // Init all to -1 in case some aren't supplied...
3095 
3096  for (i = 0; i < num_strings; i++) {
3097  const char *str = ctrl_strings[i].c_str();
3098 
3099  if (!stricmp(str, "front"))
3101  else if (!stricmp(str, "rear"))
3103  else if (!stricmp(str, "left"))
3105  else if (!stricmp(str, "right"))
3107  else if (!stricmp(str, "none"))
3108  ;
3109  else
3110  Warning(LOCATION, "Unrecognized value \"%s\" passed to $Model Point Shield Controls, ignoring...", str);
3111  }
3112  }
3113 
3114  // optional shield color
3115  if(optional_string("$Shield Color:")){
3116  stuff_ubyte(&sip->shield_color[0]);
3117  stuff_ubyte(&sip->shield_color[1]);
3118  stuff_ubyte(&sip->shield_color[2]);
3119  }
3120 
3121  if(optional_string("$Shield Impact Explosion:")) {
3122  char fname[MAX_NAME_LEN];
3123  stuff_string(fname, F_NAME, NAME_LENGTH);
3124 
3125  if ( VALID_FNAME(fname) )
3127  }
3128 
3129  if(optional_string("$Max Shield Recharge:")){
3131  CLAMP(sip->max_shield_recharge, 0.0f, 1.0f);
3132  }
3133 
3134  // The next five fields are used for the ETS
3135  if (optional_string("$Power Output:"))
3136  stuff_float(&sip->power_output);
3137 
3138  // Goober5000
3139  if (optional_string("$Shield Regeneration Rate:"))
3141  else if (first_time)
3142  sip->max_shield_regen_per_second = 0.02f;
3143 
3144  // Support ship hull shield rate - if allowed
3145  if(optional_string("$Support Shield Repair Rate:"))
3146  {
3148  sip->sup_shield_repair_rate *= 0.01f;
3149  CLAMP(sip->sup_shield_repair_rate, 0.0f, 1.0f);
3150  }
3151 
3152  // Goober5000
3153  if (optional_string("$Weapon Regeneration Rate:"))
3155  else if (first_time)
3156  sip->max_weapon_regen_per_second = 0.04f;
3157 
3158  if (optional_string("$Max Oclk Speed:") || optional_string("$Max Overclock Speed:"))
3160  else if (first_time)
3161  sip->max_overclocked_speed = sip->max_vel.xyz.z * 1.5f;
3162 
3163  if (optional_string("$Max Weapon Eng:") || optional_string("$Max Weapon Energy:"))
3165 
3166  if(optional_string("$Hitpoints:"))
3167  {
3169  if (sip->max_hull_strength < 0.0f)
3170  {
3171  Warning(LOCATION, "Max hull strength on %s '%s' cannot be less than 0. Defaulting to 100.\n", info_type_name, sip->name);
3172  sip->max_hull_strength = 100.0f;
3173  }
3174  }
3175 
3176  //Hull rep rate
3177 
3178  if(optional_string("$Hull Repair Rate:"))
3179  {
3181  sip->hull_repair_rate *= 0.01f;
3182 
3183  //Sanity checking
3184  if(sip->hull_repair_rate > 1.0f)
3185  sip->hull_repair_rate = 1.0f;
3186  else if(sip->hull_repair_rate < -1.0f)
3187  sip->hull_repair_rate = -1.0f;
3188  }
3189 
3190  // Support ship hull repair rate - if allowed
3191  if(optional_string("$Support Hull Repair Rate:"))
3192  {
3194  sip->sup_hull_repair_rate *= 0.01f;
3195  CLAMP(sip->sup_hull_repair_rate, 0.0f, 1.0f);
3196  }
3197 
3198  //Subsys rep rate
3199  if(optional_string("$Subsystem Repair Rate:"))
3200  {
3202  sip->subsys_repair_rate *= 0.01f;
3203 
3204  //Sanity checking
3205  if(sip->subsys_repair_rate > 1.0f)
3206  sip->subsys_repair_rate = 1.0f;
3207  else if(sip->subsys_repair_rate < -1.0f)
3208  sip->subsys_repair_rate = -1.0f;
3209  }
3210 
3211  // Support ship hull repair rate
3212  if(optional_string("$Support Subsystem Repair Rate:"))
3213  {
3215  sip->sup_subsys_repair_rate *= 0.01f;
3216  CLAMP(sip->sup_subsys_repair_rate, 0.0f, 1.0f);
3217  }
3218 
3219  if(optional_string("$Armor Type:"))
3220  {
3222  sip->armor_type_idx = armor_type_get_idx(buf);
3223 
3224  if(sip->armor_type_idx == -1)
3225  Warning(LOCATION,"Invalid armor name %s specified for hull in %s '%s'", buf, info_type_name, sip->name);
3226  }
3227 
3228  if(optional_string("$Shield Armor Type:"))
3229  {
3232 
3233  if(sip->shield_armor_type_idx == -1)
3234  Warning(LOCATION,"Invalid armor name %s specified for shield in %s '%s'", buf, info_type_name, sip->name);
3235  }
3236 
3237  if (optional_string("$Flags:"))
3238  {
3239  // we'll assume the list will contain no more than 20 distinct tokens
3240  char ship_strings[20][NAME_LENGTH];
3241  int num_strings = stuff_string_list(ship_strings, 20);
3242 
3243  int ship_type_index = -1;
3244 
3245  if (!optional_string("+noreplace")) {
3246  // clear flags since we might have a modular table
3247  // clear only those which are actually set in the flags
3248  sip->flags = (sip->flags & SIF_MASK);
3249  sip->flags2 = (sip->flags2 & SIF2_MASK);
3250  }
3251 
3252  for (i = 0; i < num_strings; i++)
3253  {
3254  // get ship type from ship flags
3255  char *ship_type = ship_strings[i];
3256  bool flag_found = false;
3257 
3258  // Goober5000 - in retail FreeSpace, some ship classes were specified differently
3259  // in ships.tbl and the ship type array; this patches those differences so that
3260  // the ship type lookup will work properly
3261  if (!stricmp(ship_type, "sentrygun"))
3262  ship_type = "sentry gun";
3263  else if (!stricmp(ship_type, "escapepod"))
3264  ship_type = "escape pod";
3265  else if (!stricmp(ship_type, "repair_rearm"))
3266  ship_type = "support";
3267  else if (!stricmp(ship_type, "supercap"))
3268  ship_type = "super cap";
3269  else if (!stricmp(ship_type, "knossos"))
3270  ship_type = "knossos device";
3271 
3272  // look it up in the object types table
3273  ship_type_index = ship_type_name_lookup(ship_type);
3274 
3275  // set ship class type
3276  if ((ship_type_index >= 0) && (sip->class_type < 0))
3277  sip->class_type = ship_type_index;
3278 
3279  // check various ship flags
3280  for (int idx = 0; idx < Num_ship_flags; idx++) {
3281  if ( !stricmp(Ship_flags[idx].name, ship_strings[i]) ) {
3282  flag_found = true;
3283 
3284  if (Ship_flags[idx].var == 255)
3285  Warning(LOCATION, "Use of '%s' flag for %s '%s' - this flag is no longer needed.", Ship_flags[idx].name, info_type_name, sip->name);
3286  else if (Ship_flags[idx].var == 0)
3287  sip->flags |= Ship_flags[idx].def;
3288  else if (Ship_flags[idx].var == 1)
3289  sip->flags2 |= Ship_flags[idx].def;
3290  }
3291  }
3292 
3293  if ( !flag_found && (ship_type_index < 0) )
3294  Warning(LOCATION, "Bogus string in ship flags: %s\n", ship_strings[i]);
3295  }
3296 
3297  // set original status of tech database flags - Goober5000
3298  if (sip->flags & SIF_IN_TECH_DATABASE)
3300  if (sip->flags & SIF_IN_TECH_DATABASE_M)
3302  }
3303 
3304  // Goober5000 - ensure number of banks checks out
3306  {
3307  Error(LOCATION, "%s '%s' has too many primary banks (%d). Maximum for ships is currently %d.\n", info_type_name, sip->name, sip->num_primary_banks, MAX_SHIP_PRIMARY_BANKS);
3308  }
3309 
3310  memset(sip->allowed_weapons, 0, sizeof(int) * MAX_WEAPON_TYPES);
3311 
3312  // copy to regular allowed_weapons array
3313  for (i = 0; i < MAX_SHIP_WEAPONS; i++)
3314  {
3315  for (j = 0; j < Num_weapon_types; j++)
3316  {
3318  sip->allowed_weapons[j] |= REGULAR_WEAPON;
3319 
3321  sip->allowed_weapons[j] |= DOGFIGHT_WEAPON;
3322  }
3323  }
3324 
3325  sip->flags &= ~SIF_BALLISTIC_PRIMARIES;
3326 
3327  //Set ship ballistic flag if necessary
3328  for (i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++)
3329  {
3330  for (j = 0; j < Num_weapon_types; j++)
3331  {
3333  {
3335  break;
3336  }
3337  }
3338  }
3339 
3340  find_and_stuff_optional("$AI Class:", &sip->ai_class, F_NAME, Ai_class_names, Num_ai_classes, "AI class names");
3341 
3342  // Get Afterburner information
3343  // Be aware that if $Afterburner is not 1, the other Afterburner fields are not read in
3344  int has_afterburner = 0;
3345 
3346  if(optional_string("$Afterburner:"))
3347  stuff_boolean(&has_afterburner);
3348 
3349  if ( has_afterburner == 1 )
3350  {
3351  sip->flags |= SIF_AFTERBURNER;
3352 
3353  if(optional_string("+Aburn Max Vel:")) {
3355  }
3356 
3357  if(optional_string("+Aburn For accel:")) {
3359  }
3360 
3361  // SparK: added reverse burner capability
3362  if(optional_string("+Aburn Max Reverse Vel:")) {
3364  }
3365  if(optional_string("+Aburn Rev accel:")) {
3367  }
3368 
3369  if(optional_string("+Aburn Fuel:")) {
3371  }
3372 
3373  if(optional_string("+Aburn Burn Rate:")) {
3375  }
3376 
3377  if(optional_string("+Aburn Rec Rate:")) {
3379  }
3380 
3381  if (!(sip->afterburner_fuel_capacity) ) {
3382  Warning(LOCATION, "%s '%s' has an afterburner but has no afterburner fuel. Setting fuel to 1", info_type_name, sip->name);
3383  sip->afterburner_fuel_capacity = 1.0f;
3384  }
3385  }
3386 
3387  if ( optional_string("$Trails:") ) {
3388  bool trails_warning = true;
3389 
3390  if (optional_string("+Bitmap:") ) {
3391  trails_warning = false;
3394  }
3395 
3396  if ( optional_string("+Width:") ) {
3397  trails_warning = false;
3399  }
3400 
3401  if ( optional_string("+Alpha:") ) {
3402  trails_warning = false;
3404  }
3405 
3406  if ( optional_string("+Life:") ) {
3407  trails_warning = false;
3409  }
3410 
3411  if ( optional_string("+Faded Out Sections:") ) {
3412  trails_warning = false;
3414  }
3415 
3416  if (trails_warning)
3417  Warning(LOCATION, "%s %s entry has $Trails field specified, but no properties given.", info_type_name, sip->name);
3418  }
3419 
3420  if (optional_string("$Countermeasure type:")) {
3422  int res = weapon_info_lookup(buf);
3423  if (res < 0) {
3424  Warning(LOCATION, "Could not find weapon type '%s' to use as countermeasure on %s '%s'", buf, info_type_name, sip->name);
3425  } else if (Weapon_info[res].wi_flags & WIF_BEAM) {
3426  Warning(LOCATION, "Attempt made to set a beam weapon as a countermeasure on %s '%s'", info_type_name, sip->name);
3427  } else {
3428  sip->cmeasure_type = res;
3429  }
3430  } else if (Species_info[sip->species].cmeasure_index >= 0) {
3431  sip->cmeasure_type = Species_info[sip->species].cmeasure_index;
3432  }
3433 
3434  if(optional_string("$Countermeasures:"))
3435  stuff_int(&sip->cmeasure_max);
3436 
3437  if(optional_string("$Scan time:"))
3438  stuff_int(&sip->scan_time);
3439 
3440  //Parse the engine sound
3441  parse_sound("$EngineSnd:", &sip->engine_snd, sip->name);
3442 
3443  if(optional_string("$Minimum Engine Volume:"))
3444  stuff_float(&sip->min_engine_vol);
3445 
3446  //Parse optional sound to be used for beginning of a glide
3447  parse_sound("$GlideStartSnd:", &sip->glide_start_snd, sip->name);
3448 
3449  //Parse optional sound to be used for end of a glide
3450  parse_sound("$GlideEndSnd:", &sip->glide_end_snd, sip->name);
3451 
3452  parse_ship_sounds(sip);
3453 
3454  if(optional_string("$Closeup_pos:"))
3455  {
3456  stuff_vec3d(&sip->closeup_pos);
3457  }
3458  else if (first_time && strlen(sip->pof_file))
3459  {
3460  //Calculate from the model file. This is inefficient, but whatever
3461  int model_idx = model_load(sip->pof_file, 0, NULL);
3462  polymodel *pm = model_get(model_idx);
3463 
3464  //Go through, find best
3465  sip->closeup_pos.xyz.z = fabsf(pm->maxs.xyz.z);
3466 
3467  float temp = fabsf(pm->mins.xyz.z);
3468  if(temp > sip->closeup_pos.xyz.z)
3469  sip->closeup_pos.xyz.z = temp;
3470 
3471  //Now multiply by 2
3472  sip->closeup_pos.xyz.z *= -2.0f;
3473 
3474  //We're done with the model.
3475  model_unload(model_idx);
3476  }
3477 
3478  if (optional_string("$Closeup_zoom:")) {
3479  stuff_float(&sip->closeup_zoom);
3480 
3481  if (sip->closeup_zoom <= 0.0f) {
3482  mprintf(("Warning! Ship '%s' has a $Closeup_zoom value that is less than or equal to 0 (%f). Setting to default value.\n", sip->name, sip->closeup_zoom));
3483  sip->closeup_zoom = 0.5f;
3484  }
3485  }
3486 
3487  if(optional_string("$Topdown offset:")) {
3488  sip->topdown_offset_def = true;
3489  stuff_vec3d(&sip->topdown_offset);
3490  }
3491 
3492  if (optional_string("$Shield_icon:")) {
3493  stuff_string(name_tmp, F_NAME, sizeof(name_tmp));
3494  hud_shield_assign_info(sip, name_tmp);
3495  }
3496 
3497  // read in filename for icon that is used in ship selection
3498  if ( optional_string("$Ship_icon:") ) {
3500  }
3501 
3502  if ( optional_string("$Model Icon Direction:") ) {
3503  char str[NAME_LENGTH];
3505 
3506  angles model_icon_angles = {0.0f,0.0f,0.0f};
3507 
3508  if (!stricmp(str, "top")) {
3509  model_icon_angles.p = -PI_2;
3510  } else if (!stricmp(str, "bottom")) {
3511  model_icon_angles.p = -PI_2;
3512  model_icon_angles.b = 2 * PI_2;
3513  } else if (!stricmp(str, "front")) {
3514  model_icon_angles.h = 2 * PI_2;
3515  } else if (!stricmp(str, "back")) {
3516  model_icon_angles.h = 4 * PI_2;
3517  } else if (!stricmp(str, "left")) {
3518  model_icon_angles.h = -PI_2;
3519  } else if (!stricmp(str, "right")) {
3520  model_icon_angles.h = PI_2;
3521  } else {
3522  Warning(LOCATION, "Unrecognized value \"%s\" passed to $Model Icon Direction, ignoring...", str);
3523  }
3524 
3525  sip->model_icon_angles = model_icon_angles;
3526  }
3527 
3528  // read in filename for animation that is used in ship selection
3529  if ( optional_string("$Ship_anim:") ) {
3531  }
3532 
3533  // read in filename for animation that is used in ship selection
3534  if ( optional_string("$Ship_overhead:") ) {
3536  }
3537 
3538  // read in briefing stuff
3539  if ( optional_string("$Briefing icon:") )
3541  if ( optional_string("$Briefing icon with cargo:") )
3543  if ( optional_string("$Briefing wing icon:") )
3545  if ( optional_string("$Briefing wing icon with cargo:") )
3547 
3548  // check for inconsistencies
3549  if ((sip->bii_index_wing_with_cargo >= 0) && (sip->bii_index_wing < 0 || sip->bii_index_ship_with_cargo < 0))
3550  Warning(LOCATION, "%s '%s' has a wing-with-cargo briefing icon but is missing a wing briefing icon or a ship-with-cargo briefing icon!", info_type_name, sip->name);
3551  if ((sip->bii_index_wing_with_cargo < 0) && (sip->bii_index_wing >= 0) && (sip->bii_index_ship_with_cargo >= 0))
3552  Warning(LOCATION, "%s '%s' has both a wing briefing icon and a ship-with-cargo briefing icon but does not have a wing-with-cargo briefing icon!", info_type_name, sip->name);
3553 
3554  if ( optional_string("$Score:") ){
3555  stuff_int( &sip->score );
3556  }
3557 
3558  if (first_time)
3559  {
3560  species_info *species = &Species_info[sip->species];
3561 
3562  sip->thruster_flame_info = species->thruster_info.flames;
3563  sip->thruster_glow_info = species->thruster_info.glow;
3567  }
3568 
3569  if ( optional_string("$Thruster Normal Flame:") ) {
3570  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3571 
3572  if ( VALID_FNAME(name_tmp) )
3573  generic_anim_init( &sip->thruster_flame_info.normal, name_tmp );
3574  }
3575 
3576  if ( optional_string("$Thruster Afterburner Flame:") ) {
3577  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3578 
3579  if ( VALID_FNAME(name_tmp) )
3580  generic_anim_init( &sip->thruster_flame_info.afterburn, name_tmp );
3581  }
3582 
3583  if ( optional_string("$Thruster Bitmap 1:") ) {
3584  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3585 
3586  if ( VALID_FNAME(name_tmp) ) {
3587  strcpy_s(sip->thruster_glow_info.normal.filename, name_tmp);
3589  }
3590  }
3591 
3592  if ( optional_string("$Thruster Bitmap 1a:") ) {
3593  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3594 
3595  if ( VALID_FNAME(name_tmp) ) {
3598  }
3599  }
3600 
3601  if ( optional_string("$Thruster01 Radius factor:") ) {
3603  }
3604 
3605  if ( optional_string("$Thruster Bitmap 2:") ) {
3606  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3607 
3608  if ( VALID_FNAME(name_tmp) )
3610  }
3611 
3612  if ( optional_string("$Thruster Bitmap 2a:") ) {
3613  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3614 
3615  if ( VALID_FNAME(name_tmp) )
3617  }
3618 
3619  if ( optional_string("$Thruster02 Radius factor:") ) {
3621  }
3622 
3623  if ( optional_string("$Thruster01 Length factor:") ) {
3625  Warning(LOCATION, "Deprecated spelling: \"$Thruster01 Length factor:\". Use \"$Thruster02 Length factor:\" instead.");
3626  }
3627 
3628  if ( optional_string("$Thruster02 Length factor:") ) {
3630  }
3631 
3632  if ( optional_string("$Thruster Bitmap 3:") ) {
3633  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3634 
3635  if ( VALID_FNAME(name_tmp) )
3637  }
3638 
3639  if ( optional_string("$Thruster Bitmap 3a:") ) {
3640  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3641 
3642  if ( VALID_FNAME(name_tmp) )
3644  }
3645 
3646  if ( optional_string("$Thruster03 Radius factor:") ) {
3648  }
3649 
3650  // Valathil - Custom Thruster Distortion
3651  if ( optional_string("$Thruster Bitmap Distortion:") ) {
3652  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3653 
3654  if ( VALID_FNAME(name_tmp) )
3656  }
3657 
3658  if ( optional_string("$Thruster Bitmap Distortion a:") ) {
3659  stuff_string( name_tmp, F_NAME, sizeof(name_tmp) );
3660 
3661  if ( VALID_FNAME(name_tmp) )
3663  }
3664 
3665  if ( optional_string("$Thruster Distortion Radius factor:") ) {
3667  }
3668 
3669  if ( optional_string("$Thruster Distortion Length factor:") ) {
3671  }
3672 
3673  if ( optional_string("$Thruster Distortion:") ) {
3675  }
3676 
3677  if ( optional_string("$Thruster Glow Noise Mult:") ) {
3679  }
3680 
3681  while ( optional_string("$Thruster Particles:") ) {
3682  bool afterburner = false;
3683  thruster_particles tpart;
3684 
3685  if ( optional_string("$Thruster Particle Bitmap:") )
3686  afterburner = false;
3687  else if ( optional_string("$Afterburner Particle Bitmap:") )
3688  afterburner = true;
3689  else
3690  Error( LOCATION, "formatting error in the thruster's particle section for %s '%s'\n", info_type_name, sip->name );
3691 
3692  generic_anim_init(&tpart.thruster_bitmap, NULL);
3694 
3695  required_string("$Min Radius:");
3696  stuff_float(&tpart.min_rad);
3697 
3698  required_string("$Max Radius:");
3699  stuff_float(&tpart.max_rad);
3700 
3701  required_string("$Min created:");
3702  stuff_int(&tpart.n_low);
3703 
3704  required_string("$Max created:");
3705  stuff_int(&tpart.n_high);
3706 
3707  required_string("$Variance:");
3708  stuff_float(&tpart.variance);
3709 
3710  if (afterburner) {
3711  sip->afterburner_thruster_particles.push_back( tpart );
3712  } else {
3713  sip->normal_thruster_particles.push_back( tpart );
3714  }
3715  }
3716 
3717  // if the ship is a stealth ship
3718  if ( optional_string("$Stealth:") ) {
3719  sip->flags |= SIF_STEALTH;
3720  }
3721 
3722  else if ( optional_string("$Stealth") ) {
3723  Warning(LOCATION, "%s '%s' is missing the colon after \"$Stealth\". Note that you may also use the ship flag \"stealth\".", info_type_name, sip->name);
3724  sip->flags |= SIF_STEALTH;
3725  }
3726 
3727  if ( optional_string("$max decals:") ){
3728  int bogus;
3729  stuff_int(&bogus);
3730  WarningEx(LOCATION, "The decal system has been deactivated in FSO builds. Entries will be discarded.\n");
3731  mprintf(("WARNING: The decal system has been deactivated in FSO builds. Entries will be discarded.\n"));
3732  //Do nothing, left in for compatibility.
3733  }
3734 
3735  // parse contrail info
3736  while ( optional_string("$Trail:") ) {
3737  // setting '+ClearAll' resets the trails
3738  if ( optional_string("+ClearAll")) {
3739  memset(&sip->ct_info, 0, sizeof(trail_info) * MAX_SHIP_CONTRAILS);
3740  sip->ct_count = 0;
3741  }
3742 
3743  // this means you've reached the max # of contrails for a ship
3744  if (sip->ct_count >= MAX_SHIP_CONTRAILS) {
3745  Warning(LOCATION, "%s '%s' has more contrails than the max of %d", info_type_name, sip->name, MAX_SHIP_CONTRAILS);
3746  break;
3747  }
3748 
3749  trail_info *ci = &sip->ct_info[sip->ct_count++];
3750 
3751  required_string("+Offset:");
3752  stuff_vec3d(&ci->pt);
3753 
3754  required_string("+Start Width:");
3755  stuff_float(&ci->w_start);
3756 
3757  required_string("+End Width:");
3758  stuff_float(&ci->w_end);
3759 
3760  required_string("+Start Alpha:");
3761  stuff_float(&ci->a_start);
3762 
3763  required_string("+End Alpha:");
3764  stuff_float(&ci->a_end);
3765 
3766  required_string("+Max Life:");
3767  stuff_float(&ci->max_life);
3768 
3769  required_string("+Spew Time:");
3770  stuff_int(&ci->stamp);
3771 
3772  required_string("+Bitmap:");
3773  stuff_string(name_tmp, F_NAME, NAME_LENGTH);
3774  generic_bitmap_init(&ci->texture, name_tmp);
3776 
3777  if (optional_string("+Faded Out Sections:") ) {
3779  }
3780  }
3781 
3782  man_thruster *mtp = NULL;
3783  man_thruster manwich;
3784  while(optional_string("$Thruster:"))
3785  {
3786  int idx = -1;
3787  if(optional_string("+index:")) {
3788  stuff_int(&idx);
3789  }
3790 
3791  if(idx >= 0 && idx < sip->num_maneuvering) {
3792  mtp = &sip->maneuvering[idx];
3793  } else if(idx < 0) {
3794  if(sip->num_maneuvering < MAX_MAN_THRUSTERS) {
3795  mtp = &sip->maneuvering[sip->num_maneuvering++];
3796  } else {
3797  Warning(LOCATION, "Too many maneuvering thrusters on %s '%s'; maximum is %d", info_type_name, sip->name, MAX_MAN_THRUSTERS);
3798  }
3799  } else {
3800  mtp = &manwich;
3801  Warning(LOCATION, "Invalid index (%d) specified for maneuvering thruster on %s '%s'", idx, info_type_name, sip->name);
3802  }
3803 
3804  if(optional_string("+Used for:")) {
3805  parse_string_flag_list(&mtp->use_flags, Man_types, Num_man_types);
3806  }
3807 
3808  if(optional_string("+Position:")) {
3809  stuff_float_list(mtp->pos.a1d, 3);
3810  }
3811 
3812  if(optional_string("+Normal:")) {
3813  stuff_float_list(mtp->norm.a1d, 3);
3814  }
3815 
3816  if(optional_string("+Texture:"))
3817  {
3818  stuff_string(name_tmp, F_NAME, sizeof(name_tmp));
3819  int tex_fps=0, tex_nframes=0, tex_id=-1;;
3820  tex_id = bm_load_animation(name_tmp, &tex_nframes, &tex_fps, NULL, 1);
3821  if(tex_id < 0)
3822  tex_id = bm_load(name_tmp);
3823  if(tex_id >= 0)
3824  {
3825  if(mtp->tex_id >= 0) {
3826  bm_unload(mtp->tex_id);
3827  }
3828 
3829  mtp->tex_id = tex_id;
3830  mtp->tex_fps = tex_fps;
3831  mtp->tex_nframes = tex_nframes;
3832  }
3833  }
3834 
3835  if(optional_string("+Radius:")) {
3836  stuff_float(&mtp->radius);
3837  }
3838 
3839  if(optional_string("+Length:")) {
3840  stuff_float(&mtp->length);
3841  }
3842 
3843  parse_sound("+StartSnd:", &mtp->start_snd, sip->name);
3844  parse_sound("+LoopSnd:", &mtp->loop_snd, sip->name);
3845  parse_sound("+StopSnd:", &mtp->stop_snd, sip->name);
3846  }
3847 
3848  if (optional_string("$Glowpoint overrides:")) {
3849  SCP_vector<SCP_string> tokens;
3850  tokens.clear();
3851  stuff_string_list(tokens);
3852  for(SCP_vector<SCP_string>::iterator token = tokens.begin(); token != tokens.end(); ++token) {
3853  SCP_string name, banks;
3854  size_t seppos;
3855  seppos = token->find_first_of(':');
3856  if(seppos == SCP_string::npos) {
3857  Warning(LOCATION, "Couldn't find ':' seperator in Glowpoint override for ship %s ignoring token", sip->name);
3858  continue;
3859  }
3860  name = token->substr(0, seppos);
3861  banks = token->substr(seppos+1);
3863  if(gpo == glowpoint_bank_overrides.end()){
3864  Warning(LOCATION, "Couldn't find preset %s in glowpoints.tbl when parsing ship: %s", name.data(), sip->name);
3865  continue;
3866  }
3867  if(banks == "*") {
3868  sip->glowpoint_bank_override_map[-1] = (void*)(&(*gpo));
3869  continue;
3870  }
3871  SCP_string banktoken;
3872  int start = -1;
3873  int end = -1;
3874  do {
3875  end = banks.find_first_of(',', ++start);
3876  banktoken = banks.substr(start, end);
3877  start = end;
3878 
3879  size_t fromtopos;
3880  fromtopos = banktoken.find_first_of('-');
3881  if(fromtopos != SCP_string::npos) {
3882  SCP_string from, to;
3883  int ifrom, ito;
3884  from = banktoken.substr(0, fromtopos);
3885  to = banktoken.substr(fromtopos+1);
3886  ifrom = atoi(from.data()) - 1;
3887  ito = atoi(to.data()) - 1;
3888  for(int bank = ifrom; bank <= ito; ++bank) {
3889  sip->glowpoint_bank_override_map[bank] = (void*)(&(*gpo));
3890  }
3891  } else {
3892  int bank = atoi(banktoken.data()) - 1;
3893  sip->glowpoint_bank_override_map[bank] = (void*)(&(*gpo));
3894  }
3895  } while(start!=-1);
3896  }
3897  }
3898 
3899  if (optional_string("$Radar Image 2D:"))
3900  {
3901  stuff_string(name_tmp, F_NAME, NAME_LENGTH);
3902  sip->radar_image_2d_idx = bm_load(name_tmp);
3903 
3904  if ( optional_string("$Radar Color Image 2D:") ) {
3905  stuff_string(name_tmp, F_NAME, NAME_LENGTH);
3906  sip->radar_color_image_2d_idx = bm_load(name_tmp);
3907  }
3908 
3909  if (optional_string("$Radar Image Size:"))
3910  stuff_int(&sip->radar_image_size);
3911 
3912  if (optional_string("$3D Radar Blip Size Multiplier:"))
3914  }
3915 
3916  // Alternate - per ship class - IFF colors
3917  while((optional_string("$Ship IFF Colors:")) || (optional_string("$Ship IFF Colours:")))
3918  {
3919  char iff_1[NAME_LENGTH];
3920  char iff_2[NAME_LENGTH];
3921  int iff_color_data[3];
3922  int iff_data[2];
3923 
3924  // Get the iff strings and get the iff indexes
3925  required_string("+Seen By:");
3926  stuff_string(iff_1, F_NAME, NAME_LENGTH);
3927 
3928  required_string("+When IFF Is:");
3929  stuff_string(iff_2, F_NAME, NAME_LENGTH);
3930  iff_data[0] = iff_lookup(iff_1);
3931  iff_data[1] = iff_lookup(iff_2);
3932 
3933  if (iff_data[0] == -1)
3934  WarningEx(LOCATION, "%s '%s'\nIFF colour seen by \"%s\" invalid!", info_type_name, sip->name, iff_1);
3935 
3936  if (iff_data[1] == -1)
3937  WarningEx(LOCATION, "%s '%s'\nIFF colour when IFF is \"%s\" invalid!", info_type_name, sip->name, iff_2);
3938 
3939  // Set the color
3940  required_string("+As Color:");
3941  stuff_int_list(iff_color_data, 3, RAW_INTEGER_TYPE);
3942  sip->ship_iff_info[iff_data[0]][iff_data[1]] = iff_init_color(iff_color_data[0],iff_color_data[1],iff_color_data[2]);
3943  }
3944 
3945  if (optional_string("$Target Priority Groups:") ) {
3946  SCP_vector<SCP_string> target_group_strings;
3947  int num_strings = stuff_string_list(target_group_strings);
3948  int num_groups = Ai_tp_list.size();
3949  bool override_strings = false;
3950 
3951  if (optional_string("+Override")) {
3952  override_strings = true;
3953  }
3954 
3955  for(j = 0; j < num_strings; j++) {
3956  for(i = 0; i < num_groups; i++) {
3957  if ( !stricmp(target_group_strings[j].c_str(), Ai_tp_list[i].name) ) {
3958  //so now the string from the list above as well as the ai priority group name match
3959  //clear it if override has been set
3960  if (override_strings) {
3961  Ai_tp_list[i].ship_class.clear();
3962  override_strings = false;
3963  }
3964  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
3965  //find the index number of the current ship info type
3966  if (it->name == sip->name) {
3967  Ai_tp_list[i].ship_class.push_back(std::distance(Ship_info.cbegin(), it));
3968  break;
3969  }
3970  }
3971  // found something, try next string
3972  break;
3973  }
3974  }
3975  if (i == num_groups) {
3976  Warning(LOCATION,"Unidentified priority group '%s' set for %s '%s'\n", target_group_strings[j].c_str(), info_type_name, sip->name);
3977  }
3978  }
3979  }
3980 
3981  if (optional_string("$EMP Resistance Modifier:")) {
3983  }
3984 
3985  if (optional_string("$Piercing Damage Draw Limit:")) {
3986  float tempf;
3987  stuff_float(&tempf);
3988  sip->piercing_damage_draw_limit = tempf / 100.0f;
3989  }
3990 
3991  while(optional_string("$Path Metadata:"))
3992  {
3993  char path_name[64];
3994  stuff_string(path_name, F_NAME, sizeof(path_name));
3995 
3996  path_metadata metadata;
3997  init_path_metadata(metadata);
3998 
3999  //Get +departure rvec and store on the path_metadata object
4000  if (optional_string("+departure rvec:"))
4001  {
4002  stuff_vec3d(&metadata.departure_rvec);
4003  }
4004 
4005  if (optional_string("+arrive speed multiplier:"))
4006  {
4007  stuff_float(&metadata.arrive_speed_mult);
4008  }
4009  if (optional_string("+depart speed multiplier:"))
4010  {
4011  stuff_float(&metadata.depart_speed_mult);
4012  }
4013 
4014  //Add the new path_metadata to sip->pathMetadata keyed by path name
4015  SCP_string pathName(path_name);
4016  sip->pathMetadata[pathName] = metadata;
4017  }
4018 
4019  int n_subsystems = 0;
4020  int cont_flag = 1;
4021  model_subsystem subsystems[MAX_MODEL_SUBSYSTEMS]; // see model.h for max_model_subsystems
4022  for (i=0; i<MAX_MODEL_SUBSYSTEMS; i++) {
4023  subsystems[i].stepped_rotation = NULL;
4024  }
4025 
4026  float hull_percentage_of_hits = 100.0f;
4027  //If the ship already has subsystem entries (ie this is a modular table)
4028  //make sure hull_percentage_of_hits is set properly
4029  for(i=0; i < sip->n_subsystems; i++) {
4030  hull_percentage_of_hits -= sip->subsystems[i].max_subsys_strength / sip->max_hull_strength;
4031  }
4032 
4033  while (cont_flag) {
4034  int r = required_string_one_of(3, "#End", "$Subsystem:", type_name);
4035  switch (r) {
4036  case 0:
4037  cont_flag = 0;
4038  break;
4039  case 1:
4040  {
4041  float turning_rate;
4042  float percentage_of_hits;
4043  bool turret_has_base_fov = false;
4044  model_subsystem *sp = NULL; // to append on the ships list of subsystems
4045 
4046  int sfo_return;
4047  required_string("$Subsystem:");
4048  stuff_string(name_tmp, F_NAME, sizeof(name_tmp), ",");
4049  Mp++;
4050  for(i = 0;i < sip->n_subsystems; i++)
4051  {
4052  if(!subsystem_stricmp(sip->subsystems[i].subobj_name, name_tmp))
4053  sp = &sip->subsystems[i];
4054  }
4055 
4056  if(sp == NULL)
4057  {
4058  if( sip->n_subsystems + n_subsystems >= MAX_MODEL_SUBSYSTEMS )
4059  {
4060  Warning(LOCATION, "Number of subsystems for %s '%s' (%d) exceeds max of %d; only the first %d will be used", info_type_name, sip->name, sip->n_subsystems, n_subsystems, MAX_MODEL_SUBSYSTEMS);
4061  break;
4062  }
4063  sp = &subsystems[n_subsystems++]; // subsystems a local -- when done, we will malloc and copy
4064  strcpy_s(sp->subobj_name, name_tmp);
4065 
4066  //Init blank values
4067  sp->max_subsys_strength = 0.0f;
4068  sp->turret_turning_rate = 0.0f;
4069  sp->weapon_rotation_pbank = -1;
4070 
4071  memset(sp->alt_sub_name, 0, sizeof(sp->alt_sub_name) );
4072  memset(sp->alt_dmg_sub_name, 0, sizeof(sp->alt_dmg_sub_name) );
4073 
4074  for (i=0; i<MAX_SHIP_PRIMARY_BANKS; i++) {
4075  sp->primary_banks[i] = -1;
4076  sp->primary_bank_capacity[i] = 0;
4077  }
4078 
4079  for (i=0; i<MAX_SHIP_SECONDARY_BANKS; i++) {
4080  sp->secondary_banks[i] = -1;
4081  sp->secondary_bank_capacity[i] = 0;
4082  }
4083 
4084  sp->engine_wash_pointer = NULL;
4085 
4086  sp->alive_snd = -1;
4087  sp->dead_snd = -1;
4088  sp->rotation_snd = -1;
4089  sp->turret_gun_rotation_snd = -1;
4090  sp->turret_gun_rotation_snd_mult = 1.0f;
4091  sp->turret_base_rotation_snd = -1;
4092  sp->turret_base_rotation_snd_mult = 1.0f;
4093 
4094  sp->flags = 0;
4095  sp->flags2 = 0;
4096 
4097  sp->n_triggers = 0;
4098  sp->triggers = NULL;
4099 
4100  sp->model_num = -1; // init value for later sanity checking!!
4101  sp->armor_type_idx = -1;
4102  sp->path_num = -1;
4103  sp->turret_max_fov = 1.0f;
4104 
4105  sp->turret_reset_delay = 2000;
4106 
4107  sp->num_target_priorities = 0;
4108  for (i = 0; i < 32; i++) {
4109  sp->target_priority[i] = -1;
4110  }
4111  sp->optimum_range = 0.0f;
4112  sp->favor_current_facing = 0.0f;
4113 
4114  sp->turret_rof_scaler = 1.0f;
4115 
4116  sp->turret_max_bomb_ownage = -1;
4117  sp->turret_max_target_ownage = -1;
4118  }
4119  sfo_return = stuff_float_optional(&percentage_of_hits);
4120  if(sfo_return==2)
4121  {
4122  hull_percentage_of_hits -= percentage_of_hits;
4123  sp->max_subsys_strength = sip->max_hull_strength * (percentage_of_hits / 100.0f);
4124  sp->type = SUBSYSTEM_UNKNOWN;
4125  }
4126  if(sfo_return > 0)
4127  {
4128  if(stuff_float_optional(&turning_rate)==2)
4129  {
4130  // specified as how long to turn 360 degrees in ships.tbl
4131  if ( turning_rate > 0.0f ){
4132  sp->turret_turning_rate = PI2 / turning_rate;
4133  } else {
4134  sp->turret_turning_rate = 0.0f;
4135  }
4136  }
4137  else
4138  {
4139  Error(LOCATION, "Malformed $Subsystem entry '%s' in %s '%s'.\n\n"
4140  "Specify a turning rate or remove the trailing comma.",
4141  sp->subobj_name, info_type_name, sip->name);
4142  }
4143  }
4144 
4145  if(optional_string("$Alt Subsystem Name:")) {
4147  strcpy_s(sp->alt_sub_name, buf);
4148  }
4149 
4150  if(optional_string("$Alt Damage Popup Subsystem Name:")) {
4152  strcpy_s(sp->alt_dmg_sub_name, buf);
4153  }
4154 
4155  if(optional_string("$Armor Type:")) {
4158 
4159  if (sp->armor_type_idx == -1)
4160  WarningEx(LOCATION, "%s '%s', subsystem %s\nInvalid armor type %s!", info_type_name, sip->name, sp->subobj_name, buf);
4161  }
4162 
4163  // Get primary bank weapons
4164  parse_weapon_bank(sip, true, NULL, sp->primary_banks, sp->primary_bank_capacity);
4165 
4166  // Get secondary bank weapons
4167  parse_weapon_bank(sip, false, NULL, sp->secondary_banks, sp->secondary_bank_capacity);
4168 
4169  // Get optional engine wake info
4170  if (optional_string("$Engine Wash:")) {
4171  stuff_string(name_tmp, F_NAME, sizeof(name_tmp));
4172  // get and set index
4174 
4175  if(sp->engine_wash_pointer == NULL)
4176  WarningEx(LOCATION,"Invalid engine wash name %s specified for subsystem %s in %s '%s'", name_tmp, sp->subobj_name, info_type_name, sip->name);
4177  }
4178 
4179  parse_sound("$AliveSnd:", &sp->alive_snd, sp->subobj_name);
4180  parse_sound("$DeadSnd:", &sp->dead_snd, sp->subobj_name);
4181  parse_sound("$RotationSnd:", &sp->rotation_snd, sp->subobj_name);
4182  parse_sound("$Turret Base RotationSnd:", &sp->turret_base_rotation_snd, sp->subobj_name);
4183  parse_sound("$Turret Gun RotationSnd:", &sp->turret_gun_rotation_snd, sp->subobj_name);
4184 
4185  if (optional_string("$Turret BaseSnd Volume:"))
4187 
4188  if (optional_string("$Turret GunSnd Volume:"))
4190 
4191  // Get any AWACS info
4192  sp->awacs_intensity = 0.0f;
4193  if(optional_string("$AWACS:")){
4194  sfo_return = stuff_float_optional(&sp->awacs_intensity);
4195  if(sfo_return > 0)
4197  sip->flags |= SIF_HAS_AWACS;
4198  }
4199 
4200  if(optional_string("$Maximum Barrel Elevation:")){
4201  int value;
4202  stuff_int(&value);
4203  CAP(value, 0, 90);
4204  float angle = fl_radians(90 - value);
4205  sp->turret_max_fov = cosf(angle);
4206  }
4207 
4208  if(optional_string("$Turret Base FOV:")) {
4209  int value;
4210  stuff_int(&value);
4211  CAP(value, 0, 359);
4212  float angle = fl_radians(value)/2.0f;
4213  sp->turret_y_fov = cosf(angle);
4214  turret_has_base_fov = true;
4215  }
4216 
4217  if (optional_string("$Turret Reset Delay:"))
4219 
4220  if (optional_string("$Turret Optimum Range:"))
4221  stuff_float(&sp->optimum_range);
4222 
4223  if (optional_string("$Turret Direction Preference:")) {
4224  int temp;
4225  stuff_int(&temp);
4226  if (temp == 0) {
4227  sp->favor_current_facing = 0.0f;
4228  } else {
4229  CAP(temp, 1, 100);
4230  sp->favor_current_facing = 1.0f + (((float) (100 - temp)) / 10.0f);
4231  }
4232  }
4233 
4234  if (optional_string("$Target Priority:")) {
4235  SCP_vector <SCP_string> tgt_priorities;
4236  int num_strings = stuff_string_list(tgt_priorities);
4237  sp->num_target_priorities = 0;
4238 
4239  if (num_strings > 32)
4240  num_strings = 32;
4241 
4242  int num_groups = Ai_tp_list.size();
4243 
4244  for(i = 0; i < num_strings; i++) {
4245  for(j = 0; j < num_groups; j++) {
4246  if ( !stricmp(Ai_tp_list[j].name, tgt_priorities[i].c_str())) {
4247  sp->target_priority[i] = j;
4248  sp->num_target_priorities++;
4249  break;
4250  }
4251  }
4252  if (j == num_groups) {
4253  Warning(LOCATION, "Unidentified target priority '%s' set for\nsubsystem '%s' in %s '%s'.", tgt_priorities[i].c_str(), sp->subobj_name, info_type_name, sip->name);
4254  }
4255  }
4256  }
4257 
4258  if (optional_string("$Max Turrets per Bomb:")) {
4260  }
4261 
4262  if (optional_string("$Max Turrets per Target:")) {
4264  }
4265 
4266  if (optional_string("$ROF:")) {
4267 
4268  if (optional_string("+Use firingpoints")) {
4269  sp->turret_rof_scaler = 0;
4270  } else {
4271  if (optional_string("+Multiplier:")) {
4272  float tempf;
4273  stuff_float(&tempf);
4274 
4275  if (tempf < 0) {
4276  mprintf(("RoF multiplier clamped to 0 for subsystem '%s' in %s '%s'.\n", sp->subobj_name, info_type_name, sip->name));
4277  sp->turret_rof_scaler = 0;
4278  } else {
4279  sp->turret_rof_scaler = tempf;
4280  }
4281  } else {
4282  Warning(LOCATION, "RoF multiplier not set for subsystem\n'%s' in %s '%s'.", sp->subobj_name, info_type_name, sip->name);
4283  }
4284  }
4285  }
4286 
4287  if (optional_string("$Flags:")) {
4288  char flag_strings[Num_subsystem_flags][NAME_LENGTH];
4289  int num_strings = stuff_string_list(flag_strings, NUM_SUBSYSTEM_FLAGS);
4290 
4291  if (!optional_string("+noreplace")) {
4292  // clear flags since we might have a modular table
4293  // clear only those which are actually set in the flags
4294  sp->flags = 0;
4295  sp->flags2 = 0;
4296  }
4297 
4298  for (i = 0; i < num_strings; i++)
4299  {
4300 
4301  bool flag_found = false;
4302  // check various subsystem flags
4303  for (int idx = 0; idx < Num_subsystem_flags; idx++) {
4304  if ( !stricmp(Subsystem_flags[idx].name, flag_strings[i]) ) {
4305  flag_found = true;
4306 
4307  if (Subsystem_flags[idx].var == 0)
4308  sp->flags |= Subsystem_flags[idx].def;
4309  else if (Subsystem_flags[idx].var == 1)
4310  sp->flags2 |= Subsystem_flags[idx].def;
4311  }
4312  }
4313 
4314  if ( !flag_found )
4315  Warning(LOCATION, "Bogus string in subsystem flags: %s\n", flag_strings[i]);
4316  }
4317 
4318  //If we've set any subsystem as landable, set a ship-info flag as a shortcut for later
4319  if (sp->flags & MSS_FLAG_ALLOW_LANDING)
4320  sip->flags2 |= SIF2_ALLOW_LANDINGS;
4321  }
4322 
4323  if (turret_has_base_fov)
4325 
4326  if (optional_string("+non-targetable")) {
4327  Warning(LOCATION, "Grammar error in table file. Please change \"+non-targetable\" to \"+untargetable\".");
4329  }
4330 
4331  bool old_flags = false;
4332  if (optional_string("+untargetable")) {
4334  old_flags = true;
4335  }
4336 
4337  if (optional_string("+carry-no-damage")) {
4339  old_flags = true;
4340  }
4341 
4342  if (optional_string("+use-multiple-guns")) {
4344  old_flags = true;
4345  }
4346 
4347  if (optional_string("+fire-down-normals")) {
4349  old_flags = true;
4350  }
4351 
4353  Warning(LOCATION, "\"fixed firingpoints\" flag used without \"use multiple guns\" flag on a subsystem on %s '%s'.\n\"use multiple guns\" flags added by default\n", info_type_name, sip->name);
4355  }
4356 
4358  Warning(LOCATION, "\"autorepair if disabled\" flag used with \"don't autorepair if disabled\" flag on a subsystem on %s '%s'.\nWhichever flag would be default behavior anyway for this ship has been removed.\n", info_type_name, sip->name);
4361  } else {
4363  }
4364  }
4365 
4366  if (old_flags) {
4367  mprintf(("Use of deprecated subsystem syntax. Please use the $Flags: field for subsystem flags.\n\n" \
4368  "At least one of the following tags was used on %s '%s', subsystem %s:\n" \
4369  "\t+untargetable\n" \
4370  "\t+carry-no-damage\n" \
4371  "\t+use-multiple-guns\n" \
4372  "\t+fire-down-normals\n", info_type_name, sip->name, sp->subobj_name));
4373  }
4374 
4375  while(optional_string("$animation:"))
4376  {
4377  stuff_string(name_tmp, F_NAME, sizeof(name_tmp));
4378  if(!stricmp(name_tmp, "triggered"))
4379  {
4380  queued_animation *current_trigger;
4381 
4382  sp->triggers = (queued_animation*)vm_realloc(sp->triggers, sizeof(queued_animation) * (sp->n_triggers + 1));
4383  Verify(sp->triggers != NULL);
4384 
4385  //add a new trigger
4386  current_trigger = &sp->triggers[sp->n_triggers];
4387  queued_animation_init(current_trigger);
4388  sp->n_triggers++;
4389 
4390  required_string("$type:");
4391  char atype[NAME_LENGTH];
4392  stuff_string(atype, F_NAME, NAME_LENGTH);
4393  current_trigger->type = model_anim_match_type(atype);
4394 
4395  if(optional_string("+sub_type:")){
4396  stuff_int(&current_trigger->subtype);
4397  }else{
4398  current_trigger->subtype = ANIMATION_SUBTYPE_ALL;
4399  }
4400 
4401  if(optional_string("+sub_name:")) {
4402  stuff_string(current_trigger->sub_name, F_NAME, NAME_LENGTH);
4403  } else {
4404  strcpy_s(current_trigger->sub_name, "<none>");
4405  }
4406 
4407 
4408  if(current_trigger->type == TRIGGER_TYPE_INITIAL){
4409  //the only thing initial animation type needs is the angle,
4410  //so to save space lets just make everything optional in this case
4411 
4412  if(optional_string("+delay:"))
4413  stuff_int(&current_trigger->start);
4414  else
4415  current_trigger->start = 0;
4416 
4417  if ( optional_string("+reverse_delay:") )
4418  stuff_int(&current_trigger->reverse_start);
4419  else
4420  current_trigger->reverse_start = 0;
4421 
4422  if(optional_string("+absolute_angle:")){
4423  current_trigger->absolute = true;
4424  stuff_vec3d(&current_trigger->angle );
4425 
4426  current_trigger->angle.xyz.x = fl_radians(current_trigger->angle.xyz.x);
4427  current_trigger->angle.xyz.y = fl_radians(current_trigger->angle.xyz.y);
4428  current_trigger->angle.xyz.z = fl_radians(current_trigger->angle.xyz.z);
4429  }else{
4430  current_trigger->absolute = false;
4431  if(!optional_string("+relative_angle:"))
4432  required_string("+relative_angle:");
4433 
4434  stuff_vec3d(&current_trigger->angle );
4435 
4436  current_trigger->angle.xyz.x = fl_radians(current_trigger->angle.xyz.x);
4437  current_trigger->angle.xyz.y = fl_radians(current_trigger->angle.xyz.y);
4438  current_trigger->angle.xyz.z = fl_radians(current_trigger->angle.xyz.z);
4439  }
4440 
4441  if(optional_string("+velocity:")){
4442  stuff_vec3d(&current_trigger->vel );
4443  current_trigger->vel.xyz.x = fl_radians(current_trigger->vel.xyz.x);
4444  current_trigger->vel.xyz.y = fl_radians(current_trigger->vel.xyz.y);
4445  current_trigger->vel.xyz.z = fl_radians(current_trigger->vel.xyz.z);
4446  }
4447 
4448  if(optional_string("+acceleration:")){
4449  stuff_vec3d(&current_trigger->accel );
4450  current_trigger->accel.xyz.x = fl_radians(current_trigger->accel.xyz.x);
4451  current_trigger->accel.xyz.y = fl_radians(current_trigger->accel.xyz.y);
4452  current_trigger->accel.xyz.z = fl_radians(current_trigger->accel.xyz.z);
4453  }
4454 
4455  if(optional_string("+time:"))
4456  stuff_int(&current_trigger->end );
4457  else
4458  current_trigger->end = 0;
4459  }else{
4460 
4461  if(optional_string("+delay:"))
4462  stuff_int(&current_trigger->start);
4463  else
4464  current_trigger->start = 0;
4465 
4466  if ( optional_string("+reverse_delay:") )
4467  stuff_int(&current_trigger->reverse_start);
4468  else
4469  current_trigger->reverse_start = -1; //have some code figure this out for us
4470 
4471  if(optional_string("+absolute_angle:")){
4472  current_trigger->absolute = true;
4473  stuff_vec3d(&current_trigger->angle );
4474 
4475  current_trigger->angle.xyz.x = fl_radians(current_trigger->angle.xyz.x);
4476  current_trigger->angle.xyz.y = fl_radians(current_trigger->angle.xyz.y);
4477  current_trigger->angle.xyz.z = fl_radians(current_trigger->angle.xyz.z);
4478  }else{
4479  current_trigger->absolute = false;
4480  required_string("+relative_angle:");
4481  stuff_vec3d(&current_trigger->angle );
4482 
4483  current_trigger->angle.xyz.x = fl_radians(current_trigger->angle.xyz.x);
4484  current_trigger->angle.xyz.y = fl_radians(current_trigger->angle.xyz.y);
4485  current_trigger->angle.xyz.z = fl_radians(current_trigger->angle.xyz.z);
4486  }
4487 
4488  required_string("+velocity:");
4489  stuff_vec3d(&current_trigger->vel );
4490  current_trigger->vel.xyz.x = fl_radians(current_trigger->vel.xyz.x);
4491  current_trigger->vel.xyz.y = fl_radians(current_trigger->vel.xyz.y);
4492  current_trigger->vel.xyz.z = fl_radians(current_trigger->vel.xyz.z);
4493 
4494  if (optional_string("+acceleration:")){
4495  stuff_vec3d(&current_trigger->accel );
4496  current_trigger->accel.xyz.x = fl_radians(current_trigger->accel.xyz.x);
4497  current_trigger->accel.xyz.y = fl_radians(current_trigger->accel.xyz.y);
4498  current_trigger->accel.xyz.z = fl_radians(current_trigger->accel.xyz.z);
4499  } else {
4500  current_trigger->accel.xyz.x = 0.0f;
4501  current_trigger->accel.xyz.y = 0.0f;
4502  current_trigger->accel.xyz.z = 0.0f;
4503  }
4504 
4505  if(optional_string("+time:"))
4506  stuff_int(&current_trigger->end );
4507  else
4508  current_trigger->end = 0;
4509 
4510  if(optional_string("$Sound:")){
4511  parse_sound("+Start:", &current_trigger->start_sound, sip->name);
4512 
4513  parse_sound("+Loop:", &current_trigger->loop_sound, sip->name);
4514 
4515  parse_sound("+End:", &current_trigger->end_sound, sip->name);
4516 
4517  required_string("+Radius:");
4518  stuff_float(&current_trigger->snd_rad );
4519  }else{
4520  current_trigger->start_sound = -1;
4521  current_trigger->loop_sound = -1;
4522  current_trigger->end_sound = -1;
4523  current_trigger->snd_rad = 0;
4524  }
4525  }
4526 
4527  //make sure that the amount of time it takes to accelerate up and down doesn't make it go farther than the angle
4528  queued_animation_correct(current_trigger);
4529  }
4530  else if(!stricmp(name_tmp, "linked"))
4531  {
4532  mprintf(("TODO: set up linked animation\n"));
4533  }
4534  }
4535 
4536  }
4537  break;
4538  case 2:
4539  cont_flag = 0;
4540  break;
4541  case -1: // Possible return value if -noparseerrors is used
4542  break;
4543  default:
4544  Assertion(false, "This should never happen.\n"); // Impossible return value from required_string_one_of.
4545  }
4546  }
4547 
4548  // must be > 0//no it doesn't :P -Bobboau
4549  // yes it does! - Goober5000
4550  // (we don't want a div-0 error)
4551  if (hull_percentage_of_hits <= 0.0f )
4552  {
4553  //Warning(LOCATION, "The subsystems defined for the %s can take more (or the same) combined damage than the ship itself. Adjust the tables so that the percentages add up to less than 100", sip->name);
4554  }
4555  // when done reading subsystems, malloc and copy the subsystem data to the ship info structure
4556  int orig_n_subsystems = sip->n_subsystems;
4557  if ( n_subsystems > 0 ) {
4558  if(sip->n_subsystems < 1) {
4559  sip->n_subsystems = n_subsystems;
4561  } else {
4562  sip->n_subsystems += n_subsystems;
4564  }
4565  Assert( sip->subsystems != NULL );
4566 
4567  for ( i = 0; i < n_subsystems; i++ ){
4568  sip->subsystems[orig_n_subsystems+i] = subsystems[i];
4569  }
4570  }
4571 
4573 
4574  return rtn; //0 for success
4575 }
4576 
4578 {
4579  for(int i = 0; i < Num_engine_wash_types; i++)
4580  {
4581  if(!stricmp(engine_wash_name, Engine_wash_info[i].name))
4582  {
4583  return &Engine_wash_info[i];
4584  }
4585  }
4586 
4587  //Didn't find anything.
4588  return NULL;
4589 }
4590 
4592 {
4593  char name_buf[NAME_LENGTH];
4594  bool nocreate = false;
4595  ship_type_info stp_buf, *stp = NULL;
4596 
4597  required_string("$Name:");
4598  stuff_string(name_buf, F_NAME, NAME_LENGTH);
4599 
4600  if(optional_string("+nocreate")) {
4601  nocreate = true;
4602  }
4603 
4604  int idx = ship_type_name_lookup(name_buf);
4605  if (idx >= 0)
4606  {
4607  stp = &Ship_types[idx];
4608  }
4609  else
4610  {
4611  stp = &stp_buf;
4612  strcpy_s(stp->name, name_buf);
4613  }
4614 
4615  char *ship_type = NULL;
4616  if (!stricmp(stp->name, "sentrygun")) {
4617  ship_type = "sentry gun";
4618  } else if (!stricmp(stp->name, "escapepod")) {
4619  ship_type = "escape pod";
4620  } else if (!stricmp(stp->name, "repair_rearm")) {
4621  ship_type = "support";
4622  } else if (!stricmp(stp->name, "supercap")) {
4623  ship_type = "super cap";
4624  } else if (!stricmp(stp->name, "knossos")) {
4625  ship_type = "knossos device";
4626  }
4627 
4628  if (ship_type != NULL) {
4629  Warning(LOCATION, "Bad ship type name in objecttypes.tbl\n\nUsed ship type is redirected to another ship type.\nReplace \"%s\" with \"%s\"\nin objecttypes.tbl to fix this.\n", stp->name, ship_type);
4630  }
4631 
4632  //Okay, now we should have the values to parse
4633  //But they aren't here!! :O
4634  //Now they are!! Whee fogging!!
4635 
4636  //AI turret targeting priority setup
4637  if (optional_string("$Target Priority Groups:") ) {
4638  SCP_vector <SCP_string> target_group_strings;
4639  int num_strings = stuff_string_list(target_group_strings);
4640  int num_groups = Ai_tp_list.size();
4641  int i, j;
4642  bool override_strings = false;
4643 
4644  if (optional_string("+Override")) {
4645  override_strings = true;
4646  }
4647 
4648  for(j = 0; j < num_strings; j++) {
4649  for(i = 0; i < num_groups; i++) {
4650  if ( !stricmp(target_group_strings[j].c_str(), Ai_tp_list[i].name) ) {
4651  //so now the string from the list above as well as the ai priority group name match
4652  //clear it if override has been set
4653  if (override_strings) {
4654  Ai_tp_list[i].ship_type.clear();
4655  override_strings = false;
4656  }
4657  //find the index number of the current ship info type
4658  Ai_tp_list[i].ship_type.push_back(ship_type_name_lookup(name_buf));
4659  break;
4660  }
4661  }
4662  if (i == num_groups) {
4663  Warning(LOCATION,"Unidentified priority group '%s' set for objecttype '%s'\n", target_group_strings[j].c_str(), stp->name);
4664  }
4665  }
4666  }
4667 
4668  if(optional_string("$Counts for Alone:")) {
4670  }
4671 
4672  if(optional_string("$Praise Destruction:")) {
4674  }
4675 
4676  if(optional_string("$On Hotkey list:")) {
4678  }
4679 
4680  if(optional_string("$Target as Threat:")) {
4682  }
4683 
4684  if(optional_string("$Show Attack Direction:")) {
4686  }
4687 
4688  if(optional_string("$Scannable:")) {
4690  }
4691 
4692  if(optional_string("$Warp Pushes:")) {
4694  }
4695 
4696  if(optional_string("$Warp Pushable:")) {
4698  }
4699 
4700  if(optional_string("$Turrets prioritize ship target:")) {
4702  }
4703 
4704  if(optional_string("$Max Debris Speed:")) {
4706  }
4707 
4708  if(optional_string("$FF Multiplier:")) {
4709  stuff_float(&stp->ff_multiplier);
4710  }
4711 
4712  if(optional_string("$EMP Multiplier:")) {
4713  stuff_float(&stp->emp_multiplier);
4714  }
4715 
4716  if(optional_string("$Beams Easily Hit:")) {
4718  }
4719 
4720  if(optional_string("$Protected on cripple:")) {
4722  }
4723 
4724  if(optional_string("$No Huge Beam Impact Effects:")) {
4726  }
4727 
4728  if(optional_string("$Don't display class in briefing:")) {
4730  }
4731 
4732  if(optional_string("$Fog:"))
4733  {
4734  if(optional_string("+Start dist:")) {
4735  stuff_float(&stp->fog_start_dist);
4736  }
4737 
4738  if(optional_string("+Compl dist:")) {
4740  }
4741  }
4742 
4743  if(optional_string("$AI:"))
4744  {
4745  if(optional_string("+Valid goals:")) {
4747  }
4748 
4749  if(optional_string("+Accept Player Orders:")) {
4751  }
4752 
4753  if(optional_string("+Player Orders:")) {
4754  parse_string_flag_list(&stp->ai_player_orders, Player_orders, Num_player_orders);
4755  }
4756 
4757  if(optional_string("+Auto attacks:")) {
4759  }
4760 
4761  if(optional_string("+Attempt broadside:")) {
4763  }
4764 
4765  if(optional_string("+Actively Pursues:")) {
4767  }
4768 
4769  if(optional_string("+Guards attack this:")) {
4771  }
4772 
4773  if(optional_string("+Turrets attack this:")) {
4775  }
4776 
4777  if(optional_string("+Can form wing:")) {
4779  }
4780 
4781  if(optional_string("+Active docks:")) {
4783  }
4784 
4785  if(optional_string("+Passive docks:")) {
4787  }
4788 
4789  if(optional_string("+Ignored on cripple by:")) {
4791  }
4792  }
4793 
4794  if(optional_string("$Explosion Animations:"))
4795  {
4796  int temp[MAX_FIREBALL_TYPES];
4797  int parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
4798  stp->explosion_bitmap_anims.clear();
4799  stp->explosion_bitmap_anims.insert(stp->explosion_bitmap_anims.begin(), temp, temp+parsed_ints);
4800  }
4801 
4802  if(optional_string("$Vaporize Percent Chance:")) {
4804  if (stp->vaporize_chance < 0.0f || stp->vaporize_chance > 100.0f) {
4805  stp->vaporize_chance = 0.0f;
4806  Warning(LOCATION, "$Vaporize Percent Chance should be between 0 and 100.0 (read %f). Setting to 0.", stp->vaporize_chance);
4807  }
4808  //Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
4809  stp->vaporize_chance /= 100.0;
4810  }
4811 
4812  if (!nocreate)
4813  Ship_types.push_back(stp_buf);
4814 }
4815 
4816 void parse_shiptype_tbl(const char *filename)
4817 {
4818  try
4819  {
4820  if (filename != NULL)
4821  read_file_text(filename, CF_TYPE_TABLES);
4822  else
4823  read_file_text_from_array(defaults_get_file("objecttypes.tbl"));
4824 
4825  reset_parse();
4826 
4827  if (optional_string("#Target Priorities"))
4828  {
4829  while (required_string_either("#End", "$Name:"))
4831 
4832  required_string("#End");
4833  }
4834 
4835  if (optional_string("#Weapon Targeting Priorities"))
4836  {
4837  while (required_string_either("#End", "$Name:"))
4839 
4840  required_string("#End");
4841  }
4842 
4843  if (optional_string("#Ship Types"))
4844  {
4845  while (required_string_either("#End", "$Name:"))
4846  parse_ship_type();
4847 
4848  required_string("#End");
4849  }
4850 
4851  // add tbl/tbm to multiplayer validation list
4852  fs2netd_add_table_validation(filename);
4853  }
4854  catch (const parse::ParseException& e)
4855  {
4856  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
4857  return;
4858  }
4859 }
4860 
4861 // The E - Simple lookup function for FRED.
4863 {
4864  if (strlen(default_player_ship))
4865  {
4866  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it)
4867  {
4868  if (stricmp(default_player_ship, it->name) == 0)
4869  return std::distance(Ship_info.cbegin(), it);
4870  }
4871  return 0;
4872  } else
4873  return 0;
4874 }
4875 
4876 // Goober5000 - this works better in its own function
4878 {
4879  // already have one
4880  if(strlen(default_player_ship))
4881  return;
4882 
4883  // find the first with the default flag
4884  for(auto it = Ship_info.cbegin(); it != Ship_info.end(); ++it)
4885  {
4886  if(it->flags & SIF_DEFAULT_PLAYER_SHIP)
4887  {
4888  strcpy_s(default_player_ship, it->name);
4889  return;
4890  }
4891  }
4892 
4893  // find the first player ship
4894  for(auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it)
4895  {
4896  if(it->flags & SIF_PLAYER_SHIP)
4897  {
4898  strcpy_s(default_player_ship, it->name);
4899  return;
4900  }
4901  }
4902 
4903  // find the first ship
4904  if(!Ship_info.empty())
4905  {
4906  strcpy_s(default_player_ship, Ship_info[0].name);
4907  }
4908 }
4909 
4910 void parse_shiptbl(const char *filename)
4911 {
4912  try
4913  {
4914  read_file_text(filename, CF_TYPE_TABLES);
4915  reset_parse();
4916 
4917  // parse default ship
4918  //Override default player ship
4919  if (optional_string("#Default Player Ship"))
4920  {
4921  required_string("$Name:");
4923  required_string("#End");
4924  }
4925  //Add engine washes
4926  //This will override if they already exist
4927  if (optional_string("#Engine Wash Info"))
4928  {
4929  while (required_string_either("#End", "$Name:"))
4930  {
4932  }
4933 
4934  required_string("#End");
4935  }
4936 
4937  if ( optional_string("#Ship Templates") ) {
4938 
4939  while ( required_string_either("#End", "$Template:") ) {
4940  if ( parse_ship_template() ) {
4941  continue;
4942  }
4943  }
4944 
4945  required_string("#End");
4946  }
4947 
4948  //Add ship classes
4949  if(optional_string("#Ship Classes"))
4950  {
4951 
4952  while (required_string_either("#End", "$Name:"))
4953  {
4954  if (parse_ship(filename, Parsing_modular_table)) {
4955  continue;
4956  }
4957  }
4958 
4959  required_string("#End");
4960  }
4961 
4962  //Set default player ship
4964 
4965  // add tbl/tbm to multiplayer validation list
4966  fs2netd_add_table_validation(filename);
4967  }
4968  catch (const parse::ParseException& e)
4969  {
4970  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
4971  return;
4972  }
4973 }
4974 
4976 
4977 
4978 DCF_BOOL( show_velocity_dot, ship_show_velocity_dot )
4979 
4980 
4984 {
4985  int i, j;
4986  char name_tmp[NAME_LENGTH];
4987 
4988  for (auto sip = Ship_info.begin(); sip != Ship_info.end(); ++sip)
4989  {
4990  // ballistic primary fixage...
4991  {
4992  bool pbank_capacity_specified = false;
4993 
4994  // determine whether this ship had primary capacities specified for it
4995  for (j = 0; j < sip->num_primary_banks; j++) {
4996  if (sip->primary_bank_ammo_capacity[j] > 0) {
4997  pbank_capacity_specified = true;
4998  break;
4999  }
5000  }
5001 
5002  // be friendly; ensure ballistic flags check out
5003  if (pbank_capacity_specified) {
5004  if ( !(sip->flags & SIF_BALLISTIC_PRIMARIES) ) {
5005  Warning(LOCATION, "Pbank capacity specified for non-ballistic-primary-enabled ship %s.\nResetting capacities to 0.\nTo fix this, add a ballistic primary to the list of allowed primaries.\n", sip->name);
5006 
5007  for (j = 0; j < MAX_SHIP_PRIMARY_BANKS; j++) {
5008  sip->primary_bank_ammo_capacity[j] = 0;
5009  }
5010  }
5011  } else {
5012  if (sip->flags & SIF_BALLISTIC_PRIMARIES) {
5013  Warning(LOCATION, "Pbank capacity not specified for ballistic-primary-enabled ship %s.\nDefaulting to capacity of 1 per bank.\n", sip->name);
5014 
5015  for (j = 0; j < MAX_SHIP_PRIMARY_BANKS; j++) {
5016  sip->primary_bank_ammo_capacity[j] = 1;
5017  }
5018  }
5019  }
5020  }
5021 
5022  // ultra stupid compatbility handling for the once broken "generate hud" flag.
5023  // it was previously testing the afterburner flag, so that's what we check for that
5024  if ( (sip->shield_icon_index == 255) && (sip->flags & SIF_AFTERBURNER)
5025  && !(sip->flags2 & SIF2_GENERATE_HUD_ICON) && (sip->flags & SIF_PLAYER_SHIP) )
5026  {
5027  Warning(LOCATION, "Compatibility warning:\nNo shield icon specified for '%s' but the \"generate icon\" flag is not specified.\nEnabling flag by default.\n", sip->name);
5028  sip->flags2 |= SIF2_GENERATE_HUD_ICON;
5029  }
5030 
5031  // if we have a ship copy, then check to be sure that our base ship exists
5032  if (sip->flags & SIF_SHIP_COPY)
5033  {
5034  strcpy_s(name_tmp, sip->name);
5035 
5036  if (end_string_at_first_hash_symbol(name_tmp))
5037  {
5038  if (ship_info_lookup(name_tmp) < 0)
5039  {
5040  Warning(LOCATION, "Ship %s is a copy, but base ship %s couldn't be found.", sip->name, name_tmp);
5041  sip->flags &= ~SIF_SHIP_COPY;
5042  }
5043  }
5044  else
5045  {
5046  Warning(LOCATION, "Ship %s is defined as a copy (ship flag 'ship copy' is set), but is not named like one (no '#').\n", sip->name);
5047  sip->flags &= ~SIF_SHIP_COPY;
5048  }
5049  }
5050 
5051  // very low rotational velocity values disable rotational collisions
5052  // warn early rather than ambush the modder @ runtime (unless the ship is also no-collide!)
5053  // the 2nd part of this check is duplicated from collideshipship.cpp:ship_ship_check_collision()
5054  if (!(sip->flags & SIF_NO_COLLIDE) && (vm_vec_mag_squared( &sip->max_rotvel ) * .04) >= (PI*PI/4))
5055  {
5056  Warning(LOCATION, "$Rotation time: too low; this will disable rotational collisions. All three variables should be >= 1.39.\nFix this in ship '%s'\n", sip->name);
5057  }
5058  }
5059 
5060  // check also target groups here
5061  int n_tgt_groups = Ai_tp_list.size();
5062 
5063  if (n_tgt_groups > 0) {
5064  for(i = 0; i < n_tgt_groups; i++) {
5065  if (!(Ai_tp_list[i].obj_flags || Ai_tp_list[i].sif_flags || Ai_tp_list[i].sif2_flags || Ai_tp_list[i].wif2_flags || Ai_tp_list[i].wif_flags)) {
5066  //had none of these, check next
5067  if (Ai_tp_list[i].obj_type == -1) {
5068  //didn't have this one
5069  if (!(Ai_tp_list[i].ship_class.size() || Ai_tp_list[i].ship_type.size() || Ai_tp_list[i].weapon_class.size())) {
5070  // had nothing - time to issue a warning
5071  Warning(LOCATION, "Target priority group '%s' had no targeting rules issued for it.\n", Ai_tp_list[i].name);
5072  }
5073  }
5074  }
5075  }
5076  }
5077 
5078  // Clear out ship templates, since they're no longer needed. -MageKing17
5079  Ship_templates.clear();
5080 }
5081 
5087 {
5088  if ( !ships_inited )
5089  {
5090  //Parse main TBL first
5091  if (cf_exists_full("objecttypes.tbl", CF_TYPE_TABLES))
5092  parse_shiptype_tbl("objecttypes.tbl");
5093  else
5094  parse_shiptype_tbl(NULL);
5095 
5096  //Then other ones
5098 
5099  // DO ALL THE STUFF WE NEED TO DO AFTER LOADING Ship_types
5100  ship_type_info *stp;
5101 
5102  uint i,j;
5103  int idx;
5104  for(i = 0; i < Ship_types.size(); i++)
5105  {
5106  stp = &Ship_types[i];
5107 
5108  //Handle active pursuit
5109  for(j = 0; j < stp->ai_actively_pursues_temp.size(); j++)
5110  {
5111  idx = ship_type_name_lookup((char*)stp->ai_actively_pursues_temp[j].c_str());
5112  if(idx >= 0) {
5113  stp->ai_actively_pursues.push_back(idx);
5114  }
5115  }
5116  stp->ai_actively_pursues_temp.clear();
5117 
5118  //Handle disabled/disarmed behaviour
5119  for(j = 0; j < stp->ai_cripple_ignores_temp.size(); j++) {
5120  idx = ship_type_name_lookup((char*)stp->ai_cripple_ignores_temp[j].c_str());
5121  if(idx >= 0) {
5122  stp->ai_cripple_ignores.push_back(idx);
5123  }
5124  }
5125  stp->ai_cripple_ignores_temp.clear();
5126  }
5127 
5128  //ships.tbl
5129  {
5132 
5133  //Parse main TBL first
5134  parse_shiptbl("ships.tbl");
5135 
5136  //Then other ones
5137  parse_modular_table(NOX("*-shp.tbm"), parse_shiptbl);
5138 
5140 
5141  ships_inited = 1;
5142  }
5143 
5144  // NULL out "dynamic" subsystem ptr's
5145  for (i = 0; i < NUM_SHIP_SUBSYSTEM_SETS; i++)
5146  Ship_subsystems[i] = NULL;
5147  }
5148 
5149  ship_level_init(); // needed for FRED
5150 }
5151 
5153 
5154 static void ship_clear_subsystems()
5155 {
5156  int i;
5157 
5158  for (i = 0; i < NUM_SHIP_SUBSYSTEM_SETS; i++) {
5159  if (Ship_subsystems[i] != NULL) {
5160  delete[] Ship_subsystems[i];
5161  Ship_subsystems[i] = NULL;
5162  }
5163  }
5164 
5165  Num_ship_subsystems = 0;
5166  Num_ship_subsystems_allocated = 0;
5167 
5168  Triggered_rotations.clear();
5169 }
5170 
5171 static int ship_allocate_subsystems(int num_so, bool page_in = false)
5172 {
5173  int idx, i;
5174  int num_subsystems_save = 0;
5175 
5176  // "0" itself is safe
5177  if (num_so < 0) {
5178  Int3();
5179  return 0;
5180  }
5181 
5182  // allow a page-in thingy, so that we can grab as much as possible before mission
5183  // start, but without messing up our count for future things
5184  if (page_in)
5185  num_subsystems_save = Num_ship_subsystems;
5186 
5187  Num_ship_subsystems += num_so;
5188 
5189  // bail if we don't actually need any more
5190  if ( Num_ship_subsystems < Num_ship_subsystems_allocated )
5191  return 1;
5192 
5193  mprintf(("Allocating space for at least %i new ship subsystems ... ", num_so));
5194 
5195  // we might need more than one set worth of new subsystems, so make as many as required
5196  do {
5197  for (idx = 0; idx < NUM_SHIP_SUBSYSTEM_SETS; idx++) {
5198  if (Ship_subsystems[idx] == NULL)
5199  break;
5200  }
5201 
5202  // safety check, but even if we have this here it will fubar something else later, so we're screwed either way
5203  if (idx == NUM_SHIP_SUBSYSTEM_SETS) {
5204  return 0;
5205  }
5206 
5207  Ship_subsystems[idx] = new ship_subsys[NUM_SHIP_SUBSYSTEMS_PER_SET];
5208 
5209  // append the new set to our free list
5210  for (i = 0; i < NUM_SHIP_SUBSYSTEMS_PER_SET; i++)
5211  list_append( &ship_subsys_free_list, &Ship_subsystems[idx][i] );
5212 
5213  Num_ship_subsystems_allocated += NUM_SHIP_SUBSYSTEMS_PER_SET;
5214  } while ( (Num_ship_subsystems - Num_ship_subsystems_allocated) > 0 );
5215 
5216  if (page_in)
5217  Num_ship_subsystems = num_subsystems_save;
5218 
5219  mprintf((" a total of %i is now available (%i in-use).\n", Num_ship_subsystems_allocated, Num_ship_subsystems));
5220  return 1;
5221 }
5222 
5227 {
5228  int i;
5229 
5230  // Reset everything between levels
5231  Ships_exited.clear();
5232  Ships_exited.reserve(100);
5233  for (i=0; i<MAX_SHIPS; i++ )
5234  {
5235  Ships[i].ship_name[0] = '\0';
5236  Ships[i].objnum = -1;
5237  }
5238 
5239  Num_wings = 0;
5240  for (i = 0; i < MAX_WINGS; i++ )
5241  {
5242  Wings[i].num_waves = -1;
5243  Wings[i].wing_squad_filename[0] = '\0';
5244  Wings[i].wing_insignia_texture = -1; // Goober5000 - default to no wing insignia
5245  // don't worry about releasing textures because
5246  // they are released automatically when the model
5247  // is unloaded (because they are part of the model)
5248  }
5249 
5250  for (i=0; i<MAX_STARTING_WINGS; i++)
5251  Starting_wings[i] = -1;
5252 
5253  for (i=0; i<MAX_SQUADRON_WINGS; i++)
5254  Squadron_wings[i] = -1;
5255 
5256  for (i=0; i<MAX_TVT_WINGS; i++)
5257  TVT_wings[i] = -1;
5258 
5259  // Goober5000
5260 
5261  // set starting wing names to default
5262  strcpy_s(Starting_wing_names[0], "Alpha");
5263  strcpy_s(Starting_wing_names[1], "Beta");
5264  strcpy_s(Starting_wing_names[2], "Gamma");
5265 
5266  // set squadron wing names to default
5267  strcpy_s(Squadron_wing_names[0], "Alpha");
5268  strcpy_s(Squadron_wing_names[1], "Beta");
5269  strcpy_s(Squadron_wing_names[2], "Gamma");
5270  strcpy_s(Squadron_wing_names[3], "Delta");
5271  strcpy_s(Squadron_wing_names[4], "Epsilon");
5272 
5273  // set tvt wing names to default
5274  strcpy_s(TVT_wing_names[0], "Alpha");
5275  strcpy_s(TVT_wing_names[1], "Zeta");
5276 
5277  // Empty the subsys list
5278  ship_clear_subsystems();
5279  list_init( &ship_subsys_free_list );
5280 
5281  Laser_energy_out_snd_timer = 1;
5282  Missile_out_snd_timer = 1;
5283 
5285 
5286  Ship_cargo_check_timer = 1;
5287 
5289 
5290  Man_thruster_reset_timestamp = timestamp(0);
5291 }
5292 
5298 void ship_add_exited_ship( ship *sp, int reason )
5299 {
5300  exited_ship entry;
5301 
5302  strcpy_s(entry.ship_name, sp->ship_name );
5303  entry.obj_signature = Objects[sp->objnum].signature;
5304  entry.ship_class = sp->ship_info_index;
5305  entry.team = sp->team;
5306  entry.flags = reason;
5307  // if ship is red alert, flag as such
5308  if (sp->flags & SF_RED_ALERT_STORE_STATUS) {
5309  entry.flags |= SEF_RED_ALERT_CARRY;
5310  }
5311  entry.time = Missiontime;
5313 
5314  entry.cargo1 = sp->cargo1;
5315 
5316  entry.time_cargo_revealed = (fix)0;
5317  if ( sp->flags & SF_CARGO_REVEALED )
5318  {
5319  entry.flags |= SEF_CARGO_KNOWN;
5321  }
5322 
5323  if ( sp->time_first_tagged > 0 )
5324  entry.flags |= SEF_BEEN_TAGGED;
5325 
5326  //copy across the damage_ship arrays
5327  for (int i = 0; i < MAX_DAMAGE_SLOTS ; i++) {
5328  entry.damage_ship_id[i] = sp->damage_ship_id[i] ;
5329  entry.damage_ship[i] = sp->damage_ship[i] ;
5330  }
5331 
5332  Ships_exited.push_back(entry);
5333 }
5334 
5339 {
5340  int i;
5341 
5342  for (i = 0; i < (int)Ships_exited.size(); i++) {
5343  if ( !stricmp(name, Ships_exited[i].ship_name) )
5344  return i;
5345  }
5346 
5347  return -1;
5348 }
5349 
5354 {
5355  int i;
5356 
5357  for (i = 0; i < (int)Ships_exited.size(); i++) {
5358  if ( signature == Ships_exited[i].obj_signature )
5359  return i;
5360  }
5361 
5362  return -1;
5363 }
5364 
5365 
5367 {
5368  ship_info *sinfo = &Ship_info[Ships[objp->instance].ship_info_index];
5369  physics_info *pi = &objp->phys_info;
5370  polymodel *pm = model_get(sinfo->model_num);
5371 
5372  // use mass and I_body_inv from POF read into polymodel
5373  physics_init(pi);
5374 
5375  pi->mass = pm->mass * sinfo->density;
5376  if (pi->mass==0.0f)
5377  {
5378  vec3d size;
5379  vm_vec_sub(&size,&pm->maxs,&pm->mins);
5380  float vmass=size.xyz.x*size.xyz.y*size.xyz.z;
5381  float amass=4.65f*(float)pow(vmass,(2.0f/3.0f));
5382 
5383  nprintf(("Physics", "pi->mass==0.0f. setting to %f\n",amass));
5384  Warning(LOCATION, "%s (%s) has no mass! setting to %f", sinfo->name, sinfo->pof_file, amass);
5385  pm->mass=amass;
5386  pi->mass=amass*sinfo->density;
5387  }
5388 
5389  // ack!
5390  // if pm's MOI is invalid, compensate
5391  if ( IS_VEC_NULL(&pm->moment_of_inertia.vec.rvec)
5392  && IS_VEC_NULL(&pm->moment_of_inertia.vec.uvec)
5393  && IS_VEC_NULL(&pm->moment_of_inertia.vec.fvec) )
5394  {
5395  nprintf(("Physics", "pm->moment_of_inertia is invalid for %s!\n", pm->filename));
5396  Warning(LOCATION, "%s (%s) has a null moment of inertia!", sinfo->name, sinfo->pof_file);
5397 
5398  // TODO: generate MOI properly
5399  pi->I_body_inv = pm->moment_of_inertia;
5400  }
5401  // it's valid, so we can use it
5402  else
5403  pi->I_body_inv = pm->moment_of_inertia;
5404 
5405  // scale pm->I_body_inv value by density
5406  vm_vec_scale( &pi->I_body_inv.vec.rvec, sinfo->density );
5407  vm_vec_scale( &pi->I_body_inv.vec.uvec, sinfo->density );
5408  vm_vec_scale( &pi->I_body_inv.vec.fvec, sinfo->density );
5409 
5410  pi->center_of_mass = pm->center_of_mass;
5411  pi->side_slip_time_const = sinfo->damp;
5412  pi->delta_bank_const = sinfo->delta_bank_const;
5413  pi->rotdamp = sinfo->rotdamp;
5414  pi->max_vel = sinfo->max_vel;
5416  pi->max_rotvel = sinfo->max_rotvel;
5417  pi->max_rear_vel = sinfo->max_rear_vel;
5418  pi->flags |= PF_ACCELERATES;
5419  pi->flags &= ~PF_GLIDING; //Turn off glide
5420  pi->flags &= ~PF_FORCE_GLIDE;
5421 
5427 
5428  if ( (pi->max_vel.xyz.x > 0.000001f) || (pi->max_vel.xyz.y > 0.000001f) )
5429  pi->flags |= PF_SLIDE_ENABLED;
5430 
5431  pi->cur_glide_cap = pi->max_vel.xyz.z; //Init dynamic glide cap stuff to the max vel.
5432  if ( sinfo->glide_cap > 0.000001f || sinfo->glide_cap < -0.000001f ) //Backslash
5433  pi->glide_cap = sinfo->glide_cap;
5434  else
5436  // If there's not a value for +Max Glide Speed set in the table, we want this cap to default to the fastest speed the ship can go.
5437  // However, a negative value means we want no cap, thus allowing nearly infinite maximum gliding speeds.
5438 
5439  //SUSHI: If we are using dynamic glide capping, force the glide cap to 0 (understood by physics.cpp to mean the cap should be dynamic)
5440  if (sinfo->glide_dynamic_cap)
5441  pi->glide_cap = 0;
5442 
5443  pi->glide_accel_mult = sinfo->glide_accel_mult;
5444 
5445  //SUSHI: This defaults to the AI_Profile value, and is only optionally overridden
5447  if (sinfo->newtonian_damp_override)
5449 
5450  vm_vec_zero(&pi->vel);
5451  vm_vec_zero(&pi->rotvel);
5452  pi->speed = 0.0f;
5453  pi->heading = 0.0f;
5455 
5456  //SparK: setting the reverse burners
5459 }
5460 
5464 int ship_get_type(char* output, ship_info *sip)
5465 {
5466  if(sip->class_type < 0) {
5467  strcpy(output, "Unknown");
5468  return 0;
5469  }
5470 
5471  strcpy(output, Ship_types[sip->class_type].name);
5472  return 1;
5473 }
5474 
5481 {
5482  if(sip->class_type >= 0) {
5483  return Ship_types[sip->class_type].ai_player_orders;
5484  } else {
5485  return 0;
5486  }
5487 }
5488 
5490  polymodel*pm = model_get(model);
5491  if(pm->submodel[submodel].parent == -1)
5492  return pm->submodel[submodel].offset;
5493  vec3d ret = pm->submodel[submodel].offset;
5494  vec3d v = get_submodel_offset(model,pm->submodel[submodel].parent);
5495  vm_vec_add2(&ret, &v);
5496  return ret;
5497 
5498 }
5499 
5501 {
5502  ship *shipp = &Ships[objp->instance];
5503 
5504  if(shipp->warpin_effect != NULL)
5505  delete shipp->warpin_effect;
5506 
5507  switch(sip->warpin_type)
5508  {
5509  case WT_DEFAULT:
5510  case WT_KNOSSOS:
5512  shipp->warpin_effect = new WE_Default(objp, WD_WARP_IN);
5513  break;
5514  case WT_IN_PLACE_ANIM:
5515  shipp->warpin_effect = new WE_BSG(objp, WD_WARP_IN);
5516  break;
5517  case WT_SWEEPER:
5518  shipp->warpin_effect = new WE_Homeworld(objp, WD_WARP_IN);
5519  break;
5520  case WT_HYPERSPACE:
5521  shipp->warpin_effect = new WE_Hyperspace(objp, WD_WARP_IN);
5522  break;
5523  default:
5524  shipp->warpin_effect = new WarpEffect();
5525  }
5526 
5527  if(shipp->warpout_effect != NULL)
5528  delete shipp->warpout_effect;
5529 
5530  switch(sip->warpout_type)
5531  {
5532  case WT_DEFAULT:
5533  case WT_KNOSSOS:
5535  shipp->warpout_effect = new WE_Default(objp, WD_WARP_OUT);
5536  break;
5537  case WT_IN_PLACE_ANIM:
5538  shipp->warpout_effect = new WE_BSG(objp, WD_WARP_OUT);
5539  break;
5540  case WT_SWEEPER:
5541  shipp->warpout_effect = new WE_Homeworld(objp, WD_WARP_OUT);
5542  break;
5543  case WT_HYPERSPACE:
5544  shipp->warpout_effect = new WE_Hyperspace(objp, WD_WARP_OUT);
5545  break;
5546  default:
5547  shipp->warpout_effect = new WarpEffect();
5548  }
5549 }
5550 
5551 // Reset all ship values to empty/unused.
5553 {
5554  int i, j;
5555 
5556  objnum = -1;
5557  ai_index = -1;
5558  ship_info_index = -1;
5559  hotkey = -1;
5560  escort_priority = 0;
5561  score = 0;
5562  assist_score_pct = 0.0f;
5563  respawn_priority = 0;
5564 
5566  wash_killed = 0; // serenity lies
5567  cargo1 = 0; // "Nothing"
5568 
5570  wing_status_wing_pos = -1;
5571 
5572  alt_type_index = -1;
5573  callsign_index = -1;
5574 
5575  targeting_laser_bank = -1;
5577 
5581 
5583  death_time = timestamp(-1);
5584  end_death_time = timestamp(-1);
5587 
5588  if (warpin_effect != NULL)
5589  delete warpin_effect;
5590  if (warpout_effect != NULL)
5591  delete warpout_effect;
5592  warpin_effect = NULL;
5593  warpout_effect = NULL;
5594 
5595  next_fireball = timestamp(-1);
5596  next_hit_spark = timestamp(-1);
5597  num_hits = 0;
5598  memset(sparks, 0, MAX_SHIP_HITS * sizeof(ship_spark));
5599 
5600  use_special_explosion = false;
5601  special_exp_damage = 0;
5602  special_exp_blast = 0;
5603  special_exp_inner = 0;
5604  special_exp_outer = 0;
5605  use_shockwave = false;
5608 
5609  special_hitpoints = 0;
5610  special_shield = -1;
5611 
5612  shield_points.clear();
5613 
5614  ship_max_shield_strength = 0.0f;
5615  ship_max_hull_strength = 0.0f;
5616 
5618 
5619  ship_name[0] = 0;
5620  team = 0;
5621 
5622  time_cargo_revealed = 0;
5623 
5624  arrival_location = 0;
5625  arrival_distance = 0;
5626  arrival_anchor = -1;
5627  arrival_path_mask = 0;
5628  arrival_cue = -1;
5629  arrival_delay = 0;
5630 
5631  departure_location = 0;
5632  departure_anchor = -1;
5633  departure_path_mask = 0;
5634  departure_cue = -1;
5635  departure_delay = 0;
5636 
5637  wingnum = -1;
5638  orders_accepted = 0;
5639 
5640  subsys_list.clear();
5641  // since these aren't cleared by clear()
5642  subsys_list.next = NULL;
5643  subsys_list.prev = NULL;
5644 
5645  memset(&subsys_info, 0, SUBSYSTEM_MAX * sizeof(ship_subsys_info));
5646 
5647  memset(last_targeted_subobject, 0, MAX_PLAYERS * sizeof(ship_subsys *));
5648 
5649  shield_integrity = NULL;
5650 
5654  weapon_energy = 0;
5655  current_max_speed = 0.0f;
5657 
5658  flags = 0;
5659  flags2 = 0;
5660  reinforcement_index = -1;
5661 
5662  afterburner_fuel = 0.0f;
5663 
5664  cmeasure_count = 0;
5665  current_cmeasure = -1;
5666 
5668 
5669  target_shields_delta = 0.0f;
5671 
5672  memset(&weapons, 0, sizeof(ship_weapon));
5673 
5674  // ---------- special weapons init that isn't setting things to 0
5675  for (i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++)
5676  {
5678 
5682 
5684 
5687 
5688  // not part of weapons!
5689  primary_rotate_rate[i] = 0.0f;
5690  primary_rotate_ang[i] = 0.0f;
5691  last_fired_point[i] = 0;
5692  // for fighter beams
5693  was_firing_last_frame[i] = 0;
5694  }
5695 
5696  for (i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++)
5697  {
5699 
5702 
5705 
5706  for (j = 0; j < MAX_SLOTS; j++)
5707  secondary_point_reload_pct[i][j] = 1.0f;
5708  }
5709 
5711 
5714  // ---------- done with weapons init
5715 
5716  shield_hits = 0;
5717 
5718  wash_intensity = 0.0f;
5721 
5724  next_swarm_path = 0;
5726  swarm_missile_bank = -1;
5727 
5728  group = -1;
5729  death_roll_snd = -1;
5730  ship_list_index = -1;
5731 
5732  thruster_bitmap = -1;
5733  thruster_frame = 0.0f;
5734 
5735  thruster_glow_bitmap = -1;
5736  thruster_glow_frame = 0.0f;
5737  thruster_glow_noise = 1.0f;
5738 
5742 
5744 
5746 
5747  total_damage_received = 0.0f;
5748  memset(&damage_ship, 0, MAX_DAMAGE_SLOTS * sizeof(float));
5749  for(i = 0; i < MAX_DAMAGE_SLOTS; i++)
5750  damage_ship_id[i] = -1;
5751 
5752  persona_index = -1;
5753 
5756 
5757  create_time = 0;
5758 
5759  ts_index = -1;
5760 
5762  for (i = 0; i < NUM_SUB_EXPL_HANDLES; i++)
5763  sub_expl_sound_handle[i] = -1;
5764 
5765  memset(&arc_pts, 0, MAX_SHIP_ARCS * 2 * sizeof(vec3d));
5766  for (i = 0; i < MAX_SHIP_ARCS; i++)
5767  arc_timestamp[i] = timestamp(-1);
5768  memset(&arc_type, 0, MAX_SHIP_ARCS * sizeof(ubyte));
5769  arc_next_time = timestamp(-1);
5770 
5771  emp_intensity = -1.0f;
5772  emp_decr = 0.0f;
5773 
5774  memset(trail_ptr, 0, MAX_SHIP_CONTRAILS * sizeof(trail *));
5775 
5776  tag_total = 0.0f;
5777  tag_left = -1.0f;
5778  time_first_tagged = 0;
5779  level2_tag_total = 0.0f;
5780  level2_tag_left = -1.0f;
5781 
5782  for (i = 0; i < MAX_PLAYERS; i++ )
5783  {
5784  np_updates[i].seq = 0;
5785  np_updates[i].update_stamp = -1;
5788  np_updates[i].pos_chksum = 0;
5789  np_updates[i].orient_chksum = 0;
5790  }
5791 
5792  lightning_stamp = timestamp(-1);
5793 
5794  // set awacs warning flags so awacs ship only asks for help once at each level
5796 
5797  special_warpin_objnum = -1;
5799 
5801  memset(&beam_sys_info, 0, sizeof(model_subsystem));
5802 
5804 
5806 
5807  current_viewpoint = -1;
5808 
5809  for (i = 0; i < MAX_SHIP_CONTRAILS; i++)
5810  ABtrail_ptr[i] = NULL;
5811  memset(&ab_info, 0, MAX_SHIP_CONTRAILS * sizeof(trail_info));
5812  ab_count = 0;
5813 
5814  glow_point_bank_active.clear();
5815 
5816  shader_effect_num = 0;
5819  shader_effect_active = false;
5820 
5821  last_fired_turret = NULL;
5822 
5827  bay_doors_need_open = false;
5829 
5830  for(i = 0; i < MAX_MAN_THRUSTERS; i++)
5831  {
5832  thrusters_start[i] = timestamp(-1);
5833  thrusters_sounds[i] = -1;
5834  }
5835 
5836  s_alt_classes.clear();
5837 
5838  for(i=0;i<MAX_IFFS;i++)
5839  for(j=0;j<MAX_IFFS;j++)
5840  ship_iff_color[i][j] = -1;
5841 
5843 
5844  armor_type_idx = -1;
5845  shield_armor_type_idx = -1;
5848  debris_net_sig = 0;
5849 
5850  model_instance_num = -1;
5851 
5852  time_created = 0;
5853 
5854  radar_visible_since = -1;
5855  radar_last_contact = -1;
5856 
5859 
5860  team_name = "";
5861  secondary_team_name = "";
5863  team_change_time = 0;
5864 
5865  autoaim_fov = 0.0f;
5866 }
5867 
5868 // NOTE: Now that the clear() member function exists, this function only sets the stuff associated with the object and ship class.
5869 void ship_set(int ship_index, int objnum, int ship_type)
5870 {
5871  int i;
5872  ship *shipp = &Ships[ship_index];
5873  object *objp = &Objects[objnum];
5874  ship_info *sip = &(Ship_info[ship_type]);
5875  ship_weapon *swp = &shipp->weapons;
5876  polymodel *pm = model_get(sip->model_num);
5877 
5878  extern int oo_arrive_time_count[MAX_SHIPS];
5879  extern int oo_interp_count[MAX_SHIPS];
5880  oo_arrive_time_count[shipp - Ships] = 0;
5881  oo_interp_count[shipp - Ships] = 0;
5882 
5883  Assert(strlen(shipp->ship_name) <= NAME_LENGTH - 1);
5884  shipp->ship_info_index = ship_type;
5885  shipp->objnum = objnum;
5886  shipp->score = sip->score;
5887 
5888  ai_object_init(objp, shipp->ai_index);
5889  physics_ship_init(objp);
5890 
5891  if ( !Fred_running ) {
5892  ship_set_warp_effects(objp, sip);
5893  }
5894 
5895  if (Fred_running){
5896  shipp->ship_max_hull_strength = 100.0f;
5897  } else {
5899  }
5900  objp->hull_strength = shipp->ship_max_hull_strength;
5901 
5903 
5904  if (Fred_running) {
5905  shipp->ship_max_shield_strength = 100.0f;
5906  objp->shield_quadrant[0] = 100.0f;
5907  } else {
5910  }
5911 
5912  if (sip->flags2 & SIF2_MODEL_POINT_SHIELDS) {
5913  objp->n_quadrants = pm->shield_points.size();
5914  shipp->shield_points = pm->shield_points;
5915  objp->shield_quadrant.resize(objp->n_quadrants);
5916  }
5917 
5919 
5920  if (!subsys_set(objnum))
5921  {
5922  char err_msg[512];
5923  sprintf (err_msg, "Unable to allocate ship subsystems. Maximum is %d. No subsystems have been assigned to %s.", (NUM_SHIP_SUBSYSTEM_SETS* NUM_SHIP_SUBSYSTEMS_PER_SET), shipp->ship_name);
5924 
5925  if (Fred_running)
5926  MessageBox(NULL, err_msg, "Error", MB_OK);
5927  else
5928  Error(LOCATION, "%s", err_msg);
5929  }
5930 
5931  ets_init_ship(objp); // init ship fields that are used for the ETS
5932 
5933  shipp->current_max_speed = Ship_info[ship_type].max_speed;
5934 
5935  shipp->flags |= SF_ENGINES_ON;
5936 
5937  // set certain flags that used to be in ship_info - Goober5000
5938  if (sip->flags & SIF_STEALTH)
5939  shipp->flags2 |= SF2_STEALTH;
5941  shipp->flags2 |= SF2_DONT_COLLIDE_INVIS;
5942 
5943  if (sip->flags & SIF_NO_COLLIDE)
5944  obj_set_flags(objp, objp->flags & ~OF_COLLIDES);
5945  else
5946  obj_set_flags(objp, objp->flags | OF_COLLIDES);
5947 
5948  if (sip->flags2 & SIF2_NO_ETS)
5949  shipp->flags2 |= SF2_NO_ETS;
5950 
5952 
5953  shipp->cmeasure_count = sip->cmeasure_max;
5954  shipp->current_cmeasure = sip->cmeasure_type;
5955 
5956  if (sip->num_primary_banks == 0 || swp->primary_bank_weapons[0] < 0) {
5957  swp->current_primary_bank = -1;
5958  swp->previous_primary_bank = -1;
5959  }
5960  if (sip->num_secondary_banks == 0 || swp->secondary_bank_weapons[0] < 0) {
5961  swp->current_secondary_bank = -1;
5962  swp->previous_secondary_bank = -1;
5963  }
5964  swp->current_tertiary_bank = -1;
5965 
5966  swp->ai_class = Ai_info[shipp->ai_index].ai_class;
5967 
5968  // handle ballistic primaries - kinda hackish; is this actually necessary?
5969  // because I think it's not needed - when I accidentally left this unreachable
5970  // it didn't cause any problems - Goober5000
5971  for ( i = 0; i < sip->num_primary_banks; i++ )
5972  {
5973  float weapon_size = Weapon_info[sip->primary_bank_weapons[i]].cargo_size;
5974 
5975  if ( weapon_size > 0.0f )
5976  {
5977  if (Fred_running)
5978  swp->primary_bank_ammo[i] = 100;
5979  else
5980  swp->primary_bank_ammo[i] = fl2i(sip->primary_bank_ammo_capacity[i] / weapon_size + 0.5f );
5981  }
5982  }
5983 
5984  for ( i = 0; i < sip->num_secondary_banks; i++ )
5985  {
5986  float weapon_size = Weapon_info[sip->secondary_bank_weapons[i]].cargo_size;
5987  Assertion( weapon_size > 0.0f, "Cargo size for secondary weapon %s is invalid, must be greater than 0.\n", Weapon_info[sip->secondary_bank_weapons[i]].name );
5988 
5989  if (Fred_running)
5990  swp->secondary_bank_ammo[i] = 100;
5991  else
5992  swp->secondary_bank_ammo[i] = fl2i(sip->secondary_bank_ammo_capacity[i] / weapon_size + 0.5f );
5993  }
5994 
5995  shipp->armor_type_idx = sip->armor_type_idx;
5999 
6000  if(pm != NULL && pm->n_view_positions > 0)
6001  ship_set_eye(objp, 0);
6002  else
6003  ship_set_eye(objp, -1);
6004 
6006 
6007  // Team colors
6008  shipp->team_name.assign( sip->default_team_name);
6009  shipp->secondary_team_name = "none";
6010 
6011  shipp->autoaim_fov = sip->autoaim_fov;
6012 }
6013 
6021 {
6022  int i;
6023  ship_subsys *ship_system;
6024 
6025  // fill in the subsys_info fields for all particular types of subsystems
6026  // make the current strength be 1.0. If there are initial conditions on the ship, then
6027  // the mission parse code should take care of setting that.
6028  for (i = 0; i < SUBSYSTEM_MAX; i++) {
6029  shipp->subsys_info[i].type_count = 0;
6030  shipp->subsys_info[i].aggregate_max_hits = 0.0f;
6031  shipp->subsys_info[i].aggregate_current_hits = 0.0f;
6032  }
6033 
6034  // count all of the subsystems of a particular type. For each generic type of subsystem, we store the
6035  // total count of hits. (i.e. for 3 engines, we store the sum of the max_hits for each engine)
6036  for ( ship_system = GET_FIRST(&shipp->subsys_list); ship_system != END_OF_LIST(&shipp->subsys_list); ship_system = GET_NEXT(ship_system) ) {
6037 
6038  if (!(ship_system->flags & SSF_NO_AGGREGATE)) {
6039  int type = ship_system->system_info->type;
6040  Assert ( (type >= 0) && (type < SUBSYSTEM_MAX) );
6041 
6042  shipp->subsys_info[type].type_count++;
6043  shipp->subsys_info[type].aggregate_max_hits += ship_system->max_hits;
6044  shipp->subsys_info[type].aggregate_current_hits += ship_system->current_hits;
6045  }
6046 
6047  //Get rid of any persistent sounds on the subsystem
6048  //This is inefficient + sloppy but there's not really an easy way to handle things
6049  //if a subsystem is brought back from the dead, other than this
6050  if(ship_system->current_hits > 0.0f)
6051  {
6052  if(ship_system->subsys_snd_flags & SSSF_DEAD)
6053  {
6054  obj_snd_delete_type(shipp->objnum, ship_system->system_info->dead_snd, ship_system);
6055  ship_system->subsys_snd_flags &= ~SSSF_DEAD;
6056  }
6057  if((ship_system->system_info->alive_snd != -1) && !(ship_system->subsys_snd_flags & SSSF_ALIVE))
6058  {
6059  obj_snd_assign(shipp->objnum, ship_system->system_info->alive_snd, &ship_system->system_info->pnt, 0, OS_SUBSYS_ALIVE, ship_system);
6060  ship_system->subsys_snd_flags |= SSSF_ALIVE;
6061  }
6062  if(!(ship_system->subsys_snd_flags & SSSF_TURRET_ROTATION))
6063  {
6064  if(ship_system->system_info->turret_base_rotation_snd != -1)
6065  {
6066  obj_snd_assign(shipp->objnum, ship_system->system_info->turret_base_rotation_snd, &ship_system->system_info->pnt, 0, OS_TURRET_BASE_ROTATION, ship_system);
6067  ship_system->subsys_snd_flags |= SSSF_TURRET_ROTATION;
6068  }
6069  if(ship_system->system_info->turret_gun_rotation_snd != -1)
6070  {
6071  obj_snd_assign(shipp->objnum, ship_system->system_info->turret_gun_rotation_snd, &ship_system->system_info->pnt, 0, OS_TURRET_GUN_ROTATION, ship_system);
6072  ship_system->subsys_snd_flags |= SSSF_TURRET_ROTATION;
6073  }
6074  }
6075  if((ship_system->flags & SSF_ROTATES) && (ship_system->system_info->rotation_snd != -1) && !(ship_system->subsys_snd_flags & SSSF_ROTATE))
6076  {
6077  obj_snd_assign(shipp->objnum, ship_system->system_info->rotation_snd, &ship_system->system_info->pnt, 0, OS_SUBSYS_ROTATION, ship_system);
6078  ship_system->subsys_snd_flags |= SSSF_ROTATE;
6079  }
6080  }
6081  else
6082  {
6083  if(ship_system->subsys_snd_flags & SSSF_ALIVE)
6084  {
6085  obj_snd_delete_type(shipp->objnum, ship_system->system_info->alive_snd, ship_system);
6086  ship_system->subsys_snd_flags &= ~SSSF_ALIVE;
6087  }
6088  if(ship_system->subsys_snd_flags & SSSF_TURRET_ROTATION)
6089  {
6090  obj_snd_delete_type(shipp->objnum, ship_system->system_info->turret_base_rotation_snd, ship_system);
6091  obj_snd_delete_type(shipp->objnum, ship_system->system_info->turret_gun_rotation_snd, ship_system);
6092  ship_system->subsys_snd_flags &= ~SSSF_TURRET_ROTATION;
6093  }
6094  if(ship_system->subsys_snd_flags & SSSF_ROTATE)
6095  {
6096  obj_snd_delete_type(shipp->objnum, ship_system->system_info->rotation_snd, ship_system);
6097  ship_system->subsys_snd_flags &= ~SSSF_ROTATE;
6098  }
6099  if((ship_system->system_info->dead_snd != -1) && !(ship_system->subsys_snd_flags & SSSF_DEAD))
6100  {
6101  obj_snd_assign(shipp->objnum, ship_system->system_info->dead_snd, &ship_system->system_info->pnt, 0, OS_SUBSYS_DEAD, ship_system);
6102  ship_system->subsys_snd_flags |= SSSF_DEAD;
6103  }
6104  }
6105  }
6106 
6107  // set any ship flags which should be set. unset the flags since we might be repairing a subsystem
6108  // through sexpressions.
6110  shipp->flags |= SF_DISABLED;
6111  } else {
6112  shipp->flags &= ~SF_DISABLED;
6114  }
6115 }
6116 
6122 {
6123  int model_num;
6124 
6125  model_num = sip->model_num;
6126 
6127  // no point copying the subsystem data if the ship in question has none...
6128  // mark that the ship (cargo container) has the path fixup done.
6129  if (sip->n_subsystems == 0) {
6130  sip->flags |= SIF_PATH_FIXUP;
6131  return;
6132  }
6133 
6134  // if we need to get information for all our subsystems, we need to find another ship with the same model
6135  // number as our own and that has the model information
6136  for ( auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it ) {
6137  model_subsystem *source_msp, *dest_msp;
6138 
6139  if ( (it->model_num != model_num) || (&(*it) == sip) ){
6140  continue;
6141  }
6142 
6143  // see if this ship has subsystems and a model for the subsystems. We only need check the first
6144  // subsystem since previous error checking would have trapped its loading as an error.
6145  Assert( it->n_subsystems == sip->n_subsystems );
6146 
6147  source_msp = &it->subsystems[0];
6148  dest_msp = &(sip->subsystems[0]);
6149  if (source_msp->model_num != -1) {
6150  model_copy_subsystems( sip->n_subsystems, dest_msp, source_msp );
6151  } else if (dest_msp->model_num != -1) {
6152  model_copy_subsystems( sip->n_subsystems, source_msp, dest_msp );
6153  } else {
6154  // if none were found try finding a another ship to copy the data from
6155  continue;
6156  }
6157  sip->flags |= SIF_PATH_FIXUP;
6158  break;
6159  }
6160 
6161 }
6162 
6163 // as with object, don't set next and prev to NULL because they keep the object on the free and used lists
6165 {
6166  int i;
6167 
6168  system_info = NULL;
6169 
6170  parent_objnum = -1;
6171 
6172  sub_name[0] = 0;
6173  current_hits = max_hits = 0.0f;
6174 
6175  flags = 0;
6176 
6178  armor_type_idx = -1;
6179 
6180  turret_best_weapon = -1;
6184  turret_enemy_objnum = -1;
6185  turret_enemy_sig = 0;
6188 
6189  for (i = 0; i < NUM_TURRET_ORDER_TYPES; i++)
6190  turret_targeting_order[i] = -1;
6191  optimum_range = 0.0f;
6192  favor_current_facing = 0.0f;
6193  targeted_subsys = NULL;
6194  scripting_target_override = false;
6196 
6199 
6202 
6203  for (i = 0; i < MAX_TFP; i++)
6204  turret_swarm_info_index[i] = -1;
6205  turret_swarm_num = 0;
6206 
6207  awacs_intensity = 0.0f;
6208  awacs_radius = 0.0f;
6209 
6210  memset(&weapons, 0, sizeof(ship_weapon));
6211 
6212  memset(&submodel_info_1, 0, sizeof(submodel_instance_info));
6213  memset(&submodel_info_2, 0, sizeof(submodel_instance_info));
6214 
6216 
6217  subsys_cargo_name = 0;
6219 
6221 
6222  points_to_target = 0.0f;
6223  base_rotation_rate_pct = 0.0f;
6224  gun_rotation_rate_pct = 0.0f;
6225 
6226  subsys_snd_flags = 0;
6227 
6229 
6231 
6232  for (i = 0; i < 32; i++)
6233  target_priority[i] = -1;
6235 
6236  next_aim_pos_time = 0;
6239 
6240  rof_scaler = 1.0f;
6241  turn_rate = 0.0f;
6242 
6243  turret_max_bomb_ownage = -1;
6245 }
6246 
6253 int subsys_set(int objnum, int ignore_subsys_info)
6254 {
6255  ship *shipp = &Ships[Objects[objnum].instance];
6256  ship_info *sinfo = &Ship_info[Ships[Objects[objnum].instance].ship_info_index];
6257  model_subsystem *model_system;
6258  ship_subsys *ship_system;
6259  int i, j, k;
6260 
6261  // set up the subsystems for this ship. walk through list of subsystems in the ship-info array.
6262  // for each subsystem, get a new ship_subsys instance and set up the pointers and other values
6263  list_init ( &shipp->subsys_list ); // initialize the ship's list of subsystems
6264 
6265  // make sure to have allocated the number of subsystems we require
6266  if (!ship_allocate_subsystems( sinfo->n_subsystems )) {
6267  return 0;
6268  }
6269 
6270  for ( i = 0; i < sinfo->n_subsystems; i++ )
6271  {
6272  model_system = &(sinfo->subsystems[i]);
6273  if (model_system->model_num < 0) {
6274  Warning (LOCATION, "Invalid subobj_num or model_num in subsystem '%s' on ship type '%s'.\nNot linking into ship!\n\n(This warning means that a subsystem was present in the table entry and not present in the model\nit should probably be removed from the table or added to the model.)\n", model_system->subobj_name, sinfo->name );
6275  continue;
6276  }
6277 
6278  // set up the linked list
6279  ship_system = GET_FIRST( &ship_subsys_free_list ); // get a new element from the ship_subsystem array
6280  Assert ( ship_system != &ship_subsys_free_list ); // shouldn't have the dummy element
6281  list_remove( ship_subsys_free_list, ship_system ); // remove the element from the array
6282  list_append( &shipp->subsys_list, ship_system ); // link the element into the ship
6283  ship_system->clear(); // initialize it to a known blank slate
6284 
6285  ship_system->system_info = model_system; // set the system_info pointer to point to the data read in from the model
6286 
6287  ship_system->parent_objnum = objnum;
6288 
6289  // if the table has set an name copy it
6290  if (ship_system->system_info->alt_sub_name[0] != '\0') {
6291  strcpy_s(ship_system->sub_name, ship_system->system_info->alt_sub_name);
6292  }
6293  else {
6294  memset(ship_system->sub_name, '\0', sizeof(ship_system->sub_name));
6295  }
6296 
6297  // copy subsystem target priorities stuff
6298  ship_system->num_target_priorities = ship_system->system_info->num_target_priorities;
6299  for (j = 0; j < 32; j++) {
6300  ship_system->target_priority[j] = ship_system->system_info->target_priority[j];
6301  }
6302 
6303  ship_system->rof_scaler = ship_system->system_info->turret_rof_scaler;
6304 
6305  // zero flags
6306  ship_system->flags = 0;
6307  ship_system->weapons.flags = 0;
6308  ship_system->subsys_snd_flags = 0;
6309 
6310  // Goober5000
6311  if (model_system->flags & MSS_FLAG_UNTARGETABLE)
6312  ship_system->flags |= SSF_UNTARGETABLE;
6313  // Wanderer
6314  if (model_system->flags & MSS_FLAG_NO_SS_TARGETING)
6315  ship_system->flags |= SSF_NO_SS_TARGETING;
6317  ship_system->flags |= SSF_FOV_EDGE_CHECK;
6319  ship_system->flags |= SSF_FOV_REQUIRED;
6320 
6321  if (model_system->flags & MSS_FLAG_NO_REPLACE)
6322  ship_system->flags |= SSF_NO_REPLACE;
6323  if (model_system->flags & MSS_FLAG_NO_LIVE_DEBRIS)
6324  ship_system->flags |= SSF_NO_LIVE_DEBRIS;
6325  if (model_system->flags & MSS_FLAG_IGNORE_IF_DEAD)
6326  ship_system->flags |= SSF_MISSILES_IGNORE_IF_DEAD;
6327  if (model_system->flags & MSS_FLAG_ALLOW_VANISHING)
6328  ship_system->flags |= SSF_VANISHED;
6329  if (model_system->flags & MSS_FLAG_DAMAGE_AS_HULL)
6330  ship_system->flags |= SSF_DAMAGE_AS_HULL;
6331  if (model_system->flags & MSS_FLAG_NO_AGGREGATE)
6332  ship_system->flags |= SSF_NO_AGGREGATE;
6333  if (model_system->flags & MSS_FLAG_ROTATES)
6334  ship_system->flags |= SSF_ROTATES;
6335  if (model_system->flags2 & MSS_FLAG2_PLAYER_TURRET_SOUND)
6336  ship_system->flags |= SSF_PLAY_SOUND_FOR_PLAYER;
6337  if (model_system->flags2 & MSS_FLAG2_NO_DISAPPEAR)
6338  ship_system->flags |= SSF_NO_DISAPPEAR;
6339  if (model_system->flags2 & MSS_FLAG2_AUTOREPAIR_IF_DISABLED)
6340  ship_system->flags |= SSF_AUTOREPAIR_IF_DISABLED;
6341  if (model_system->flags2 & MSS_FLAG2_NO_AUTOREPAIR_IF_DISABLED)
6342  ship_system->flags |= SSF_NO_AUTOREPAIR_IF_DISABLED;
6343 
6344  ship_system->turn_rate = model_system->turn_rate;
6345 
6346  // Goober5000 - this has to be moved outside back to parse_create_object, because
6347  // a lot of the ship creation code is duplicated in several points and overwrites
6348  // previous things... ugh.
6349  ship_system->max_hits = model_system->max_subsys_strength; // * shipp->ship_max_hull_strength / sinfo->max_hull_strength;
6350 
6351  if ( !Fred_running ) {
6352  ship_system->current_hits = ship_system->max_hits; // set the current hits
6353  } else {
6354  ship_system->current_hits = 0.0f; // Jason wants this to be 0 in Fred.
6355  }
6356 
6357  ship_system->subsys_guardian_threshold = 0;
6358  ship_system->armor_type_idx = model_system->armor_type_idx;
6359  ship_system->turret_next_fire_stamp = timestamp(0);
6360  ship_system->turret_next_enemy_check_stamp = timestamp(0);
6361  ship_system->turret_enemy_objnum = -1;
6362  ship_system->turret_next_fire_stamp = timestamp((int) frand_range(1.0f, 500.0f)); // next time this turret can fire
6363  ship_system->turret_last_fire_direction = model_system->turret_norm;
6364  ship_system->turret_next_fire_pos = 0;
6365  ship_system->turret_time_enemy_in_range = 0.0f;
6366  ship_system->disruption_timestamp=timestamp(0);
6368  ship_system->scripting_target_override = false;
6369  vm_vec_zero(&ship_system->turret_big_attack_point);
6370  for(j = 0; j < NUM_TURRET_ORDER_TYPES; j++)
6371  {
6372  //WMC - Set targeting order to default.
6373  ship_system->turret_targeting_order[j] = j;
6374  }
6375  ship_system->optimum_range = model_system->optimum_range;
6376  ship_system->favor_current_facing = model_system->favor_current_facing;
6377  ship_system->subsys_cargo_name = 0;
6378  ship_system->time_subsys_cargo_revealed = 0;
6379 
6380  j = 0;
6381  int number_of_weapons = 0;
6382 
6383  for (k=0; k<MAX_SHIP_PRIMARY_BANKS; k++){
6384  if (model_system->primary_banks[k] != -1) {
6385  ship_system->weapons.primary_bank_weapons[j] = model_system->primary_banks[k];
6386  ship_system->weapons.primary_bank_capacity[j] = model_system->primary_bank_capacity[k]; // added by Goober5000
6387  ship_system->weapons.next_primary_fire_stamp[j] = timestamp(0);
6388  ship_system->weapons.last_primary_fire_stamp[j++] = -1;
6389  }
6390  ship_system->weapons.burst_counter[k] = 0;
6391  }
6392 
6393  ship_system->weapons.num_primary_banks = j;
6394  number_of_weapons += j;
6395 
6396  j = 0;
6397  for (k=0; k<MAX_SHIP_SECONDARY_BANKS; k++){
6398  if (model_system->secondary_banks[k] != -1) {
6399  ship_system->weapons.secondary_bank_weapons[j] = model_system->secondary_banks[k];
6400  ship_system->weapons.secondary_bank_capacity[j] = model_system->secondary_bank_capacity[k];
6401  ship_system->weapons.next_secondary_fire_stamp[j] = timestamp(0);
6402  ship_system->weapons.last_secondary_fire_stamp[j++] = -1;
6403  }
6404  ship_system->weapons.burst_counter[k + MAX_SHIP_PRIMARY_BANKS] = 0;
6405  }
6406 
6407  ship_system->weapons.num_secondary_banks = j;
6408  number_of_weapons += j;
6409  ship_system->weapons.current_primary_bank = -1;
6410  ship_system->weapons.current_secondary_bank = -1;
6411 
6412  ship_system->next_aim_pos_time = 0;
6413 
6414  ship_system->turret_max_bomb_ownage = model_system->turret_max_bomb_ownage;
6415  ship_system->turret_max_target_ownage = model_system->turret_max_target_ownage;
6416 
6417  // Make turret flag checks and warnings
6418  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_SALVO) && (ship_system->system_info->flags & MSS_FLAG_TURRET_FIXED_FP))
6419  {
6420  Warning (LOCATION, "\"salvo mode\" flag used with \"fixed firingpoints\" flag\nsubsystem '%s' on ship type '%s'.\n\"salvo mode\" flag is ignored\n", model_system->subobj_name, sinfo->name );
6421  ship_system->system_info->flags &= (~MSS_FLAG_TURRET_SALVO);
6422  }
6423 
6424  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_SALVO) && (model_system->turret_num_firing_points < 2))
6425  {
6426  Warning (LOCATION, "\"salvo mode\" flag used with turret which has less than two firingpoints\nsubsystem '%s' on ship type '%s'.\n\"salvo mode\" flag is ignored\n", model_system->subobj_name, sinfo->name );
6427  ship_system->system_info->flags &= (~MSS_FLAG_TURRET_SALVO);
6428  }
6429 
6430  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_FIXED_FP) && (model_system->turret_num_firing_points < 2))
6431  {
6432  Warning (LOCATION, "\"fixed firingpoints\" flag used with turret which has less than two firingpoints\nsubsystem '%s' on ship type '%s'.\n\"fixed firingpoints\" flag is ignored\n", model_system->subobj_name, sinfo->name );
6433  ship_system->system_info->flags &= (~MSS_FLAG_TURRET_FIXED_FP);
6434  }
6435 
6436  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_SALVO) && (ship_system->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS))
6437  {
6438  Warning (LOCATION, "\"salvo mode\" flag used with \"use multiple guns\" flag\nsubsystem '%s' on ship type '%s'.\n\"use multiple guns\" flag is ignored\n", model_system->subobj_name, sinfo->name );
6439  ship_system->system_info->flags &= (~MSS_FLAG_USE_MULTIPLE_GUNS);
6440  }
6441 
6442  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_FIXED_FP) && !(ship_system->system_info->flags & MSS_FLAG_USE_MULTIPLE_GUNS))
6443  {
6444  Warning (LOCATION, "\"fixed firingpoints\" flag used without \"use multiple guns\" flag\nsubsystem '%s' on ship type '%s'.\n\"use multiple guns\" guns added by default\n", model_system->subobj_name, sinfo->name );
6445  ship_system->system_info->flags |= MSS_FLAG_USE_MULTIPLE_GUNS;
6446  }
6447 
6448  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_SALVO) && (number_of_weapons > 1))
6449  {
6450  Warning (LOCATION, "\"salvo mode\" flag used with turret which has more than one weapon defined for it\nsubsystem '%s' on ship type '%s'.\nonly single weapon will be used\n", model_system->subobj_name, sinfo->name );
6451  }
6452 
6453  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_FIXED_FP) && (number_of_weapons > model_system->turret_num_firing_points))
6454  {
6455  Warning (LOCATION, "\"fixed firingpoint\" flag used with turret which has more weapons defined for it than it has firingpoints\nsubsystem '%s' on ship type '%s'.\nweapons will share firingpoints\n", model_system->subobj_name, sinfo->name );
6456  }
6457 
6458  if ((ship_system->system_info->flags & MSS_FLAG_TURRET_FIXED_FP) && (number_of_weapons < model_system->turret_num_firing_points))
6459  {
6460  Warning (LOCATION, "\"fixed firingpoint\" flag used with turret which has less weapons defined for it than it has firingpoints\nsubsystem '%s' on ship type '%s'.\nsome of the firingpoints will be left unused\n", model_system->subobj_name, sinfo->name );
6461  }
6462 
6463  if ((ship_system->system_info->flags2 & MSS_FLAG2_SHARE_FIRE_DIRECTION) && !(ship_system->system_info->flags & MSS_FLAG_TURRET_SALVO))
6464  {
6465  Warning(LOCATION, "\"share fire direction\" flag used with turret which does not have the \"salvo mode\" flag set\nsubsystem '%s' on ship type '%s'.\nsetting the \"salvo mode\" flag\n", model_system->subobj_name, sinfo->name);
6466  ship_system->system_info->flags |= MSS_FLAG_TURRET_SALVO;
6467  }
6468 
6469  for (k=0; k<ship_system->weapons.num_secondary_banks; k++) {
6470  float weapon_size = Weapon_info[ship_system->weapons.secondary_bank_weapons[k]].cargo_size;
6471  Assertion( weapon_size > 0.0f, "Cargo size for secondary weapon %s is invalid, must be greater than 0.\n", Weapon_info[ship_system->weapons.secondary_bank_weapons[k]].name );
6472  ship_system->weapons.secondary_bank_ammo[k] = (Fred_running ? 100 : fl2i(ship_system->weapons.secondary_bank_capacity[k] / weapon_size + 0.5f));
6473 
6474  ship_system->weapons.secondary_next_slot[k] = 0;
6475  }
6476 
6477  // Goober5000
6478  for (k=0; k<ship_system->weapons.num_primary_banks; k++)
6479  {
6480  float weapon_size = Weapon_info[ship_system->weapons.primary_bank_weapons[k]].cargo_size;
6481 
6482  if (weapon_size > 0.0f) { // Non-ballistic primaries are supposed to have a cargo_size of 0
6483  ship_system->weapons.primary_bank_ammo[k] = (Fred_running ? 100 : fl2i(ship_system->weapons.primary_bank_capacity[k] / weapon_size + 0.5f));
6484  }
6485  }
6486 
6487  ship_system->weapons.last_fired_weapon_index = -1;
6488  ship_system->weapons.last_fired_weapon_signature = -1;
6489  ship_system->weapons.detonate_weapon_time = -1;
6490  ship_system->weapons.ai_class = sinfo->ai_class; // assume ai class of ship for turret
6491 
6492  // rapid fire (swarm) stuff
6493  for (k = 0; k < MAX_TFP; k++)
6494  ship_system->turret_swarm_info_index[k] = -1;
6495 
6496  ship_system->turret_swarm_num = 0;
6497 
6498  // AWACS stuff
6499  ship_system->awacs_intensity = model_system->awacs_intensity;
6500  ship_system->awacs_radius = model_system->awacs_radius;
6501  if (ship_system->awacs_intensity > 0) {
6502  ship_system->system_info->flags |= MSS_FLAG_AWACS;
6503  }
6504 
6505  // turn_rate, turn_accel
6506  float turn_accel = 0.5f;
6507  model_set_instance_info(&ship_system->submodel_info_1, model_system->turn_rate, turn_accel);
6508 
6509  model_clear_instance_info( &ship_system->submodel_info_2 );
6510 
6511  // Clear this flag here so we correctly rebuild the turret matrix on mission load
6512  model_system->flags &= ~MSS_FLAG_TURRET_MATRIX;
6513 
6514  // Allocate a triggered rotation instance if we need it
6515  if (model_system->flags & MSS_FLAG_TRIGGERED) {
6516  ship_system->triggered_rotation_index = Triggered_rotations.size();
6517  triggered_rotation tr;
6518  Triggered_rotations.push_back(tr);
6519  }
6520  }
6521 
6522  if ( !ignore_subsys_info ) {
6523  ship_recalc_subsys_strength( shipp );
6524  }
6525 
6526  // Fix up animation code references
6527  for (i = 0; i < sinfo->n_subsystems; i++) {
6528  for (j = 0; j < sinfo->subsystems[i].n_triggers; j++) {
6529  if (subsystem_stricmp(sinfo->subsystems[i].triggers[j].sub_name, "<none>")) {
6530  int idx = ship_get_subobj_model_num(sinfo, sinfo->subsystems[i].triggers[j].sub_name);
6531  if (idx != -1) {
6532  sinfo->subsystems[i].triggers[j].subtype = idx;
6533  } else {
6534  WarningEx(LOCATION, "Could not find subobject %s in ship class %s. Animation triggers will not work correctly.\n", sinfo->subsystems[i].triggers[j].sub_name, sinfo->name);
6535  }
6536  }
6537  }
6538  }
6539 
6540  return 1;
6541 }
6542 
6547 {
6548  matrix tmp, tmp2;
6549  angles t1, t2;
6550 
6551  t1 = t2 = *a;
6552  t1.h = 0.0f; t1.b = 0.0f;
6553  t2.p = 0.0f; t2.b = 0.0f;
6554 
6555  // put in p & b like normal
6556  vm_angles_2_matrix(&tmp, &t2 ); // Changed the order of axis rotations. First pitch, then yaw (Swifty)
6557  vm_matrix_x_matrix( &tmp2, orient, &tmp);
6558 
6559  // Put in heading separately
6560  vm_angles_2_matrix(&tmp, &t1 );
6561  vm_matrix_x_matrix( orient, &tmp2, &tmp );
6562 
6563  vm_orthogonalize_matrix(orient);
6564 }
6565 
6566 
6567 #ifndef NDEBUG
6568 
6571 void render_dock_bays(object *objp)
6572 {
6573  polymodel *pm;
6574  dock_bay *db;
6575 
6576  pm = model_get(Ship_info[Ships[objp->instance].ship_info_index].model_num);
6577 
6578  if (pm->docking_bays == NULL)
6579  return;
6580 
6581  if (pm->docking_bays[0].num_slots != 2)
6582  return;
6583 
6584  db = &pm->docking_bays[0];
6585 
6586  vertex v0, v1;
6587  vec3d p0, p1, p2, p3, nr;
6588 
6589  vm_vec_unrotate(&p0, &db->pnt[0], &objp->orient);
6590  vm_vec_add2(&p0, &objp->pos);
6591  g3_rotate_vertex(&v0, &p0);
6592 
6593  vm_vec_unrotate(&p1, &db->pnt[1], &objp->orient);
6594  vm_vec_add2(&p1, &objp->pos);
6595  g3_rotate_vertex(&v1, &p1);
6596 
6597  gr_set_color(255, 0, 0);
6598  g3_draw_line(&v0, &v1);
6599 
6600  vm_vec_avg(&p2, &p0, &p1);
6601 
6602  vm_vec_unrotate(&nr, &db->norm[0], &objp->orient);
6603  vm_vec_scale_add(&p3, &p2, &nr, 10.0f);
6604 
6605  g3_rotate_vertex(&v0, &p2);
6606  g3_rotate_vertex(&v1, &p3);
6607  gr_set_color(255, 255, 0);
6608  g3_draw_line(&v0, &v1);
6609  g3_draw_sphere(&v1, 1.25f);
6610 
6611 }
6612 #endif
6613 
6615 
6616 DCF_BOOL( ship_shadows, Ship_shadows )
6617 
6618 MONITOR( NumShipsRend )
6619 
6621 DCF_BOOL( show_shield_hits, Show_shield_hits )
6622 
6623 int Show_tnorms = 0;
6624 DCF_BOOL( show_tnorms, Show_tnorms )
6625 
6626 int Show_paths = 0;
6627 DCF_BOOL( show_paths, Show_paths )
6628 
6629 int Show_fpaths = 0;
6630 DCF_BOOL( show_fpaths, Show_fpaths )
6631 
6633 {
6634  // only check ships
6635  if (objp->type != OBJ_SHIP)
6636  return;
6637 
6638  // am I arriving or departing by warp?
6639  if ( Ships[objp->instance].flags & (SF_ARRIVING|SF_DEPART_WARP) )
6640  {
6641 #ifndef NDEBUG
6642  // in debug builds, make sure only one of the docked objects has these flags set
6643  if (infop->maintained_variables.bool_value)
6644  {
6645  //WMC - This is annoying and triggered in sm2-10
6646  //Warning(LOCATION, "Ship %s and its docked ship %s are arriving or departing at the same time.\n",
6647  //Ships[infop->maintained_variables.objp_value->instance].ship_name, Ships[objp->instance].ship_name);
6648  }
6649 #endif
6650  // we found someone
6651  infop->maintained_variables.bool_value = true;
6652  infop->maintained_variables.objp_value = objp;
6653 
6654 #ifdef NDEBUG
6655  // return early in release builds
6656  infop->early_return_condition = true;
6657 #endif
6658  }
6659 }
6660 
6662 
6669 {
6670  man_thruster_renderer *mtr;
6671  size_t mant_size = Man_thrusters.size();
6672 
6673  if (mant_size == 0)
6674  return;
6675 
6676  for(size_t i = 0; i < mant_size; i++)
6677  {
6678  mtr = &Man_thrusters[i];
6680 
6682  mtr->bmap_id = -1; //Mark as free
6683  }
6684 
6685  //WMC - clear maneuvering thruster render queue every 10 seconds
6686  if(timestamp() - Man_thruster_reset_timestamp > 10000)
6687  {
6688  Man_thrusters.clear();
6689  Man_thruster_reset_timestamp = timestamp();
6690  }
6691 }
6692 
6706 {
6707  man_thruster_renderer *mtr;
6708  size_t mant_size = Man_thrusters.size();
6709 
6710  for(size_t mi = 0; mi < mant_size; mi++)
6711  {
6712  mtr = &Man_thrusters[mi];
6713  if(mtr->bmap_id == bmap_frame)
6714  return mtr;
6715  }
6716  for(size_t mj = 0; mj < mant_size; mj++)
6717  {
6718  mtr = &Man_thrusters[mj];
6719  if(mtr->bmap_id == -1)
6720  {
6721  mtr->bmap_id = bmap_frame;
6722  return mtr;
6723  }
6724  }
6725 
6726  Man_thrusters.push_back(man_thruster_renderer(bmap_frame));
6727  return &Man_thrusters[Man_thrusters.size()-1];
6728 }
6729 
6730 //WMC - used for FTL and maneuvering thrusters
6732 extern bool Rendering_to_shadow_map;
6734 {
6735  int num = obj->instance;
6736  Assert( num >= 0);
6737  ship *shipp = &Ships[num];
6738  ship *warp_shipp = NULL;
6739  ship_info *sip = &Ship_info[Ships[num].ship_info_index];
6740  bool is_first_stage_arrival = false;
6741  bool show_thrusters = ((shipp->flags2 & SF2_NO_THRUSTERS) == 0) && !Rendering_to_shadow_map;
6742  dock_function_info dfi;
6743 
6744 
6745 #if 0
6746  // show target when attacking big ship
6747  vec3d temp, target;
6748  ai_info *aip = &Ai_info[Ships[obj->instance].ai_index];
6749  if ( (aip->target_objnum >= 0) && (Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index].flags & (SIF_SUPERCAP|SIF_CAPITAL|SIF_CRUISER)) ) {
6751  vm_vec_add(&target, &temp, &Objects[aip->target_objnum].pos);
6752 
6753  vertex v0, v1;
6754  gr_set_color(128,0,0);
6755  g3_rotate_vertex( &v0, &obj->pos );
6756  g3_rotate_vertex( &v1, &target );
6757 
6758  g3_draw_line(&v0, &v1);
6759 
6760  g3_draw_sphere(&v1, 5.0f);
6761  }
6762 #endif
6763 
6764 
6765  if ( obj == Viewer_obj && !Rendering_to_shadow_map)
6766  {
6767  if (ship_show_velocity_dot && (obj==Player_obj) )
6768  {
6769  vec3d p0,v;
6770  vertex v0;
6771 
6772  vm_vec_scale_add( &v, &obj->phys_info.vel, &obj->orient.vec.fvec, 3.0f );
6773  vm_vec_normalize( &v );
6774 
6775 
6776  vm_vec_scale_add( &p0, &obj->pos, &v, 20.0f);
6777 
6778  g3_rotate_vertex( &v0, &p0 );
6779 
6780  gr_set_color(0,128,0);
6781  g3_draw_sphere( &v0, 0.1f );
6782  }
6783 
6784  // Show the shield hit effect for the viewer.
6785  if ( Show_shield_hits )
6786  {
6787  shipp = &Ships[num];
6788  if (shipp->shield_hits)
6789  {
6791  shipp->shield_hits = 0;
6792  }
6793  }
6794 
6795  if (!(Viewer_mode & VM_TOPDOWN))
6796  {
6797  return;
6798  }
6799  }
6800 
6801  MONITOR_INC( NumShipsRend, 1 );
6802 
6803  // look for a warping ship, whether for me or for anybody I'm docked with
6805 
6806  // if any docked objects are set to stage 1 arrival then set bool
6807  if (dfi.maintained_variables.bool_value) {
6808  warp_shipp = &Ships[dfi.maintained_variables.objp_value->instance];
6809 
6810  is_first_stage_arrival = ((warp_shipp->flags & SF_ARRIVING_STAGE_1) > 0);
6811 
6812  // This is a hack to make ships using the hyperspace warpin type to
6813  // render even in stage 1, which is used for collision detection
6814  // purposes -zookeeper
6815  if (Ship_info[warp_shipp->ship_info_index].warpin_type == WT_HYPERSPACE) {
6816  warp_shipp = NULL;
6817  is_first_stage_arrival = false;
6818  }
6819  }
6820 
6821 
6822  // Make ships that are warping in not render during stage 1
6823  if ( !(is_first_stage_arrival) )
6824  {
6825  if ( Ship_shadows && shipfx_in_shadow( obj ) ) {
6826  light_set_shadow(1);
6827  } else {
6828  light_set_shadow(0);
6829  }
6830 
6831  ship_model_start(obj);
6832 
6833  uint render_flags = MR_DEPRECATED_NORMAL;
6834  #ifndef NDEBUG
6835 // if(Show_paths || Show_fpaths){
6836 // render_flags |= MR_DEPRECATED_BAY_PATHS;
6837 // }
6838  #endif
6839 
6840  // Only render electrical arcs if within 500m of the eye (for a 10m piece)
6841  if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f && !Rendering_to_shadow_map) {
6842  int i;
6843  for (i=0; i<MAX_SHIP_ARCS; i++ ) {
6844  if ( timestamp_valid( shipp->arc_timestamp[i] ) ) {
6845  model_add_arc(sip->model_num, -1, &shipp->arc_pts[i][0], &shipp->arc_pts[i][1], shipp->arc_type[i]);
6846  }
6847  }
6848  }
6849 
6850  if ( shipp->large_ship_blowup_index >= 0 ) {
6852  } else {
6853  //WMC - I suppose this is a bit hackish.
6854  if(!Rendering_to_shadow_map)
6855  {
6856  physics_info *pi = &Objects[shipp->objnum].phys_info;
6857  float render_amount;
6858  fx_batcher.allocate(sip->num_maneuvering); //Act as if all thrusters are going.
6859 
6860  for(int i = 0; i < sip->num_maneuvering; i++)
6861  {
6862  man_thruster *mtp = &sip->maneuvering[i];
6863 
6864  render_amount = 0.0f;
6865 
6866  //WMC - get us a steady value
6867  vec3d des_vel;
6868  vm_vec_rotate(&des_vel, &pi->desired_vel, &obj->orient);
6869 
6870  if(pi->desired_rotvel.xyz.x < 0 && (mtp->use_flags & MT_PITCH_UP)) {
6871  render_amount = fl_abs(pi->desired_rotvel.xyz.x) / pi->max_rotvel.xyz.x;
6872  } else if(pi->desired_rotvel.xyz.x > 0 && (mtp->use_flags & MT_PITCH_DOWN)) {
6873  render_amount = fl_abs(pi->desired_rotvel.xyz.x) / pi->max_rotvel.xyz.x;
6874  } else if(pi->desired_rotvel.xyz.y < 0 && (mtp->use_flags & MT_ROLL_RIGHT)) {
6875  render_amount = fl_abs(pi->desired_rotvel.xyz.y) / pi->max_rotvel.xyz.y;
6876  } else if(pi->desired_rotvel.xyz.y > 0 && (mtp->use_flags & MT_ROLL_LEFT)) {
6877  render_amount = fl_abs(pi->desired_rotvel.xyz.y) / pi->max_rotvel.xyz.y;
6878  } else if(pi->desired_rotvel.xyz.z < 0 && (mtp->use_flags & MT_BANK_RIGHT)) {
6879  render_amount = fl_abs(pi->desired_rotvel.xyz.z) / pi->max_rotvel.xyz.z;
6880  } else if(pi->desired_rotvel.xyz.z > 0 && (mtp->use_flags & MT_BANK_LEFT)) {
6881  render_amount = fl_abs(pi->desired_rotvel.xyz.z) / pi->max_rotvel.xyz.z;
6882  }
6883 
6884  //Backslash - show thrusters according to thrust amount, not speed
6885  if(pi->side_thrust > 0 && (mtp->use_flags & MT_SLIDE_RIGHT)) {
6886  render_amount = pi->side_thrust;
6887  } else if(pi->side_thrust < 0 && (mtp->use_flags & MT_SLIDE_LEFT)) {
6888  render_amount = -pi->side_thrust;
6889  } else if(pi->vert_thrust > 0 && (mtp->use_flags & MT_SLIDE_UP)) {
6890  render_amount = pi->vert_thrust;
6891  } else if(pi->vert_thrust < 0 && (mtp->use_flags & MT_SLIDE_DOWN)) {
6892  render_amount = -pi->vert_thrust;
6893  } else if(pi->forward_thrust > 0 && (mtp->use_flags & MT_FORWARD)) {
6894  render_amount = pi->forward_thrust;
6895  } else if(pi->forward_thrust < 0 && (mtp->use_flags & MT_REVERSE)) {
6896  render_amount = -pi->forward_thrust;
6897  }
6898 
6899  //Don't render small faraway thrusters (more than 10k * radius away)
6900  if (vm_vec_dist(&Eye_position, &obj->pos) > (10000.0f * mtp->radius))
6901  render_amount = 0.0f;
6902 
6903  if(render_amount > 0.0f)
6904  {
6905  //Handle sounds and stuff
6906  if(shipp->thrusters_start[i] <= 0)
6907  {
6908  shipp->thrusters_start[i] = timestamp();
6909  if(mtp->start_snd >= 0)
6910  snd_play_3d( &Snds[mtp->start_snd], &mtp->pos, &Eye_position, 0.0f, &obj->phys_info.vel );
6911  }
6912 
6913  //Only assign looping sound if
6914  //it is specified
6915  //it isn't assigned already
6916  //start sound doesn't exist or has finished
6918  if(mtp->loop_snd >= 0
6919  && shipp->thrusters_sounds[i] < 0
6920  && (mtp->start_snd < 0 || (snd_get_duration(mtp->start_snd) < timestamp() - shipp->thrusters_start[i]))
6921  )
6922  {
6923  shipp->thrusters_sounds[i] = obj_snd_assign(OBJ_INDEX(obj), mtp->loop_snd, &mtp->pos, 1);
6924  }
6925 
6926  //Draw graphics
6927  //Skip invalid ones
6928  if(mtp->tex_id >= 0)
6929  {
6930  float rad = mtp->radius;
6931  if(rad <= 0.0f)
6932  rad = 1.0f;
6933 
6934  float len = mtp->length;
6935  if(len == 0.0f)
6936  len = rad;
6937 
6938  vec3d start, tmpend, end;
6939  //Start
6940  vm_vec_unrotate(&start, &mtp->pos, &obj->orient);
6941  vm_vec_add2(&start, &obj->pos);
6942 
6943  //End
6944  vm_vec_scale_add(&tmpend, &mtp->pos, &mtp->norm, len * render_amount);
6945  vm_vec_unrotate(&end, &tmpend, &obj->orient);
6946  vm_vec_add2(&end, &obj->pos);
6947 
6948  //Draw
6949  fx_batcher.draw_beam(&start, &end, rad, 1.0f);
6950 
6951  int bmap_frame = mtp->tex_id;
6952  if(mtp->tex_nframes > 0)
6953  bmap_frame += (int)(((float)(timestamp() - shipp->thrusters_start[i]) / 1000.0f) * (float)mtp->tex_fps) % mtp->tex_nframes;
6954 
6955  man_thruster_renderer *mtr = man_thruster_get_slot(bmap_frame);
6956  mtr->man_batcher.add_allocate(1);
6957  mtr->man_batcher.draw_beam(&start, &end, rad, 1.0f);
6958  }
6959 
6960  }
6961  //We've stopped firing a thruster
6962  else if(shipp->thrusters_start[i] > 0)
6963  {
6964  shipp->thrusters_start[i] = 0;
6965  if(shipp->thrusters_sounds[i] >= 0)
6966  {
6967  obj_snd_delete(OBJ_INDEX(obj), shipp->thrusters_sounds[i]);
6968  shipp->thrusters_sounds[i] = -1;
6969  }
6970 
6971  if(mtp->stop_snd >= 0)
6972  {
6973  //Get world pos
6974  vec3d start;
6975  vm_vec_unrotate(&start, &mtp->pos, &obj->orient);
6976  vm_vec_add2(&start, &obj->pos);
6977 
6978  snd_play_3d( &Snds[mtp->stop_snd], &mtp->pos, &Eye_position, 0.0f, &obj->phys_info.vel );
6979  }
6980  }
6981  }
6982  }
6983 
6984  if ( !(shipp->flags & SF_DISABLED) && !ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) && show_thrusters) {
6985  mst_info mst;
6986 
6987  mst.length.xyz.z = obj->phys_info.forward_thrust;
6988  mst.length.xyz.x = obj->phys_info.side_thrust;
6989  mst.length.xyz.y = obj->phys_info.vert_thrust;
6990 
6991  // Maybe add noise to thruster geometry.
6992  if (!(sip->flags2 & SIF2_NO_THRUSTER_GEO_NOISE)) {
6993  mst.length.xyz.z *= (1.0f + frand()/5.0f - 0.1f);
6994  mst.length.xyz.y *= (1.0f + frand()/5.0f - 0.1f);
6995  mst.length.xyz.x *= (1.0f + frand()/5.0f - 0.1f);
6996  }
6997 
6998  CLAMP(mst.length.xyz.z, -1.0f, 1.0f);
6999  CLAMP(mst.length.xyz.y, -1.0f, 1.0f);
7000  CLAMP(mst.length.xyz.x, -1.0f, 1.0f);
7001 
7002  mst.primary_bitmap = shipp->thruster_bitmap;
7007 
7010  mst.rotvel = Objects[shipp->objnum].phys_info.rotvel;
7011 
7018 
7019  mst.draw_distortion = sip->draw_distortion;
7020 
7021  model_set_thrust(sip->model_num, &mst);
7022 
7023  render_flags |= MR_DEPRECATED_SHOW_THRUSTERS;
7024  }
7025 
7026  // fill the model flash lighting values in
7027  shipfx_flash_light_model( obj, sip->model_num );
7028 
7029 
7030  // If the ship is going "through" the warp effect, then
7031  // set up the model renderer to only draw the polygons in front
7032  // of the warp in effect
7033  int clip_started = 0;
7034 
7035  // Warp_shipp points to the ship that is going through a
7036  // warp... either this ship or the ship it is docked with.
7037  if ( warp_shipp != NULL )
7038  {
7039  if(warp_shipp->flags & SF_ARRIVING)
7040  clip_started = warp_shipp->warpin_effect->warpShipClip();
7041  else if(warp_shipp->flags & SF_DEPART_WARP)
7042  clip_started = warp_shipp->warpout_effect->warpShipClip();
7043  }
7044 
7045  // maybe set squad logo bitmap
7047  if(!Rendering_to_shadow_map)
7048  {
7049  if(Game_mode & GM_MULTIPLAYER){
7050  // if its any player's object
7051  int np_index = multi_find_player_by_object( obj );
7052  if((np_index >= 0) && (np_index < MAX_PLAYERS) && MULTI_CONNECTED(Net_players[np_index]) && (Net_players[np_index].m_player != NULL)){
7053  model_set_insignia_bitmap(Net_players[np_index].m_player->insignia_texture);
7054  }
7055  }
7056  // in single player, we want to render model insignias on all ships in alpha beta and gamma
7057  // Goober5000 - and also on wings that have their logos set
7058  else {
7059  // if its an object in my squadron
7060  if(ship_in_my_squadron(shipp)) {
7062  }
7063 
7064  // maybe it has a wing squad logo - Goober5000
7065  if (shipp->wingnum >= 0)
7066  {
7067  // don't override the player's wing
7068  if (shipp->wingnum != Player_ship->wingnum)
7069  {
7070  // if we have a logo texture
7071  if (Wings[shipp->wingnum].wing_insignia_texture >= 0)
7072  {
7074  }
7075  }
7076  }
7077  }
7078 
7079 
7080  // nebula
7082  extern void model_set_fog_level(float l);
7084  }
7085 
7086  // Valathil - maybe do a scripting hook here to do some scriptable effects?
7088  {
7089  float timer;
7090  render_flags |= (MR_DEPRECATED_ANIMATED_SHADER);
7091 
7092  ship_effect* sep = &Ship_effects[shipp->shader_effect_num];
7093 
7094  if (sep->invert_timer) {
7095  timer = 1.0f - ((timer_get_milliseconds() - shipp->shader_effect_start_time) / (float)shipp->shader_effect_duration);
7096  timer = MAX(timer,0.0f);
7097  } else {
7098  timer = ((timer_get_milliseconds() - shipp->shader_effect_start_time) / (float)shipp->shader_effect_duration);
7099  }
7100 
7102 
7104  shipp->flags2 |= SF2_CLOAKED;
7105  shipp->shader_effect_active = false;
7106  } else {
7107  shipp->flags2 &= ~SF2_CLOAKED;
7109  shipp->shader_effect_active = false;
7110  }
7111  }
7112 
7113  if (sip->uses_team_colors) {
7115  }
7116 
7117  if(sip->flags2 & SIF2_NO_LIGHTING)
7118  render_flags |= MR_DEPRECATED_NO_LIGHTING;
7119  }
7120  if(Rendering_to_shadow_map)
7122 
7123  //draw weapon models
7124  if ((sip->flags2 & SIF2_DRAW_WEAPON_MODELS) && !(shipp->flags2 & SF2_CLOAKED)) {
7125  int i,k;
7126  ship_weapon *swp = &shipp->weapons;
7127  g3_start_instance_matrix(&obj->pos, &obj->orient, true);
7128 
7129  int save_flags = render_flags;
7130 
7131  render_flags &= ~MR_DEPRECATED_SHOW_THRUSTERS;
7132  render_flags |= MR_DEPRECATED_ATTACHED_MODEL;
7133 
7134  //primary weapons
7135  for (i = 0; i < swp->num_primary_banks; i++) {
7137  continue;
7138 
7139  w_bank *bank = &model_get(sip->model_num)->gun_banks[i];
7140  for(k = 0; k < bank->num_slots; k++) {
7144  pm->gun_submodel_rotation = 0.0f;
7145  }
7146  }
7147 
7148  //secondary weapons
7149  int num_secondaries_rendered = 0;
7150  vec3d secondary_weapon_pos;
7151  w_bank* bank;
7152 
7153  for (i = 0; i < swp->num_secondary_banks; i++) {
7155  continue;
7156 
7157  bank = &(model_get(sip->model_num))->missile_banks[i];
7158 
7160  for(k = 0; k < bank->num_slots; k++) {
7162  }
7163  } else {
7164  num_secondaries_rendered = 0;
7165 
7166  for(k = 0; k < bank->num_slots; k++)
7167  {
7168  secondary_weapon_pos = bank->pnt[k];
7169 
7170  if (num_secondaries_rendered >= shipp->weapons.secondary_bank_ammo[i])
7171  break;
7172 
7173  if(shipp->secondary_point_reload_pct[i][k] <= 0.0)
7174  continue;
7175 
7176  num_secondaries_rendered++;
7177 
7179 
7180  model_render_DEPRECATED(Weapon_info[swp->secondary_bank_weapons[i]].external_model_num, &vmd_identity_matrix, &secondary_weapon_pos, render_flags, shipp->objnum);
7181  }
7182  }
7183  }
7184  g3_done_instance(true);
7185  render_flags = save_flags;
7186  }
7187 
7188  // small ships
7189  if (!(shipp->flags2 & SF2_CLOAKED)) {
7191  // force detail levels
7192  float fog_val = neb2_get_fog_intensity(obj);
7193  if(fog_val >= 0.6f){
7195  model_render_DEPRECATED( sip->model_num, &obj->orient, &obj->pos, render_flags, OBJ_INDEX(obj), -1, shipp->ship_replacement_textures, ship_render_mode );
7196  } else {
7197  model_render_DEPRECATED( sip->model_num, &obj->orient, &obj->pos, render_flags, OBJ_INDEX(obj), -1, shipp->ship_replacement_textures, ship_render_mode );
7198  }
7199  } else {
7200  model_render_DEPRECATED( sip->model_num, &obj->orient, &obj->pos, render_flags, OBJ_INDEX(obj), -1, shipp->ship_replacement_textures, ship_render_mode );
7201  }
7202  }
7203 
7204  // always turn off fog after rendering a ship
7205  gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
7206  light_set_shadow(0);
7207 
7208  #ifndef NDEBUG
7209  if (Show_shield_mesh)
7210  ship_draw_shield( obj); // Render the shield.
7211  #endif
7212 
7213  if ( clip_started ) {
7215  }
7216  }
7217 
7218  ship_model_stop(obj);
7219 
7220  if (shipp->shield_hits && !Rendering_to_shadow_map) {
7222  shipp->shield_hits = 0;
7223  }
7224 
7225  #ifndef NDEBUG
7227  if ( shipp->ai_index != -1 ){
7228  render_path_points(obj);
7229  }
7230 
7231  render_dock_bays(obj);
7232  }
7233  #endif
7234 
7235  #ifndef NDEBUG
7236  if(Show_tnorms){
7237  ship_subsys *systemp;
7238  vec3d tpos, tnorm, temp;
7239  vec3d v1, v2;
7240  vertex l1, l2;
7241 
7242  gr_set_color(0, 0, 255);
7243  systemp = GET_FIRST( &shipp->subsys_list );
7244  while ( systemp != END_OF_LIST(&shipp->subsys_list) ) {
7245  ship_get_global_turret_gun_info(obj, systemp, &tpos, &tnorm, 1, &temp);
7246 
7247  v1 = tpos;
7248  vm_vec_scale_add(&v2, &v1, &tnorm, 20.0f);
7249 
7250  g3_rotate_vertex(&l1, &v1);
7251  g3_rotate_vertex(&l2, &v2);
7252 
7253  g3_draw_sphere(&l1, 2.0f);
7254  g3_draw_line(&l1, &l2);
7255 
7256  systemp = GET_NEXT(systemp);
7257  }
7258  }
7259  #endif
7260  }
7261 
7262  //WMC - Draw animated warp effect (ie BSG thingy)
7263  //WMC - based on Bobb's secondary thruster stuff
7264  //which was in turn based on the beam code.
7265  //I'm gonna need some serious acid to neutralize this base.
7266  if(shipp->flags & SF_ARRIVING)
7267  shipp->warpin_effect->warpShipRender();
7268  else if(shipp->flags & SF_DEPART_WARP)
7269  shipp->warpout_effect->warpShipRender();
7270 }
7271 
7273 {
7274  if(objp->type != OBJ_SHIP || objp->instance < 0)
7275  return;
7276 
7277  ship *shipp = &Ships[objp->instance];
7278  ship_info *sip = &Ship_info[shipp->ship_info_index];
7279 
7280  if(sip->cockpit_model_num < 0)
7281  return;
7282 
7284  Assert(pm != NULL);
7285 
7286  //Setup
7287  gr_reset_clip();
7289 
7290  matrix eye_ori = vmd_identity_matrix;
7292  ship_get_eye(&eye_pos, &eye_ori, objp, false, true);
7293 
7295 
7296  vm_vec_unrotate(&pos, &sip->cockpit_offset, &eye_ori);
7297  if (!Cmdline_nohtl)
7298  {
7299  gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, 0.02f, 10.0f*pm->rad);
7301  }
7302 
7303  //Deal with the model
7305 
7306  model_render_params render_info;
7307  render_info.set_detail_level_lock(0);
7308  render_info.set_flags(MR_NO_FOGGING);
7310 
7311  model_render_immediate(&render_info, sip->cockpit_model_num, &eye_ori, &pos);
7312 
7313  if (!Cmdline_nohtl)
7314  {
7317  }
7318 
7320 }
7321 
7323 {
7324  vec3d cockpit_eye_pos;
7325  matrix dummy;
7326  ship_get_eye(&cockpit_eye_pos, &dummy, objp, true, true); //Get cockpit eye position
7327 
7331  gr_set_view_matrix(&cockpit_eye_pos, &Eye_matrix); // Set Camera to cockpit eye position
7332 
7333  Glowpoint_override = true; // Turn off glowpoints so they dont get rendered fixed at origin
7334 
7335  model_render_params render_info;
7336 
7337  render_info.set_object_number(OBJ_INDEX(objp));
7338  render_info.set_detail_level_lock(0);
7339 
7340  model_render_immediate(&render_info, Ship_info[Ships[objp->instance].ship_info_index].model_num, &objp->orient, &vmd_zero_vector); // Render ship model with fixed detail level 0 so its not switching LOD when moving away from origin
7341  Glowpoint_override = false;
7342 
7346  gr_set_view_matrix(&Eye_position, &Eye_matrix); // Reset Camera to normal
7347 }
7348 
7350 {
7351  ship_info *sip = &Ship_info[shipp->ship_info_index];
7352 
7353  int cockpit_model_num = sip->cockpit_model_num;
7354 
7355  // don't bother creating cockpit texture replacements if this ship has no cockpit
7356  if ( cockpit_model_num < 0 ) {
7357  return;
7358  }
7359 
7360  // check if we even have cockpit displays
7361  if ( sip->displays.size() <= 0 ) {
7362  return;
7363  }
7364 
7365  if ( Player_cockpit_textures != NULL) {
7366  return;
7367  }
7368 
7369  // ship's cockpit texture replacements haven't been setup yet, so do it.
7371 
7372  int i;
7373 
7374  for ( i = 0; i < MAX_REPLACEMENT_TEXTURES; i++ ) {
7375  Player_cockpit_textures[i] = -1;
7376  }
7377 
7378  for ( i = 0; i < (int)sip->displays.size(); i++ ) {
7379  ship_add_cockpit_display(&sip->displays[i], cockpit_model_num);
7380  }
7381 
7383 }
7384 
7386 {
7387  for ( int i = 0; i < (int)Player_displays.size(); i++ ) {
7388  if ( Player_displays[i].background >= 0 ) {
7389  bm_release(Player_displays[i].background);
7390  }
7391 
7392  if ( Player_displays[i].foreground >= 0 ) {
7393  bm_release(Player_displays[i].foreground);
7394  }
7395 
7396  if ( Player_displays[i].target >= 0 ) {
7397  bm_release(Player_displays[i].target);
7398  }
7399  }
7400 
7401  Player_displays.clear();
7402 
7403  if ( Player_cockpit_textures != NULL ) {
7405  Player_cockpit_textures = NULL;
7406  }
7407 }
7408 
7409 void ship_add_cockpit_display(cockpit_display_info *display, int cockpit_model_num)
7410 {
7411  if ( strlen(display->filename) <= 0 ) {
7412  return;
7413  }
7414 
7415  if( cockpit_model_num < 0 ) {
7416  return;
7417  }
7418 
7419  int i, tm_num, glow_target = -1, glow_handle = -1, diffuse_handle = -1;
7420  int w, h;
7421  cockpit_display new_display;
7422 
7423  // if no texture target has been found yet, find one.
7424  polymodel *pm = model_get(cockpit_model_num);
7425 
7426  for ( i = 0; i < pm->n_textures; i++ )
7427  {
7428  tm_num = pm->maps[i].FindTexture(display->filename);
7429  if ( tm_num >= 0 ) {
7430  glow_target = i*TM_NUM_TYPES+TM_GLOW_TYPE;
7431 
7432  diffuse_handle = pm->maps[i].textures[TM_BASE_TYPE].GetTexture();
7433  glow_handle = pm->maps[i].textures[TM_GLOW_TYPE].GetTexture();
7434  break;
7435  }
7436  }
7437 
7438  // create a render target for this cockpit texture
7439  if ( Player_cockpit_textures[glow_target] < 0) {
7440 
7441  bm_get_info(diffuse_handle, &w, &h);
7443 
7444  // if no render target was made, bail
7445  if ( Player_cockpit_textures[glow_target] < 0 ) {
7446  return;
7447  }
7448  }
7449 
7450  new_display.background = -1;
7451  if ( display->bg_filename[0] != '\0' ) {
7452  new_display.background = bm_load(display->bg_filename);
7453 
7454  if ( new_display.background < 0 ) {
7455  Warning(LOCATION, "Unable to load background %s for cockpit display %s", display->bg_filename, display->name);
7456  }
7457  }
7458 
7459  new_display.foreground = -1;
7460  if ( display->fg_filename[0] != '\0' ) {
7461  new_display.foreground = bm_load(display->fg_filename);
7462 
7463  if ( new_display.foreground < 0 ) {
7464  Warning(LOCATION, "Unable to load background %s for cockpit display %s", display->fg_filename, display->name);
7465  }
7466  }
7467 
7468  strcpy_s(new_display.name, display->name);
7469  new_display.offset[0] = display->offset[0];
7470  new_display.offset[1] = display->offset[1];
7471  new_display.size[0] = display->size[0];
7472  new_display.size[1] = display->size[1];
7473  new_display.source = glow_handle;
7474  new_display.target = Player_cockpit_textures[glow_target];
7475 
7476  Player_displays.push_back(new_display);
7477 }
7478 
7480 {
7481  if ( !Ship_info[Player_ship->ship_info_index].hud_enabled ) {
7482  return;
7483  }
7484 
7485  SCP_vector<HudGauge*> &hud = Ship_info[Player_ship->ship_info_index].hud_gauges;
7486 
7487  for ( int i = 0; i < (int)hud.size(); i++ ) {
7488  for ( int j = 0; j < (int)Player_displays.size(); j++ ) {
7489  hud[i]->setCockpitTarget(&Player_displays[j]);
7490  }
7491  }
7492 }
7493 
7494 int ship_start_render_cockpit_display(int cockpit_display_num)
7495 {
7496  // make sure this thing even has a cockpit
7497  if ( Ship_info[Player_ship->ship_info_index].cockpit_model_num < 0 ) {
7498  return -1;
7499  }
7500 
7501  if ( Player_cockpit_textures == NULL ) {
7502  return -1;
7503  }
7504 
7505  // check sanity of the cockpit display handle
7506  if ( cockpit_display_num >= (int)Player_displays.size() || cockpit_display_num < 0 ) {
7507  return -1;
7508  }
7509 
7510  cockpit_display* display = &Player_displays[cockpit_display_num];
7511 
7512  if ( display->target < 0 ) {
7513  return -1;
7514  }
7515 
7516  if ( !bm_set_render_target(display->target) ) {
7517  return -1;
7518  }
7519 
7520  int cull = gr_set_cull(0);
7521 
7522  gr_clear();
7523 
7524  if ( display->source >= 0 ) {
7525  gr_set_bitmap(display->source);
7526  gr_bitmap(0, 0, GR_RESIZE_NONE);
7527  }
7528 
7529  if ( display->background >= 0 ) {
7530  gr_set_bitmap(display->background);
7531  gr_bitmap_ex(display->offset[0], display->offset[1], display->size[0], display->size[1], 0, 0, GR_RESIZE_NONE);
7532  }
7533 
7534  gr_set_cull(cull);
7535 
7536  return display->target;
7537 }
7538 
7539 void ship_end_render_cockpit_display(int cockpit_display_num)
7540 {
7541  // make sure this thing even has a cockpit
7542  if ( Ship_info[Player_ship->ship_info_index].cockpit_model_num < 0 ) {
7543  return;
7544  }
7545 
7546  if ( Player_cockpit_textures == NULL ) {
7547  return;
7548  }
7549 
7550  // check sanity of the cockpit display handle
7551  if ( cockpit_display_num >= (int)Player_displays.size() || cockpit_display_num < 0 ) {
7552  return;
7553  }
7554 
7555  cockpit_display* display = &Player_displays[cockpit_display_num];
7556 
7557  int cull = gr_set_cull(0);
7558  if ( display->foreground >= 0 ) {
7559  gr_reset_clip();
7560  gr_set_bitmap(display->foreground);
7561  gr_bitmap_ex(display->offset[0], display->offset[1], display->size[0], display->size[1], 0, 0, GR_RESIZE_NONE);
7562  }
7563 
7564  gr_set_cull(cull);
7566 }
7567 
7569 {
7570  if ( NOT_EMPTY(&shipp->subsys_list) )
7571  {
7572  ship_subsys *systemp, *temp;
7573 
7574  systemp = GET_FIRST( &shipp->subsys_list );
7575  while ( systemp != END_OF_LIST(&shipp->subsys_list) ) {
7576  temp = GET_NEXT( systemp ); // use temporary since pointers will get screwed with next operation
7577  list_remove( shipp->subsys_list, systemp ); // remove the element
7578  list_append( &ship_subsys_free_list, systemp ); // and place back onto free list
7579  Num_ship_subsystems--; // subtract from our in-use total
7580  systemp = temp; // use the temp variable to move right along
7581  }
7582  }
7583 }
7584 
7585 void ship_delete( object * obj )
7586 {
7587  ship *shipp;
7588  int num, objnum __UNUSED;
7589 
7590  num = obj->instance;
7591  Assert( num >= 0);
7592 
7593  objnum = OBJ_INDEX(obj);
7594  Assert( Ships[num].objnum == objnum );
7595 
7596  shipp = &Ships[num];
7597 
7598  if (shipp->ai_index != -1){
7599  ai_free_slot(shipp->ai_index);
7600  }
7601 
7602  // free up the list of subsystems of this ship. walk through list and move remaining subsystems
7603  // on ship back to the free list for other ships to use.
7604  ship_subsystems_delete(&Ships[num]);
7605  shipp->objnum = -1;
7606 
7607  if (shipp->shield_integrity != NULL) {
7608  vm_free(shipp->shield_integrity);
7609  shipp->shield_integrity = NULL;
7610  }
7611 
7612  if (shipp->ship_replacement_textures != NULL) {
7614  shipp->ship_replacement_textures = NULL;
7615  }
7616 
7617  // glow point banks
7618  shipp->glow_point_bank_active.clear();
7619 
7620  if ( shipp->ship_list_index != -1 ) {
7622  shipp->ship_list_index = -1;
7623  }
7624 
7625  free_sexp2(shipp->arrival_cue);
7626  free_sexp2(shipp->departure_cue);
7627 
7628  // call the contrail system
7629  ct_ship_delete(shipp);
7630 
7632 }
7633 
7640 void ship_wing_cleanup( int shipnum, wing *wingp )
7641 {
7642  int i, index = -1, team = Ships[shipnum].team;
7643 
7644  // find this ship's position within its wing
7645  for (i = 0; i < wingp->current_count; i++)
7646  {
7647  if (wingp->ship_index[i] == shipnum)
7648  {
7649  index = i;
7650  break;
7651  }
7652  }
7653 
7654  // this can happen in multiplayer (dogfight, ingame join specifically)
7655  if (index == -1)
7656  return;
7657 
7658  // compress the ship_index array and mark the last entry with a -1
7659  for (i = index; i < wingp->current_count - 1; i++)
7660  wingp->ship_index[i] = wingp->ship_index[i+1];
7661 
7662  wingp->current_count--;
7663  Assert ( wingp->current_count >= 0 );
7664  wingp->ship_index[wingp->current_count] = -1;
7665 
7666  // if the current count is 0, check to see if the wing departed or was destroyed.
7667  if (wingp->current_count == 0)
7668  {
7669  // if this wing was ordered to depart by the player, set the current_wave equal to the total
7670  // waves so we can mark the wing as gone and no other ships arrive
7671  // Goober5000 - also if it's departing... this is sort of, but not exactly, what :V: did;
7672  // but it seems to be consistent with how it should behave
7673  if (wingp->flags & (WF_WING_DEPARTING | WF_DEPARTURE_ORDERED))
7674  wingp->current_wave = wingp->num_waves;
7675 
7676  // Goober5000 - some changes for clarity and closing holes
7677  // make sure to flag the wing as gone if all of its member ships are gone and no more can arrive
7678  if ((wingp->current_wave == wingp->num_waves) && (wingp->total_destroyed + wingp->total_departed + wingp->total_vanished == wingp->total_arrived_count))
7679  {
7680  // mark the wing as gone
7681  wingp->flags |= WF_WING_GONE;
7682  wingp->time_gone = Missiontime;
7683 
7684  // if all ships were destroyed, log it as destroyed
7685  if (wingp->total_destroyed == wingp->total_arrived_count)
7686  {
7687  // first, be sure to mark a wing destroyed event if all members of wing were destroyed and on
7688  // the last wave. This circumvents a problem where the wing could be marked as departed and
7689  // destroyed if the last ships were destroyed after the wing's departure cue became true.
7691  }
7692  // if some ships escaped, log it as departed
7693  else if (wingp->total_vanished != wingp->total_arrived_count)
7694  {
7695  // if the wing wasn't destroyed, and it is departing, then mark it as departed -- in this
7696  // case, there had better be ships in this wing with departure entries in the log file. The
7697  // logfile code checks for this case.
7699  }
7700 
7701 #ifndef NDEBUG
7702  //WMC - Ships can depart too, besides being destroyed :P
7703  if ((wingp->total_destroyed + wingp->total_departed + wingp->total_vanished) != wingp->total_arrived_count)
7704  {
7705  // apparently, there have been reports of ships still present in the mission when this log
7706  // entry if written. Do a sanity check here to find out for sure.
7707  for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
7708  {
7709  // skip the player -- stupid special case.
7710  if (&Objects[so->objnum] == Player_obj)
7711  continue;
7712 
7714  continue;
7715 
7716  if ((Ships[Objects[so->objnum].instance].wingnum == WING_INDEX(wingp)) && !(Ships[Objects[so->objnum].instance].flags & (SF_DEPARTING|SF_DYING)))
7717  {
7718  // TODO: I think this Int3() is triggered when a wing whose ships are all docked to ships of another
7719  // wing departs. It can be reliably seen in TVWP chapter 1 mission 7, when Torino and Iota wing depart.
7720  // Not sure how to fix this. -- Goober5000
7721  Int3();
7722  }
7723  }
7724  }
7725 #endif
7726  }
7727  }
7728 }
7729 
7730 // functions to do management, like log entries and wing cleanup after a ship has been destroyed
7731 
7732 // Goober5000
7734 {
7735  // do standard departure stuff first
7736  objp->flags |= OF_SHOULD_BE_DEAD;
7737  if (objp->type == OBJ_SHIP)
7739 
7740  // do the end-mission stuff if it's the player ship
7741  if (objp == Player_obj)
7743 }
7744 
7748 void ship_actually_depart(int shipnum, int method)
7749 {
7750  dock_function_info dfi;
7751  dfi.parameter_variables.bool_value = (method == SHIP_VANISHED ? true:false);
7753 
7754  // in a couple of cases we'll need to send a packet to update clients
7755  if (MULTIPLAYER_MASTER && ((method == SHIP_DEPARTED_BAY) || (method == SHIP_VANISHED)) ) {
7756  send_ship_depart_packet(&Objects[Ships[shipnum].objnum], method);
7757  }
7758 }
7759 
7760 // no destruction effects, not for player destruction and multiplayer, only self-destruction
7761 void ship_destroy_instantly(object *ship_objp, int shipnum)
7762 {
7763  Assert(ship_objp->type == OBJ_SHIP);
7764  Assert(!(ship_objp == Player_obj));
7766 
7767  // undocking and death preparation
7768  ship_stop_fire_primary(ship_objp);
7769  ai_deathroll_start(ship_objp);
7770 
7771  mission_log_add_entry(LOG_SELF_DESTRUCTED, Ships[ship_objp->instance].ship_name, NULL );
7772 
7773  // scripting stuff
7774  Script_system.SetHookObject("Self", ship_objp);
7775  Script_system.RunCondition(CHA_DEATH, 0, NULL, ship_objp);
7776  Script_system.RemHookVar("Self");
7777 
7778  ship_objp->flags |= OF_SHOULD_BE_DEAD;
7779  ship_cleanup(shipnum,SHIP_DESTROYED);
7780 }
7781 
7782 
7786 void ship_cleanup(int shipnum, int cleanup_mode)
7787 {
7788  Assert(shipnum >= 0 && shipnum < MAX_SHIPS);
7789  Assert(cleanup_mode == SHIP_DESTROYED || cleanup_mode == SHIP_DEPARTED || cleanup_mode == SHIP_VANISHED);
7790  Assert(Objects[Ships[shipnum].objnum].type == OBJ_SHIP);
7791  Assert(Objects[Ships[shipnum].objnum].flags & OF_SHOULD_BE_DEAD);
7792 
7793  ship *shipp = &Ships[shipnum];
7794  object *objp = &Objects[shipp->objnum];
7795 
7796  // add the information to the exited ship list
7797  if (cleanup_mode == SHIP_DESTROYED) {
7799  } else {
7801  }
7802 
7803  // record kill?
7804  if (cleanup_mode == SHIP_DESTROYED) {
7805  // determine if we need to count this ship as a kill in counting number of kills per ship type
7806  // look at the ignore flag for the ship (if not in a wing), or the ignore flag for the wing
7807  // (if the ship is in a wing), and add to the kill count if the flags are not set
7808  if ( !(shipp->flags & SF_IGNORE_COUNT) || ((shipp->wingnum != -1) && !(Wings[shipp->wingnum].flags & WF_IGNORE_COUNT)) )
7810 
7811  // let the event music system know an enemy was destroyed (important for deciding when to transition from battle to normal music)
7812  if (Player_ship != NULL && iff_x_attacks_y(Player_ship->team, shipp->team))
7814  }
7815 
7816  // add mission log entry?
7817  // (vanished ships have no log, and destroyed ships are logged in ship_hit_kill)
7818  if (cleanup_mode == SHIP_DEPARTED) {
7819  // see if this ship departed within the radius of a jump node -- if so, put the node name into
7820  // the secondary mission log field
7821  CJumpNode *jnp = jumpnode_get_which_in(objp);
7822  if(jnp==NULL)
7824  else
7826  }
7827 
7828 #ifndef NDEBUG
7829  // add a debug log entry
7830  if (cleanup_mode == SHIP_DESTROYED) {
7831  nprintf(("Alan", "SHIP DESTROYED: %s\n", shipp->ship_name));
7832  } else if (cleanup_mode == SHIP_DEPARTED) {
7833  nprintf(("Alan", "SHIP DEPARTED: %s\n", shipp->ship_name));
7834  } else {
7835  nprintf(("Alan", "SHIP VANISHED: %s\n", shipp->ship_name));
7836  }
7837 #endif
7838 
7839  // update wingman status gauge
7840  if ( (shipp->wing_status_wing_index >= 0) && (shipp->wing_status_wing_pos >= 0) ) {
7841  if (cleanup_mode == SHIP_DESTROYED) {
7843  } else if (cleanup_mode == SHIP_DEPARTED) {
7845  } else {
7847  }
7848  }
7849 
7850  // if ship belongs to a wing, do the wing cleanup
7851  if ( shipp->wingnum != -1 ) {
7852  wing *wingp = &Wings[shipp->wingnum];
7853 
7854  if (cleanup_mode == SHIP_DESTROYED) {
7855  wingp->total_destroyed++;
7856  } else if (cleanup_mode == SHIP_DEPARTED) {
7857  wingp->total_departed++;
7858  } else {
7859  wingp->total_vanished++;
7860  }
7861 
7862  ship_wing_cleanup(shipnum, wingp);
7863  }
7864 
7865  // Note, this call to ai_ship_destroy must come after ship_wing_cleanup for guarded wings to
7866  // properly note the destruction of a ship in their wing.
7867  if (cleanup_mode == SHIP_DESTROYED) {
7868  ai_ship_destroy(shipnum, SEF_DESTROYED); // Do AI stuff for destruction of ship.
7869  } else {
7870  ai_ship_destroy(shipnum, SEF_DEPARTED); // should still do AI cleanup after ship has departed
7871  }
7872 
7873  // Goober5000 - lastly, clear out the dead-docked list, per Mantis #2294
7874  // (for exploding ships, this list should have already been cleared by now, via
7875  // do_dying_undock_physics, except in the case of the destroy-instantly sexp)
7876  while (object_is_dead_docked(objp))
7877  {
7878  object *docked_objp = dock_get_first_dead_docked_object(objp);
7879  dock_dead_undock_objects(objp, docked_objp);
7880  }
7881 }
7882 
7895 int ship_explode_area_calc_damage( vec3d *pos1, vec3d *pos2, float inner_rad, float outer_rad, float max_damage, float max_blast, float *damage, float *blast )
7896 {
7897  float dist;
7898 
7899  dist = vm_vec_dist_quick( pos1, pos2 );
7900 
7901  // check outside outer radius
7902  if ( dist > outer_rad )
7903  return -1;
7904 
7905  if ( dist < inner_rad ) {
7906  // check insider inner radius
7907  *damage = max_damage;
7908  *blast = max_blast;
7909  } else {
7910  // between inner and outer
7911  float fraction = 1.0f - (dist - inner_rad) / (outer_rad - inner_rad);
7912  *damage = fraction * max_damage;
7913  *blast = fraction * max_blast;
7914  }
7915 
7916  return 1;
7917 }
7918 
7919 static const float MAX_SHOCK_ANGLE_RANGE = 1.99f * PI;
7920 
7926 void ship_blow_up_area_apply_blast( object *exp_objp)
7927 {
7928  ship *shipp;
7929  ship_info *sip;
7930  float inner_rad, outer_rad, max_damage, max_blast, shockwave_speed;
7931 
7932  // No area explosion in training missions.
7934  return;
7935  }
7936 
7937  Assert( exp_objp != NULL );
7938  Assert( exp_objp->type == OBJ_SHIP );
7939  Assert( exp_objp->instance >= 0 );
7940 
7941  shipp = &Ships[exp_objp->instance];
7942  sip = &Ship_info[shipp->ship_info_index];
7943 
7944  Assert( (shipp != NULL) && (sip != NULL) );
7945 
7946  if ((exp_objp->hull_strength <= KAMIKAZE_HULL_ON_DEATH) && (Ai_info[Ships[exp_objp->instance].ai_index].ai_flags & AIF_KAMIKAZE) && (shipp->special_exp_damage == -1)) {
7947  int override = Ai_info[shipp->ai_index].kamikaze_damage;
7948 
7949  inner_rad = exp_objp->radius*2.0f;
7950  outer_rad = exp_objp->radius*4.0f; // + (override * 0.3f);
7951  max_damage = i2fl(override);
7952  max_blast = override * 5.0f;
7953  shockwave_speed = 100.0f;
7954  } else {
7955  if (shipp->use_special_explosion) {
7956  inner_rad = i2fl(shipp->special_exp_inner);
7957  outer_rad = i2fl(shipp->special_exp_outer);
7958  max_damage = i2fl(shipp->special_exp_damage);
7959  max_blast = i2fl(shipp->special_exp_blast);
7960  shockwave_speed = i2fl(shipp->special_exp_shockwave_speed);
7961  } else {
7962  inner_rad = sip->shockwave.inner_rad;
7963  outer_rad = sip->shockwave.outer_rad;
7964  max_damage = sip->shockwave.damage;
7965  max_blast = sip->shockwave.blast;
7966  shockwave_speed = sip->shockwave.speed;
7967  }
7968  }
7969 
7970  // account for ships that give no damage when they blow up.
7971  if ( (max_damage < 0.1f) && (max_blast < 0.1f) ){
7972  return;
7973  }
7974 
7975  if ( shockwave_speed > 0 ) {
7976  shockwave_create_info sci = sip->shockwave;
7977 
7978  sci.inner_rad = inner_rad;
7979  sci.outer_rad = outer_rad;
7980  sci.blast = max_blast;
7981  sci.damage = max_damage;
7982  sci.speed = shockwave_speed;
7983  sci.rot_angles.p = frand_range(0.0f, MAX_SHOCK_ANGLE_RANGE);
7984  sci.rot_angles.b = frand_range(0.0f, MAX_SHOCK_ANGLE_RANGE);
7985  sci.rot_angles.h = frand_range(0.0f, MAX_SHOCK_ANGLE_RANGE);
7986  shipfx_do_shockwave_stuff(shipp, &sci);
7987  } else {
7988  object *objp;
7989  float blast = 0.0f;
7990  float damage = 0.0f;
7991  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
7992  if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_ASTEROID) ) {
7993  continue;
7994  }
7995 
7996  if ( objp == exp_objp ){
7997  continue;
7998  }
7999 
8000  // don't blast navbuoys
8001  if ( objp->type == OBJ_SHIP ) {
8002  if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
8003  continue;
8004  }
8005  }
8006 
8007  if ( ship_explode_area_calc_damage( &exp_objp->pos, &objp->pos, inner_rad, outer_rad, max_damage, max_blast, &damage, &blast ) == -1 ){
8008  continue;
8009  }
8010 
8011  switch ( objp->type ) {
8012  case OBJ_SHIP:
8013  ship_apply_global_damage( objp, exp_objp, &exp_objp->pos, damage );
8014  vec3d force, vec_ship_to_impact;
8015  vm_vec_sub( &vec_ship_to_impact, &objp->pos, &exp_objp->pos );
8016  vm_vec_copy_normalize( &force, &vec_ship_to_impact );
8017  vm_vec_scale( &force, blast );
8018  ship_apply_whack( &force, &vec_ship_to_impact, objp );
8019  break;
8020  case OBJ_ASTEROID:
8021  asteroid_hit(objp, NULL, NULL, damage);
8022  break;
8023  default:
8024  Int3();
8025  break;
8026  }
8027  } // end for
8028  }
8029 }
8030 
8037 void do_dying_undock_physics(object *dying_objp, ship *dying_shipp)
8038 {
8039  // this function should only be called for an object that was docked...
8040  // no harm in calling it if it wasn't, but we want to enforce this
8041  Assert(object_is_dead_docked(dying_objp));
8042 
8043  object *docked_objp;
8044 
8045  float damage;
8046  float impulse_mag;
8047 
8048  vec3d impulse_norm, impulse_vec, pos;
8049 
8050  // damage applied to each docked object
8051  damage = 0.2f * dying_shipp->ship_max_hull_strength;
8052 
8053  // Goober5000 - as with ai_deathroll_start, we can't simply iterate through the dock list while we're
8054  // unlinking things. So just repeatedly unlink the first object.
8055  while (object_is_dead_docked(dying_objp))
8056  {
8057  docked_objp = dock_get_first_dead_docked_object(dying_objp);
8058  ship *docked_shipp = &Ships[docked_objp->instance];
8059  int dockee_index = dock_find_dead_dockpoint_used_by_object(docked_objp, dying_objp);
8060 
8061  // undo all the docking animations for the docked ship only
8062  model_anim_start_type(docked_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
8063  model_anim_start_type(docked_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
8064  model_anim_start_type(docked_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
8065  model_anim_start_type(docked_shipp, TRIGGER_TYPE_DOCKING_STAGE_1, dockee_index, -1);
8066 
8067  // only consider the mass of these two objects, not the whole assembly
8068  // (this is inaccurate, but the alternative is a huge mess of extra code for a very small gain in realism)
8069  float docked_mass = dying_objp->phys_info.mass + docked_objp->phys_info.mass;
8070 
8071  // damage this docked object
8072  ship_apply_global_damage(docked_objp, dying_objp, &dying_objp->pos, damage);
8073 
8074  // do physics
8075  vm_vec_sub(&impulse_norm, &docked_objp->pos, &dying_objp->pos);
8076  vm_vec_normalize(&impulse_norm);
8077  // set for relative separation velocity of ~30
8078  impulse_mag = 50.f * docked_objp->phys_info.mass * dying_objp->phys_info.mass / docked_mass;
8079  vm_vec_copy_scale(&impulse_vec, &impulse_norm, impulse_mag);
8080  vm_vec_rand_vec_quick(&pos);
8081  vm_vec_scale(&pos, docked_objp->radius);
8082  // apply whack to docked object
8083  physics_apply_whack(&impulse_vec, &pos, &docked_objp->phys_info, &docked_objp->orient, docked_objp->phys_info.mass);
8084  // enhance rotation of the docked object
8085  vm_vec_scale(&docked_objp->phys_info.rotvel, 2.0f);
8086 
8087  // apply whack to dying object
8088  vm_vec_negate(&impulse_vec);
8089  vm_vec_rand_vec_quick(&pos);
8090  vm_vec_scale(&pos, dying_objp->radius);
8091  physics_apply_whack(&impulse_vec, &pos, &dying_objp->phys_info, &dying_objp->orient, dying_objp->phys_info.mass);
8092 
8093  // unlink the two objects, since dying_objp has blown up
8094  dock_dead_undock_objects(dying_objp, docked_objp);
8095  }
8096 }
8097 
8101 void ship_dying_frame(object *objp, int ship_num)
8102 {
8103  ship *shipp = &Ships[ship_num];
8104 
8105  if ( shipp->flags & SF_DYING ) {
8106  ship_info *sip = &Ship_info[shipp->ship_info_index];
8107  int knossos_ship = (sip->flags & SIF_KNOSSOS_DEVICE);
8108 
8109  // bash hull value toward 0 (from self destruct)
8110  if (objp->hull_strength > 0) {
8111  int time_left = timestamp_until(shipp->final_death_time);
8112  float hits_left = objp->hull_strength;
8113 
8114  objp->hull_strength -= hits_left * (1000.0f * flFrametime) / time_left;
8115  }
8116 
8117  // special case of VAPORIZE
8118  if (shipp->flags & SF_VAPORIZE) {
8119  if (timestamp_elapsed(shipp->final_death_time)) {
8120  // play death sound
8121  snd_play_3d( &Snds[SND_VAPORIZED], &objp->pos, &View_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY );
8122 
8123  // do joystick effect
8124  if (objp == Player_obj) {
8125  joy_ff_explode();
8126  }
8127 
8128  // if dying ship is docked, do damage to docked and physics
8129  if (object_is_dead_docked(objp)) {
8130  do_dying_undock_physics(objp, shipp);
8131  }
8132 
8133  // do all accounting for respawning client and server side here.
8134  if (objp == Player_obj) {
8136  }
8137 
8138  // mark object as dead
8139  objp->flags |= OF_SHOULD_BE_DEAD;
8140 
8141  // Don't blow up model. Only use debris shards.
8142  // call ship function to clean up after the ship is destroyed.
8143  ship_cleanup(ship_num, SHIP_DESTROYED);
8144  return;
8145  } else {
8146  return;
8147  }
8148  }
8149 
8150  // bash the desired rotvel
8151  objp->phys_info.desired_rotvel = shipp->deathroll_rotvel;
8152 
8153  // Do fireballs for Big ship with propagating explostion, but not Kamikaze
8154  if (!(Ai_info[shipp->ai_index].ai_flags & AIF_KAMIKAZE) && ship_get_exp_propagates(shipp) && (sip->death_roll_r_mult > 0.0f)) {
8155  if ( timestamp_elapsed(shipp->next_fireball)) {
8156  vec3d outpnt, pnt1, pnt2;
8157  polymodel *pm = model_get(sip->model_num);
8158 
8159  // Gets two random points on the surface of a submodel
8160  if ( Cmdline_old_collision_sys ) {
8161  submodel_get_two_random_points(pm->id, pm->detail[0], &pnt1, &pnt2 );
8162  } else {
8163  submodel_get_two_random_points_better(pm->id, pm->detail[0], &pnt1, &pnt2 );
8164  }
8165 
8166  model_find_world_point(&outpnt, &pnt1, sip->model_num, pm->detail[0], &objp->orient, &objp->pos );
8167 
8168  float rad = objp->radius*0.1f;
8169 
8170  if (sip->death_roll_r_mult != 1.0f)
8171  rad *= sip->death_roll_r_mult;
8172 
8173  int fireball_type = fireball_ship_explosion_type(sip);
8174  if(fireball_type < 0) {
8176  }
8177  fireball_create( &outpnt, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), rad, 0, &objp->phys_info.vel );
8178  // start the next fireball up in the next 50 - 200 ms (2-3 per frame)
8179  int min_time = 333;
8180  int max_time = 500;
8181 
8182  if (sip->death_roll_time_mult != 1.0f) {
8183  min_time = (int) (min_time / sip->death_roll_time_mult);
8184  max_time = (int) (max_time / sip->death_roll_time_mult);
8185  }
8186 
8187  shipp->next_fireball = timestamp_rand(min_time,max_time);
8188 
8189  // do sound - maybe start a random sound, if it has played far enough.
8190  do_sub_expl_sound(objp->radius, &outpnt, shipp->sub_expl_sound_handle);
8191  }
8192  }
8193 
8194  // create little fireballs for knossos as it dies
8195  if (knossos_ship) {
8196  if ( timestamp_elapsed(shipp->next_fireball)) {
8197  vec3d rand_vec, outpnt; // [0-.7 rad] in plane
8198  vm_vec_rand_vec_quick(&rand_vec);
8199  float scale = -vm_vec_dot(&objp->orient.vec.fvec, &rand_vec) * (0.9f + 0.2f * frand());
8200  vm_vec_scale_add2(&rand_vec, &objp->orient.vec.fvec, scale);
8201  vm_vec_normalize_quick(&rand_vec);
8202  scale = objp->radius * frand() * 0.717f;
8203  vm_vec_scale(&rand_vec, scale);
8204  vm_vec_add(&outpnt, &objp->pos, &rand_vec);
8205 
8206  float rad = objp->radius*0.2f;
8207 
8208  int fireball_type = fireball_ship_explosion_type(sip);
8209  if(fireball_type < 0) {
8211  }
8212  fireball_create( &outpnt, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), rad, 0, &objp->phys_info.vel );
8213  // start the next fireball up in the next 50 - 200 ms (2-3 per frame)
8214  shipp->next_fireball = timestamp_rand(333,500);
8215 
8216  // emit particles
8217  particle_emitter pe;
8219 
8220  pe.num_low = pef.n_low; // Lowest number of particles to create
8221  pe.num_high = pef.n_high; // Highest number of particles to create
8222  pe.pos = outpnt; // Where the particles emit from
8223  pe.vel = objp->phys_info.vel; // Initial velocity of all the particles
8224  pe.min_life = pef.min_life; // How long the particles live
8225  pe.max_life = pef.max_life; // How long the particles live
8226  pe.normal = objp->orient.vec.uvec; // What normal the particle emit around
8227  pe.normal_variance = pef.variance; // How close they stick to that normal 0=on normal, 1=180, 2=360 degree
8228  pe.min_vel = pef.min_vel;
8229  pe.max_vel = pef.max_vel;
8230  pe.min_rad = pef.min_rad; // * objp->radius;
8231  pe.max_rad = pef.max_rad; // * objp->radius;
8232 
8233  if (pe.num_high > 0) {
8234  particle_emit( &pe, PARTICLE_SMOKE2, 0, 50 );
8235  }
8236 
8237  // do sound - maybe start a random sound, if it has played far enough.
8238  do_sub_expl_sound(objp->radius, &outpnt, shipp->sub_expl_sound_handle);
8239  }
8240  }
8241 
8242  int time_until_minor_explosions = timestamp_until(shipp->final_death_time);
8243 
8244  // Wait until just before death and set off some explosions
8245  // If it is less than 1/2 second until large explosion, but there is
8246  // at least 1/10th of a second left, then create 5 small explosions
8247  if ( (time_until_minor_explosions < 500) && (time_until_minor_explosions > 100) && (!shipp->pre_death_explosion_happened) ) {
8248  shipp->next_fireball = timestamp(-1); // never time out again
8249  shipp->pre_death_explosion_happened=1; // Mark this event as having occurred
8250 
8251  polymodel *pm = model_get(sip->model_num);
8252 
8253  // Start shockwave for ship with propagating explosion, do now for timing
8254  if ( ship_get_exp_propagates(shipp) ) {
8256  }
8257 
8258  int zz_max = sip->death_fx_count;
8259 
8260  for (int zz=0; zz<zz_max; zz++ ) {
8261  // don't make sequence of fireballs for knossos
8262  if (knossos_ship) {
8263  break;
8264  }
8265 
8266  if (sip->death_fx_r_mult <= 0.0f) {
8267  break;
8268  }
8269  // Find two random vertices on the model, then average them
8270  // and make the piece start there.
8271  vec3d tmp, outpnt, pnt1, pnt2;
8272 
8273  // Gets two random points on the surface of a submodel [KNOSSOS]
8274  if ( Cmdline_old_collision_sys ) {
8275  submodel_get_two_random_points(pm->id, pm->detail[0], &pnt1, &pnt2 );
8276  } else {
8277  submodel_get_two_random_points_better(pm->id, pm->detail[0], &pnt1, &pnt2 );
8278  }
8279 
8280  vm_vec_avg( &tmp, &pnt1, &pnt2 );
8281  model_find_world_point(&outpnt, &tmp, pm->id, pm->detail[0], &objp->orient, &objp->pos );
8282 
8283  float rad = objp->radius*0.40f;
8284 
8285  rad *= sip->death_fx_r_mult;
8286 
8287  int fireball_type = fireball_ship_explosion_type(sip);
8288  if(fireball_type < 0) {
8289  fireball_type = FIREBALL_EXPLOSION_MEDIUM;
8290  }
8291  fireball_create( &outpnt, fireball_type, FIREBALL_MEDIUM_EXPLOSION, OBJ_INDEX(objp), rad, 0, &objp->phys_info.vel );
8292  }
8293  }
8294 
8295  if ( timestamp_elapsed(shipp->final_death_time)) {
8296  shipp->death_time = shipp->final_death_time;
8297  shipp->final_death_time = timestamp(-1); // never time out again
8298 
8299  // play ship explosion sound effect, pick appropriate explosion sound
8300  int sound_index;
8301 
8303  {
8304  sound_index = ship_get_sound(objp, SND_SHIP_EXPLODE_1);
8305  }
8306  else
8307  {
8308  if ( sip->flags & (SIF_CAPITAL | SIF_KNOSSOS_DEVICE) ) {
8309  sound_index=SND_CAPSHIP_EXPLODE;
8310  } else {
8311  if ( OBJ_INDEX(objp) & 1 ) {
8312  sound_index=SND_SHIP_EXPLODE_1;
8313  } else {
8314  sound_index=SND_SHIP_EXPLODE_2;
8315  }
8316  }
8317  }
8318 
8319  snd_play_3d( &Snds[sound_index], &objp->pos, &View_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY );
8320  if (objp == Player_obj)
8321  joy_ff_explode();
8322 
8323  if ( shipp->death_roll_snd != -1 ) {
8324  snd_stop(shipp->death_roll_snd);
8325  shipp->death_roll_snd = -1;
8326  }
8327 
8328  // if dying ship is docked, do damage to docked and physics
8329  if (object_is_dead_docked(objp)) {
8330  do_dying_undock_physics(objp, shipp);
8331  }
8332 
8333  // play a random explosion
8334  particle_emitter pe;
8336 
8337  pe.num_low = pef.n_low; // Lowest number of particles to create
8338  pe.num_high = pef.n_high; // Highest number of particles to create
8339  pe.pos = objp->pos; // Where the particles emit from
8340  pe.vel = objp->phys_info.vel; // Initial velocity of all the particles
8341  pe.min_life = pef.min_life; // How long the particles live
8342  pe.max_life = pef.max_life; // How long the particles live
8343  pe.normal = objp->orient.vec.uvec; // What normal the particle emit around
8344  pe.normal_variance = pef.variance; // How close they stick to that normal 0=on normal, 1=180, 2=360 degree
8345  pe.min_vel = pef.min_vel; // How fast the slowest particle can move
8346  pe.max_vel = pef.max_vel; // How fast the fastest particle can move
8347  pe.min_rad = pef.min_rad; // Min radius
8348  pe.max_rad = pef.max_rad; // Max radius
8349 
8350  if ((!knossos_ship) && (pe.num_high > 0)) {
8351  particle_emit( &pe, PARTICLE_SMOKE2, 0 );
8352  }
8353 
8354  // If this is a large ship with a propagating explosion, set it to blow up.
8355  if ( ship_get_exp_propagates(shipp) ) {
8356  if (Ai_info[shipp->ai_index].ai_flags & AIF_KAMIKAZE) {
8358  }
8359  shipfx_large_blowup_init(shipp);
8360  // need to timeout immediately to keep physics in sync
8361  shipp->really_final_death_time = timestamp(0);
8362  polymodel *pm = model_get(sip->model_num);
8363  shipp->end_death_time = timestamp((int) pm->core_radius);
8364  } else {
8365  // only do big fireball if not big ship
8366  float big_rad;
8367  int fireball_objnum, fireball_type, default_fireball_type;
8368  float explosion_life;
8369  big_rad = objp->radius*1.75f;
8370 
8371  default_fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
8372  if (knossos_ship) {
8373  big_rad = objp->radius * 1.2f;
8374  default_fireball_type = FIREBALL_EXPLOSION_LARGE1;
8375  }
8376  //SUSHI: Option to override radius of big fireball
8377  if (Ship_info[shipp->ship_info_index].big_exp_visual_rad >= 0)
8378  big_rad = Ship_info[shipp->ship_info_index].big_exp_visual_rad;
8379 
8380  fireball_type = fireball_ship_explosion_type(sip);
8381  if(fireball_type < 0) {
8382  fireball_type = default_fireball_type;
8383  }
8384  fireball_objnum = fireball_create( &objp->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(objp), big_rad, 0, &objp->phys_info.vel );
8385  if ( fireball_objnum >= 0 ) {
8386  explosion_life = fireball_lifeleft(&Objects[fireball_objnum]);
8387  } else {
8388  explosion_life = 0.0f;
8389  }
8390 
8391  // JAS: I put in all this code because of an item on my todo list that
8392  // said that the ship destroyed debris shouldn't pop in until the
8393  // big explosion is 30% done. I did this on Oct24 and me & Adam
8394  // thought it looked dumb since the explosion didn't move with the
8395  // ship, so instead of just taking this code out, since we might need
8396  // it in the future, I disabled it. You can reenable it by changing
8397  // the commenting on the following two lines.
8398  shipp->end_death_time = shipp->really_final_death_time = timestamp( fl2i(explosion_life*1000.0f)/5 ); // Wait till 30% of vclip time before breaking the ship up.
8399  }
8400 
8401  shipp->flags |= SF_EXPLODED;
8402 
8403  if ( !(ship_get_exp_propagates(shipp)) ) {
8404  // apply area of effect blast damage from ship explosion
8406  }
8407  }
8408 
8410  // Copied from lock all turrets sexp
8411  // Locks all turrets on ship that is about to split.
8412  ship_subsys *subsys;
8413  subsys = GET_FIRST(&shipp->subsys_list);
8414  while ( subsys != END_OF_LIST(&shipp->subsys_list) )
8415  {
8416  // just mark all turrets as locked
8417  if (subsys->system_info->type == SUBSYSTEM_TURRET) {
8418  subsys->weapons.flags |= SW_FLAG_TURRET_LOCK;
8419  }
8420  subsys = GET_NEXT(subsys);
8421  }
8422 
8423  // do large_ship_split and explosion
8424  if ( shipp->large_ship_blowup_index >= 0 ) {
8425  if ( shipfx_large_blowup_do_frame(shipp, flFrametime) ) {
8426  // do all accounting for respawning client and server side here.
8427  if(objp == Player_obj) {
8429  }
8430 
8431  objp->flags |= OF_SHOULD_BE_DEAD;
8432 
8433  ship_cleanup(ship_num, SHIP_DESTROYED); // call ship function to clean up after the ship is destroyed.
8434  }
8435  return;
8436  }
8437 
8438  shipfx_blow_up_model(objp, sip->model_num, 0, 20, &objp->pos );
8439 
8440  // do all accounting for respawning client and server side here.
8441  if(objp == Player_obj) {
8443  }
8444 
8445  objp->flags |= OF_SHOULD_BE_DEAD;
8446 
8447  ship_cleanup(ship_num, SHIP_DESTROYED); // call ship function to clean up after the ship is destroyed.
8448  shipp->really_final_death_time = timestamp( -1 ); // Never time out again!
8449  }
8450 
8451  // If a ship is dying (and not a capital or big ship) then stutter the engine sound
8452  if ( timestamp_elapsed(shipp->next_engine_stutter) ) {
8453  if ( !(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
8454  shipp->flags ^= SF_ENGINES_ON; // toggle state of engines
8455  shipp->next_engine_stutter = timestamp_rand(50, 250);
8456  }
8457  }
8458  }
8459 }
8460 
8461 void ship_chase_shield_energy_targets(ship *shipp, object *obj, float frametime)
8462 {
8463  float delta;
8464  ship_info *sip;
8465 
8466  if (shipp->flags & SF_DYING)
8467  return;
8468 
8469  sip = &Ship_info[shipp->ship_info_index];
8470 
8471  delta = frametime * ETS_RECHARGE_RATE * shipp->ship_max_shield_strength / 100.0f;
8472 
8473  // Chase target_shields and target_weapon_energy
8474  if (shipp->target_shields_delta > 0.0f) {
8475  if (delta > shipp->target_shields_delta)
8476  delta = shipp->target_shields_delta;
8477 
8478  shield_add_strength(obj, delta);
8479  shipp->target_shields_delta -= delta;
8480  } else if (shipp->target_shields_delta < 0.0f) {
8481  if (delta < -shipp->target_shields_delta)
8482  delta = -shipp->target_shields_delta;
8483 
8484  shield_add_strength(obj, -delta);
8485  shipp->target_shields_delta += delta;
8486  }
8487 
8488  delta = frametime * ETS_RECHARGE_RATE * sip->max_weapon_reserve / 100.0f;
8489 
8490  if (shipp->target_weapon_energy_delta > 0.0f) {
8491  if (delta > shipp->target_weapon_energy_delta)
8492  delta = shipp->target_weapon_energy_delta;
8493 
8494  shipp->weapon_energy += delta;
8496  } else if (shipp->target_weapon_energy_delta < 0.0f) {
8497  if (delta < -shipp->target_weapon_energy_delta)
8498  delta = -shipp->target_weapon_energy_delta;
8499 
8500  shipp->weapon_energy -= delta;
8502  }
8503 
8504 }
8505 
8507 {
8508  if ( !VALID_FNAME(ga->filename) )
8509  return -1;
8510 
8511  int fps = 15;
8512 
8513  ga->first_frame = bm_load(ga->filename);
8514  if (ga->first_frame < 0)
8515  {
8516  Warning(LOCATION, "Couldn't load thruster glow animation '%s'\nPrimary glow type effect does not accept .EFF or .ANI effects", ga->filename);
8517  return -1;
8518  }
8520 
8521  Assert(fps != 0);
8522  ga->total_time = i2fl(ga->num_frames)/fps;
8523 
8524  return 0;
8525 }
8526 
8531 {
8532  if ( Thrust_anim_inited == 1 )
8533  return;
8534 
8535  for (size_t i = 0; i < Species_info.size(); i++)
8536  {
8537  species_info *species = &Species_info[i];
8538 
8541 
8542  // Bobboau's extra thruster stuff
8543  {
8550  }
8551 
8552  // glows are handled a bit strangely
8555  }
8556 
8557  Thrust_anim_inited = 1;
8558 }
8559 
8560 
8567 void ship_do_thruster_frame( ship *shipp, object *objp, float frametime )
8568 {
8569  float rate;
8570  int framenum;
8571  int secondary_glow_bitmap, tertiary_glow_bitmap, distortion_bitmap;
8572  generic_anim *flame_anim, *glow_anim;
8573  ship_info *sinfo = &Ship_info[shipp->ship_info_index];
8574 
8575  if ( !Thrust_anim_inited ) {
8577  }
8578 
8579  if (objp->phys_info.flags & PF_AFTERBURNER_ON) {
8580  flame_anim = &sinfo->thruster_flame_info.afterburn; // select afterburner flame
8581  glow_anim = &sinfo->thruster_glow_info.afterburn; // select afterburner glow
8582  secondary_glow_bitmap = sinfo->thruster_secondary_glow_info.afterburn.bitmap_id;
8583  tertiary_glow_bitmap = sinfo->thruster_tertiary_glow_info.afterburn.bitmap_id;
8584  distortion_bitmap = sinfo->thruster_distortion_info.afterburn.bitmap_id;
8585 
8586  rate = 1.5f; // go at 1.5x faster when afterburners on
8587  } else if (objp->phys_info.flags & PF_BOOSTER_ON) {
8588  flame_anim = &sinfo->thruster_flame_info.afterburn; // select afterburner flame
8589  glow_anim = &sinfo->thruster_glow_info.afterburn; // select afterburner glow
8590  secondary_glow_bitmap = sinfo->thruster_secondary_glow_info.afterburn.bitmap_id;
8591  tertiary_glow_bitmap = sinfo->thruster_tertiary_glow_info.afterburn.bitmap_id;
8592  distortion_bitmap = sinfo->thruster_distortion_info.afterburn.bitmap_id;
8593 
8594  rate = 2.5f; // go at 2.5x faster when boosters on
8595  } else {
8596  flame_anim = &sinfo->thruster_flame_info.normal; // select normal flame
8597  glow_anim = &sinfo->thruster_glow_info.normal; // select normal glow
8598  secondary_glow_bitmap = sinfo->thruster_secondary_glow_info.normal.bitmap_id;
8599  tertiary_glow_bitmap = sinfo->thruster_tertiary_glow_info.normal.bitmap_id;
8600  distortion_bitmap = sinfo->thruster_distortion_info.normal.bitmap_id;
8601 
8602  // If thrust at 0, go at half as fast, full thrust; full framerate
8603  // so set rate from 0.67 to 1.67, depending on thrust from 0 to 1
8604  rate = 0.67f * (1.0f + objp->phys_info.forward_thrust);
8605  }
8606 
8607  Assert( frametime > 0.0f );
8608 
8609  // add primary thruster effects ...
8610 
8611  if (flame_anim->first_frame >= 0) {
8612  shipp->thruster_frame += frametime * rate;
8613 
8614  // Sanity checks
8615  if (shipp->thruster_frame < 0.0f) {
8616  shipp->thruster_frame = 0.0f;
8617  } else if (shipp->thruster_frame > 100.0f) {
8618  shipp->thruster_frame = 0.0f;
8619  }
8620 
8621  while (shipp->thruster_frame > flame_anim->total_time) {
8622  shipp->thruster_frame -= flame_anim->total_time;
8623  }
8624 
8625  framenum = fl2i( (shipp->thruster_frame * flame_anim->num_frames) / flame_anim->total_time );
8626  CLAMP(framenum, 0, (flame_anim->num_frames - 1));
8627 
8628  // Get the bitmap for this frame
8629  shipp->thruster_bitmap = flame_anim->first_frame + framenum;
8630  } else {
8631  shipp->thruster_frame = 0.0f;
8632  shipp->thruster_bitmap = -1;
8633  }
8634 
8635  // primary glows ...
8636  if (glow_anim->first_frame >= 0) {
8637  shipp->thruster_glow_frame += frametime * rate;
8638 
8639  // Sanity checks
8640  if (shipp->thruster_glow_frame < 0.0f) {
8641  shipp->thruster_glow_frame = 0.0f;
8642  } else if (shipp->thruster_glow_frame > 100.0f) {
8643  shipp->thruster_glow_frame = 0.0f;
8644  }
8645 
8646  while (shipp->thruster_glow_frame > glow_anim->total_time) {
8647  shipp->thruster_glow_frame -= glow_anim->total_time;
8648  }
8649 
8650  framenum = fl2i( (shipp->thruster_glow_frame*glow_anim->num_frames) / glow_anim->total_time );
8651  CLAMP(framenum, 0, (glow_anim->num_frames - 1));
8652 
8653  // Get the bitmap for this frame
8654  shipp->thruster_glow_bitmap = glow_anim->first_frame; // + framenum;
8655  shipp->thruster_glow_noise = Noise[framenum];
8656  } else {
8657  shipp->thruster_glow_frame = 0.0f;
8658  shipp->thruster_glow_bitmap = -1;
8659  shipp->thruster_glow_noise = 1.0f;
8660  }
8661 
8662  // add extra thruster effects
8663  shipp->thruster_secondary_glow_bitmap = secondary_glow_bitmap;
8664  shipp->thruster_tertiary_glow_bitmap = tertiary_glow_bitmap;
8665  shipp->thruster_distortion_bitmap = distortion_bitmap;
8666 }
8667 
8668 
8680 void ship_do_weapon_thruster_frame( weapon *weaponp, object *objp, float frametime )
8681 {
8682  float rate;
8683  int framenum;
8684  generic_anim *flame_anim, *glow_anim;
8685 
8686  if (!Thrust_anim_inited)
8688 
8689  species_info *species = &Species_info[weaponp->species];
8690  weapon_info *wip = &Weapon_info[weaponp->weapon_info_index];
8691 
8692  // If thrust at 0, go at half as fast, full thrust; full framerate
8693  // so set rate from 0.67 to 1.67, depending on thrust from 0 to 1
8694  rate = 0.67f * (1.0f + objp->phys_info.forward_thrust);
8695 
8696  if (wip->thruster_flame.first_frame >= 0)
8697  flame_anim = &wip->thruster_flame;
8698  else
8699  flame_anim = &species->thruster_info.flames.normal;
8700 
8701  if (wip->thruster_glow.first_frame >= 0)
8702  glow_anim = &wip->thruster_glow;
8703  else
8704  glow_anim = &species->thruster_info.glow.normal;
8705 
8706  Assert( frametime > 0.0f );
8707 
8708  if (flame_anim->first_frame >= 0) {
8709  weaponp->thruster_frame += frametime * rate;
8710 
8711  // Sanity checks
8712  if ( weaponp->thruster_frame < 0.0f ) weaponp->thruster_frame = 0.0f;
8713  if ( weaponp->thruster_frame > 100.0f ) weaponp->thruster_frame = 0.0f;
8714 
8715  while ( weaponp->thruster_frame > flame_anim->total_time ) {
8716  weaponp->thruster_frame -= flame_anim->total_time;
8717  }
8718  framenum = fl2i( (weaponp->thruster_frame*flame_anim->num_frames) / flame_anim->total_time );
8719  if ( framenum < 0 ) framenum = 0;
8720  if ( framenum >= flame_anim->num_frames ) framenum = flame_anim->num_frames-1;
8721 
8722  // Get the bitmap for this frame
8723  weaponp->thruster_bitmap = flame_anim->first_frame + framenum;
8724  } else {
8725  weaponp->thruster_frame = 0.0f;
8726  weaponp->thruster_bitmap = -1;
8727  }
8728 
8729  // Do it for glow bitmaps
8730  if (glow_anim->first_frame >= 0) {
8731  weaponp->thruster_glow_frame += frametime * rate;
8732 
8733  // Sanity checks
8734  if ( weaponp->thruster_glow_frame < 0.0f ) weaponp->thruster_glow_frame = 0.0f;
8735  if ( weaponp->thruster_glow_frame > 100.0f ) weaponp->thruster_glow_frame = 0.0f;
8736 
8737  while ( weaponp->thruster_glow_frame > glow_anim->total_time ) {
8738  weaponp->thruster_glow_frame -= glow_anim->total_time;
8739  }
8740  framenum = fl2i( (weaponp->thruster_glow_frame*glow_anim->num_frames) / glow_anim->total_time );
8741  if ( framenum < 0 ) framenum = 0;
8742  if ( framenum >= glow_anim->num_frames ) framenum = glow_anim->num_frames-1;
8743 
8744  // Get the bitmap for this frame
8745  weaponp->thruster_glow_bitmap = glow_anim->first_frame; // + framenum;
8746  weaponp->thruster_glow_noise = Noise[framenum];
8747  } else {
8748  weaponp->thruster_glow_frame = 0.0f;
8749  weaponp->thruster_glow_bitmap = -1;
8750  weaponp->thruster_glow_noise = 1.0f;
8751  }
8752 }
8753 
8754 
8755 
8756 // Repair damaged subsystems for a ship, called for each ship once per frame.
8757 // TODO: optimize by only calling ever N seconds and keeping track of elapsed time
8758 //
8759 // NOTE: need to update current_hits in the sp->subsys_list element, and the sp->subsys_info[]
8760 // element.
8761 #define SHIP_REPAIR_SUBSYSTEM_RATE 0.01f // percent repair per second for a subsystem
8762 #define SUBSYS_REPAIR_THRESHOLD 0.1 // only repair subsystems that have > 10% strength
8763 void ship_auto_repair_frame(int shipnum, float frametime)
8764 {
8765  ship_subsys *ssp;
8766  ship_subsys_info *ssip;
8767  ship *sp;
8768  ship_info *sip;
8769  object *objp;
8770  float real_repair_rate;
8771 
8772  #ifndef NDEBUG
8773  if ( !Ship_auto_repair ) // only repair subsystems if Ship_auto_repair flag is set
8774  return;
8775  #endif
8776 
8777  Assert( shipnum >= 0 && shipnum < MAX_SHIPS);
8778  sp = &Ships[shipnum];
8779  sip = &Ship_info[sp->ship_info_index];
8780  objp = &Objects[sp->objnum];
8781 
8782  //Repair the hull...or maybe unrepair?
8783  if(sip->hull_repair_rate != 0.0f)
8784  {
8785  objp->hull_strength += sp->ship_max_hull_strength * sip->hull_repair_rate * frametime;
8786 
8787  if(objp->hull_strength > sp->ship_max_hull_strength)
8788  {
8790  }
8791  }
8792 
8793  // only allow for the auto-repair of subsystems on small ships
8794  //...NOT. Check if var has been changed from def -C
8795  if ( !(sip->flags & SIF_SMALL_SHIP) && sip->subsys_repair_rate == -2.0f)
8796  return;
8797 
8798  if(sip->subsys_repair_rate == -2.0f)
8799  real_repair_rate = SHIP_REPAIR_SUBSYSTEM_RATE;
8800  else
8801  real_repair_rate = sip->subsys_repair_rate;
8802 
8803  // AL 3-14-98: only allow auto-repair if power output not zero
8804  if (sip->power_output <= 0)
8805  return;
8806 
8807  // iterate through subsystems, repair as needed based on elapsed frametime
8808  for ( ssp = GET_FIRST(&sp->subsys_list); ssp != END_OF_LIST(&sp->subsys_list); ssp = GET_NEXT(ssp) ) {
8809  Assert(ssp->system_info->type >= 0 && ssp->system_info->type < SUBSYSTEM_MAX);
8810  ssip = &sp->subsys_info[ssp->system_info->type];
8811 
8812  if ( ssp->current_hits < ssp->max_hits ) {
8813 
8814  // only repair those subsystems which are not destroyed
8815  if ( ssp->max_hits <= 0 )
8816  continue;
8817 
8818  if ( ssp->current_hits <= 0 ) {
8820  if (ssp->flags & SSF_NO_AUTOREPAIR_IF_DISABLED) {
8821  continue;
8822  }
8823  } else if (!(ssp->flags & SSF_AUTOREPAIR_IF_DISABLED)) {
8824  continue;
8825  }
8826  }
8827 
8828  // do incremental repair on the subsystem
8829  // check for overflow of current_hits
8830  ssp->current_hits += ssp->max_hits * real_repair_rate * frametime;
8831  if ( ssp->current_hits > ssp->max_hits ) {
8832  ssp->current_hits = ssp->max_hits;
8833  }
8834 
8835  // aggregate repair
8836  if (!(ssp->flags & SSF_NO_AGGREGATE)) {
8837  ssip->aggregate_current_hits += ssip->aggregate_max_hits * real_repair_rate * frametime;
8838  if ( ssip->aggregate_current_hits > ssip->aggregate_max_hits ) {
8840  }
8841  }
8842 
8843  // check to see if this subsystem was totally non functional before -- if so, then
8844  // reset the flags
8845  if ( (ssp->system_info->type == SUBSYSTEM_ENGINE) && (sp->flags & SF_DISABLED) ) {
8846  sp->flags &= ~SF_DISABLED;
8848  }
8849  }
8850  } // end for
8851 }
8852 
8853 // this function checks to see how far the player has strayed from his starting location (should be
8854 // single player only). Issues a warning at some distance. Makes mission end if he keeps flying away
8855 // 3 strikes and you're out or too far away
8856 #define PLAYER_MAX_DIST_WARNING 700000 // distance in KM at which player gets warning to return to battle
8857 #define PLAYER_DISTANCE_MAX_WARNINGS 3 // maximum number of warnings player can receive before mission ends
8858 #define PLAYER_MAX_DIST_END 750000 // distance from starting loc at which we end mission
8859 #define PLAYER_WARN_DELTA_TIME 10000 //ms
8860 #define PLAYER_DEATH_DELTA_TIME 5000 //ms
8861 
8862 void ship_check_player_distance_sub(player *p, int multi_target=-1)
8863 {
8864  // only check distance for ships
8865  if ( p->control_mode != PCM_NORMAL ) {
8866  // already warping out... don't bother checking anymore
8867  return;
8868  }
8869 
8870  float dist = vm_vec_dist_quick(&Objects[p->objnum].pos, &vmd_zero_vector);
8871 
8872  int give_warning_to_player = 0;
8873  if ( dist > PLAYER_MAX_DIST_WARNING ) {
8874  if (p->distance_warning_count == 0) {
8875  give_warning_to_player = 1;
8876  } else {
8877  if (timestamp_until(p->distance_warning_time) < 0) {
8878  give_warning_to_player = 1;
8879  }
8880  }
8881  }
8882 
8883  if ( give_warning_to_player ) {
8884  // increase warning count
8886  // set timestamp unless player PLAYER_FLAGS_DIST_TO_BE_KILLED flag is set
8887  if ( !(p->flags & PLAYER_FLAGS_DIST_TO_BE_KILLED) ) {
8889  }
8890  // issue up to max warnings
8893  }
8894 
8897  }
8898  }
8899 
8901 // DKA 5/17/99 - DON'T force warpout. Won't work multiplayer. Blow up ship.
8902  if ( !(p->flags & PLAYER_FLAGS_DIST_TO_BE_KILLED) ) {
8906  }
8907 
8908  // get hull strength and blow up
8911  float damage = 10.0f * Objects[p->objnum].hull_strength;
8912  ship_apply_global_damage(&Objects[p->objnum], &Objects[p->objnum], NULL, damage);
8913  }
8914  }
8915 
8916  // see if player has moved back into "bounds"
8919  p->distance_warning_count = 1;
8920  }
8921 }
8922 
8924 {
8925  int idx;
8926 
8927  // multiplayer
8928  if (Game_mode & GM_MULTIPLAYER) {
8929  // if I'm the server, check all non-observer players including myself
8930  if (MULTIPLAYER_MASTER) {
8931  // warn all players
8932  for (idx=0; idx<MAX_PLAYERS; idx++) {
8933  if (MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Objects[Net_players[idx].m_player->objnum].type != OBJ_GHOST) ) {
8934  // if bad, blow him up
8935  ship_check_player_distance_sub(Net_players[idx].m_player, idx);
8936  }
8937  }
8938  }
8939  }
8940  // single player
8941  else {
8942  // maybe blow him up
8944  }
8945 }
8946 
8948 {
8949  Assert(objp != NULL);
8950 
8951  if (objp == NULL)
8952  return;
8953 
8954  Assert(objp->type == OBJ_OBSERVER);
8955 
8956  if (Game_mode & GM_MULTIPLAYER) {
8957  // if I'm just an observer
8959  float dist = vm_vec_dist_quick(&Player_obj->pos, &vmd_zero_vector);
8960  // if beyond max dist, reset to 0
8961  if (dist > PLAYER_MAX_DIST_END) {
8962  // set me to zero
8963  if ((Player_obj != NULL) && (Player_obj->type != OBJ_GHOST)) {
8965  }
8966  }
8967  }
8968  }
8969 }
8970 
8974 void ship_reset_disabled_physics(object *objp, int ship_class)
8975 {
8976  Assert(objp != NULL);
8977 
8978  if (objp == NULL)
8979  return;
8980 
8982  objp->phys_info.side_slip_time_const = Ship_info[ship_class].damp;
8983 }
8984 
8989 {
8990  ship_subsys *ss;
8991  int engines_disabled=0;
8992 
8993  if ( sp->subsys_disrupted_flags & (1<<SUBSYSTEM_ENGINE) ) {
8994  engines_disabled=1;
8995  }
8996 
8997  sp->subsys_disrupted_flags=0;
8998 
8999  ss = GET_FIRST(&sp->subsys_list);
9000  while ( ss != END_OF_LIST( &sp->subsys_list ) ) {
9002  sp->subsys_disrupted_flags |= (1<<ss->system_info->type);
9003  }
9004  ss = GET_NEXT( ss );
9005  }
9006 
9007  if ( engines_disabled ) {
9008  if ( !(sp->subsys_disrupted_flags & (1<<SUBSYSTEM_ENGINE)) ) {
9009  if ( !(sp->flags & SF_DISABLED) ) {
9011  }
9012  }
9013  }
9014 }
9015 
9020 {
9024  }
9025 }
9026 
9034 {
9035  if ( !ss ) {
9036  Int3(); // should never happen, get Alan if it does.
9037  return 0;
9038  }
9039 
9041  return 0;
9042  } else {
9043  return 1;
9044  }
9045 }
9046 
9054 {
9055  int time_left=0;
9056 
9057  if ( !ss ) {
9058  Int3(); // should never happen, get Alan if it does.
9059  return;
9060  }
9061 
9062  time_left=timestamp_until(ss->disruption_timestamp);
9063  if ( time_left < 0 ) {
9064  time_left=0;
9065  }
9066 
9067  ss->disruption_timestamp = timestamp(time+time_left);
9068 }
9069 
9078 {
9079  Assert ( sp != NULL );
9080  Assert ( type >= 0 && type < SUBSYSTEM_MAX );
9081 
9082  // Bogus pointer to ship to check for disrupted subsystem
9083  if (sp == NULL)
9084  return 0;
9085 
9086  if ( sp->subsys_disrupted_flags & (1<<type) ) {
9087  return 1;
9088  } else {
9089  return 0;
9090  }
9091 }
9092 
9093 float Decay_rate = 1.0f / 120.0f;
9094 DCF(lethality_decay, "Sets ship lethality_decay, or the time in sec to go from 100 to 0 health (default is 1/120)")
9095 {
9096  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
9097  dc_printf("Decay rate is currently %f\n", Decay_rate);
9098  return;
9099  }
9100 
9101  dc_stuff_float(&Decay_rate);
9102 }
9103 
9104 float min_lethality = 0.0f;
9105 
9107 {
9108  float decay_rate = Decay_rate;
9109  aip->lethality -= 100.0f * decay_rate * flFrametime;
9110  aip->lethality = MAX(-10.0f, aip->lethality);
9111 
9112 #ifndef NDEBUG
9113  if (Objects[Ships[aip->shipnum].objnum].flags & OF_PLAYER_SHIP) {
9114  if (Framecount % 10 == 0) {
9115  int num_turrets = 0;
9116  if ((aip->target_objnum != -1) && (Objects[aip->target_objnum].type == OBJ_SHIP)) {
9117  //TODO: put this where it belongs, this would involve recompiling *everything* right now
9118  //-WMC
9119  int num_turrets_attacking(object *turret_parent, int target_objnum);
9120  num_turrets = num_turrets_attacking(&Objects[aip->target_objnum], Ships[aip->shipnum].objnum);
9121  }
9122  nprintf(("lethality", "Player lethality: %.1f, num turrets targeting player: %d\n", aip->lethality, num_turrets));
9123  }
9124  }
9125 #endif
9126 }
9127 
9128 void ship_process_pre(object *objp, float frametime)
9129 {
9130  if ( (objp == NULL) || !frametime )
9131  return;
9132 }
9133 
9134 MONITOR( NumShips )
9135 
9137 {
9138  Assert( obj != NULL);
9139  Assert( shipp != NULL );
9140  Assert( sip != NULL);
9141 
9142  shipp->radar_last_status = shipp->radar_current_status;
9143 
9144  RadarVisibility visibility = radar_is_visible(obj);
9145 
9146  if (visibility == NOT_VISIBLE)
9147  {
9148  if (shipp->radar_last_contact < 0 && shipp->radar_visible_since < 0)
9149  {
9150  shipp->radar_visible_since = -1;
9151  shipp->radar_last_contact = -1;
9152  }
9153  else
9154  {
9155  shipp->radar_visible_since = -1;
9156  shipp->radar_last_contact = Missiontime;
9157  }
9158  }
9159  else if (visibility == VISIBLE || visibility == DISTORTED)
9160  {
9161  if (shipp->radar_visible_since < 0)
9162  {
9163  shipp->radar_visible_since = Missiontime;
9164  }
9165 
9166  shipp->radar_last_contact = Missiontime;
9167  }
9168 
9169  shipp->radar_current_status = visibility;
9170 }
9171 
9172 
9180 void ship_process_post(object * obj, float frametime)
9181 {
9182  int num;
9183  ship *shipp;
9184  ship_info *sip;
9185 
9186  if(obj->type != OBJ_SHIP){
9187  nprintf(("Network","Ignoring non-ship object in ship_process_post()\n"));
9188  return;
9189  }
9190 
9191  MONITOR_INC( NumShips, 1 );
9192 
9193  num = obj->instance;
9194  Assert( num >= 0 && num < MAX_SHIPS);
9195  Assert( obj->type == OBJ_SHIP );
9196  Assert( Ships[num].objnum == OBJ_INDEX(obj));
9197 
9198  shipp = &Ships[num];
9199 
9200  sip = &Ship_info[shipp->ship_info_index];
9201 
9202  shipp->shield_hits = 0;
9203 
9204  update_ets(obj, frametime);
9205 
9206  afterburners_update(obj, frametime);
9207 
9209 
9210  ship_dying_frame(obj, num);
9211 
9212  ship_chase_shield_energy_targets(shipp, obj, frametime);
9213 
9214  // AL 1-6-98: record the initial ammo counts for ships, which is used as the max limit for rearming
9215  // Goober5000 - added ballistics support
9216  if ( !(shipp->flags & SF_AMMO_COUNT_RECORDED) )
9217  {
9218  int max_missiles;
9219  for ( int i=0; i<MAX_SHIP_SECONDARY_BANKS; i++ ) {
9220  if ( red_alert_mission() )
9221  {
9222  max_missiles = get_max_ammo_count_for_bank(shipp->ship_info_index, i, shipp->weapons.secondary_bank_weapons[i]);
9223  shipp->weapons.secondary_bank_start_ammo[i] = max_missiles;
9224  }
9225  else
9226  {
9228  }
9229  }
9230 
9231  if ( sip->flags & SIF_BALLISTIC_PRIMARIES )
9232  {
9233  for ( int i=0; i<MAX_SHIP_PRIMARY_BANKS; i++ )
9234  {
9235  if ( red_alert_mission() )
9236  {
9238  shipp->weapons.primary_bank_start_ammo[i] = max_missiles;
9239  }
9240  else
9241  {
9243  }
9244  }
9245  }
9246 
9247  shipp->flags |= SF_AMMO_COUNT_RECORDED;
9248  }
9249 
9250  if(!(Game_mode & GM_STANDALONE_SERVER)) {
9251  // Plot ship on the radar. What about multiplayer ships?
9252  if ( obj != Player_obj ) // don't plot myself.
9253  radar_plot_object( obj );
9254 
9255  // MWA -- move the spark code to before the check for multiplayer master
9256  // Do ship sparks. Don't do sparks on my ship (since I cannot see it). This
9257  // code will do sparks on other ships in multiplayer though.
9258  // JAS: Actually in external view, you can see sparks, so I don't do sparks
9259  // on the Viewer_obj, not Player_obj.
9260  if ( (obj != Viewer_obj) && timestamp_elapsed(Ships[num].next_hit_spark) ) {
9261  shipfx_emit_spark(num,-1); // -1 means choose random spark location
9262  }
9263 
9264  if ( obj != Viewer_obj ) {
9266  }
9267 
9268  // JAS - flicker the thruster bitmaps
9269  ship_do_thruster_frame(shipp,obj,frametime);
9270  }
9271 
9272  ship_auto_repair_frame(num, frametime);
9273 
9275 
9276  // if the ship has an EMP effect active, process it
9277  emp_process_ship(shipp);
9278 
9279  // call the contrail system
9280  ct_ship_process(shipp);
9281 
9282  // process engine wash
9283  void engine_wash_ship_process(ship *shipp);
9284  engine_wash_ship_process(shipp);
9285 
9286  // update TAG info
9287  if(shipp->tag_left > 0.0f){
9288  shipp->tag_left -= flFrametime;
9289  if(shipp->tag_left <= 0.000001f){
9290  shipp->tag_left = -1.0f;
9291 
9292  mprintf(("Killing TAG for %s\n", shipp->ship_name));
9293  }
9294  }
9295 
9296  // update level 2 TAG info
9297  if(shipp->level2_tag_left > 0.0f){
9298  shipp->level2_tag_left -= flFrametime;
9299  if(shipp->level2_tag_left <= 0.000001f){
9300  shipp->level2_tag_left = -1.0f;
9301 
9302  mprintf(("Killing level 2 TAG for %s\n", shipp->ship_name));
9303  }
9304  }
9305 
9306  if ( shipp->flags & SF_ARRIVING && Ai_info[shipp->ai_index].mode != AIM_BAY_EMERGE ) {
9307  // JAS -- if the ship is warping in, just move it forward at a speed
9308  // fast enough to move 2x its radius in SHIP_WARP_TIME seconds.
9309  shipfx_warpin_frame( obj, frametime );
9310  } else if ( shipp->flags & SF_DEPART_WARP ) {
9311  // JAS -- if the ship is warping out, just move it forward at a speed
9312  // fast enough to move 2x its radius in SHIP_WARP_TIME seconds.
9313  shipfx_warpout_frame( obj, frametime );
9314  }
9315 
9316  // update radar status of the ship
9317  ship_radar_process(obj, shipp, sip);
9318 
9319  if ( (!(shipp->flags & SF_ARRIVING) || (Ai_info[shipp->ai_index].mode == AIM_BAY_EMERGE)
9320  || ((sip->warpin_type == WT_IN_PLACE_ANIM) && (shipp->flags & SF_ARRIVING_STAGE_2)) )
9321  && !(shipp->flags & SF_DEPART_WARP))
9322  {
9323  // Do AI.
9324 
9325  // for multiplayer people. return here if in multiplay and not the host
9326  if ( MULTIPLAYER_CLIENT ) {
9327  model_anim_handle_multiplayer( &Ships[num] );
9328  return;
9329  }
9330 
9331  // MWA -- moved the code to maybe fire swarm missiles to after the check for
9332  // multiplayer master. Only single player and multi server needs to do this code
9333  // this code might call ship_fire_secondary which will send the fire packets
9335 
9336  // maybe fire turret swarm missiles
9337  void turret_swarm_maybe_fire_missile(int num);
9339 
9340  // maybe fire a corkscrew missile (just like swarmers)
9342 
9343  //rotate player subobjects since its processed by the ai functions
9344  // AL 2-19-98: Fire turret for player if it exists
9345  //WMC - changed this to call process_subobjects
9346  if ( (obj->flags & OF_PLAYER_SHIP) && !Player_use_ai )
9347  {
9348  ai_info *aip = &Ai_info[Ships[obj->instance].ai_index];
9350  {
9351  if (aip->support_ship_objnum >= 0)
9352  {
9353  if (vm_vec_dist_quick(&obj->pos, &Objects[aip->support_ship_objnum].pos) < (obj->radius + Objects[aip->support_ship_objnum].radius) * 1.25f)
9354  return;
9355  }
9356  }
9358  }
9359 
9360  if (obj == Player_obj) {
9362  }
9363 
9364  // update ship lethality
9365  if ( Ships[num].ai_index >= 0 ){
9366  if (!physics_paused && !ai_paused){
9367  lethality_decay(&Ai_info[Ships[num].ai_index]);
9368  }
9369  }
9370 
9371  // if the ship is an observer ship don't need to do AI
9372  if ( obj->type == OBJ_OBSERVER) {
9373  return;
9374  }
9375 
9376  // Goober5000 - player may want to use AI
9377  if ( (Ships[num].ai_index >= 0) && (!(obj->flags & OF_PLAYER_SHIP) || Player_use_ai) ){
9378  if (!physics_paused && !ai_paused){
9379  ai_process( obj, Ships[num].ai_index, frametime );
9380  }
9381  }
9382  }
9383 }
9384 
9385 
9393 {
9394  int i, j;
9395  polymodel *pm;
9396  ship_weapon *swp = &shipp->weapons;
9397  weapon_info *wip;
9398 
9399  // Copy primary and secondary weapons from ship_info to ship.
9400  // Later, this will happen in the weapon loadout screen.
9401  for (i=0; i < MAX_SHIP_PRIMARY_BANKS; i++){
9403  swp->primary_bank_slot_count[i] = 1; // RSAXVC DYN LINK CODE
9404  }
9405 
9406  for (i=0; i < MAX_SHIP_SECONDARY_BANKS; i++){
9408  }
9409 
9410  // Copy the number of primary and secondary banks to ship, and verify that
9411  // model is in synch
9412  pm = model_get( sip->model_num );
9413 
9414  // Primary banks
9415  if ( pm->n_guns > sip->num_primary_banks ) {
9416  Assert(pm->n_guns <= MAX_SHIP_PRIMARY_BANKS);
9417  Error(LOCATION, "There are %d primary banks in the model file,\nbut only %d primary banks specified for %s.\nThis must be fixed, as it will cause crashes.\n", pm->n_guns, sip->num_primary_banks, sip->name);
9418  for ( i = sip->num_primary_banks; i < pm->n_guns; i++ ) {
9419  // Make unspecified weapon for bank be a laser
9420  for ( j = 0; j < Num_player_weapon_precedence; j++ ) {
9421  Assertion((Player_weapon_precedence[j] > 0), "Error reading player weapon precedence list. Check weapons.tbl for $Player Weapon Precedence entry, and correct as necessary.\n");
9422  int weapon_id = Player_weapon_precedence[j];
9423  if ( (Weapon_info[weapon_id].subtype == WP_LASER) || (Weapon_info[weapon_id].subtype == WP_BEAM) ) {
9424  swp->primary_bank_weapons[i] = weapon_id;
9425  break;
9426  }
9427  }
9428  Assert(swp->primary_bank_weapons[i] >= 0);
9429  }
9430  sip->num_primary_banks = pm->n_guns;
9431  }
9432  else if ( pm->n_guns < sip->num_primary_banks ) {
9433  Warning(LOCATION, "There are %d primary banks specified for %s\nbut only %d primary banks in the model\n", sip->num_primary_banks, sip->name, pm->n_guns);
9434  sip->num_primary_banks = pm->n_guns;
9435  }
9436 
9437  // Secondary banks
9438  if ( pm->n_missiles > sip->num_secondary_banks ) {
9439  Assert(pm->n_missiles <= MAX_SHIP_SECONDARY_BANKS);
9440  Error(LOCATION, "There are %d secondary banks in the model file,\nbut only %d secondary banks specified for %s.\nThis must be fixed, as it will cause crashes.\n", pm->n_missiles, sip->num_secondary_banks, sip->name);
9441  for ( i = sip->num_secondary_banks; i < pm->n_missiles; i++ ) {
9442  // Make unspecified weapon for bank be a missile
9443  for ( j = 0; j < Num_player_weapon_precedence; j++ ) {
9444  Assertion((Player_weapon_precedence[j] > 0), "Error reading player weapon precedence list. Check weapons.tbl for $Player Weapon Precedence entry, and correct as necessary.\n");
9445  int weapon_id = Player_weapon_precedence[j];
9446  if (Weapon_info[weapon_id].subtype == WP_MISSILE) {
9447  swp->secondary_bank_weapons[i] = weapon_id;
9448  break;
9449  }
9450  }
9451  Assert(swp->secondary_bank_weapons[i] >= 0);
9452  }
9453  sip->num_secondary_banks = pm->n_missiles;
9454  }
9455  else if ( pm->n_missiles < sip->num_secondary_banks ) {
9456  Warning(LOCATION, "There are %d secondary banks specified for %s,\n but only %d secondary banks in the model.\n", sip->num_secondary_banks, sip->name, pm->n_missiles);
9457  sip->num_secondary_banks = pm->n_missiles;
9458  }
9459 
9460  // added ballistic primary support - Goober5000
9462  for ( i = 0; i < swp->num_primary_banks; i++ )
9463  {
9464  wip = &Weapon_info[swp->primary_bank_weapons[i]];
9465 
9466  if ( wip->wi_flags2 & WIF2_BALLISTIC )
9467  {
9468  if (Fred_running){
9469  swp->primary_bank_ammo[i] = 100;
9470  }
9471  else
9472  {
9473  float capacity, size;
9474  capacity = (float) sip->primary_bank_ammo_capacity[i];
9475  size = (float) wip->cargo_size;
9476  swp->primary_bank_ammo[i] = fl2i((capacity / size)+0.5f);
9478  }
9479 
9481  }
9482  }
9483 
9485  for ( i = 0; i < swp->num_secondary_banks; i++ ) {
9486  if (Fred_running){
9487  swp->secondary_bank_ammo[i] = 100;
9488  } else {
9489  wip = &Weapon_info[swp->secondary_bank_weapons[i]];
9490  float size = (float) wip->cargo_size;
9491  swp->secondary_bank_ammo[i] = fl2i(sip->secondary_bank_ammo_capacity[i]/size);
9492  // Karajorma - Support ships will use the wrong values if we don't set this.
9494  }
9495 
9497  }
9498 
9499  for ( i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++ ){
9500  swp->next_primary_fire_stamp[i] = timestamp(0);
9501  swp->last_primary_fire_stamp[i] = -1;
9502  swp->burst_counter[i] = 0;
9504  }
9505 
9506  for ( i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++ ){
9508  swp->last_secondary_fire_stamp[i] = -1;
9509  swp->burst_counter[i + MAX_SHIP_PRIMARY_BANKS] = 0;
9510  }
9511 
9512  //Countermeasures
9513  shipp->current_cmeasure = sip->cmeasure_type;
9514 }
9515 
9516 
9521 int ship_check_collision_fast( object * obj, object * other_obj, vec3d * hitpos)
9522 {
9523  int num;
9524  mc_info mc;
9525 
9526  Assert( obj->type == OBJ_SHIP );
9527  Assert( obj->instance >= 0 );
9528 
9529  num = obj->instance;
9530 
9531  mc_info_init(&mc);
9533  mc.model_num = Ship_info[Ships[num].ship_info_index].model_num; // Fill in the model to check
9534  mc.orient = &obj->orient; // The object's orient
9535  mc.pos = &obj->pos; // The object's position
9536  mc.p0 = &other_obj->last_pos; // Point 1 of ray to check
9537  mc.p1 = &other_obj->pos; // Point 2 of ray to check
9538  mc.flags = MC_ONLY_SPHERE; // flags
9539 
9540  model_collide(&mc);
9541  if (mc.num_hits)
9542  *hitpos = mc.hit_point_world;
9543 
9544  return mc.num_hits;
9545 }
9546 
9551 {
9552  static int last_smctu_initial_time = -1;
9553  static int last_smctu_final_time = -1;
9554  int sanity_counter = 0, collision;
9555  ship *compare_shipp;
9556  ship_obj *so;
9557  uint new_create_time;
9558 
9559  new_create_time = shipp->create_time;
9560 
9561  while (1) {
9562 
9563  collision = 0;
9564 
9565  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
9566  compare_shipp = &Ships[Objects[so->objnum].instance];
9567 
9568  if ( compare_shipp == shipp ) {
9569  continue;
9570  }
9571 
9572  if ( compare_shipp->create_time == new_create_time )
9573  {
9574  if((unsigned int)sanity_counter == 0 && (unsigned int)last_smctu_initial_time == shipp->create_time)
9575  {
9576  //WMC: If we're creating a whole bunch of ships at once, we can
9577  //shortcut this process by looking at the last call to this function
9578  //This fixes a bug when more than 50 ships are created at once.
9579  new_create_time = last_smctu_final_time + 1;
9580  }
9581  else
9582  {
9583  new_create_time++;
9584  }
9585  collision = 1;
9586  break;
9587  }
9588  }
9589 
9590  if ( !collision ) {
9591  last_smctu_initial_time = shipp->create_time;
9592  last_smctu_final_time = new_create_time;
9593  shipp->create_time = new_create_time;
9594  break;
9595  }
9596 
9597  if ( sanity_counter++ > MAX_SHIPS ) {
9598  Int3();
9599  break;
9600  }
9601  }
9602 }
9603 
9605 
9607 {
9608  object *objp;
9609  int count = 0;
9610  int o_type = 0;
9611 
9612  for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
9613  o_type = (int)objp->type;
9614  if (o_type == OBJ_SHIP) {
9615  count += Ship_info[Ships[objp->instance].ship_info_index].n_subsystems;
9616  }
9617  }
9618 
9619  if (count > Ship_subsys_hwm) {
9620  Ship_subsys_hwm = count;
9621  }
9622 }
9623 
9625 {
9626  Assert( shipp );
9627 
9628  shipp->ab_count = 0;
9629 
9630  if (shipp->ship_info_index < 0) {
9631  Int3();
9632  return;
9633  }
9634 
9635  ship_info *sip = &Ship_info[shipp->ship_info_index];
9636  Assert( sip->model_num >= 0 );
9637  polymodel *pm = model_get(sip->model_num);
9638  Assert( pm != NULL );
9639 
9640  if ( !(sip->flags & SIF_AFTERBURNER) ) {
9641  return;
9642  }
9643 
9644  if (sip->afterburner_trail.bitmap_id < 0) {
9645  return;
9646  }
9647 
9648  for (int i = 0; i < pm->n_thrusters; i++) {
9649  thruster_bank *bank = &pm->thrusters[i];
9650 
9651  for (int j = 0; j < bank->num_points; j++) {
9652  // this means you've reached the max # of AB trails for a ship
9653  if (shipp->ab_count >= MAX_SHIP_CONTRAILS) {
9654  Int3();
9655  break;
9656  }
9657 
9658  trail_info *ci = &shipp->ab_info[shipp->ab_count];
9659 
9660  if (bank->points[j].norm.xyz.z > -0.5f) {
9661  continue; // only make ab trails for thrusters that are pointing backwards
9662  }
9663 
9664  ci->pt = bank->points[j].pnt; //offset
9665 
9666  ci->w_start = bank->points[j].radius * sip->afterburner_trail_width_factor; // width * table loaded width factor
9667  ci->w_end = 0.05f; //end width
9668 
9669  ci->a_start = 1.0f * sip->afterburner_trail_alpha_factor; // start alpha * table loaded alpha factor
9670  ci->a_end = 0.0f; //end alpha
9671 
9672  ci->max_life = sip->afterburner_trail_life; // table loaded max life
9673  ci->stamp = 60; //spew time???
9674 
9675  ci->n_fade_out_sections = sip->afterburner_trail_faded_out_sections; // initial fade out
9676 
9677  ci->texture.bitmap_id = sip->afterburner_trail.bitmap_id; // table loaded bitmap used on this ships burner trails
9678 
9679  nprintf(("AB TRAIL", "AB trail point #%d made for '%s'\n", shipp->ab_count, shipp->ship_name));
9680 
9681  shipp->ab_count++;
9682  }
9683  }
9684 }
9685 
9690 int ship_create(matrix *orient, vec3d *pos, int ship_type, char *ship_name)
9691 {
9692  int i, n, objnum, j, k, t;
9693  ship_info *sip;
9694  ship *shipp;
9695 
9696  t = ship_get_num_ships();
9697 
9698  // The following check caps the number of ships that can be created. Because Fred needs
9699  // to create all the ships, regardless of when they arrive/depart, it needs a higher
9700  // limit than FreeSpace. On release, however, we will reduce it, thus FreeSpace needs
9701  // to check against what this limit will be, otherwise testing the missions before
9702  // release could work fine, yet not work anymore once a release build is made.
9703  if (Fred_running) {
9704  if (t >= MAX_SHIPS)
9705  return -1;
9706 
9707  } else {
9708  if (t >= SHIPS_LIMIT) {
9709  Error(LOCATION, XSTR("There is a limit of %d ships in the mission at once. Please be sure that you do not have more than %d ships present in the mission at the same time.", 1495), SHIPS_LIMIT, SHIPS_LIMIT );
9710  return -1;
9711  }
9712  }
9713 
9714  for (n=0; n<MAX_SHIPS; n++){
9715  if (Ships[n].objnum == -1){
9716  break;
9717  }
9718  }
9719 
9720  if (n == MAX_SHIPS){
9721  return -1;
9722  }
9723 
9724  Assert((ship_type >= 0) && (ship_type < static_cast<int>(Ship_info.size())));
9725  sip = &(Ship_info[ship_type]);
9726  shipp = &Ships[n];
9727  shipp->clear();
9728 
9729  sip->model_num = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]); // use the highest detail level
9730  if(strlen(sip->cockpit_pof_file))
9731  {
9732  sip->cockpit_model_num = model_load(sip->cockpit_pof_file, 0, NULL);
9733  }
9734 
9735  // maybe load an optional hud target model
9736  if(strlen(sip->pof_file_hud)){
9737  // check to see if a "real" ship uses this model. if so, load it up for him so that subsystems are setup properly
9738  for(auto it = Ship_info.begin(); it != Ship_info.end(); ++it){
9739  if(!stricmp(it->pof_file, sip->pof_file_hud)){
9740  it->model_num = model_load(it->pof_file, it->n_subsystems, &it->subsystems[0]);
9741  }
9742  }
9743 
9744  // mow load it for me with no subsystems
9745  sip->model_num_hud = model_load(sip->pof_file_hud, 0, NULL);
9746  }
9747 
9748  polymodel *pm = model_get(sip->model_num);
9749 
9752 
9753  if ( sip->num_detail_levels != pm->n_detail_levels )
9754  {
9755  if ( !Is_standalone )
9756  {
9757  // just log to file for standalone servers
9758  Warning(LOCATION, "For ship '%s', detail level\nmismatch. Table has %d,\nPOF has %d.", sip->name, sip->num_detail_levels, pm->n_detail_levels );
9759  }
9760  else
9761  {
9762  nprintf(("Warning", "For ship '%s', detail level mismatch. Table has %d, POF has %d.", sip->name, sip->num_detail_levels, pm->n_detail_levels ));
9763  }
9764  }
9765  for ( i=0; i<pm->n_detail_levels; i++ )
9766  pm->detail_depth[i] = (i < sip->num_detail_levels) ? i2fl(sip->detail_distance[i]) : 0.0f;
9767 
9768  // JAS: Nav buoys don't need to do collisions!
9769  // G5K: Corrected to apply specifically for ships with the no-collide flag. (In retail, navbuoys already have this flag, so this doesn't break anything.)
9770  if ( sip->flags & SIF_NO_COLLIDE ) {
9771  objnum = obj_create(OBJ_SHIP, -1, n, orient, pos, model_get_radius(sip->model_num), OF_RENDERS | OF_PHYSICS );
9772  } else {
9773  objnum = obj_create(OBJ_SHIP, -1, n, orient, pos, model_get_radius(sip->model_num), OF_RENDERS | OF_COLLIDES | OF_PHYSICS );
9774  }
9775  Assert( objnum >= 0 );
9776 
9777  shipp->ai_index = ai_get_slot(n);
9778  Assert( shipp->ai_index >= 0 );
9779 
9780  // Goober5000 - if no ship name specified, or if specified ship already exists,
9781  // or if specified ship has exited, use a default name
9782  if ((ship_name == NULL) || (ship_name_lookup(ship_name) >= 0) || (ship_find_exited_ship_by_name(ship_name) >= 0)) {
9783  char suffix[NAME_LENGTH];
9784  sprintf(suffix, NOX(" %d"), n);
9785 
9786  // ensure complete ship name doesn't overflow the buffer
9787  int name_len = MIN(NAME_LENGTH - strlen(suffix) - 1, strlen(Ship_info[ship_type].name));
9788  Assert(name_len > 0);
9789 
9790  strncpy(shipp->ship_name, Ship_info[ship_type].name, name_len);
9791  strcpy(shipp->ship_name + name_len, suffix);
9792  } else {
9793  strcpy_s(shipp->ship_name, ship_name);
9794  }
9795 
9796  ship_set_default_weapons(shipp, sip); // Moved up here because ship_set requires that weapon info be valid. MK, 4/28/98
9797  ship_set(n, objnum, ship_type);
9798 
9799  init_ai_object(objnum);
9800  ai_clear_ship_goals( &Ai_info[Ships[n].ai_index] ); // only do this one here. Can't do it in init_ai because it might wipe out goals in mission file
9801 
9802  // Allocate shield and initialize it.
9803  if (pm->shield.ntris) {
9804  shipp->shield_integrity = (float *) vm_malloc(sizeof(float) * pm->shield.ntris);
9805  for (i=0; i<pm->shield.ntris; i++)
9806  shipp->shield_integrity[i] = 1.0f;
9807  } else
9808  shipp->shield_integrity = NULL;
9809 
9810  // Bump the object radius to ensure that collision detection works right
9811  // even when spread shields extend outside the model's natural radius
9812  if (sip->flags2 & SIF2_AUTO_SPREAD_SHIELDS) {
9813  Objects[objnum].radius += sip->auto_shield_spread;
9814  }
9815 
9816  // allocate memory for keeping glow point bank status (enabled/disabled)
9817  {
9818  bool val = true; // default value, enabled
9819 
9820  if (pm->n_glow_point_banks)
9821  shipp->glow_point_bank_active.resize( pm->n_glow_point_banks, val );
9822  }
9823 
9824  // fix up references into paths for this ship's model to point to a ship_subsys entry instead
9825  // of a submodel index. The ship_subsys entry should be the same for *all* instances of the
9826  // same ship.
9827  if (!(sip->flags & SIF_PATH_FIXUP))
9828  {
9829  for ( i = 0; i < pm->n_paths; i++ )
9830  {
9831  for ( j = 0; j < pm->paths[i].nverts; j++ )
9832  {
9833  for ( k = 0; k < pm->paths[i].verts[j].nturrets; k++ )
9834  {
9835  int ptindex = pm->paths[i].verts[j].turret_ids[k]; // this index is a submodel number (ala bspgen)
9836  int index;
9837  ship_subsys *ss;
9838 
9839  // iterate through the ship_subsystems looking for an id that matches
9840  index = 0;
9841  ss = GET_FIRST(&Ships[n].subsys_list);
9842  while ( ss != END_OF_LIST( &Ships[n].subsys_list ) ) {
9843  if ( ss->system_info->subobj_num == ptindex ) { // when these are equal, fix up the ref
9844  pm->paths[i].verts[j].turret_ids[k] = index; // in path structure to index a ship_subsys
9845  break;
9846  }
9847  index++;
9848  ss = GET_NEXT( ss );
9849  }
9850 
9851  if ( ss == END_OF_LIST(&Ships[n].subsys_list) )
9852  Warning(LOCATION, "Couldn't fix up turret indices in spline path\n\nModel: %s\nPath: %s\nVertex: %d\nTurret model id:%d\n\nThis probably means that the turret was not specified in the ship table(s).", sip->pof_file, pm->paths[i].name, j, ptindex );
9853  }
9854  }
9855  }
9856  sip->flags |= SIF_PATH_FIXUP;
9857  }
9858 
9859  // Add this ship to Ship_obj_list
9860  shipp->ship_list_index = ship_obj_list_add(objnum);
9861 
9862  // Set time when ship is created
9864 
9866 
9867  // first try at ABtrails -Bobboau
9868  ship_init_afterburners(shipp);
9869 
9870  // call the contrail system
9871  ct_ship_create(shipp);
9872 
9874 
9875  shipp->model_instance_num = model_create_instance(true, sip->model_num);
9876 
9877  shipp->time_created = Missiontime;
9878 
9879  return objnum;
9880 }
9881 
9888 void ship_model_change(int n, int ship_type)
9889 {
9890  int i;
9891  ship_info *sip;
9892  ship *sp;
9893  polymodel * pm;
9894  object *objp;
9895 
9896  Assert( n >= 0 && n < MAX_SHIPS );
9897  sp = &Ships[n];
9898  sip = &(Ship_info[ship_type]);
9899  objp = &Objects[sp->objnum];
9900 
9901  // get new model
9902  if (sip->model_num == -1) {
9903  sip->model_num = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);
9904  }
9905 
9906  if ( sip->cockpit_model_num == -1 ) {
9907  if ( strlen(sip->cockpit_pof_file) ) {
9908  sip->cockpit_model_num = model_load(sip->cockpit_pof_file, 0, NULL);
9909  }
9910  }
9911 
9912  pm = model_get(sip->model_num);
9913  Objects[sp->objnum].radius = model_get_radius(pm->id);
9914 
9915  // page in nondims in game
9916  if ( !Fred_running )
9917  model_page_in_textures(sip->model_num, ship_type);
9918 
9919  // allocate memory for keeping glow point bank status (enabled/disabled)
9920  {
9921  bool val = true; // default value, enabled
9922 
9923  // clear out any old gpb's first, then add new ones if needed
9924  sp->glow_point_bank_active.clear();
9925 
9926  if (pm->n_glow_point_banks)
9927  sp->glow_point_bank_active.resize( pm->n_glow_point_banks, val );
9928  }
9929 
9931 
9932  if ( sip->num_detail_levels != pm->n_detail_levels )
9933  {
9934  if ( !Is_standalone )
9935  {
9936  // just log to file for standalone servers
9937  Warning(LOCATION, "For ship '%s', detail level\nmismatch. Table has %d,\nPOF has %d.", sip->name, sip->num_detail_levels, pm->n_detail_levels );
9938  }
9939  else
9940  {
9941  nprintf(("Warning", "For ship '%s', detail level mismatch. Table has %d, POF has %d.", sip->name, sip->num_detail_levels, pm->n_detail_levels ));
9942  }
9943  }
9944  for ( i=0; i<pm->n_detail_levels; i++ )
9945  pm->detail_depth[i] = (i < sip->num_detail_levels) ? i2fl(sip->detail_distance[i]) : 0.0f;
9946 
9947  if (sip->flags2 & SIF2_MODEL_POINT_SHIELDS) {
9948  objp->n_quadrants = pm->shield_points.size();
9949  sp->shield_points = pm->shield_points;
9950  } else {
9952  }
9953  objp->shield_quadrant.resize(objp->n_quadrants);
9954 
9955  if (sp->shield_integrity != NULL) {
9957  sp->shield_integrity = NULL;
9958  }
9959 
9960  // Allocate shield and initialize it.
9961  if (pm->shield.ntris) {
9962  sp->shield_integrity = (float *) vm_malloc(sizeof(float) * pm->shield.ntris);
9963 
9964  for (i = 0; i < pm->shield.ntris; i++) {
9965  sp->shield_integrity[i] = 1.0f;
9966  }
9967  } else {
9968  sp->shield_integrity = NULL;
9969  }
9970 
9971  // reset texture animations
9973 }
9974 
9983 void change_ship_type(int n, int ship_type, int by_sexp)
9984 {
9985  int i;
9986  ship_info *sip;
9987  ship_info *sip_orig;
9988  ship *sp;
9989  ship_weapon *swp;
9990  ship_subsys *ss;
9991  object *objp;
9992  p_object *p_objp;
9993  float hull_pct, shield_pct;
9994  physics_info ph_inf;
9995 
9996  Assert( n >= 0 && n < MAX_SHIPS );
9997  sp = &Ships[n];
9998 
9999  // do a quick out if we're already using the new ship class
10000  if (sp->ship_info_index == ship_type)
10001  return;
10002 
10003  swp = &sp->weapons;
10004  sip = &(Ship_info[ship_type]);
10005  sip_orig = &Ship_info[sp->ship_info_index];
10006  objp = &Objects[sp->objnum];
10008  ph_inf = objp->phys_info;
10009 
10010 
10011  // Goober5000 - we can't copy the ship object because the tree of structs contains at least
10012  // one class without a copy constructor. So let's just save the information we need.
10013 
10014  // these are wiped by ets_init_ship
10015  int orig_wep_rechg_idx = sp->weapon_recharge_index;
10016  int orig_shd_rechg_idx = sp->shield_recharge_index;
10017  int orig_eng_rechg_idx = sp->engine_recharge_index;
10018 
10019 
10020  // Goober5000 - maintain the original hull, shield, and subsystem percentages... gah
10021  // ...except when in FRED, because this stuff is handled in the missionparse/missionsave part. The E
10022 
10023  if (!Fred_running) {
10024  // hull
10025  if (sp->special_hitpoints) {
10026  hull_pct = objp->hull_strength / sp->ship_max_hull_strength;
10027  } else {
10028  Assert( Ship_info[sp->ship_info_index].max_hull_strength > 0.0f );
10029  hull_pct = objp->hull_strength / Ship_info[sp->ship_info_index].max_hull_strength;
10030  }
10031 
10032  // extra check
10033  Assert(hull_pct > 0.0f && hull_pct <= 1.0f);
10034  CLAMP(hull_pct, 0.1f, 1.0f);
10035 
10036  // shield
10037  if (sp->special_shield > 0) {
10038  shield_pct = shield_get_strength(objp) / sp->ship_max_shield_strength;
10039  } else if (Ship_info[sp->ship_info_index].max_shield_strength > 0.0f) {
10040  shield_pct = shield_get_strength(objp) / Ship_info[sp->ship_info_index].max_shield_strength;
10041  } else {
10042  shield_pct = 0.0f;
10043  }
10044 
10045  // extra check
10046  Assert(shield_pct >= 0.0f && shield_pct <= 1.0f);
10047  CLAMP(shield_pct, 0.0f, 1.0f);
10048  } else {
10049  shield_pct = hull_pct = 1.0f;
10050  }
10051 
10052  // subsystems
10053  int num_saved_subsystems = 0;
10054  char **subsys_names = new char *[sip_orig->n_subsystems];
10055  float *subsys_pcts = new float[sip_orig->n_subsystems];
10056 
10057  ss = GET_FIRST(&sp->subsys_list);
10058  while ( ss != END_OF_LIST(&sp->subsys_list) )
10059  {
10060  if (num_saved_subsystems == sip_orig->n_subsystems)
10061  {
10062  Error(LOCATION, "Subsystem mismatch while changing ship class from '%s' to '%s'!", sip_orig->name, sip->name);
10063  break;
10064  }
10065 
10066  // save subsys information
10067  subsys_names[num_saved_subsystems] = new char[NAME_LENGTH];
10068  strcpy(subsys_names[num_saved_subsystems], ss->system_info->subobj_name);
10069 
10070  if (ss->max_hits > 0.0f)
10071  subsys_pcts[num_saved_subsystems] = ss->current_hits / ss->max_hits;
10072  else
10073  subsys_pcts[num_saved_subsystems] = ss->max_hits;
10074 
10075  // extra check
10076  Assert(subsys_pcts[num_saved_subsystems] >= 0.0f && subsys_pcts[num_saved_subsystems] <= 1.0f);
10077  CLAMP(subsys_pcts[num_saved_subsystems], 0.0f, 1.0f);
10078 
10079  num_saved_subsystems++;
10080  ss = GET_NEXT(ss);
10081  }
10082 
10083  // point to new ship data
10084  ship_model_change(n, ship_type);
10085  sp->ship_info_index = ship_type;
10086 
10087  if (!Fred_running) {
10088  //WMC - set warp effects
10089  ship_set_warp_effects(objp, sip);
10090  }
10091 
10092  // set the correct hull strength
10093  if (Fred_running) {
10094  sp->ship_max_hull_strength = 100.0f;
10095  objp->hull_strength = 100.0f;
10096  } else {
10097  if (sp->special_hitpoints > 0) {
10099  } else {
10101  }
10102 
10103  objp->hull_strength = hull_pct * sp->ship_max_hull_strength;
10104  }
10105 
10107 
10108  // set the correct shield strength
10109  if (Fred_running) {
10110  if (sp->ship_max_shield_strength)
10111  sp->ship_max_shield_strength = 100.0f;
10112  objp->shield_quadrant[0] = 100.0f;
10113  } else {
10114  if (sp->special_shield >= 0) {
10116  } else {
10118  }
10119 
10120  shield_set_strength(objp, shield_pct * sp->ship_max_shield_strength);
10121  }
10122 
10123  // Goober5000: div-0 checks
10124  Assert(sp->ship_max_hull_strength > 0.0f);
10125  Assert(objp->hull_strength > 0.0f);
10126 
10127  // Mantis 2763: moved down to have access to the right ship_max_shield_strength value
10128  // make sure that shields are disabled/enabled if they need to be - Chief1983
10129  if (!Fred_running) {
10130  if ((p_objp->flags2 & P2_OF_FORCE_SHIELDS_ON) && (sp->ship_max_shield_strength > 0.0f)) {
10131  objp->flags &= ~OF_NO_SHIELDS;
10132  } else if ((p_objp->flags & P_OF_NO_SHIELDS) || (sp->ship_max_shield_strength == 0.0f)) {
10133  objp->flags |= OF_NO_SHIELDS;
10134  // Since there's not a mission flag set to be adjusting this, see if there was a change from a ship that normally has shields to one that doesn't, and vice versa
10135  } else if (!(sip_orig->flags2 & SIF2_INTRINSIC_NO_SHIELDS) && (sip->flags2 & SIF2_INTRINSIC_NO_SHIELDS)) {
10136  objp->flags |= OF_NO_SHIELDS;
10137  } else if ((sip_orig->flags2 & SIF2_INTRINSIC_NO_SHIELDS) && !(sip->flags2 & SIF2_INTRINSIC_NO_SHIELDS) && (sp->ship_max_shield_strength > 0.0f)) {
10138  objp->flags &= ~OF_NO_SHIELDS;
10139  }
10140  }
10141 
10142  // niffiwan: set new armor types
10143  sp->armor_type_idx = sip->armor_type_idx;
10147 
10148  // subsys stuff done only after hull stuff is set
10149  // if the subsystem list is not currently empty, then we need to clear it out first.
10151 
10152  // fix up the subsystems
10153  subsys_set( sp->objnum );
10154 
10155  // Goober5000 - restore the subsystem percentages
10156  ss = GET_FIRST(&sp->subsys_list);
10157  while ( ss != END_OF_LIST(&sp->subsys_list) )
10158  {
10159  for (i = 0; i < num_saved_subsystems; i++)
10160  {
10161  if (!subsystem_stricmp(ss->system_info->subobj_name, subsys_names[i]))
10162  {
10163  ss->current_hits = ss->max_hits * subsys_pcts[i];
10164  break;
10165  }
10166  }
10167 
10168  ss = GET_NEXT(ss);
10169  }
10171 
10172  // now free the memory
10173  for (i = 0; i < sip_orig->n_subsystems; i++)
10174  delete[] subsys_names[i];
10175 
10176  delete [] subsys_names;
10177  delete [] subsys_pcts;
10178 
10180  sp->cmeasure_count = MAX(0, sip->cmeasure_max - (sip_orig->cmeasure_max - sp->cmeasure_count));
10181 
10182  // avoid cases where either of these are 0
10183  if (sp->current_max_speed != 0 && sip_orig->max_speed != 0) {
10184  sp->current_max_speed = sip->max_speed * (sp->current_max_speed / sip_orig->max_speed);
10185  }
10186  else {
10187  sp->current_max_speed = sip->max_speed;
10188  }
10189 
10190  ship_set_default_weapons(sp, sip);
10192  ets_init_ship(&Objects[sp->objnum]);
10193 
10194  // Reset physics to previous values
10195  if (by_sexp) {
10199  Objects[sp->objnum].phys_info.fspeed = ph_inf.fspeed;
10200  Objects[sp->objnum].phys_info.heading = ph_inf.heading;
10202  Objects[sp->objnum].phys_info.prev_fvec = ph_inf.prev_fvec;
10205  Objects[sp->objnum].phys_info.rotvel = ph_inf.rotvel;
10209  Objects[sp->objnum].phys_info.speed = ph_inf.speed;
10210  Objects[sp->objnum].phys_info.vel = ph_inf.vel;
10212  }
10213 
10215 
10216  //======================================================
10217 
10218  // Bobboau's thruster stuff again
10219  if (sip->afterburner_trail.bitmap_id < 0)
10221 
10222  sp->ab_count = 0;
10223  if (sip->flags & SIF_AFTERBURNER)
10224  {
10225  polymodel *pm = model_get(sip->model_num);
10226 
10227  for (int h = 0; h < pm->n_thrusters; h++)
10228  {
10229  for (int j = 0; j < pm->thrusters[h].num_points; j++)
10230  {
10231  // this means you've reached the max # of AB trails for a ship
10233 
10234  trail_info *ci = &sp->ab_info[sp->ab_count];
10235 
10236  // only make ab trails for thrusters that are pointing backwards
10237  if (pm->thrusters[h].points[j].norm.xyz.z > -0.5)
10238  continue;
10239 
10240  ci->pt = pm->thrusters[h].points[j].pnt; //offset
10241  ci->w_start = pm->thrusters[h].points[j].radius * sip->afterburner_trail_width_factor; // width * table loaded width factor
10242 
10243  ci->w_end = 0.05f;//end width
10244 
10245  ci->a_start = 1.0f * sip->afterburner_trail_alpha_factor; // start alpha * table loaded alpha factor
10246 
10247  ci->a_end = 0.0f;//end alpha
10248 
10249  ci->max_life = sip->afterburner_trail_life; // table loaded max life
10250 
10251  ci->stamp = 60; //spew time???
10252 
10253  ci->n_fade_out_sections = sip->afterburner_trail_faded_out_sections; // table loaded n sections to be faded out
10254 
10255  ci->texture.bitmap_id = sip->afterburner_trail.bitmap_id; // table loaded bitmap used on this ships burner trails
10256  nprintf(("AB TRAIL", "AB trail point #%d made for '%s'\n", sp->ab_count, sp->ship_name));
10257  sp->ab_count++;
10259  }
10260  }
10261  }//end AB trails -Bobboau
10262 
10263  // Goober5000 - check other class-specific flags too
10264 
10265  if (sip->flags & SIF_STEALTH) // changing TO a stealthy ship class
10266  sp->flags2 |= SF2_STEALTH;
10267  else if (sip_orig->flags & SIF_STEALTH) // changing FROM a stealthy ship class
10268  sp->flags2 &= ~SF2_STEALTH;
10269 
10270  if (sip->flags & SIF_SHIP_CLASS_DONT_COLLIDE_INVIS) // changing TO a don't-collide-invisible ship class
10272  else if (sip_orig->flags & SIF_SHIP_CLASS_DONT_COLLIDE_INVIS) // changing FROM a don't-collide-invisible ship class
10274 
10275  if (sip->flags & SIF_NO_COLLIDE) // changing TO a no-collision ship class
10276  obj_set_flags(objp, objp->flags & ~OF_COLLIDES);
10277  else if (sip_orig->flags & SIF_NO_COLLIDE) // changing FROM a no-collision ship class
10278  obj_set_flags(objp, objp->flags | OF_COLLIDES);
10279 
10280  if (sip->flags2 & SIF2_NO_ETS)
10281  sp->flags2 |= SF2_NO_ETS;
10282  else if (sip_orig->flags2 & SIF2_NO_ETS)
10283  sp->flags2 &= ~SF2_NO_ETS;
10284 
10285 
10286  // Chief1983: Make sure that when changing to a new ship with secondaries, you switch to bank 0. They still won't
10287  // fire if the SF2_SECONDARIES_LOCKED flag is on as this should have carried over.
10288  if ( swp->num_secondary_banks > 0 && swp->current_secondary_bank == -1 ){
10289  swp->current_secondary_bank = 0;
10290  }
10291 
10292  // Bobboau's animation fixup
10293  for( i = 0; i<MAX_SHIP_PRIMARY_BANKS;i++){
10295  }
10296  for( i = 0; i<MAX_SHIP_SECONDARY_BANKS;i++){
10298  }
10300 
10301  //Reassign sound stuff
10302  ship_assign_sound(sp);
10303 
10304  // create new model instance data
10306 
10307  // Valathil - Reinitialize collision checks
10308  if ( Cmdline_old_collision_sys ) {
10309  obj_remove_pairs(objp);
10310  obj_add_pairs(OBJ_INDEX(objp));
10311  } else {
10313  obj_add_collider(OBJ_INDEX(objp));
10314  }
10315 
10316  // The E - If we're switching during gameplay, make sure we get valid primary/secondary selections
10317  if ( by_sexp ) {
10318  if (sip_orig->num_primary_banks > sip->num_primary_banks) {
10319  sp->weapons.current_primary_bank = 0;
10320  }
10321 
10322  if (sip_orig->num_secondary_banks > sip->num_secondary_banks) {
10324  }
10325 
10326  // While we're at it, let's copy over the ETS settings too
10327  sp->weapon_recharge_index = orig_wep_rechg_idx;
10328  sp->shield_recharge_index = orig_shd_rechg_idx;
10329  sp->engine_recharge_index = orig_eng_rechg_idx;
10330  }
10331 
10332  // zookeeper - If we're switching in the loadout screen, make sure we retain initial velocity set in FRED
10333  if (!(Game_mode & GM_IN_MISSION) && !(Fred_running)) {
10334  Objects[sp->objnum].phys_info.speed = (float) p_objp->initial_velocity * sip->max_speed / 100.0f;
10338  }
10339 
10340  // Goober5000 - if we're changing to a ship class that has a different default set of orders, update the orders
10341  // (this avoids wiping the orders if we're e.g. changing between fighter classes)
10342  if (Fred_running)
10343  {
10344  int old_defaults = ship_get_default_orders_accepted(sip_orig);
10345  int new_defaults = ship_get_default_orders_accepted(sip);
10346 
10347  if (old_defaults != new_defaults)
10348  sp->orders_accepted = new_defaults;
10349  }
10350 
10351  // Goober5000 - deal with texture replacement by re-applying the same code we used during parsing
10352  if (sp->ship_replacement_textures != NULL)
10353  {
10354  // clear them out because the new positions may be different
10355  for (i = 0; i < MAX_REPLACEMENT_TEXTURES; i++)
10356  sp->ship_replacement_textures[i] = -1;
10357 
10358  // now fill them in according to texture name
10359  for (SCP_vector<texture_replace>::iterator tr = p_objp->replacement_textures.begin(); tr != p_objp->replacement_textures.end(); ++tr)
10360  {
10361  int j;
10362  polymodel *pm = model_get(sip->model_num);
10363 
10364  // look for textures
10365  for (j = 0; j < pm->n_textures; j++)
10366  {
10367  texture_map *tmap = &pm->maps[j];
10368 
10369  int tnum = tmap->FindTexture(tr->old_texture);
10370  if(tnum > -1)
10371  sp->ship_replacement_textures[j * TM_NUM_TYPES + tnum] = tr->new_texture_id;
10372  }
10373  }
10374  }
10375 
10376  if (sip->uses_team_colors)
10377  {
10378  sp->team_name = sip->default_team_name;
10379  }
10380 }
10381 
10382 #ifndef NDEBUG
10383 
10387 {
10388  int i;
10389  ship *shipp = &Ships[objp->instance];
10390  vec3d wpos;
10391 
10393  return 0;
10394 
10395  // do timestamp stuff for next firing time
10396  shipp->weapons.next_primary_fire_stamp[0] = timestamp(250);
10398 
10399  // Debug code! Make the single laser fire only one bolt and from the object center!
10400  for (i=0; i<MAX_WEAPON_TYPES; i++)
10401  if (!stricmp(Weapon_info[i].name, NOX("Debug Laser")))
10402  break;
10403 
10404  vm_vec_add(&wpos, &objp->pos, &(objp->orient.vec.fvec) );
10405  if (i != MAX_WEAPONS) {
10406  int weapon_objnum;
10407  weapon_objnum = weapon_create( &wpos, &objp->orient, i, OBJ_INDEX(objp) );
10408  weapon_set_tracking_info(weapon_objnum, OBJ_INDEX(objp), Ai_info[shipp->ai_index].target_objnum);
10409  return 1;
10410  } else
10411  return 0;
10412 }
10413 #endif
10414 
10421 int ship_launch_countermeasure(object *objp, int rand_val)
10422 {
10424  return 0;
10425  }
10426 
10427  int check_count, cmeasure_count;
10428  int cobjnum=-1;
10429  vec3d pos;
10430  ship *shipp;
10431  ship_info *sip;
10432 
10433  shipp = &Ships[objp->instance];
10434  sip = &Ship_info[shipp->ship_info_index];
10435 
10436  int arand;
10437  if(rand_val < 0) {
10438  arand = myrand();
10439  } else {
10440  arand = rand_val;
10441  }
10442 
10443  // in the case where the server is an observer, he can launch countermeasures unless we do this.
10444  if( objp->type == OBJ_OBSERVER){
10445  return 0;
10446  }
10447 
10448  if ( !timestamp_elapsed(shipp->cmeasure_fire_stamp) ){
10449  return 0;
10450  }
10451 
10452  shipp->cmeasure_fire_stamp = timestamp(CMEASURE_WAIT); // Can launch every half second.
10453 #ifndef NDEBUG
10454  if (Weapon_energy_cheat) {
10455  shipp->cmeasure_count++;
10456  }
10457 #endif
10458 
10459  // we might check the count of countermeasures left depending on game state. Multiplayer clients
10460  // do not need to check any objects other than themselves for the count
10461  check_count = 1;
10462 
10463  if ( MULTIPLAYER_CLIENT && (objp != Player_obj) ){
10464  check_count = 0;
10465  }
10466 
10467  if ( check_count && ((shipp->cmeasure_count <= 0) || (sip->cmeasure_type < 0)) ) {
10468  if ( objp == Player_obj ) {
10469  if(sip->cmeasure_max < 1 || sip->cmeasure_type < 0) {
10470  //TODO: multi-lingual support
10471  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Not equipped with countermeasures", 1633));
10472  } else if(shipp->current_cmeasure < 0) {
10473  //TODO: multi-lingual support
10474  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No countermeasures selected", 1634));
10475  } else if(shipp->cmeasure_count <= 0) {
10476  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No more countermeasure charges.", 485));
10477  }
10479  }
10480 
10481  // if we have a player ship, then send the fired packet anyway so that the player
10482  // who fired will get his 'out of countermeasures' sound
10483  cmeasure_count = 0;
10484  if (objp->flags & OF_PLAYER_SHIP){
10485  // the new way of doing things
10486  if (Game_mode & GM_MULTIPLAYER){
10487  send_NEW_countermeasure_fired_packet(objp, cmeasure_count, -1);
10488  }
10489  return 0;
10490  }
10491 
10492  return 0;
10493  }
10494 
10495  cmeasure_count = shipp->cmeasure_count;
10496  shipp->cmeasure_count--;
10497 
10498  vm_vec_scale_add(&pos, &objp->pos, &objp->orient.vec.fvec, -objp->radius/2.0f);
10499 
10500  cobjnum = weapon_create(&pos, &objp->orient, shipp->current_cmeasure, OBJ_INDEX(objp));
10501  if (cobjnum >= 0)
10502  {
10503  cmeasure_set_ship_launch_vel(&Objects[cobjnum], objp, arand);
10504  nprintf(("Network", "Cmeasure created by %s\n", shipp->ship_name));
10505 
10506  // Play sound effect for counter measure launch
10508  if ( Weapon_info[shipp->current_cmeasure].launch_snd >= 0 ) {
10510  }
10511 
10512  // the new way of doing things
10513  if(Game_mode & GM_MULTIPLAYER){
10514  send_NEW_countermeasure_fired_packet(objp, cmeasure_count, Objects[cobjnum].net_signature);
10515  }
10516  }
10517 
10518  return (cobjnum >= 0); // return 0 if not fired, 1 otherwise
10519 }
10520 
10525 {
10526  ship_weapon *swp = &Player_ship->weapons;
10527  int stampval;
10528 
10530 
10531  if ( timestamp_elapsed(Laser_energy_out_snd_timer) )
10532  {
10533  // check timestamp according to ballistics
10535  {
10536  stampval = 500;
10537  }
10538  else
10539  {
10540  stampval = 50;
10541  }
10542  Laser_energy_out_snd_timer = timestamp(stampval);
10544  }
10545 }
10546 
10551 {
10553 
10554  if ( timestamp_elapsed(Missile_out_snd_timer) ) {
10555 
10556  if ( wip->wi_flags & WIF_SWARM ) {
10557  Missile_out_snd_timer = timestamp(500);
10558  } else {
10559  Missile_out_snd_timer = timestamp(50);
10560  }
10562  return 1;
10563  }
10564  return 0;
10565 }
10566 
10573 {
10574  int rval;
10575  float weapons_subsys_str;
10576 
10577  // If playing on lowest skill level, weapons will not fail due to subsystem damage
10578  if ( Game_skill_level == 0 ){
10579  return 0;
10580  }
10581 
10582  rval = 0;
10583  weapons_subsys_str = ship_get_subsystem_strength( sp, SUBSYSTEM_WEAPONS );
10584  if ( weapons_subsys_str < SUBSYS_WEAPONS_STR_FIRE_FAIL ) {
10585  rval = 1;
10586  }
10587  else if ( weapons_subsys_str < SUBSYS_WEAPONS_STR_FIRE_OK ) {
10588  // chance to fire depends on weapons subsystem strength
10589  if ( (frand()-0.2f) > weapons_subsys_str )
10590  rval = 1;
10591  }
10592 
10593  if (!rval) {
10594  // is subsystem disrupted?
10596  rval=1;
10597  }
10598  }
10599 
10600  return rval;
10601 }
10602 
10603 // create a moving tracer based upon a weapon which just fired
10604 float t_rad = 0.5f;
10605 float t_len = 10.0f;
10606 float t_vel = 0.2f;
10607 float t_min = 150.0f;
10608 float t_max = 300.0f;
10609 DCF(t_rad, "Sets weapon tracer radius")
10610 {
10611  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
10612  dc_printf("t_rad : %f\n", t_rad);
10613  return;
10614  }
10615 
10616  dc_stuff_float(&t_rad);
10617 }
10618 DCF(t_len, "Sets weapon tracer length")
10619 {
10620  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
10621  dc_printf("t_len : %f\n", t_len);
10622  return;
10623  }
10624 
10625  dc_stuff_float(&t_len);
10626 }
10627 DCF(t_vel, "Sets weapon tracer velocity")
10628 {
10629  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
10630  dc_printf("t_vel : %f\n", t_vel);
10631  return;
10632  }
10633 
10634  dc_stuff_float(&t_vel);
10635 }
10636 /*
10637  TODO: These two DCF's (and variables) are unused
10638 DCF(t_min, "")
10639 {
10640  dc_stuff_float(&t_min);
10641 }
10642 DCF(t_max, "")
10643 {
10644  dc_stuff_float(&t_max);
10645 }
10646 */
10647 void ship_fire_tracer(int weapon_objnum)
10648 {
10649  particle_info pinfo;
10650  object *objp = &Objects[weapon_objnum];
10652 
10653  // setup particle info
10654  memset(&pinfo, 0, sizeof(particle_info));
10655  pinfo.pos = objp->pos;
10656  pinfo.vel = objp->phys_info.vel;
10657  vm_vec_scale(&pinfo.vel, t_vel);
10658  pinfo.lifetime = wip->lifetime;
10659  pinfo.rad = t_rad;
10660  pinfo.type = PARTICLE_BITMAP;
10661  pinfo.optional_data = wip->laser_bitmap.first_frame;
10662  pinfo.tracer_length = t_len;
10663  pinfo.reverse = 0;
10664  pinfo.attached_objnum = -1;
10665  pinfo.attached_sig = 0;
10666 
10667  // create the particle
10668  particle_create(&pinfo);
10669 }
10670 
10674 int ship_stop_fire_primary_bank(object * obj, int bank_to_stop)
10675 {
10676  ship *shipp;
10677  ship_weapon *swp;
10678 
10679  if(obj == NULL){
10680  return 0;
10681  }
10682 
10683  if(obj->type != OBJ_SHIP){
10684  return 0;
10685  }
10686 
10687  shipp = &Ships[obj->instance];
10688  swp = &shipp->weapons;
10689 
10690  if(Ship_info[shipp->ship_info_index].draw_primary_models[bank_to_stop]){
10691  if(shipp->primary_rotate_rate[bank_to_stop] > 0.0f)
10693  if(shipp->primary_rotate_rate[bank_to_stop] < 0.0f)shipp->primary_rotate_rate[bank_to_stop] = 0.0f;
10694  shipp->primary_rotate_ang[bank_to_stop] += shipp->primary_rotate_rate[bank_to_stop]*flFrametime;
10695  if(shipp->primary_rotate_ang[bank_to_stop] > PI2)shipp->primary_rotate_ang[bank_to_stop] -= PI2;
10696  if(shipp->primary_rotate_ang[bank_to_stop] < 0.0f)shipp->primary_rotate_ang[bank_to_stop] += PI2;
10697  }
10698 
10699  if(shipp->was_firing_last_frame[bank_to_stop] == 0)
10700  return 0;
10701 
10702  shipp->was_firing_last_frame[bank_to_stop] = 0;
10703 
10704  return 1;
10705 }
10706 
10707 
10712 {
10713  int i, num_primary_banks = 0, bank_to_stop = 0;
10714  ship *shipp;
10715  ship_weapon *swp;
10716 
10717  if(obj == NULL){
10718  return 0;
10719  }
10720 
10721  if(obj->type != OBJ_SHIP){
10722  return 0;
10723  }
10724 
10725  shipp = &Ships[obj->instance];
10726  swp = &shipp->weapons;
10727 
10728  bank_to_stop = swp->current_primary_bank;
10729 
10730  if ( shipp->flags & SF_PRIMARY_LINKED ) {
10731  num_primary_banks = swp->num_primary_banks;
10732  } else {
10733  num_primary_banks = MIN(1, swp->num_primary_banks);
10734  }
10735 
10736  for ( i = 0; i < num_primary_banks; i++ ) {
10737  // Goober5000 - allow more than two banks
10738  bank_to_stop = (swp->current_primary_bank+i) % swp->num_primary_banks;
10739  //only stop if it was fireing last frame
10740  ship_stop_fire_primary_bank(obj, bank_to_stop);
10741  }
10742  for(i = 0; i<swp->num_primary_banks+num_primary_banks;i++)
10744 
10745  return 1;
10746 }
10747 
10748 
10749 
10750 int tracers[MAX_SHIPS][4][4];
10751 
10753 
10754 // fires a primary weapon for the given object. It also handles multiplayer cases.
10755 // in multiplayer, the starting network signature, and number of banks fired are sent
10756 // to all the clients in the game. All the info is passed to send_primary at the end of
10757 // the function. The check_energy parameter (defaults to 1) tells us whether or not
10758 // we should check the energy. It will be 0 when a multiplayer client is firing an AI
10759 // primary.
10760 int ship_fire_primary(object * obj, int stream_weapons, int force)
10761 {
10762  vec3d gun_point, pnt, firing_pos, target_position, target_velocity_vec;
10763  int n = obj->instance;
10764  ship *shipp;
10765  ship_weapon *swp;
10766  ship_info *sip;
10767  ai_info *aip;
10768  int weapon_idx, i, j, w, v, weapon_objnum;
10769  int bank_to_fire, num_fired = 0;
10770  int banks_fired; // used for multiplayer to help determine whether or not to send packet
10771  banks_fired = 0; // used in multiplayer -- bitfield of banks that were fired
10772  bool has_fired = false; // used to determine whether we should fire the scripting hook
10773  bool has_autoaim, has_converging_autoaim, needs_target_pos; // used to flag weapon/ship as having autoaim
10774  float autoaim_fov = 0; // autoaim limit
10775  float dist_to_target = 0; // distance to target, for autoaim & automatic convergence
10776 
10777  int sound_played; // used to track what sound is played. If the player is firing two banks
10778  // of the same laser, we only want to play one sound
10779  Assert( obj != NULL );
10780 
10781  if(obj == NULL){
10782  return 0;
10783  }
10784 
10785  // in the case where the server is an observer, he can fire (which) would be bad - unless we do this.
10786  if( obj->type == OBJ_OBSERVER){
10787  return 0;
10788  }
10789 
10790  Assert( obj->type == OBJ_SHIP );
10791  Assert( n >= 0 );
10792  Assert( Ships[n].objnum == OBJ_INDEX(obj));
10793  if((obj->type != OBJ_SHIP) || (n < 0) || (n >= MAX_SHIPS) || (Ships[n].objnum != OBJ_INDEX(obj))){
10794  return 0;
10795  }
10796 
10797  shipp = &Ships[n];
10798  swp = &shipp->weapons;
10799 
10800  // bogus
10801  if((shipp->ship_info_index < 0) || (shipp->ship_info_index >= static_cast<int>(Ship_info.size()))){
10802  return 0;
10803  }
10804  if((shipp->ai_index < 0) || (shipp->ai_index >= MAX_AI_INFO)){
10805  return 0;
10806  }
10807  sip = &Ship_info[shipp->ship_info_index];
10808  aip = &Ai_info[shipp->ai_index];
10809 
10810  if ( swp->num_primary_banks <= 0 ) {
10811  return 0;
10812  }
10813 
10814  if ( swp->current_primary_bank < 0 ){
10815  return 0;
10816  }
10817 
10818  // If the primaries have been locked, bail
10819  if (shipp->flags2 & SF2_PRIMARIES_LOCKED)
10820  {
10821  return 0;
10822  }
10823 
10824  sound_played = -1;
10825 
10826  // Fire the correct primary bank. If primaries are linked (SF_PRIMARY_LINKED set), then fire
10827  // both primary banks.
10828  int num_primary_banks;
10829 
10830  if ( shipp->flags & SF_PRIMARY_LINKED ) {
10831  num_primary_banks = swp->num_primary_banks;
10832  } else {
10833  num_primary_banks = MIN(1, swp->num_primary_banks);
10834  }
10835 
10836  Assert(num_primary_banks > 0);
10837  if (num_primary_banks < 1){
10838  return 0;
10839  }
10840 
10841  // if we're firing stream weapons, but the trigger is not down, do nothing
10842  if(stream_weapons && !(shipp->flags & SF_TRIGGER_DOWN)){
10843  return 0;
10844  }
10845 
10846  if(num_primary_banks == 1)
10847  for(i = 0; i<swp->num_primary_banks; i++){
10849  }
10850 
10851  // lets start gun convergence / autoaim code from here - Wanderer
10852  has_converging_autoaim = ((sip->aiming_flags & AIM_FLAG_AUTOAIM_CONVERGENCE || (The_mission.ai_profile->player_autoaim_fov[Game_skill_level] > 0.0f && !( Game_mode & GM_MULTIPLAYER ))) && aip->target_objnum != -1);
10853  has_autoaim = ((has_converging_autoaim || (sip->aiming_flags & AIM_FLAG_AUTOAIM)) && aip->target_objnum != -1);
10854  needs_target_pos = ((has_autoaim || (sip->aiming_flags & AIM_FLAG_AUTO_CONVERGENCE)) && aip->target_objnum != -1);
10855 
10856  if (needs_target_pos) {
10857  if (has_autoaim) {
10859  }
10860 
10861  // If a subsystem is targeted, fire in that direction instead
10862  if (aip->targeted_subsys != NULL)
10863  {
10864  get_subsystem_world_pos(&Objects[aip->target_objnum], aip->targeted_subsys, &target_position);
10865  }
10866  else
10867  {
10868  target_position = Objects[aip->target_objnum].pos;
10869  }
10870 
10871  dist_to_target = vm_vec_dist_quick(&target_position, &obj->pos);
10872  }
10873 
10874  for ( i = 0; i < num_primary_banks; i++ ) {
10875  // Goober5000 - allow more than two banks
10876  bank_to_fire = (swp->current_primary_bank+i) % swp->num_primary_banks;
10877 
10878 
10879  weapon_idx = swp->primary_bank_weapons[bank_to_fire];
10880  Assert( weapon_idx >= 0 && weapon_idx < MAX_WEAPON_TYPES );
10881  if ( (weapon_idx < 0) || (weapon_idx >= MAX_WEAPON_TYPES) ) {
10882  Int3(); // why would a ship try to fire a weapon that doesn't exist?
10883  continue;
10884  }
10885 
10886  if (swp->primary_animation_position[bank_to_fire] == MA_POS_SET) {
10887  if ( timestamp_elapsed(swp->primary_animation_done_time[bank_to_fire]) )
10888  swp->primary_animation_position[bank_to_fire] = MA_POS_READY;
10889  else
10890  continue;
10891  }
10892 
10893  weapon_info* winfo_p = &Weapon_info[weapon_idx];
10894 
10895  if (needs_target_pos) {
10896  target_velocity_vec = Objects[aip->target_objnum].phys_info.vel;
10898  vm_vec_scale_sub2(&target_velocity_vec, &obj->phys_info.vel, winfo_p->vel_inherit_amount);
10899  }
10900 
10901  if(sip->draw_primary_models[bank_to_fire]){
10902  if(shipp->primary_rotate_rate[bank_to_fire] < winfo_p->weapon_submodel_rotate_vel)
10903  shipp->primary_rotate_rate[bank_to_fire] += winfo_p->weapon_submodel_rotate_accell*flFrametime;
10904  if(shipp->primary_rotate_rate[bank_to_fire] > winfo_p->weapon_submodel_rotate_vel)shipp->primary_rotate_rate[bank_to_fire] = winfo_p->weapon_submodel_rotate_vel;
10905  shipp->primary_rotate_ang[bank_to_fire] += shipp->primary_rotate_rate[bank_to_fire]*flFrametime;
10906  if(shipp->primary_rotate_ang[bank_to_fire] > PI2)shipp->primary_rotate_ang[bank_to_fire] -= PI2;
10907  if(shipp->primary_rotate_ang[bank_to_fire] < 0.0f)shipp->primary_rotate_ang[bank_to_fire] += PI2;
10908 
10909  if(shipp->primary_rotate_rate[bank_to_fire] < winfo_p->weapon_submodel_rotate_vel)continue;
10910  }
10911  // if this is a targeting laser, start it up ///- only targeting laser if it is tag-c, otherwise it's a fighter beam -Bobboau
10912  if((winfo_p->wi_flags & WIF_BEAM) && (winfo_p->tag_level == 3) && (shipp->flags & SF_TRIGGER_DOWN) && (winfo_p->b_info.beam_type == BEAM_TYPE_C) ){
10914  continue;
10915  }
10916 
10917  // if we're firing stream weapons and this is a non stream weapon, skip it
10918  if(stream_weapons && !(winfo_p->wi_flags & WIF_STREAM)){
10919  continue;
10920  }
10921  // if we're firing non stream weapons and this is a stream weapon, skip it
10922  if(!stream_weapons && (winfo_p->wi_flags & WIF_STREAM)){
10923  continue;
10924  }
10925 
10926  // only non-multiplayer clients (single, multi-host) need to do timestamp checking
10927  if ( !timestamp_elapsed(swp->next_primary_fire_stamp[bank_to_fire]) ) {
10928  continue;
10929  }
10930 
10931  // if weapons are linked and this is a nolink weapon, skip it
10932  if (shipp->flags & SF_PRIMARY_LINKED && winfo_p->wi_flags3 & WIF3_NOLINK) {
10933  continue;
10934  }
10935 
10936  // do timestamp stuff for next firing time
10937  float next_fire_delay;
10938  bool fast_firing = false;
10939  if (winfo_p->burst_shots > swp->burst_counter[bank_to_fire]) {
10940  next_fire_delay = winfo_p->burst_delay * 1000.0f;
10941  swp->burst_counter[bank_to_fire]++;
10942  if (winfo_p->burst_flags & WBF_FAST_FIRING)
10943  fast_firing = true;
10944  } else if (winfo_p->max_delay != 0.0f && winfo_p->min_delay != 0.0f) { // Random fire delay (DahBlount)
10945  next_fire_delay = (((float)rand()) / (((float)RAND_MAX + 1.0f) * (winfo_p->max_delay - winfo_p->min_delay + 1.0f) + winfo_p->min_delay)) * 1000.0f;
10946  } else {
10947  next_fire_delay = winfo_p->fire_wait * 1000.0f;
10948  swp->burst_counter[bank_to_fire] = 0;
10949  }
10950  if (!((obj->flags & OF_PLAYER_SHIP) || (fast_firing))) {
10951  if (shipp->team == Ships[Player_obj->instance].team){
10952  next_fire_delay *= aip->ai_ship_fire_delay_scale_friendly;
10953  } else {
10954  next_fire_delay *= aip->ai_ship_fire_delay_scale_hostile;
10955  }
10956  }
10957 
10958  polymodel *pm = model_get( sip->model_num );
10959 
10960  // Goober5000 (thanks to _argv[-1] for the original idea)
10961  if ( (num_primary_banks > 1) && !(winfo_p->wi_flags3 & WIF3_NO_LINKED_PENALTY) && !(The_mission.ai_profile->flags & AIPF_DISABLE_LINKED_FIRE_PENALTY) )
10962  {
10963  int effective_primary_banks = 0;
10964  for (int it = 0; it < num_primary_banks; it++)
10965  {
10966  if ((it == bank_to_fire) || !(Weapon_info[swp->primary_bank_weapons[it]].wi_flags3 & (WIF3_NOLINK | WIF3_NO_LINKED_PENALTY)))
10967  effective_primary_banks++;
10968  }
10969  Assert(effective_primary_banks >= 1);
10970 
10971  next_fire_delay *= 1.0f + (effective_primary_banks - 1) * 0.5f; // 50% time penalty if banks linked
10972  }
10973 
10974  if (winfo_p->fof_spread_rate > 0.0f)
10975  {
10976  //Adjust the primary_bank_fof_cooldown based on how long it's been since the last shot.
10977  float reset_amount = (timestamp_until(swp->last_primary_fire_stamp[bank_to_fire]) / 1000.0f) * winfo_p->fof_reset_rate;
10978  swp->primary_bank_fof_cooldown[bank_to_fire] += winfo_p->fof_spread_rate + reset_amount;
10979  CLAMP(swp->primary_bank_fof_cooldown[bank_to_fire], 0.0f, 1.0f);
10980  }
10981 
10982  // MK, 2/4/98: Since you probably were allowed to fire earlier, but couldn't fire until your frame interval
10983  // rolled around, subtract out up to half the previous frametime.
10984  // Note, unless we track whether the fire button has been held down, and not tapped, it's hard to
10985  // know how much time to subtract off. It could be this fire is "late" because the user didn't want to fire.
10986  if ((next_fire_delay > 0.0f)) {
10987  if (obj->flags & OF_PLAYER_SHIP) {
10988  int t = timestamp_until(swp->next_primary_fire_stamp[bank_to_fire]);
10989  if (t < 0) {
10990  float tx;
10991 
10992  tx = (float) t/-1000.0f;
10993  if (tx > flFrametime/2.0f){
10994  tx = 1000.0f * flFrametime * 0.7f;
10995  }
10996  next_fire_delay -= tx;
10997  }
10998 
10999  if ((int) next_fire_delay < 1){
11000  next_fire_delay = 1.0f;
11001  }
11002  }
11003 
11004  swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay));
11005  swp->last_primary_fire_stamp[bank_to_fire] = timestamp();
11006  }
11007 
11008  if (sip->flags2 & SIF2_DYN_PRIMARY_LINKING ) {
11009  Assert(pm->gun_banks[bank_to_fire].num_slots != 0);
11010  swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay * ( swp->primary_bank_slot_count[ bank_to_fire ] ) / pm->gun_banks[bank_to_fire].num_slots ) );
11011  swp->last_primary_fire_stamp[bank_to_fire] = timestamp();
11012  } else if (winfo_p->wi_flags2 & WIF2_CYCLE) {
11013  Assert(pm->gun_banks[bank_to_fire].num_slots != 0);
11014  swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay / pm->gun_banks[bank_to_fire].num_slots));
11015  swp->last_primary_fire_stamp[bank_to_fire] = timestamp();
11016  //to maintain balance of fighters with more fire points they will fire faster than ships with fewer points
11017  }else{
11018  swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay));
11019  swp->last_primary_fire_stamp[bank_to_fire] = timestamp();
11020  }
11021  // Here is where we check if weapons subsystem is capable of firing the weapon.
11022  // Note that we can have partial bank firing, if the weapons subsystem is partially
11023  // functional, which should be cool.
11024  if ( ship_weapon_maybe_fail(shipp) && !force) {
11025  if ( obj == Player_obj ) {
11027  }
11028  ship_stop_fire_primary_bank(obj, bank_to_fire);
11029  continue;
11030  }
11031 
11032 
11033  if ( pm->n_guns > 0 ) {
11034  int num_slots = pm->gun_banks[bank_to_fire].num_slots;
11035  vec3d predicted_target_pos, plr_to_target_vec;
11036  vec3d player_forward_vec = obj->orient.vec.fvec;
11037  bool in_automatic_aim_fov = false;
11038  float dist_to_aim = 0;
11039 
11040  // more autoaim stuff here - Wanderer
11041  // needs weapon speed
11042  if (needs_target_pos) {
11043  float time_to_target, angle_to_target;
11044  vec3d last_delta_vec;
11045 
11046  time_to_target = 0.0f;
11047 
11048  if (winfo_p->max_speed != 0)
11049  {
11050  time_to_target = dist_to_target / winfo_p->max_speed;
11051  }
11052 
11053  vm_vec_scale_add(&predicted_target_pos, &target_position, &target_velocity_vec, time_to_target);
11054  polish_predicted_target_pos(winfo_p, &Objects[aip->target_objnum], &target_position, &predicted_target_pos, dist_to_target, &last_delta_vec, 1);
11055  vm_vec_sub(&plr_to_target_vec, &predicted_target_pos, &obj->pos);
11056 
11057  if (has_autoaim) {
11058  angle_to_target = vm_vec_delta_ang(&player_forward_vec, &plr_to_target_vec, NULL);
11059  if (angle_to_target < autoaim_fov)
11060  in_automatic_aim_fov = true;
11061  }
11062 
11063  dist_to_aim = vm_vec_mag_quick(&plr_to_target_vec);
11064 
11065  // minimum convergence distance
11066  if (sip->minimum_convergence_distance > dist_to_aim) {
11067  float dist_mult;
11068  dist_mult = sip->minimum_convergence_distance / dist_to_aim;
11069  vm_vec_scale_add(&predicted_target_pos, &obj->pos, &plr_to_target_vec, dist_mult);
11070  }
11071  }
11072 
11073  if(winfo_p->wi_flags & WIF_BEAM){ // the big change I made for fighter beams, if there beams fill out the Fire_Info for a targeting laser then fire it, for each point in the weapon bank -Bobboau
11074  float t;
11075  if (winfo_p->burst_shots > swp->burst_counter[bank_to_fire]) {
11076  t = winfo_p->burst_delay;
11077  swp->burst_counter[bank_to_fire]++;
11078  } else {
11079  t = winfo_p->fire_wait;//doing that time scale thing on enemy fighter is just ugly with beams, especaly ones that have careful timeing
11080  swp->burst_counter[bank_to_fire] = 0;
11081  }
11082  swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int) (t * 1000.0f));
11083  swp->last_primary_fire_stamp[bank_to_fire] = timestamp();
11084  beam_fire_info fbfire_info;
11085 
11086  int points;
11087  if (winfo_p->b_info.beam_shots){
11088  if (winfo_p->b_info.beam_shots > num_slots){
11089  points = num_slots;
11090  }else{
11091  points = winfo_p->b_info.beam_shots;
11092  }
11093  }else{
11094  points = num_slots;
11095  }
11096 
11097  if ( shipp->weapon_energy < points*winfo_p->energy_consumed*flFrametime)
11098  {
11099  swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay));
11100  if ( obj == Player_obj )
11101  {
11103  }
11104  ship_stop_fire_primary_bank(obj, bank_to_fire);
11105  continue;
11106  }
11107 
11108  shipp->beam_sys_info.turret_norm.xyz.x = 0.0f;
11109  shipp->beam_sys_info.turret_norm.xyz.y = 0.0f;
11110  shipp->beam_sys_info.turret_norm.xyz.z = 1.0f;
11111  shipp->beam_sys_info.model_num = sip->model_num;
11112  shipp->beam_sys_info.turret_gun_sobj = pm->detail[0];
11113  shipp->beam_sys_info.turret_num_firing_points = 1; // dummy turret info is used per firepoint
11114  shipp->beam_sys_info.turret_fov = cosf((winfo_p->field_of_fire != 0.0f)?winfo_p->field_of_fire:180);
11115 
11120 
11121  fbfire_info.target_subsys = Ai_info[shipp->ai_index].targeted_subsys;
11122  fbfire_info.beam_info_index = shipp->weapons.primary_bank_weapons[bank_to_fire];
11123  fbfire_info.beam_info_override = NULL;
11124  fbfire_info.shooter = &Objects[shipp->objnum];
11125 
11126  if (aip->target_objnum >= 0) {
11127  fbfire_info.target = &Objects[aip->target_objnum];
11128  } else {
11129  fbfire_info.target = NULL;
11130  }
11131  fbfire_info.turret = &shipp->fighter_beam_turret_data;
11132  fbfire_info.bfi_flags = BFIF_IS_FIGHTER_BEAM;
11133  fbfire_info.bank = bank_to_fire;
11134 
11135  for ( v = 0; v < points; v++ ){
11136  if(winfo_p->b_info.beam_shots){
11137  j = (shipp->last_fired_point[bank_to_fire]+1)%num_slots;
11138  shipp->last_fired_point[bank_to_fire] = j;
11139  }else{
11140  j=v;
11141  }
11142 
11143  fbfire_info.targeting_laser_offset = pm->gun_banks[bank_to_fire].pnt[j];
11144  shipp->beam_sys_info.pnt = pm->gun_banks[bank_to_fire].pnt[j];
11145  shipp->beam_sys_info.turret_firing_point[0] = pm->gun_banks[bank_to_fire].pnt[j];
11146 
11147  fbfire_info.point = j;
11148 
11149  beam_fire(&fbfire_info);
11150  has_fired = true;
11151  num_fired++;
11152  }
11153  }
11154  else //if this isn't a fighter beam, do it normally -Bobboau
11155  {
11156  int points = 0, numtimes = 1;
11157 
11158  // ok if this is a cycling weapon use shots as the number of points to fire from at a time
11159  // otherwise shots is the number of times all points will be fired (used mostly for the 'shotgun' effect)
11160  if ( sip->flags2 & SIF2_DYN_PRIMARY_LINKING ) {
11161  numtimes = 1;
11162  points = MIN( num_slots, swp->primary_bank_slot_count[ bank_to_fire ] );
11163  } else if ( winfo_p->wi_flags2 & WIF2_CYCLE ) {
11164  numtimes = 1;
11165  points = MIN(num_slots, winfo_p->shots);
11166  } else {
11167  numtimes = winfo_p->shots;
11168  points = num_slots;
11169  }
11170 
11171  // The energy-consumption code executes even for ballistic primaries, because
11172  // there may be a reason why you want to have ballistics consume energy. Perhaps
11173  // you can't fire too many too quickly or they'll overheat. If not, just set
11174  // the weapon's energy_consumed to 0 and it'll work just fine. - Goober5000
11175 
11176  // fail unless we're forcing (energy based primaries)
11177  if ( (shipp->weapon_energy < points*numtimes * winfo_p->energy_consumed) //was num_slots
11178  && !force ) {
11179 
11180  swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay));
11181  if ( obj == Player_obj )
11182  {
11184  }
11185  ship_stop_fire_primary_bank(obj, bank_to_fire);
11186  continue;
11187  }
11188  // moved the above to here to use points instead of num_slots for energy consumption check
11189 
11190  // ballistics support for primaries - Goober5000
11191  if ( winfo_p->wi_flags2 & WIF2_BALLISTIC )
11192  {
11193  // Make sure this ship is set up for ballistics.
11194  // If you get this error, add the ballistic primaries tags to ships.tbl.
11196 
11197  // If ship is being repaired/rearmed, it cannot fire ballistics
11198  if ( aip->ai_flags & AIF_BEING_REPAIRED )
11199  {
11200  continue;
11201  }
11202 
11203  // duplicated from the secondaries firing routine...
11204  // determine if there is enough ammo left to fire weapons on this bank. As with primary
11205  // weapons, we might or might not check ammo counts depending on game mode, who is firing,
11206  // and if I am a client in multiplayer
11207  int check_ammo = 1;
11208 
11209  if ( MULTIPLAYER_CLIENT && (obj != Player_obj) )
11210  {
11211  check_ammo = 0;
11212  }
11213 
11214  // not enough ammo
11215  if ( check_ammo && ( swp->primary_bank_ammo[bank_to_fire] <= 0) )
11216  {
11217  if ( obj == Player_obj )
11218  {
11220  }
11221  else
11222  {
11223  // TODO: AI switch primary weapon / re-arm?
11224  }
11225  continue;
11226  }
11227 
11228  // deplete ammo
11229  if ( Weapon_energy_cheat == 0 )
11230  {
11231  swp->primary_bank_ammo[bank_to_fire] -= points*numtimes;
11232 
11233  // make sure we don't go below zero; any such error is excusable
11234  // because it only happens when the bank is depleted in one shot
11235  if (swp->primary_bank_ammo[bank_to_fire] < 0)
11236  {
11237  swp->primary_bank_ammo[bank_to_fire] = 0;
11238  }
11239  }
11240  }
11241 
11242  // now handle the energy as usual
11243  // deplete the weapon reserve energy by the amount of energy used to fire the weapon
11244  // Only subtract the energy amount required for equipment operation once
11245  shipp->weapon_energy -= points*numtimes * winfo_p->energy_consumed;
11246  // note for later: option for fuel!
11247 
11248  // Mark all these weapons as in the same group
11249  int new_group_id = weapon_create_group_id();
11250 
11251  vec3d total_impulse;
11252  vec3d *firepoint_list;
11253  size_t current_firepoint = 0;
11254 
11255  if (winfo_p->wi_flags3 & WIF3_APPLY_RECOIL){
11256  firepoint_list = new vec3d[numtimes * points];
11257  vm_vec_zero(&total_impulse);
11258  } else {
11259  firepoint_list = nullptr;
11260  }
11261 
11262  for ( w = 0; w < numtimes; w++ ) {
11263  polymodel *weapon_model = NULL;
11264  if(winfo_p->external_model_num >= 0)
11265  weapon_model = model_get(winfo_p->external_model_num);
11266 
11267  if (weapon_model)
11268  if ((weapon_model->n_guns <= swp->external_model_fp_counter[bank_to_fire]) || (swp->external_model_fp_counter[bank_to_fire] < 0))
11269  swp->external_model_fp_counter[bank_to_fire] = 0;
11270 
11271  for ( j = 0; j < points; j++ ) {
11272  int pt; //point
11273  if ( (winfo_p->wi_flags2 & WIF2_CYCLE) || (sip->flags2 & SIF2_DYN_PRIMARY_LINKING) ){
11274  pt = (shipp->last_fired_point[bank_to_fire]+1)%num_slots;
11275  }else{
11276  pt = j;
11277  }
11278 
11279  int sub_shots = 1;
11280  // Use 0 instead of bank_to_fire as index when checking the number of external weapon model firingpoints
11281  if (weapon_model && weapon_model->n_guns)
11282  if (!(winfo_p->wi_flags2 & WIF2_EXTERNAL_WEAPON_FP))
11283  sub_shots = weapon_model->gun_banks[0].num_slots;
11284 
11285  for(int s = 0; s<sub_shots; s++){
11286  pnt = pm->gun_banks[bank_to_fire].pnt[pt];
11287  // Use 0 instead of bank_to_fire as index to external weapon model firingpoints
11288  if (weapon_model && weapon_model->n_guns) {
11289  if (winfo_p->wi_flags2 & WIF2_EXTERNAL_WEAPON_FP) {
11290  vm_vec_add2(&pnt, &weapon_model->gun_banks[0].pnt[swp->external_model_fp_counter[bank_to_fire]]);
11291  } else {
11292  vm_vec_add2(&pnt, &weapon_model->gun_banks[0].pnt[s]);
11293  }
11294  }
11295 
11296  vm_vec_unrotate(&gun_point, &pnt, &obj->orient);
11297  vm_vec_add(&firing_pos, &gun_point, &obj->pos);
11298 
11299  matrix firing_orient;
11300 
11301  /* I AIM autoaim convergence
11302  II AIM autoaim
11303  III AIM auto convergence
11304  IV AIM std convergence
11305  V SIF convergence
11306  no convergence or autoaim
11307  */
11308  if (has_autoaim && in_automatic_aim_fov) {
11309  vec3d firing_vec;
11310 
11311  if (has_converging_autoaim) {
11312  // converging autoaim
11313  vm_vec_sub(&firing_vec, &predicted_target_pos, &firing_pos);
11314  } else {
11315  // autoaim
11316  vm_vec_sub(&firing_vec, &predicted_target_pos, &obj->pos);
11317  }
11318 
11319  vm_vector_2_matrix(&firing_orient, &firing_vec, NULL, NULL);
11320  } else if ((sip->aiming_flags & AIM_FLAG_STD_CONVERGENCE) || ((sip->aiming_flags & AIM_FLAG_AUTO_CONVERGENCE) && (aip->target_objnum != -1))) {
11321  // std & auto convergence
11322  vec3d target_vec, firing_vec, convergence_offset;
11323 
11324  // make sure vector is of the set length
11325  vm_vec_copy_normalize(&target_vec, &player_forward_vec);
11326  if ((sip->aiming_flags & AIM_FLAG_AUTO_CONVERGENCE) && (aip->target_objnum != -1)) {
11327  // auto convergence
11328  vm_vec_scale(&target_vec, dist_to_aim);
11329  } else {
11330  // std convergence
11331  vm_vec_scale(&target_vec, sip->convergence_distance);
11332  }
11333 
11334  // if there is convergence offset then make use of it)
11336  vm_vec_unrotate(&convergence_offset, &sip->convergence_offset, &obj->orient);
11337  vm_vec_add2(&target_vec, &convergence_offset);
11338  }
11339 
11340  vm_vec_add2(&target_vec, &obj->pos);
11341  vm_vec_sub(&firing_vec, &target_vec, &firing_pos);
11342 
11343  // set orientation
11344  vm_vector_2_matrix(&firing_orient, &firing_vec, NULL, NULL);
11345  } else if (sip->aiming_flags & AIM_FLAG_STD_CONVERGENCE) {
11346  // fixed distance convergence
11347  vec3d target_vec, firing_vec, convergence_offset;
11348 
11349  // make sure vector is of the set length
11350  vm_vec_copy_normalize(&target_vec, &player_forward_vec);
11351  vm_vec_scale(&target_vec, sip->convergence_distance);
11352 
11353  // if there is convergence offset then make use of it)
11355  vm_vec_unrotate(&convergence_offset, &sip->convergence_offset, &obj->orient);
11356  vm_vec_add2(&target_vec, &convergence_offset);
11357  }
11358 
11359  vm_vec_add2(&target_vec, &obj->pos);
11360  vm_vec_sub(&firing_vec, &target_vec, &firing_pos);
11361 
11362  // set orientation
11363  vm_vector_2_matrix(&firing_orient, &firing_vec, NULL, NULL);
11364  } else if (sip->flags2 & SIF2_GUN_CONVERGENCE) {
11365  // model file defined convergence
11366  vec3d firing_vec;
11367  vm_vec_unrotate(&firing_vec, &pm->gun_banks[bank_to_fire].norm[pt], &obj->orient);
11368  vm_vector_2_matrix(&firing_orient, &firing_vec, NULL, NULL);
11369  } else {
11370  // no autoaim or convergence
11371  firing_orient = obj->orient;
11372  }
11373 
11374  if (winfo_p->wi_flags3 & WIF3_APPLY_RECOIL){ // Function to add recoil functionality - DahBlount
11375  vec3d local_impulse = firing_orient.vec.fvec;
11376 
11377  float recoil_force = (winfo_p->mass * winfo_p->max_speed * winfo_p->recoil_modifier * sip->ship_recoil_modifier);
11378 
11379  firepoint_list[current_firepoint++] = firing_pos;
11380 
11381  vm_vec_scale(&local_impulse, (-1 * recoil_force));
11382  vm_vec_add2(&total_impulse, &local_impulse);
11383  }
11384 
11385  // create the weapon -- the network signature for multiplayer is created inside
11386  // of weapon_create
11387  weapon_objnum = weapon_create( &firing_pos, &firing_orient, weapon_idx, OBJ_INDEX(obj), new_group_id,
11388  0, 0, swp->primary_bank_fof_cooldown[bank_to_fire] );
11389  winfo_p = &Weapon_info[Weapons[Objects[weapon_objnum].instance].weapon_info_index];
11390  has_fired = true;
11391 
11393 
11394  if (winfo_p->wi_flags & WIF_FLAK)
11395  {
11396  object *target;
11397  vec3d predicted_pos;
11398  float flak_range=(winfo_p->lifetime)*(winfo_p->max_speed);
11399  float range_to_target = flak_range;
11400  float wepstr=ship_get_subsystem_strength(shipp, SUBSYSTEM_WEAPONS);
11401 
11402  if (aip->target_objnum != -1) {
11403  target = &Objects[aip->target_objnum];
11404  } else {
11405  target = NULL;
11406  }
11407 
11408  if (target != NULL) {
11409  set_predicted_enemy_pos(&predicted_pos, obj, &target->pos, &target->phys_info.vel, aip);
11410  range_to_target=vm_vec_dist(&predicted_pos, &obj->pos);
11411  }
11412 
11413  //if we have a target and its in range
11414  if ( (target != NULL) && (range_to_target < flak_range) )
11415  {
11416  //set flak range to range of ship
11417  flak_pick_range(&Objects[weapon_objnum], &firing_pos, &predicted_pos,wepstr);
11418  }
11419  else
11420  {
11421  flak_set_range(&Objects[weapon_objnum], flak_range - winfo_p->untargeted_flak_range_penalty);
11422  }
11423 
11424  if ((winfo_p->muzzle_flash>=0) && (((shipp==Player_ship) && (vm_vec_mag(&Player_obj->phys_info.vel)>=45)) || (shipp!=Player_ship)))
11425  {
11426  flak_muzzle_flash(&firing_pos,&obj->orient.vec.fvec, &obj->phys_info, swp->primary_bank_weapons[bank_to_fire]);
11427  }
11428  }
11429  // create the muzzle flash effect
11430  if ( (obj != Player_obj) || (sip->flags2 & SIF2_SHOW_SHIP_MODEL) || (Viewer_mode) ) {
11431  // show the flash only if in not cockpit view, or if "show ship" flag is set
11432  shipfx_flash_create( obj, sip->model_num, &pnt, &obj->orient.vec.fvec, 1, weapon_idx );
11433  }
11434 
11435  // maybe shudder the ship - if its me
11436  if((winfo_p->wi_flags & WIF_SHUDDER) && (obj == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
11437  // calculate some arbitrary value between 100
11438  // (mass * velocity) / 10
11439  game_shudder_apply(500, (winfo_p->mass * winfo_p->max_speed) * 0.1f);
11440  }
11441 
11442  num_fired++;
11443  shipp->last_fired_point[bank_to_fire] = (shipp->last_fired_point[bank_to_fire] + 1) % num_slots;
11444  }
11445  }
11446  swp->external_model_fp_counter[bank_to_fire]++;
11447  }
11448  if (winfo_p->wi_flags3 & WIF3_APPLY_RECOIL){
11449  vec3d avg_firepoint;
11450 
11451  vm_vec_avg_n(&avg_firepoint, current_firepoint, firepoint_list);
11452 
11453  ship_apply_whack(&total_impulse, &avg_firepoint, obj);
11454  delete[] firepoint_list;
11455  }
11456  }
11457 
11458  CLAMP(shipp->weapon_energy, 0.0f, sip->max_weapon_reserve);
11459 
11460  banks_fired |= (1<<bank_to_fire); // mark this bank as fired.
11461  }
11462 
11463 
11464  // Only play the weapon fired sound if it hasn't been played yet. This is to
11465  // avoid playing the same sound multiple times when banks are linked with the
11466  // same weapon.
11467 
11468  if (!(winfo_p->wi_flags & WIF_BEAM)){ // not a beam weapon?
11469  if ( sound_played != winfo_p->launch_snd ) {
11470  sound_played = winfo_p->launch_snd;
11471  if ( obj == Player_obj ) {
11472  if ( winfo_p->launch_snd != -1 ) {
11473  weapon_info *wip;
11474  ship_weapon *sw_pl;
11475 
11476  //Update the last timestamp until continous fire is over, so we have the timestamp of the cease-fire.
11477  if (shipp->was_firing_last_frame[bank_to_fire] == 1) {
11478  swp->last_primary_fire_sound_stamp[bank_to_fire] = timestamp();
11479  }
11480 
11481  //Check for pre-launch sound and play if relevant
11482  if( (winfo_p->pre_launch_snd != -1) //If this weapon type has a pre-fire sound
11483  && ((timestamp() - swp->last_primary_fire_sound_stamp[bank_to_fire]) >= winfo_p->pre_launch_snd_min_interval) //and if we're past our minimum delay from the last cease-fire
11484  && (shipp->was_firing_last_frame[bank_to_fire] == 0) //and if we are at the beginning of a firing stream
11485  ){
11486  snd_play( &Snds[winfo_p->pre_launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY); //play it
11487  } else { //Otherwise, play normal firing sounds
11488  // HACK
11489  if(winfo_p->launch_snd == SND_AUTOCANNON_SHOT){
11490  snd_play( &Snds[winfo_p->launch_snd], 0.0f, 1.0f, SND_PRIORITY_TRIPLE_INSTANCE );
11491  } else {
11492  snd_play( &Snds[winfo_p->launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
11493  }
11494  }
11495 
11496  sw_pl = &Player_ship->weapons;
11497  if (sw_pl->current_primary_bank >= 0)
11498  {
11499  wip = &Weapon_info[sw_pl->primary_bank_weapons[sw_pl->current_primary_bank]];
11500  int force_level = (int) ((wip->armor_factor + wip->shield_factor * 0.2f) * (wip->damage * wip->damage - 7.5f) * 0.45f + 0.6f) * 10 + 2000;
11501 
11502  // modify force feedback for ballistics: make it stronger
11503  if (wip->wi_flags2 & WIF2_BALLISTIC)
11504  joy_ff_play_primary_shoot(force_level * 2);
11505  // no ballistics
11506  else
11507  joy_ff_play_primary_shoot(force_level);
11508  }
11509  }
11510  }else {
11511  if ( winfo_p->launch_snd != -1 ) {
11512  snd_play_3d( &Snds[winfo_p->launch_snd], &obj->pos, &View_position );
11513  }
11514  }
11515  }
11516  }
11517 
11518  shipp->was_firing_last_frame[bank_to_fire] = 1;
11519  } // end for (go to next primary bank)
11520 
11521  // if multiplayer and we're client-side firing, send the packet
11522  if(Game_mode & GM_MULTIPLAYER){
11523  // if i'm a client, and this is not me, don't send
11524  if(!(MULTIPLAYER_CLIENT && (shipp != Player_ship))){
11525  send_NEW_primary_fired_packet( shipp, banks_fired );
11526  }
11527  }
11528 
11529  // STATS
11530  if (obj->flags & OF_PLAYER_SHIP) {
11531  // in multiplayer -- only the server needs to keep track of the stats. Call the cool
11532  // function to find the player given the object *. It had better return a valid player
11533  // or our internal structure as messed up.
11534  if( Game_mode & GM_MULTIPLAYER ) {
11536  int player_num;
11537 
11538  player_num = multi_find_player_by_object ( obj );
11539  Assert ( player_num != -1 );
11540 
11541  Net_players[player_num].m_player->stats.mp_shots_fired += num_fired;
11542  }
11543  } else {
11544  Player->stats.mp_shots_fired += num_fired;
11545  }
11546  }
11547 
11548  if (has_fired) {
11549  object *objp = &Objects[shipp->objnum];
11550  object* target;
11551  if (Ai_info[shipp->ai_index].target_objnum != -1)
11552  target = &Objects[Ai_info[shipp->ai_index].target_objnum];
11553  else
11554  target = NULL;
11555  if (objp == Player_obj && Player_ai->target_objnum != -1)
11556  target = &Objects[Player_ai->target_objnum];
11557 
11558  Script_system.SetHookObjects(2, "User", objp, "Target", target);
11559  Script_system.RunCondition(CHA_ONWPFIRED, 0, NULL, objp, 1);
11560 
11561  Script_system.RunCondition(CHA_PRIMARYFIRE, 0, NULL, objp);
11562  Script_system.RemHookVars(2, "User", "Target");
11563  }
11564 
11565  return num_fired;
11566 }
11567 
11569 {
11570  int bank0_laser = 0;
11571  int bank1_laser = 0;
11572 
11573  // determine if either of our banks have a targeting laser
11575  bank0_laser = 1;
11576  }
11578  bank1_laser = 1;
11579  }
11580 
11581  // if primary banks are linked
11582  if(shipp->flags & SF_PRIMARY_LINKED){
11583  if(bank0_laser){
11584  shipp->targeting_laser_bank = 0;
11585  return;
11586  }
11587  if(bank1_laser){
11588  shipp->targeting_laser_bank = 1;
11589  return;
11590  }
11591  }
11592  // if we only have 1 bank selected
11593  else {
11594  if(bank0_laser && (shipp->weapons.current_primary_bank == 0)){
11595  shipp->targeting_laser_bank = 0;
11596  return;
11597  }
11598  if(bank1_laser && (shipp->weapons.current_primary_bank == 1)){
11599  shipp->targeting_laser_bank = 1;
11600  return;
11601  }
11602  }
11603 }
11604 
11606 {
11607  shipp->targeting_laser_bank = -1;
11608  shipp->targeting_laser_objnum = -1; // erase old laser obj num if it has any -Bobboau
11609 }
11610 
11612 {
11613  fighter_beam_fire_info fire_info;
11614  ship_obj *so;
11615  ship *shipp;
11616  polymodel *m;
11617 
11618  // interate over all ships
11619  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
11620  // sanity checks
11621  if(so->objnum < 0){
11622  continue;
11623  }
11624  if(Objects[so->objnum].type != OBJ_SHIP){
11625  continue;
11626  }
11627  if(Objects[so->objnum].instance < 0){
11628  continue;
11629  }
11630  shipp = &Ships[Objects[so->objnum].instance];
11631 
11632  // if our trigger is no longer down, switch it off
11633  if(!(shipp->flags & SF_TRIGGER_DOWN)){
11635  continue;
11636  }
11637 
11638  // if we have a bank to fire - fire it
11639  if((shipp->targeting_laser_bank >= 0) && (shipp->targeting_laser_bank < 2)){
11640  // try and get the model
11641  m = model_get(Ship_info[shipp->ship_info_index].model_num);
11642  if(m == NULL){
11643  continue;
11644  }
11645 
11646  // fire a targeting laser
11647  fire_info.life_left = 0.0; //for fighter beams
11648  fire_info.life_total = 0.0f; //for fighter beams
11649  fire_info.warmdown_stamp = -1; //for fighter beams
11650  fire_info.warmup_stamp = -1; //for fighter beams
11651  fire_info.accuracy = 0.0f;
11653  fire_info.beam_info_override = NULL;
11654  fire_info.shooter = &Objects[shipp->objnum];
11655  fire_info.target = NULL;
11656  fire_info.target_subsys = NULL;
11657  fire_info.turret = NULL;
11658  fire_info.targeting_laser_offset = m->gun_banks[shipp->targeting_laser_bank].pnt[0];
11659  shipp->targeting_laser_objnum = beam_fire_targeting(&fire_info);
11660 
11661  // hmm, why didn't it fire?
11662  if(shipp->targeting_laser_objnum < 0){
11663  Int3();
11665  }
11666  }
11667  }}
11668 
11681 {
11682  int objnum = swp->last_fired_weapon_index;
11683  object *objp;
11684  weapon_info *wip;
11685 
11686  if ((objnum < 0) || (objnum >= MAX_OBJECTS)) {
11687  return 0;
11688  }
11689 
11690  objp = &Objects[objnum];
11691 
11692  if (objp->type != OBJ_WEAPON){
11693  return 0;
11694  }
11695 
11696  if ((objp->instance < 0) || (objp->instance >= MAX_WEAPONS)){
11697  return 0;
11698  }
11699 
11700  // check to make sure that the weapon to detonate still exists
11701  if ( swp->last_fired_weapon_signature != objp->signature ){
11702  return 0;
11703  }
11704 
11705  Assert(Weapons[objp->instance].weapon_info_index != -1);
11707 
11708  if (wip->wi_flags & WIF_REMOTE) {
11709 
11710  int weapon_sig;
11711 
11712  weapon_sig = objp->signature;
11713 
11714  if (swp->last_fired_weapon_signature == weapon_sig) {
11715  weapon_detonate(objp);
11716  swp->last_fired_weapon_index = -1;
11717 
11718  return 1;
11719  }
11720  }
11721 
11722  return 0;
11723 }
11724 
11730 {
11731  if (swp->last_fired_weapon_index != -1)
11733  object *first_objp = &Objects[swp->last_fired_weapon_index];
11734  if (maybe_detonate_weapon(swp, obj)) {
11735  // If dual fire was set, there could be another weapon to detonate. Scan all weapons.
11736  missile_obj *mo;
11737 
11738  // check for currently locked missiles (highest precedence)
11739  for ( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
11740  object *mobjp;
11741  Assert(mo->objnum >= 0 && mo->objnum < MAX_OBJECTS);
11742  mobjp = &Objects[mo->objnum];
11743  if ((mobjp != first_objp) && (mobjp->parent_sig == obj->parent_sig)) {
11745  weapon_detonate(mobjp);
11746  }
11747  }
11748  }
11749 
11750  return 1;
11751  }
11752  }
11753 
11754  return 0;
11755 }
11756 
11763 {
11764  int cycled=0;
11765 
11766  int ns = swp->num_secondary_banks;
11767 
11768  if ( ns > 1 ) {
11769  int i,j=swp->current_secondary_bank+1;
11770  for (i=0; i<ns; i++) {
11771  if ( j >= ns ) {
11772  j=0;
11773  }
11774 
11775  if ( swp->secondary_bank_ammo[j] > 0 ) {
11776  swp->current_secondary_bank=j;
11777  cycled = 1;
11778  break;
11779  }
11780 
11781  j++;
11782  }
11783  }
11784 
11785  return cycled;
11786 }
11787 
11788 
11789 extern void ai_maybe_announce_shockwave_weapon(object *firing_objp, int weapon_index);
11790 
11791 // Object *obj fires its secondary weapon, if it can.
11792 // If its most recently fired weapon is a remotely detonatable weapon, detonate it.
11793 // Returns number of weapons fired. Note, for swarmers, returns 1 if it is allowed
11794 // to fire the missiles when allow_swarm is NOT set. They don't actually get fired on a call here unless allow_swarm is set.
11795 // When you want to fire swarmers, you call this function with allow_swarm NOT set and frame interval
11796 // code comes aruond and fires it.
11797 // allow_swarm -> default value is 0... since swarm missiles are fired over several frames,
11798 // need to avoid firing when normally called
11799 int ship_fire_secondary( object *obj, int allow_swarm )
11800 {
11801  int n, weapon_idx, j, bank, bank_adjusted, starting_bank_count = -1, num_fired;
11802  ushort starting_sig = 0;
11803  ship *shipp;
11804  ship_weapon *swp;
11805  ship_info *sip;
11806  weapon_info *wip;
11807  ai_info *aip;
11808  polymodel *pm;
11809  vec3d missile_point, pnt, firing_pos;
11810  bool has_fired = false; // Used to determine whether to fire the scripting hook
11811 
11812  Assert( obj != NULL );
11813 
11814  // in the case where the server is an observer, he can fire (which would be bad) - unless we do this.
11815  if( obj->type == OBJ_OBSERVER ){
11816  return 0;
11817  }
11818 
11819  // in the case where the object is a ghost (a delayed fire packet from right before he died, for instance)
11820  if( (obj->type == OBJ_GHOST) || (obj->type == OBJ_NONE) ){
11821  return 0;
11822  }
11823 
11824  Assert( obj->type == OBJ_SHIP );
11825  if(obj->type != OBJ_SHIP){
11826  return 0;
11827  }
11828  n = obj->instance;
11829  Assert( n >= 0 && n < MAX_SHIPS );
11830  if((n < 0) || (n >= MAX_SHIPS)){
11831  return 0;
11832  }
11833  Assert( Ships[n].objnum == OBJ_INDEX(obj));
11834  if(Ships[n].objnum != OBJ_INDEX(obj)){
11835  return 0;
11836  }
11837 
11838  shipp = &Ships[n];
11839  swp = &shipp->weapons;
11840  sip = &Ship_info[shipp->ship_info_index];
11841  aip = &Ai_info[shipp->ai_index];
11842 
11843  // if no secondary weapons are present on ship, return
11844  if ( swp->num_secondary_banks <= 0 ){
11845  return 0;
11846  }
11847 
11848  // If the secondaries have been locked, bail
11849  if (shipp->flags2 & SF2_SECONDARIES_LOCKED)
11850  {
11851  return 0;
11852  }
11853 
11854  // If ship is being repaired/rearmed, it cannot fire missiles
11855  if ( aip->ai_flags & AIF_BEING_REPAIRED ) {
11856  return 0;
11857  }
11858 
11859  num_fired = 0; // tracks how many missiles actually fired
11860 
11861  // niffiwan: allow swarm/corkscrew bank to keep firing if current bank changes
11862  if (shipp->swarm_missile_bank != -1 && allow_swarm) {
11863  bank = shipp->swarm_missile_bank;
11864  } else if (shipp->corkscrew_missile_bank != -1 && allow_swarm) {
11865  bank = shipp->corkscrew_missile_bank;
11866  } else {
11867  bank = swp->current_secondary_bank;
11868  }
11869 
11870  if ( bank < 0 || bank >= sip->num_secondary_banks ) {
11871  return 0;
11872  }
11873  bank_adjusted = MAX_SHIP_PRIMARY_BANKS + bank;
11874 
11875  if (swp->secondary_animation_position[bank] == MA_POS_SET) {
11878  else
11879  return 0;
11880  }
11881 
11882  weapon_idx = swp->secondary_bank_weapons[bank];
11883  Assert( (swp->secondary_bank_weapons[bank] >= 0) && (swp->secondary_bank_weapons[bank] < MAX_WEAPON_TYPES) );
11884  if((swp->secondary_bank_weapons[bank] < 0) || (swp->secondary_bank_weapons[bank] >= MAX_WEAPON_TYPES)){
11885  return 0;
11886  }
11887  wip = &Weapon_info[weapon_idx];
11888 
11889  if ( MULTIPLAYER_MASTER ) {
11891  starting_bank_count = swp->secondary_bank_ammo[bank];
11892  }
11893 
11894  if (ship_fire_secondary_detonate(obj, swp)) {
11895  // in multiplayer, master sends a secondary fired packet with starting signature of -1 -- indicates
11896  // to client code to set the detonate timer to 0.
11897  if ( MULTIPLAYER_MASTER ) {
11898  send_secondary_fired_packet( shipp, 0, starting_bank_count, 1, allow_swarm );
11899  }
11900 
11901  // For all banks, if ok to fire a weapon, make it wait a bit.
11902  // Solves problem of fire button likely being down next frame and
11903  // firing weapon despite fire causing detonation of existing weapon.
11904  if (swp->current_secondary_bank >= 0) {
11906  swp->next_secondary_fire_stamp[bank] = timestamp(MAX((int) flFrametime*3000, 250));
11907  }
11908  }
11909  return 0;
11910  }
11911 
11912  // niffiwan: 04/03/12: duplicate of a check approx 100 lines above - not needed?
11913  if ( bank < 0 ){
11914  return 0;
11915  }
11916 
11917  if ( !timestamp_elapsed(swp->next_secondary_fire_stamp[bank]) && !allow_swarm) {
11918  if (timestamp_until(swp->next_secondary_fire_stamp[bank]) > 60000){
11919  swp->next_secondary_fire_stamp[bank] = timestamp(1000);
11920  }
11921  goto done_secondary;
11922  }
11923 
11924  // Ensure if this is a "require-lock" missile, that a lock actually exists
11925  if ( wip->wi_flags & WIF_NO_DUMBFIRE ) {
11926  if ( aip->current_target_is_locked <= 0 ) {
11927  if ( obj == Player_obj ) {
11928  if ( !Weapon_energy_cheat ) {
11929  float max_dist;
11930 
11931  max_dist = wip->lifetime * wip->max_speed;
11932  if (wip->wi_flags2 & WIF2_LOCAL_SSM){
11933  max_dist= wip->lssm_lock_range;
11934  }
11935 
11936  if ((aip->target_objnum != -1) && (vm_vec_dist_quick(&obj->pos, &Objects[aip->target_objnum].pos) > max_dist)) {
11937  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Too far from target to acquire lock", 487));
11938  } else {
11939  char missile_name[NAME_LENGTH];
11940  strcpy_s(missile_name, wip->name);
11941  end_string_at_first_hash_symbol(missile_name);
11942  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Cannot fire %s without a lock", 488), missile_name);
11943  }
11944 
11946  swp->next_secondary_fire_stamp[bank] = timestamp(800); // to avoid repeating messages
11947  return 0;
11948  }
11949  } else {
11950  // multiplayer clients should always fire the weapon here, so return only if not
11951  // a multiplayer client.
11952  if ( !MULTIPLAYER_CLIENT ) {
11953  return 0;
11954  }
11955  }
11956  }
11957  }
11958 
11959  if (wip->wi_flags2 & WIF2_TAGGED_ONLY)
11960  {
11961  if (!ship_is_tagged(&Objects[aip->target_objnum]))
11962  {
11963  if (obj==Player_obj)
11964  {
11965  if ( !Weapon_energy_cheat )
11966  {
11967  HUD_sourced_printf(HUD_SOURCE_HIDDEN, NOX("Cannot fire %s if target is not tagged"),wip->name);
11969  swp->next_secondary_fire_stamp[bank] = timestamp(800); // to avoid repeating messages
11970  return 0;
11971  }
11972  }
11973  else
11974  {
11975  if ( !MULTIPLAYER_CLIENT )
11976  {
11977  return 0;
11978  }
11979  }
11980  }
11981  }
11982 
11983 
11984 
11985  // if trying to fire a swarm missile, make sure being called from right place
11986  if ( (wip->wi_flags & WIF_SWARM) && !allow_swarm ) {
11987  Assert(wip->swarm_count > 0);
11988  if(wip->swarm_count <= 0){
11990  } else {
11992  }
11993  shipp->swarm_missile_bank = bank;
11994  return 1; // Note: Missiles didn't get fired, but the frame interval code will fire them.
11995  }
11996 
11997  // if trying to fire a corkscrew missile, make sure being called from right place
11998  if ( (wip->wi_flags & WIF_CORKSCREW) && !allow_swarm ) {
11999  //phreak 11-9-02
12000  //changed this from 4 to custom number defined in tables
12002  shipp->corkscrew_missile_bank = bank;
12003  return 1; // Note: Missiles didn't get fired, but the frame interval code will fire them.
12004  }
12005 
12006  float t;
12007 
12008  if (Weapon_info[weapon_idx].burst_shots > swp->burst_counter[bank_adjusted]) {
12009  t = Weapon_info[weapon_idx].burst_delay;
12010  swp->burst_counter[bank_adjusted]++;
12011  } else {
12012  t = Weapon_info[weapon_idx].fire_wait; // They can fire 5 times a second
12013  swp->burst_counter[bank_adjusted] = 0;
12014  }
12015  swp->next_secondary_fire_stamp[bank] = timestamp((int) (t * 1000.0f));
12016  swp->last_secondary_fire_stamp[bank] = timestamp();
12017 
12018  // Here is where we check if weapons subsystem is capable of firing the weapon.
12019  // do only in single player or if I am the server of a multiplayer game
12021  if ( ship_weapon_maybe_fail(shipp) ) {
12022  if ( obj == Player_obj )
12024  char missile_name[NAME_LENGTH];
12025  strcpy_s(missile_name, Weapon_info[weapon_idx].name);
12026  end_string_at_first_hash_symbol(missile_name);
12027  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Cannot fire %s due to weapons system damage", 489), missile_name);
12028  }
12029  goto done_secondary;
12030  }
12031  }
12032 
12033  pm = model_get( sip->model_num );
12034  if ( pm->n_missiles > 0 ) {
12035  int check_ammo; // used to tell if we should check ammo counts or not
12036  int num_slots;
12037 
12038  if ( bank > pm->n_missiles ) {
12039  nprintf(("WARNING","WARNING ==> Tried to fire bank %d, but ship has only %d banks\n", bank+1, pm->n_missiles));
12040  return 0; // we can make a quick out here!!!
12041  }
12042 
12043  num_slots = pm->missile_banks[bank].num_slots;
12044 
12045  // determine if there is enough ammo left to fire weapons on this bank. As with primary
12046  // weapons, we might or might not check ammo counts depending on game mode, who is firing,
12047  // and if I am a client in multiplayer
12048  check_ammo = 1;
12049 
12050  if ( MULTIPLAYER_CLIENT && (obj != Player_obj) ){
12051  check_ammo = 0;
12052  }
12053 
12054  if ( check_ammo && ( swp->secondary_bank_ammo[bank] <= 0) ) {
12055  if ( shipp->objnum == OBJ_INDEX(Player_obj) ) {
12057 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, "No %s missiles left in bank", Weapon_info[swp->secondary_bank_weapons[bank]].name);
12058  }
12059  }
12060  else {
12061  // TODO: AI switch secondary weapon / re-arm?
12062  }
12063  goto done_secondary;
12064  }
12065 
12066  int start_slot, end_slot;
12067 
12068  if ( shipp->flags & SF_SECONDARY_DUAL_FIRE && num_slots > 1) {
12069  start_slot = swp->secondary_next_slot[bank];
12070  // AL 11-19-97: Ensure enough ammo remains when firing linked secondary weapons
12071  if ( check_ammo && (swp->secondary_bank_ammo[bank] < 2) ) {
12072  end_slot = start_slot;
12073  } else {
12074  end_slot = start_slot+1;
12075  }
12076  } else {
12077  // de-set the flag just in case dual-fire was set but couldn't be used
12078  // because there's less than two firepoints
12079  shipp->flags &= ~SF_SECONDARY_DUAL_FIRE;
12080  start_slot = swp->secondary_next_slot[bank];
12081  end_slot = start_slot;
12082  }
12083 
12084  int pnt_index=start_slot;
12085  //If this is a tertiary weapon, only subtract one piece of ammo
12086  for ( j = start_slot; j <= end_slot; j++ ) {
12087  int weapon_num;
12088 
12089  swp->secondary_next_slot[bank]++;
12090  if ( swp->secondary_next_slot[bank] > (num_slots-1) ){
12091  swp->secondary_next_slot[bank] = 0;
12092  }
12093 
12094  if ( pnt_index >= num_slots ){
12095  pnt_index = 0;
12096  }
12097  shipp->secondary_point_reload_pct[bank][pnt_index] = 0.0f;
12098  pnt = pm->missile_banks[bank].pnt[pnt_index++];
12099 
12100  polymodel *weapon_model = NULL;
12101  if(wip->external_model_num >= 0){
12102  weapon_model = model_get(wip->external_model_num);
12103  }
12104 
12105  if (weapon_model && weapon_model->n_guns) {
12106  int external_bank = bank + MAX_SHIP_PRIMARY_BANKS;
12107  if (wip->wi_flags2 & WIF2_EXTERNAL_WEAPON_FP) {
12108  if ((weapon_model->n_guns <= swp->external_model_fp_counter[external_bank]) || (swp->external_model_fp_counter[external_bank] < 0))
12109  swp->external_model_fp_counter[external_bank] = 0;
12110  vm_vec_add2(&pnt, &weapon_model->gun_banks[0].pnt[swp->external_model_fp_counter[external_bank]]);
12111  swp->external_model_fp_counter[external_bank]++;
12112  } else {
12113  // make it use the 0 index slot
12114  vm_vec_add2(&pnt, &weapon_model->gun_banks[0].pnt[0]);
12115  }
12116  }
12117  vm_vec_unrotate(&missile_point, &pnt, &obj->orient);
12118  vm_vec_add(&firing_pos, &missile_point, &obj->pos);
12119 
12120  if ( Game_mode & GM_MULTIPLAYER ) {
12121  Assert( Weapon_info[weapon_idx].subtype == WP_MISSILE );
12122  }
12123 
12124  matrix firing_orient;
12125  if(!(sip->flags2 & SIF2_GUN_CONVERGENCE))
12126  {
12127  firing_orient = obj->orient;
12128  }
12129  else
12130  {
12131  vec3d firing_vec;
12132  vm_vec_unrotate(&firing_vec, &pm->missile_banks[bank].norm[pnt_index-1], &obj->orient);
12133  vm_vector_2_matrix(&firing_orient, &firing_vec, NULL, NULL);
12134  }
12135 
12136  // create the weapon -- for multiplayer, the net_signature is assigned inside
12137  // of weapon_create
12138  weapon_num = weapon_create( &firing_pos, &firing_orient, weapon_idx, OBJ_INDEX(obj), -1, aip->current_target_is_locked);
12139 
12140  if (weapon_num >= 0) {
12141  weapon_idx = Weapons[Objects[weapon_num].instance].weapon_info_index;
12143  has_fired = true;
12144 
12145  // create the muzzle flash effect
12146  if ( (obj != Player_obj) || (sip->flags2 & SIF2_SHOW_SHIP_MODEL) || (Viewer_mode) ) {
12147  // show the flash only if in not cockpit view, or if "show ship" flag is set
12148  shipfx_flash_create(obj, sip->model_num, &pnt, &obj->orient.vec.fvec, 0, weapon_idx);
12149  }
12150 
12151  if((wip->wi_flags & WIF_SHUDDER) && (obj == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
12152  // calculate some arbitrary value between 100
12153  // (mass * velocity) / 10
12154  game_shudder_apply(500, (wip->mass * wip->max_speed) * 0.1f);
12155  }
12156 
12157  num_fired++;
12158  swp->last_fired_weapon_index = weapon_num;
12159  swp->detonate_weapon_time = timestamp(500); // Can detonate 1/2 second later.
12160  swp->last_fired_weapon_signature = Objects[weapon_num].signature;
12161 
12162  // subtract the number of missiles fired
12163  if ( Weapon_energy_cheat == 0 ){
12164  swp->secondary_bank_ammo[bank]--;
12165  }
12166  }
12167  }
12168  }
12169 
12170  if ( obj == Player_obj ) {
12171  if ( Weapon_info[weapon_idx].launch_snd != -1 ) {
12172  snd_play( &Snds[Weapon_info[weapon_idx].launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
12173  swp = &Player_ship->weapons;
12174  if (bank >= 0) {
12175  wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
12176  if (Player_ship->flags & SF_SECONDARY_DUAL_FIRE){
12177  joy_ff_play_secondary_shoot((int) (wip->cargo_size * 2.0f));
12178  } else {
12180  }
12181  }
12182  }
12183 
12184  } else {
12185  if ( Weapon_info[weapon_idx].launch_snd != -1 ) {
12186  snd_play_3d( &Snds[Weapon_info[weapon_idx].launch_snd], &obj->pos, &View_position );
12187  }
12188  }
12189 
12190 done_secondary:
12191 
12192  if(num_fired > 0){
12193  // if I am the master of a multiplayer game, send a secondary fired packet along with the
12194  // first network signatures for the newly created weapons. if nothing got fired, send a failed
12195  // packet if
12196  if ( MULTIPLAYER_MASTER ) {
12197  Assert(starting_sig != 0);
12198  send_secondary_fired_packet( shipp, starting_sig, starting_bank_count, num_fired, allow_swarm );
12199  }
12200 
12201  // STATS
12202  if (obj->flags & OF_PLAYER_SHIP) {
12203  // in multiplayer -- only the server needs to keep track of the stats. Call the cool
12204  // function to find the player given the object *. It had better return a valid player
12205  // or our internal structure as messed up.
12206  if( Game_mode & GM_MULTIPLAYER ) {
12208  int player_num;
12209 
12210  player_num = multi_find_player_by_object ( obj );
12211  Assert ( player_num != -1 );
12212 
12213  Net_players[player_num].m_player->stats.ms_shots_fired += num_fired;
12214  }
12215  } else {
12216  Player->stats.ms_shots_fired += num_fired;
12217  }
12218  }
12219 
12220  // maybe announce a shockwave weapon
12221  ai_maybe_announce_shockwave_weapon(obj, weapon_idx);
12222  }
12223 
12224  // if we are out of ammo in this bank then don't carry over firing swarm/corkscrew
12225  // missiles to a new bank
12226  if (swp->secondary_bank_ammo[bank] <= 0) {
12227  // NOTE: these are set to 1 since they will get reduced by 1 in the
12228  // swarm/corkscrew code once this function returns
12229 
12230  if (shipp->num_swarm_missiles_to_fire > 1) {
12231  shipp->num_swarm_missiles_to_fire = 1;
12232  shipp->swarm_missile_bank = -1;
12233  }
12234 
12235  if (shipp->num_corkscrew_to_fire > 1) {
12236  shipp->num_corkscrew_to_fire = 1;
12237  shipp->corkscrew_missile_bank = -1;
12238  }
12239  }
12240 
12241  // AL 3-7-98: Move to next valid secondary bank if out of ammo
12242  //
12243 
12244  //21-07-02 01:24 DTP; COMMENTED OUT some of the mistakes
12245  //this bug was made by AL, when he assumed he had to take the next fire_wait time remaining and add 250 ms of delay to it,
12246  //and put it in the next valid bank. for the player to have a 250 ms of penalty
12247  //
12248  //what that caused was that the next valid bank inherited the current valid banks FULL fire delay. since he used the Weapon_info struct that has
12249  // no information / member that stores the next valids banks remaning fire_wait delay.
12250  //
12251  //what he should have done was to check of the next valid bank had any fire delay that had elapsed, if it had elapsed,
12252  //then it would have no firedelay. and then add 250 ms of delay. in effect, this way there is no penalty if there is any firedelay remaning in
12253  //the next valid bank. the delay is there to prevent things like Trible/Quad Fire Trebuchets.
12254  //
12255  // niffiwan: only try to switch banks if object has multiple banks, and firing bank is the current bank
12256  if ( (obj->flags & OF_PLAYER_SHIP) && (swp->secondary_bank_ammo[bank] <= 0) && (swp->num_secondary_banks >= 2) && (bank == swp->current_secondary_bank) ) {
12257  // niffiwan: call ship_select_next_secondary instead of ship_select_next_valid_secondary_bank
12258  // ensures all "extras" are dealt with, like animations, scripting hooks, etc
12259  if (ship_select_next_secondary(obj) ) { //DTP here we switch to the next valid bank, but we can't call weapon_info on next fire_wait
12260 
12261  if ( timestamp_elapsed(shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank]) ) { //DTP, this is simply a copy of the manual cycle functions
12262  shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(1000); //Bumped from 250 to 1000 because some people seem to be to triggerhappy :).
12264  }
12265 
12266  if ( obj == Player_obj ) {
12268  }
12269  }
12270  }
12271 
12272  if (has_fired) {
12273  object *objp = &Objects[shipp->objnum];
12274  object* target;
12275  if (Ai_info[shipp->ai_index].target_objnum != -1)
12276  target = &Objects[Ai_info[shipp->ai_index].target_objnum];
12277  else
12278  target = NULL;
12279  if (objp == Player_obj && Player_ai->target_objnum != -1)
12280  target = &Objects[Player_ai->target_objnum];
12281  Script_system.SetHookObjects(2, "User", objp, "Target", target);
12282  Script_system.RunCondition(CHA_ONWPFIRED, 0, NULL, objp);
12284  Script_system.RemHookVars(2, "User", "Target");
12285  }
12286 
12287  return num_fired;
12288 }
12289 
12290 // Goober5000
12292 {
12293  // true if both ballistic and ammo <= 0,
12294  // false if not ballistic or if ballistic and ammo > 0
12295 
12297  {
12298  if (swp->primary_bank_ammo[bank] <= 0)
12299  {
12300  return 1;
12301  }
12302  }
12303 
12304  // note: never out of ammo if not ballistic
12305  return 0;
12306 }
12307 
12317 int ship_select_next_primary(object *objp, int direction)
12318 {
12319  ship *shipp;
12320  ship_info *sip;
12321  ship_weapon *swp;
12322  int new_bank;
12323  int original_bank;
12324  unsigned int original_link_flag;
12325  int i;
12326 
12327  Assert(objp != NULL);
12328  Assert(objp->type == OBJ_SHIP);
12329  Assert(objp->instance >= 0 && objp->instance < MAX_SHIPS);
12330 
12331  shipp = &Ships[objp->instance];
12332  sip = &Ship_info[shipp->ship_info_index];
12333  swp = &shipp->weapons;
12334 
12335  Assert(direction == CYCLE_PRIMARY_NEXT || direction == CYCLE_PRIMARY_PREV);
12336 
12337  original_bank = swp->current_primary_bank;
12338  original_link_flag = shipp->flags & SF_PRIMARY_LINKED;
12339 
12340  // redid case structure to possibly add more primaries in the future - Goober5000
12341  if ( swp->num_primary_banks == 0 )
12342  {
12343  if ( objp == Player_obj )
12344  {
12345  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no primary weapons", 490));
12347  }
12348  return 0;
12349  }
12350  else if ( swp->num_primary_banks == 1 )
12351  {
12352  if ( objp == Player_obj )
12353  {
12354  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has only one primary weapon: %s", 491),Weapon_info[swp->primary_bank_weapons[swp->current_primary_bank]].name, swp->current_primary_bank + 1);
12356  }
12357  return 0;
12358  }
12359  else if ( swp->num_primary_banks > MAX_SHIP_PRIMARY_BANKS )
12360  {
12361  Int3();
12362  return 0;
12363  }
12364  else
12365  {
12366  Assert((swp->current_primary_bank >= 0) && (swp->current_primary_bank < swp->num_primary_banks));
12367 
12368  // first check if linked
12369  if ( shipp->flags2 & SF2_SHIP_SELECTIVE_LINKING )
12370  {
12371  printf("npb:%i\n", swp->num_primary_banks );
12372  }
12373 
12374  if ( shipp->flags & SF_PRIMARY_LINKED )
12375  {
12376  shipp->flags &= ~SF_PRIMARY_LINKED;
12377  if ( direction == CYCLE_PRIMARY_NEXT )
12378  {
12379  swp->current_primary_bank = 0;
12380  }
12381  else
12382  {
12383  swp->current_primary_bank = swp->num_primary_banks - 1;
12384  }
12385  }
12386  // now handle when not linked: cycle and constrain
12387  else
12388  {
12389  if ( direction == CYCLE_PRIMARY_NEXT )
12390  {
12391  if ( swp->current_primary_bank < swp->num_primary_banks - 1 )
12392  {
12393  swp->current_primary_bank++;
12394  }
12395  else if( sip->flags2 & SIF2_NO_PRIMARY_LINKING )
12396  {
12397  swp->current_primary_bank = 0;
12398  }
12399  else
12400  {
12401  shipp->flags |= SF_PRIMARY_LINKED;
12402  }
12403  }
12404  else
12405  {
12406  if ( swp->current_primary_bank > 0 )
12407  {
12408  swp->current_primary_bank--;
12409  }
12410  else if( sip->flags2 & SIF2_NO_PRIMARY_LINKING )
12411  {
12412  swp->current_primary_bank = swp->num_primary_banks - 1;
12413  }
12414  else
12415  {
12416  shipp->flags |= SF_PRIMARY_LINKED;
12417  }
12418  }
12419  }
12420  }
12421 
12422  // test for ballistics - Goober5000
12423  if ( sip->flags & SIF_BALLISTIC_PRIMARIES )
12424  {
12425  // if we can't link, disengage primary linking and change to next available bank
12426  if (shipp->flags & SF_PRIMARY_LINKED)
12427  {
12428  for (i = 0; i < swp->num_primary_banks; i++)
12429  {
12430  if (primary_out_of_ammo(swp, i))
12431  {
12432  shipp->flags &= ~SF_PRIMARY_LINKED;
12433 
12434  if (direction == CYCLE_PRIMARY_NEXT)
12435  {
12436  swp->current_primary_bank = 0;
12437  }
12438  else
12439  {
12441  }
12442  break;
12443  }
12444  }
12445  }
12446 
12447  // check to see if we keep cycling...we have to if we're out of ammo in the current bank
12448  if ( primary_out_of_ammo(swp, swp->current_primary_bank) )
12449  {
12450  // cycle around until we find ammunition...
12451  // we land on the original bank if all banks fail
12453  new_bank = swp->current_primary_bank;
12454 
12455  for (i = 1; i < swp->num_primary_banks; i++)
12456  {
12457  // cycle in the proper direction
12458  if ( direction == CYCLE_PRIMARY_NEXT )
12459  {
12460  new_bank = (swp->current_primary_bank + i) % swp->num_primary_banks;
12461  }
12462  else
12463  {
12464  new_bank = (swp->current_primary_bank + swp->num_primary_banks - i) % swp->num_primary_banks;
12465  }
12466 
12467  // check to see if this is a valid bank
12468  if (!primary_out_of_ammo(swp, new_bank))
12469  {
12470  break;
12471  }
12472  }
12473  // set the new bank; defaults to resetting to the old bank if we completed a full iteration
12474  swp->current_primary_bank = new_bank;
12475  }
12476 
12477  // make sure we're okay
12478  Assert((swp->current_primary_bank >= 0) && (swp->current_primary_bank < swp->num_primary_banks));
12479 
12480  if(swp->current_primary_bank != original_bank)
12481  swp->previous_primary_bank = original_bank;
12482  else
12484 
12485  // if this ship is ballistics-equipped, and we cycled, then we had to verify some stuff,
12486  // so we should check if we actually changed banks
12487  if ( (swp->current_primary_bank != original_bank) || ((shipp->flags & SF_PRIMARY_LINKED) != original_link_flag) )
12488  {
12489  if ( objp == Player_obj )
12490  {
12492  }
12493  ship_primary_changed(shipp);
12494  objp = &Objects[shipp->objnum];
12495  object* target;
12496  if (Ai_info[shipp->ai_index].target_objnum != -1)
12497  target = &Objects[Ai_info[shipp->ai_index].target_objnum];
12498  else
12499  target = NULL;
12500  if (objp == Player_obj && Player_ai->target_objnum != -1)
12501  target = &Objects[Player_ai->target_objnum];
12502  Script_system.SetHookObjects(2, "User", objp, "Target", target);
12504  Script_system.SetHookObjects(2, "User", objp, "Target", target);
12506  Script_system.RemHookVars(2, "User", "Target");
12507  return 1;
12508  }
12509 
12510  // could not select new weapon:
12511  if ( objp == Player_obj )
12512  {
12514  }
12515  return 0;
12516  } // end of ballistics implementation
12517 
12518  if ( objp == Player_obj )
12519  {
12521  }
12522 
12523  ship_primary_changed(shipp);
12524  object* target;
12525  if (Ai_info[shipp->ai_index].target_objnum != -1)
12526  target = &Objects[Ai_info[shipp->ai_index].target_objnum];
12527  else
12528  target = NULL;
12529  if (objp == Player_obj && Player_ai->target_objnum != -1)
12530  target = &Objects[Player_ai->target_objnum];
12531  Script_system.SetHookObjects(2, "User", objp, "Target", target);
12533  Script_system.SetHookObjects(2, "User", objp, "Target", target);
12535  Script_system.RemHookVars(2, "User", "Target");
12536 
12537  return 1;
12538 }
12539 
12540 // ------------------------------------------------------------------------------
12541 // ship_select_next_secondary() selects the next secondary bank with missles
12542 //
12543 // returns: 1 => The secondary bank was switched
12544 // 0 => The secondary bank stayed the same
12545 //
12546 // If a secondary bank has no missles left, it is skipped.
12547 //
12548 // NOTE: This can be called for an arbitrary ship. HUD messages and sounds are only used
12549 // for the player ship.
12551 {
12552  Assert(objp != NULL);
12553  Assert(objp->type == OBJ_SHIP);
12554  Assert(objp->instance >= 0 && objp->instance < MAX_SHIPS);
12555 
12556  int original_bank, new_bank, i;
12557  ship *shipp;
12558  ship_weapon *swp;
12559 
12560  shipp = &Ships[objp->instance];
12561  swp = &shipp->weapons;
12562 
12563  // redid the switch structure to allow additional seconary banks if added later - Goober5000
12564  if ( swp->num_secondary_banks == 0 )
12565  {
12566  if ( objp == Player_obj )
12567  {
12568  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 492));
12570  }
12571  return 0;
12572  }
12573  else if ( swp->num_secondary_banks == 1 )
12574  {
12575  if ( objp == Player_obj )
12576  {
12577  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has only one secondary weapon: %s", 493), Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]].name, swp->current_secondary_bank + 1);
12579  }
12580  return 0;
12581  }
12583  {
12584  Int3();
12585  return 0;
12586  }
12587  else
12588  {
12590 
12591  original_bank = swp->current_secondary_bank;
12592 
12593  for ( i = 1; i < swp->num_secondary_banks; i++ ) {
12594  new_bank = (swp->current_secondary_bank+i) % swp->num_secondary_banks;
12595  if ( swp->secondary_bank_ammo[new_bank] <= 0 )
12596  continue;
12597  swp->current_secondary_bank = new_bank;
12598  break;
12599  }
12600 
12601  if ( swp->current_secondary_bank != original_bank )
12602  {
12603  if(swp->current_primary_bank != original_bank)
12604  swp->previous_primary_bank = original_bank;
12605  else
12607  if ( objp == Player_obj )
12608  {
12610  }
12611  ship_secondary_changed(shipp);
12612 
12613  objp = &Objects[shipp->objnum];
12614  object* target;
12615  if (Ai_info[shipp->ai_index].target_objnum != -1)
12616  target = &Objects[Ai_info[shipp->ai_index].target_objnum];
12617  else
12618  target = NULL;
12619  if (objp == Player_obj && Player_ai->target_objnum != -1)
12620  target = &Objects[Player_ai->target_objnum];
12621  Script_system.SetHookObjects(2, "User", objp, "Target", target);
12623  Script_system.SetHookObjects(2, "User", objp, "Target", target);
12625  Script_system.RemHookVars(2, "User", "Target");
12626  return 1;
12627  }
12628  } // end if
12629 
12630  // If we've reached this point, must have failed
12631  if ( objp == Player_obj )
12632  {
12634  }
12635  return 0;
12636 }
12637 
12638 // Goober5000 - copied from secondary routine
12639 // Stuff list of weapon indices for object *objp in list *outlist.
12640 // Return number of weapons in list.
12641 int get_available_primary_weapons(object *objp, int *outlist, int *outbanklist)
12642 {
12643  int count = 0;
12644  int i;
12645  ship *shipp;
12646 
12647  Assert(objp->type == OBJ_SHIP);
12648  Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
12649  shipp = &Ships[objp->instance];
12650 
12651  for (i=0; i<shipp->weapons.num_primary_banks; i++)
12652  {
12653  if (!primary_out_of_ammo(&(shipp->weapons), i))
12654  {
12655  outbanklist[count] = i;
12656  outlist[count++] = shipp->weapons.primary_bank_weapons[i];
12657  }
12658  }
12659 
12660  return count;
12661 }
12662 
12667 int get_available_secondary_weapons(object *objp, int *outlist, int *outbanklist)
12668 {
12669  int count = 0;
12670  int i;
12671  ship *shipp;
12672 
12673  Assert(objp->type == OBJ_SHIP);
12674  Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
12675  shipp = &Ships[objp->instance];
12676 
12677  for (i=0; i<shipp->weapons.num_secondary_banks; i++)
12678  if (shipp->weapons.secondary_bank_ammo[i]) {
12679  outbanklist[count] = i;
12680  outlist[count++] = shipp->weapons.secondary_bank_weapons[i];
12681  }
12682 
12683  return count;
12684 }
12685 
12686 void wing_bash_ship_name(char *ship_name, const char *wing_name, int index)
12687 {
12688  // if wing name has a hash symbol, create the ship name a particular way
12689  // (but don't do this for names that have the hash as the first or last character)
12690  const char *p = get_pointer_to_first_hash_symbol(wing_name);
12691  if ((p != NULL) && (p != wing_name) && (*(p+1) != '\0'))
12692  {
12693  size_t len = (p - wing_name);
12694  strncpy(ship_name, wing_name, len);
12695  sprintf(ship_name + len, NOX(" %d"), index);
12696  strcat(ship_name, p);
12697  }
12698  // most of the time we should create the name the standard retail way
12699  else
12700  sprintf(ship_name, NOX("%s %d"), wing_name, index);
12701 }
12702 
12706 int wing_name_lookup(const char *name, int ignore_count)
12707 {
12708  int i, wing_limit;
12709 
12710  if (name == NULL)
12711  return -1;
12712 
12713  if ( Fred_running )
12714  wing_limit = MAX_WINGS;
12715  else
12716  wing_limit = Num_wings;
12717 
12718  if (Fred_running || ignore_count ) { // current_count not used for Fred..
12719  for (i=0; i<wing_limit; i++)
12720  if (Wings[i].wave_count && !stricmp(Wings[i].name, name))
12721  return i;
12722 
12723  } else {
12724  for (i=0; i<wing_limit; i++)
12725  if (Wings[i].current_count && !stricmp(Wings[i].name, name))
12726  return i;
12727  }
12728 
12729  return -1;
12730 }
12731 
12736 int wing_lookup(const char *name)
12737 {
12738  int idx;
12739  for(idx=0;idx<Num_wings;idx++)
12740  if(stricmp(Wings[idx].name,name)==0)
12741  return idx;
12742 
12743  return -1;
12744 }
12745 
12749 int ship_info_lookup_sub(const char *token)
12750 {
12751  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it)
12752  if (!stricmp(token, it->name))
12753  return std::distance(Ship_info.cbegin(), it);
12754 
12755  return -1;
12756 }
12757 
12761 int ship_template_lookup(const char *token)
12762 {
12763  for ( auto it = Ship_templates.cbegin(); it != Ship_templates.cend(); ++it ) {
12764  if ( !stricmp(token, it->name) ) {
12765  return std::distance(Ship_templates.cbegin(), it);
12766  }
12767  }
12768  return -1;
12769 }
12770 
12771 // Goober5000
12772 int ship_info_lookup(const char *token)
12773 {
12774  int idx;
12775  const char *p;
12776  char name[NAME_LENGTH], temp1[NAME_LENGTH], temp2[NAME_LENGTH];
12777 
12778  // bogus
12779  if (token == NULL)
12780  return -1;
12781 
12782  // first try a straightforward lookup
12783  idx = ship_info_lookup_sub(token);
12784  if (idx >= 0)
12785  return idx;
12786 
12787  // ship copy types might be mismatched
12789  if (p == NULL)
12790  return -1;
12791 
12792  // conversion from FS1 missions
12793  if (!stricmp(token, "GTD Orion#1 (Galatea)"))
12794  {
12795  idx = ship_info_lookup_sub("GTD Orion#Galatea");
12796  if (idx >= 0)
12797  return idx;
12798 
12799  idx = ship_info_lookup_sub("GTD Orion (Galatea)");
12800  if (idx >= 0)
12801  return idx;
12802 
12803  return -1;
12804  }
12805  else if (!stricmp(token, "GTD Orion#2 (Bastion)"))
12806  {
12807  idx = ship_info_lookup_sub("GTD Orion#Bastion");
12808  if (idx >= 0)
12809  return idx;
12810 
12811  idx = ship_info_lookup_sub("GTD Orion (Bastion)");
12812  if (idx >= 0)
12813  return idx;
12814 
12815  return -1;
12816  }
12817  else if (!stricmp(token, "SF Dragon#2 (weakened)"))
12818  {
12819  idx = ship_info_lookup_sub("SF Dragon#weakened");
12820  if (idx >= 0)
12821  return idx;
12822 
12823  idx = ship_info_lookup_sub("SF Dragon (weakened)");
12824  if (idx >= 0)
12825  return idx;
12826 
12827  return -1;
12828  }
12829  else if (!stricmp(token, "SF Dragon#3 (Player)"))
12830  {
12831  idx = ship_info_lookup_sub("SF Dragon#Terrans");
12832  if (idx >= 0)
12833  return idx;
12834 
12835  idx = ship_info_lookup_sub("SF Dragon (Terrans)");
12836  if (idx >= 0)
12837  return idx;
12838 
12839  return -1;
12840  }
12841  else if (!stricmp(token, "GTSC Faustus#2 (big blast)"))
12842  {
12843  idx = ship_info_lookup_sub("GTSC Faustus#bigblast");
12844  if (idx >= 0)
12845  return idx;
12846 
12847  return -1;
12848  }
12849  else if (!stricmp(token, "GTF Loki (stealth)"))
12850  {
12851  idx = ship_info_lookup_sub("GTF Loki#stealth");
12852  if (idx >= 0)
12853  return idx;
12854 
12855  return -1;
12856  }
12857 
12858  // get first part of new string
12859  strcpy_s(temp1, token);
12861 
12862  // get second part
12863  strcpy_s(temp2, p + 1);
12864 
12865  // found a hash
12866  if (*p == '#')
12867  {
12868  if (strlen(token) > NAME_LENGTH-3) {
12869  // If the below sprintf would exceed NAME_LENGTH (taking \0 terminator into account), give a warning and return.
12870  Warning(LOCATION, "Token [%s] is too long to be parenthesized by ship_info_lookup()!\n", token);
12871  return -1;
12872  }
12873  // assemble using parentheses
12874  sprintf(name, "%s (%s)", temp1, temp2);
12875  }
12876  // found a parenthesis
12877  else if (*p == '(')
12878  {
12879  // chop off right parenthesis (it exists because otherwise the left wouldn't have been flagged)
12880  char *p2 = strchr(temp2, ')');
12881  *p2 = '\0';
12882 
12883  // assemble using hash
12884  sprintf(name, "%s#%s", temp1, temp2);
12885  }
12886  // oops
12887  else
12888  {
12889  Warning(LOCATION, "Unrecognized hash symbol. Contact a programmer!");
12890  return -1;
12891  }
12892 
12893  // finally check the new name
12894  return ship_info_lookup_sub(name);
12895 }
12896 
12900 int ship_name_lookup(const char *name, int inc_players)
12901 {
12902  int i;
12903 
12904  // bogus
12905  if(name == NULL){
12906  return -1;
12907  }
12908 
12909  for (i=0; i<MAX_SHIPS; i++){
12910  if (Ships[i].objnum >= 0){
12911  if (Objects[Ships[i].objnum].type == OBJ_SHIP || (Objects[Ships[i].objnum].type == OBJ_START && inc_players)){
12912  if (!stricmp(name, Ships[i].ship_name)){
12913  return i;
12914  }
12915  }
12916  }
12917  }
12918 
12919  // couldn't find it
12920  return -1;
12921 }
12922 
12923 int ship_type_name_lookup(const char *name)
12924 {
12925  // bogus
12926  if(name == NULL || !strlen(name)){
12927  return -1;
12928  }
12929 
12930  //Look through Ship_types array
12931  uint max_size = Ship_types.size();
12932  for(uint idx=0; idx < max_size; idx++){
12933  if(!stricmp(name, Ship_types[idx].name)){
12934  return idx;
12935  }
12936  }
12937  // couldn't find it
12938  return -1;
12939 }
12940 
12941 // checks the (arrival & departure) state of a ship. Return values:
12942 // -1: has yet to arrive in mission
12943 // 0: is currently in mission
12944 // 1: has been destroyed, departed, or never existed
12946 {
12947  int i;
12948 
12949  // bogus
12950  Assert(name != NULL);
12951  if(name == NULL){
12952  return -1;
12953  }
12954 
12955  for (i=0; i<MAX_SHIPS; i++){
12956  if (Ships[i].objnum >= 0){
12957  if ((Objects[Ships[i].objnum].type == OBJ_SHIP) || (Objects[Ships[i].objnum].type == OBJ_START)){
12958  if (!stricmp(name, Ships[i].ship_name)){
12959  return 0;
12960  }
12961  }
12962  }
12963  }
12964 
12966  return -1;
12967 
12968  return 1;
12969 }
12970 
12971 // Finds the world position of a subsystem.
12972 // Return true/false for subsystem found/not found.
12973 // Stuff vector *pos with absolute position.
12974 // subsysp is a pointer to the subsystem.
12975 int get_subsystem_pos(vec3d *pos, object *objp, ship_subsys *subsysp)
12976 {
12977  if (subsysp == NULL) {
12978  *pos = objp->pos;
12979  return 0;
12980  }
12981  Assertion(objp->type == OBJ_SHIP, "Only ships can have subsystems!");
12982 
12983  model_subsystem *mss = subsysp->system_info;
12984 
12985  if (mss->subobj_num == -1) {
12986  // If it's a special point subsys, we can use its offset directly
12987 
12988  vm_vec_unrotate(pos, &subsysp->system_info->pnt, &objp->orient);
12989  vm_vec_add2(pos, &objp->pos);
12990  } else {
12991  // Submodel subsystems may require a more complicated calculation
12992 
12993  find_submodel_instance_world_point(pos, Ships[objp->instance].model_instance_num, mss->subobj_num, &objp->orient, &objp->pos);
12994  }
12995 
12996  return 1;
12997 }
12998 
12999 //=================================================
13000 // Takes all the angle info from the ship structure and stuffs it
13001 // into the model data so that the model code has all the correct
13002 // angles and stuff that it needs. This is a poorly designed
13003 // system that should be re-engineered so that all the model functions
13004 // accept a list of angles and everyone passes them through, but
13005 // that would require some major code revision.
13006 // So, anytime you are using a model that has rotating parts, you
13007 // need to do a ship_model_start before any model_ functions are
13008 // called and a ship_model_stop after you're done. Even for
13009 // collision detection and stuff, not just rendering.
13010 // See John for details.
13011 
13012 void ship_model_start(object *objp)
13013 {
13014  model_subsystem *psub;
13015  ship *shipp;
13016  ship_subsys *pss;
13017  int model_num;
13018 
13019  shipp = &Ships[objp->instance];
13020  model_num = Ship_info[shipp->ship_info_index].model_num;
13021 
13022  // First clear all the angles in the model to zero
13023  model_clear_instance(model_num);
13024 
13025  // Go through all subsystems and bash the model angles for all
13026  // the subsystems that need it.
13027  for ( pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
13028  psub = pss->system_info;
13029  switch (psub->type) {
13030  case SUBSYSTEM_RADAR:
13031  case SUBSYSTEM_NAVIGATION:
13033  case SUBSYSTEM_UNKNOWN:
13034  case SUBSYSTEM_ENGINE:
13035  case SUBSYSTEM_SENSORS:
13036  case SUBSYSTEM_WEAPONS:
13037  case SUBSYSTEM_SOLAR:
13038  case SUBSYSTEM_GAS_COLLECT:
13039  case SUBSYSTEM_ACTIVATION:
13040  case SUBSYSTEM_TURRET:
13041  break;
13042  default:
13043  Error(LOCATION, "Illegal subsystem type.\n");
13044  }
13045 
13046  if ( psub->subobj_num >= 0 ) {
13047  model_set_instance(model_num, psub->subobj_num, &pss->submodel_info_1, pss->flags );
13048  }
13049 
13050  if ( (psub->subobj_num != psub->turret_gun_sobj) && (psub->turret_gun_sobj >= 0) ) {
13051  model_set_instance(model_num, psub->turret_gun_sobj, &pss->submodel_info_2, pss->flags );
13052  }
13053  }
13054 }
13055 
13059 void ship_model_stop(object *objp)
13060 {
13061  Assert(objp != NULL);
13062  Assert(objp->instance >= 0);
13063  Assert(objp->type == OBJ_SHIP);
13064 
13065  // Then, clear all the angles in the model to zero
13066  model_clear_instance(Ship_info[Ships[objp->instance].ship_info_index].model_num);
13067 }
13068 
13073 {
13074  model_subsystem *psub;
13075  ship *shipp;
13076  ship_subsys *pss;
13077  int model_instance_num;
13078 
13079  Assert(objp != NULL);
13080  Assert(objp->instance >= 0);
13081  Assert(objp->type == OBJ_SHIP);
13082 
13083  shipp = &Ships[objp->instance];
13084  model_instance_num = shipp->model_instance_num;
13085 
13086  // Then, clear all the angles in the model to zero
13087  model_clear_submodel_instances(model_instance_num);
13088 
13089  // Handle subsystem rotations for this ship
13090  for ( pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
13091  psub = pss->system_info;
13092  switch (psub->type) {
13093  case SUBSYSTEM_RADAR:
13094  case SUBSYSTEM_NAVIGATION:
13096  case SUBSYSTEM_UNKNOWN:
13097  case SUBSYSTEM_ENGINE:
13098  case SUBSYSTEM_SENSORS:
13099  case SUBSYSTEM_WEAPONS:
13100  case SUBSYSTEM_SOLAR:
13101  case SUBSYSTEM_GAS_COLLECT:
13102  case SUBSYSTEM_ACTIVATION:
13103  case SUBSYSTEM_TURRET:
13104  break;
13105  default:
13106  Error(LOCATION, "Illegal subsystem type.\n");
13107  }
13108 
13109  if ( psub->subobj_num >= 0 ) {
13110  model_update_instance(model_instance_num, psub->subobj_num, &pss->submodel_info_1, pss->flags );
13111  }
13112 
13113  if ( (psub->subobj_num != psub->turret_gun_sobj) && (psub->turret_gun_sobj >= 0) ) {
13114  model_update_instance(model_instance_num, psub->turret_gun_sobj, &pss->submodel_info_2, pss->flags );
13115  }
13116  }
13117 
13118  // Handle intrinsic rotations for this ship
13119  model_do_intrinsic_rotations(model_instance_num);
13120 
13121  // preprocess subobject orientations for collision detection
13122  model_collide_preprocess(&objp->orient, model_instance_num);
13123 }
13124 
13129 {
13130  int n = 0;
13131  model_subsystem *psub;
13132  ship *shipp;
13133  ship_subsys *pss;
13134 
13135  shipp = &Ships[objp->instance];
13136 
13137  // Go through all subsystems and record the model angles for all
13138  // the subsystems that need it.
13139  for ( pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
13140  psub = pss->system_info;
13141  switch (psub->type) {
13142  case SUBSYSTEM_TURRET:
13143  if ( psub->flags & MSS_FLAG_CREWPOINT )
13144  n++; // fall through
13145 
13146  case SUBSYSTEM_RADAR:
13147  case SUBSYSTEM_NAVIGATION:
13149  case SUBSYSTEM_UNKNOWN:
13150  case SUBSYSTEM_ENGINE:
13151  case SUBSYSTEM_GAS_COLLECT:
13152  case SUBSYSTEM_ACTIVATION:
13153  break;
13154  default:
13155  Error(LOCATION, "Illegal subsystem type.\n");
13156  }
13157  }
13158  return n;
13159 }
13160 
13165 {
13166  int n = 0;
13167  model_subsystem *psub;
13168  ship *shipp;
13169  ship_subsys *pss;
13170 
13171  shipp = &Ships[objp->instance];
13172 
13173  // Go through all subsystems and record the model angles for all
13174  // the subsystems that need it.
13175  for ( pss = GET_FIRST(&shipp->subsys_list); pss != END_OF_LIST(&shipp->subsys_list); pss = GET_NEXT(pss) ) {
13176  psub = pss->system_info;
13177  switch (psub->type) {
13178  case SUBSYSTEM_TURRET:
13179  n++; // drop through
13180 
13181  case SUBSYSTEM_RADAR:
13182  case SUBSYSTEM_NAVIGATION:
13184  case SUBSYSTEM_UNKNOWN:
13185  case SUBSYSTEM_ENGINE:
13186  case SUBSYSTEM_GAS_COLLECT:
13187  case SUBSYSTEM_ACTIVATION:
13188  break;
13189  default:
13190  Error(LOCATION, "Illegal subsystem type.\n");
13191  }
13192  }
13193  return n;
13194 }
13195 
13196 //WMC
13197 void ship_set_eye( object *obj, int eye_index)
13198 {
13199  if(obj->type != OBJ_SHIP)
13200  return;
13201 
13202  ship *shipp = &Ships[obj->instance];
13203 
13204  if(eye_index < 0)
13205  {
13206  shipp->current_viewpoint = -1;
13207  return;
13208  }
13209 
13210  ship_info *sip = &Ship_info[shipp->ship_info_index];
13211  if(sip->model_num < 0)
13212  return;
13213 
13214  polymodel *pm = model_get(sip->model_num);
13215 
13216  if(pm == NULL || eye_index > pm->n_view_positions)
13217  return;
13218 
13219  shipp->current_viewpoint = eye_index;
13220 }
13221 
13222 // calculates the eye position for this ship in the global reference frame. Uses the
13223 // view_positions array in the model. The 0th element is the normal viewing position.
13224 // the vector of the eye is returned in the parameter 'eye'. The orientation of the
13225 // eye is returned in orient. (NOTE: this is kind of bogus for now since non 0th element
13226 // eyes have no defined up vector)
13227 void ship_get_eye( vec3d *eye_pos, matrix *eye_orient, object *obj, bool do_slew , bool from_origin)
13228 {
13229  Assertion(obj->type == OBJ_SHIP, "Only ships can have eye positions!");
13230 
13231  ship *shipp = &Ships[obj->instance];
13232  polymodel *pm = model_get(Ship_info[shipp->ship_info_index].model_num);
13233 
13234  // check to be sure that we have a view eye to look at.....spit out nasty debug message
13235  if ( shipp->current_viewpoint < 0 || pm->n_view_positions == 0 || shipp->current_viewpoint > pm->n_view_positions) {
13236  *eye_pos = obj->pos;
13237  *eye_orient = obj->orient;
13238  return;
13239  }
13240 
13241  // eye points are stored in an array -- the normal viewing position for a ship is the current_eye_index
13242  // element.
13243  eye *ep = &(pm->view_positions[Ships[obj->instance].current_viewpoint]);
13244 
13245  if (ep->parent >= 0 && pm->submodel[ep->parent].can_move) {
13246  find_submodel_instance_point_orient(eye_pos, eye_orient, shipp->model_instance_num, ep->parent, &ep->pnt, &vmd_identity_matrix);
13247  vec3d tvec = *eye_pos;
13248  vm_vec_unrotate(eye_pos, &tvec, &obj->orient);
13249  vm_vec_add2(eye_pos, &obj->pos);
13250 
13251  matrix tempmat = *eye_orient;
13252  vm_matrix_x_matrix(eye_orient, &obj->orient, &tempmat);
13253  } else {
13254  model_find_world_point( eye_pos, &ep->pnt, pm->id, ep->parent, &obj->orient, from_origin ? &vmd_zero_vector : &obj->pos );
13255  *eye_orient = obj->orient;
13256  }
13257 
13258  // Modify the orientation based on head orientation.
13259  if ( Viewer_obj == obj && do_slew) {
13260  // Add the cockpit leaning translation offset
13261  vm_vec_add2(eye_pos,&leaning_position);
13263  }
13264 }
13265 
13266 // of attackers to make this decision.
13267 //
13268 // NOTE: This function takes into account how many ships are attacking a subsystem, and will
13269 // prefer an ignored subsystem over a subsystem that is in line of sight, if the in-sight
13270 // subsystem is attacked by more than MAX_SUBSYS_ATTACKERS
13271 // input:
13272 // sp => ship pointer to parent of subsystem
13273 // subsys_type => what kind of subsystem this is
13274 // attacker_pos => the world coords of the attacker of this subsystem
13275 //
13276 // returns: pointer to subsystem if one found, NULL otherwise
13277 #define MAX_SUBSYS_ATTACKERS 3
13278 ship_subsys *ship_get_best_subsys_to_attack(ship *sp, int subsys_type, vec3d *attacker_pos)
13279 {
13280  ship_subsys *ss;
13281  ship_subsys *best_in_sight_subsys, *lowest_attacker_subsys, *ss_return;
13282  int lowest_num_attackers, lowest_in_sight_attackers, num_attackers;
13283  vec3d gsubpos;
13284  ship_obj *sop;
13285 
13286  lowest_in_sight_attackers = lowest_num_attackers = 1000;
13287  ss_return = best_in_sight_subsys = lowest_attacker_subsys = NULL;
13288 
13289  for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
13290  if ( (ss->system_info->type == subsys_type) && (ss->current_hits > 0) ) {
13291 
13292  // get world pos of subsystem
13293  vm_vec_unrotate(&gsubpos, &ss->system_info->pnt, &Objects[sp->objnum].orient);
13294  vm_vec_add2(&gsubpos, &Objects[sp->objnum].pos);
13295 
13296  // now find the number of ships attacking this subsystem by iterating through the ships list,
13297  // and checking if aip->targeted_subsys matches the subsystem we're checking
13298  num_attackers = 0;
13299  sop = GET_FIRST(&Ship_obj_list);
13300  while(sop != END_OF_LIST(&Ship_obj_list)){
13301  if ( Ai_info[Ships[Objects[sop->objnum].instance].ai_index].targeted_subsys == ss ) {
13302  num_attackers++;
13303  }
13304  sop = GET_NEXT(sop);
13305  }
13306 
13307  if ( num_attackers < lowest_num_attackers ) {
13308  lowest_num_attackers = num_attackers;
13309  lowest_attacker_subsys = ss;
13310  }
13311 
13312  if ( ship_subsystem_in_sight(&Objects[sp->objnum], ss, attacker_pos, &gsubpos) ) {
13313  if ( num_attackers < lowest_in_sight_attackers ) {
13314  lowest_in_sight_attackers = num_attackers;
13315  best_in_sight_subsys = ss;
13316  }
13317  }
13318  }
13319  }
13320 
13321  if ( best_in_sight_subsys == NULL ) {
13322  // no subsystems are in sight, so return the subsystem with the lowest # of attackers
13323  ss_return = lowest_attacker_subsys;
13324  } else {
13325  if ( lowest_in_sight_attackers > MAX_SUBSYS_ATTACKERS ) {
13326  ss_return = lowest_attacker_subsys;
13327  } else {
13328  ss_return = best_in_sight_subsys;
13329  }
13330  }
13331 
13332  return ss_return;
13333 }
13334 
13335 // function to return a pointer to the 'nth' ship_subsys structure in a ship's linked list
13336 // of ship_subsys'.
13337 // attacker_pos => world pos of attacker (default value NULL). If value is non-NULL, try
13338 // to select the best subsystem to attack of that type (using line-of-sight)
13339 // and based on the number of ships already attacking the subsystem
13341 {
13342  int count;
13343  ship_subsys *ss;
13344 
13345  // first, special code to see if the index < 0. If so, we are looking for one of several possible
13346  // engines or one of several possible turrets. If we enter this if statement, we will always return
13347  // something.
13348  if ( index < 0 ) {
13349  int subsys_type;
13350 
13351  subsys_type = -index;
13352  if ( sp->subsys_info[subsys_type].aggregate_current_hits <= 0.0f ) // if there are no hits, no subsystem to attack.
13353  return NULL;
13354 
13355  if ( attacker_pos != NULL ) {
13356  ss = ship_get_best_subsys_to_attack(sp, subsys_type, attacker_pos);
13357  return ss;
13358  } else {
13359  // next, scan the list of subsystems and search for the first subsystem of the particular
13360  // type which has > 0 hits remaining.
13361  for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
13362  if ( (ss->system_info->type == subsys_type) && (ss->current_hits > 0) )
13363  return ss;
13364  }
13365  }
13366 
13367  // maybe we shouldn't get here, but with possible floating point rounding, I suppose we could
13368  Warning(LOCATION, "Unable to get a nonspecific subsystem of index %d on ship %s!", index, sp->ship_name);
13369  return NULL;
13370  }
13371 
13372 
13373  count = 0;
13374  ss = GET_FIRST(&sp->subsys_list);
13375  while ( ss != END_OF_LIST( &sp->subsys_list ) ) {
13376  if ( count == index )
13377  return ss;
13378  count++;
13379  ss = GET_NEXT( ss );
13380  }
13381 
13382  // get allender -- turret ref didn't fixup correctly!!!!
13383  Warning(LOCATION, "In ship_get_indexed_subsys, unable to get a subsystem of index %d on ship %s, due to a broken subsystem reference! This is most likely due to a table/model mismatch.", index, sp->ship_name);
13384  return NULL;
13385 }
13386 
13390 int ship_get_index_from_subsys(ship_subsys *ssp, int objnum, int error_bypass)
13391 {
13392  if (ssp == NULL)
13393  return -1;
13394  else {
13395  int count;
13396  ship *shipp;
13397  ship_subsys *ss;
13398 
13399  Assert(objnum >= 0);
13400  Assert(Objects[objnum].instance >= 0);
13401 
13402  shipp = &Ships[Objects[objnum].instance];
13403 
13404  count = 0;
13405  ss = GET_FIRST(&shipp->subsys_list);
13406  while ( ss != END_OF_LIST( &shipp->subsys_list ) ) {
13407  if ( ss == ssp)
13408  return count;
13409  count++;
13410  ss = GET_NEXT( ss );
13411  }
13412  if ( !error_bypass )
13413  Int3(); // get allender -- turret ref didn't fixup correctly!!!!
13414  return -1;
13415  }
13416 }
13417 
13421 int ship_get_subsys_index(ship *sp, char *ss_name, int error_bypass)
13422 {
13423  int count;
13424  ship_subsys *ss;
13425 
13426  count = 0;
13427  ss = GET_FIRST(&sp->subsys_list);
13428  while ( ss != END_OF_LIST( &sp->subsys_list ) ) {
13429  if ( !subsystem_stricmp(ss->system_info->subobj_name, ss_name) )
13430  return count;
13431  count++;
13432  ss = GET_NEXT( ss );
13433  }
13434 
13435  if (!error_bypass)
13436  Int3();
13437 
13438  return -1;
13439 }
13440 
13441 // routine to return the strength of a subsystem. We keep a total hit tally for all subsystems
13442 // which are similar (i.e. a total for all engines). These routines will return a number between
13443 // 0.0 and 1.0 which is the relative combined strength of the given subsystem type. The number
13444 // calculated for the engines is slightly different. Once an engine reaches < 15% of its hits, its
13445 // output drops to that %. A dead engine has no output.
13447 {
13448  float strength;
13449  ship_subsys *ssp;
13450 
13451  Assert ( (type >= 0) && (type < SUBSYSTEM_MAX) );
13452 
13453  // For a dying ship, all subsystem strengths are zero.
13454  if (Objects[shipp->objnum].hull_strength <= 0.0f)
13455  return 0.0f;
13456 
13457  // short circuit 1
13458  if (shipp->subsys_info[type].aggregate_max_hits <= 0.0f)
13459  return 1.0f;
13460 
13461  // short circuit 0
13462  if (shipp->subsys_info[type].aggregate_current_hits <= 0.0f)
13463  return 0.0f;
13464 
13466  Assert( strength != 0.0f );
13467 
13468  if ( (type == SUBSYSTEM_ENGINE) && (strength < 1.0f) ) {
13469  float percent;
13470 
13471  percent = 0.0f;
13472  ssp = GET_FIRST(&shipp->subsys_list);
13473  while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) {
13474 
13475  if ( ssp->system_info->type == SUBSYSTEM_ENGINE ) {
13476  float ratio;
13477 
13478  ratio = ssp->current_hits / ssp->max_hits;
13479  if ( ratio < ENGINE_MIN_STR )
13480  ratio = ENGINE_MIN_STR;
13481 
13482  percent += ratio;
13483  }
13484  ssp = GET_NEXT( ssp );
13485  }
13486  strength = percent / (float)shipp->subsys_info[type].type_count;
13487  }
13488 
13489  return strength;
13490 }
13491 
13500 void ship_set_subsystem_strength( ship *shipp, int type, float strength )
13501 {
13502  float total_current_hits, diff;
13503  ship_subsys *ssp;
13504 
13505  Assert ( (type >= 0) && (type < SUBSYSTEM_MAX) );
13506  if ( shipp->subsys_info[type].aggregate_max_hits <= 0.0f )
13507  return;
13508 
13509  total_current_hits = 0.0f;
13510  ssp = GET_FIRST(&shipp->subsys_list);
13511  while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) {
13512 
13513  if ( (ssp->system_info->type == type) && !(ssp->flags & SSF_NO_AGGREGATE) ) {
13514  ssp->current_hits = strength * ssp->max_hits;
13515  total_current_hits += ssp->current_hits;
13516  }
13517  ssp = GET_NEXT( ssp );
13518  }
13519 
13520  // update the objects integrity, needed since we've bashed the strength of a subsysem
13521  diff = total_current_hits - shipp->subsys_info[type].aggregate_current_hits;
13522  Objects[shipp->objnum].hull_strength += diff;
13523  // fix up the shipp->subsys_info[type] aggregate_current_hits value
13524  shipp->subsys_info[type].aggregate_current_hits = total_current_hits;
13525 }
13526 
13527 #define SHIELD_REPAIR_RATE 0.20f // Percent of shield repaired per second.
13528 #define HULL_REPAIR_RATE 0.15f // Percent of hull repaired per second.
13529 #define SUBSYS_REPAIR_RATE 0.10f // Percent of subsystems repaired per second.
13530 
13531 #define REARM_NUM_MISSILES_PER_BATCH 4 // how many missiles are dropped in per load sound
13532 #define REARM_NUM_BALLISTIC_PRIMARIES_PER_BATCH 100 // how many bullets are dropped in per load sound
13533 
13538 {
13539  ship* sp;
13540  ship_info* sip;
13541  ship_subsys* ssp;
13542  ship_weapon* swp;
13543  weapon_info* wip;
13544 
13545  float shield_rep_time = 0;
13546  float subsys_rep_time = 0;
13547  float hull_rep_time = 0;
13548  float prim_rearm_time = 0;
13549  float sec_rearm_time = 0;
13550 
13551  float max_hull_repair;
13552  float max_subsys_repair;
13553 
13554  int i;
13555  int num_reloads;
13556 
13557  bool found_first_empty;
13558 
13559  Assert(objp->type == OBJ_SHIP);
13560 
13561  sp = &Ships[objp->instance];
13562  swp = &sp->weapons;
13563  sip = &Ship_info[sp->ship_info_index];
13564 
13565  //find out time to repair shields
13566  if(sip->sup_shield_repair_rate > 0.0f)
13568 
13569  max_hull_repair = sp->ship_max_hull_strength * (The_mission.support_ships.max_hull_repair_val * 0.01f);
13570  if ((The_mission.flags & MISSION_FLAG_SUPPORT_REPAIRS_HULL) && (max_hull_repair > objp->hull_strength) && (sip->sup_hull_repair_rate > 0.0f))
13571  {
13572  hull_rep_time = (max_hull_repair - objp->hull_strength) / (sp->ship_max_hull_strength * sip->sup_hull_repair_rate);
13573  }
13574 
13575  //caluclate subsystem repair time
13576  ssp = GET_FIRST(&sp->subsys_list);
13577  while (ssp != END_OF_LIST(&sp->subsys_list))
13578  {
13579  max_subsys_repair = ssp->max_hits * (The_mission.support_ships.max_subsys_repair_val * 0.01f);
13580  if ((max_subsys_repair > ssp->current_hits) && (sip->sup_subsys_repair_rate > 0.0f))
13581  {
13582  subsys_rep_time += (max_subsys_repair - ssp->current_hits) / (ssp->max_hits * sip->sup_subsys_repair_rate);
13583  }
13584 
13585  ssp = GET_NEXT( ssp );
13586  }
13587 
13588  //now do the primary rearm time
13589  found_first_empty = false;
13590  if (sip->flags & SIF_BALLISTIC_PRIMARIES)
13591  {
13592  for (i = 0; i < swp->num_primary_banks; i++)
13593  {
13594  wip = &Weapon_info[swp->primary_bank_weapons[i]];
13595  if (wip->wi_flags2 & WIF2_BALLISTIC)
13596  {
13597  //check how many full reloads we need
13599 
13600  //take into account a fractional reload
13602  {
13603  num_reloads++;
13604  }
13605 
13606  //don't factor in the time it takes for the first reload, since that is loaded instantly
13607  num_reloads--;
13608 
13609  if (num_reloads < 0) continue;
13610 
13611  if (!found_first_empty && (swp->primary_bank_start_ammo[i] - swp->primary_bank_ammo[i]))
13612  {
13613  found_first_empty = true;
13614  prim_rearm_time += (float)snd_get_duration(Snds[SND_MISSILE_START_LOAD].id) / 1000.0f;
13615  }
13616 
13617  prim_rearm_time += num_reloads * wip->rearm_rate;
13618  }
13619  }
13620  }
13621 
13622  //and on to secondary rearm time
13623  found_first_empty = false;
13624  for (i = 0; i < swp->num_secondary_banks; i++)
13625  {
13626  wip = &Weapon_info[swp->secondary_bank_weapons[i]];
13627 
13628  //check how many full reloads we need
13630 
13631  //take into account a fractional reload
13633  {
13634  num_reloads++;
13635  }
13636 
13637  //don't factor in the time it takes for the first reload, since that is loaded instantly
13638  num_reloads--;
13639 
13640  if (num_reloads < 0) continue;
13641 
13642  if (!found_first_empty && (swp->secondary_bank_start_ammo[i] - swp->secondary_bank_ammo[i]))
13643  {
13644  found_first_empty = true;
13645  sec_rearm_time += (float)snd_get_duration(Snds[SND_MISSILE_START_LOAD].id) / 1000.0f;
13646  }
13647 
13648  sec_rearm_time += num_reloads * wip->rearm_rate;
13649  }
13650 
13651  //sum them up and you've got an estimated rearm time.
13652  //add 1.2 to compensate for release delay
13653  return shield_rep_time + hull_rep_time + subsys_rep_time + prim_rearm_time + sec_rearm_time + 1.2f;
13654 }
13655 
13656 
13657 
13658 // ==================================================================================
13659 // ship_do_rearm_frame()
13660 //
13661 // function to rearm a ship. This function gets called from the ai code ai_do_rearm_frame (or
13662 // some function of a similar name). Returns 1 when ship is fully repaired and rearmed, 0 otherwise
13663 //
13664 int ship_do_rearm_frame( object *objp, float frametime )
13665 {
13666  int i, banks_full, primary_banks_full, subsys_type, subsys_all_ok, last_ballistic_idx = 0;
13667  float shield_str, repair_delta, repair_allocated, max_hull_repair, max_subsys_repair;
13668  ship *shipp;
13669  ship_weapon *swp;
13670  ship_info *sip;
13671  ship_subsys *ssp;
13672  ai_info *aip;
13673 
13674  shipp = &Ships[objp->instance];
13675  swp = &shipp->weapons;
13676  sip = &Ship_info[shipp->ship_info_index];
13677  aip = &Ai_info[shipp->ai_index];
13678 
13679  // AL 10-31-97: Add missing primary weapons to the ship. This is required since designers
13680  // want to have ships that start with no primaries, but can get them through
13681  // rearm/repair
13682  if ( swp->num_primary_banks < sip->num_primary_banks ) {
13683  for ( i = swp->num_primary_banks; i < sip->num_primary_banks; i++ ) {
13685  }
13687  }
13688  // AL 12-30-97: Repair broken warp drive
13689  if ( shipp->flags & SF_WARP_BROKEN ) {
13690  // TODO: maybe do something here like informing player warp is fixed?
13691  // like this? -- Goober5000
13692  HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Subspace drive repaired.", 1635));
13693  shipp->flags &= ~SF_WARP_BROKEN;
13694  }
13695 
13696  // AL 1-16-97: Replenish countermeasures
13697  shipp->cmeasure_count = sip->cmeasure_max;
13698 
13699  // Do shield repair here
13700  if ( !(objp->flags & OF_NO_SHIELDS) )
13701  {
13702  shield_str = shield_get_strength(objp);
13703  if ( shield_str < (shipp->ship_max_shield_strength * shipp->max_shield_recharge) ) {
13704  if ( objp == Player_obj ) {
13706  }
13707  shield_str += shipp->ship_max_shield_strength * frametime * sip->sup_shield_repair_rate;
13708  if ( shield_str > shipp->ship_max_shield_strength ) {
13709  shield_str = shipp->ship_max_shield_strength;
13710  }
13711  shield_set_strength(objp, shield_str);
13712  }
13713  }
13714 
13715  // Repair the ship integrity (subsystems + hull). This works by applying the repair points
13716  // to the subsystems. Ships integrity is stored is objp->hull_strength, so that always is
13717  // incremented by repair_allocated
13718  repair_allocated = shipp->ship_max_hull_strength * frametime * sip->sup_hull_repair_rate;
13719 
13720 // AL 11-24-97: remove increase to hull integrity
13721 // Comments removed by PhReAk; Note that this is toggled on/off with a mission flag
13722 
13723  //Figure out how much of the ship's hull we can repair
13724  max_hull_repair = shipp->ship_max_hull_strength * (The_mission.support_ships.max_hull_repair_val * 0.01f);
13725 
13726  //Don't "reverse-repair" the hull if it's already above the max repair threshold
13727  if (objp->hull_strength > max_hull_repair)
13728  {
13729  max_hull_repair = objp->hull_strength;
13730  }
13731 
13733  {
13734  objp->hull_strength += repair_allocated;
13735  if ( objp->hull_strength > max_hull_repair ) {
13736  objp->hull_strength = max_hull_repair;
13737  }
13738 
13739  if ( objp->hull_strength > shipp->ship_max_hull_strength )
13740  {
13741  objp->hull_strength = shipp->ship_max_hull_strength;
13742  repair_allocated -= ( shipp->ship_max_hull_strength - objp->hull_strength);
13743  }
13744  }
13745 
13746  // figure out repairs for subsystems
13747  if(sip->sup_subsys_repair_rate == 0.0f)
13748  repair_allocated = 0.0f;
13749  else if(sip->sup_hull_repair_rate == 0.0f)
13750  repair_allocated = shipp->ship_max_hull_strength * frametime * sip->sup_subsys_repair_rate;
13751  else if(!(sip->sup_hull_repair_rate == sip->sup_subsys_repair_rate))
13752  repair_allocated = repair_allocated * sip->sup_subsys_repair_rate / sip->sup_hull_repair_rate;
13753 
13754  // check the subsystems of the ship.
13755  subsys_all_ok = 1;
13756  ssp = GET_FIRST(&shipp->subsys_list);
13757  while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) {
13758  //Figure out how much we *can* repair the current subsystem -C
13759  max_subsys_repair = ssp->max_hits * (The_mission.support_ships.max_subsys_repair_val * 0.01f);
13760 
13761  if ( ssp->current_hits < max_subsys_repair && repair_allocated > 0 ) {
13762  subsys_all_ok = 0;
13763  subsys_type = ssp->system_info->type;
13764 
13765  if ( objp == Player_obj ) {
13767  }
13768 
13769  repair_delta = max_subsys_repair - ssp->current_hits;
13770  if ( repair_delta > repair_allocated ) {
13771  repair_delta = repair_allocated;
13772  }
13773  repair_allocated -= repair_delta;
13774  Assert(repair_allocated >= 0.0f);
13775 
13776  // add repair to current strength of single subsystem
13777  ssp->current_hits += repair_delta;
13778  if ( ssp->current_hits > max_subsys_repair ) {
13779  ssp->current_hits = max_subsys_repair;
13780  }
13781 
13782  // add repair to aggregate strength of subsystems of that type
13783  if (!(ssp->flags & SSF_NO_AGGREGATE)) {
13784  shipp->subsys_info[subsys_type].aggregate_current_hits += repair_delta;
13785  if ( shipp->subsys_info[subsys_type].aggregate_current_hits > shipp->subsys_info[subsys_type].aggregate_max_hits )
13786  shipp->subsys_info[subsys_type].aggregate_current_hits = shipp->subsys_info[subsys_type].aggregate_max_hits;
13787  }
13788 
13789  // check to see if this subsystem was totally non functional before -- if so, then
13790  // reset the flags
13791  if ( (ssp->system_info->type == SUBSYSTEM_ENGINE) && (shipp->flags & SF_DISABLED) ) {
13792  shipp->flags &= ~SF_DISABLED;
13794  }
13795  break;
13796  }
13797  ssp = GET_NEXT( ssp );
13798  }
13799 
13800  // now deal with rearming the player. All secondary weapons have a certain rate at which
13801  // they can be rearmed. We can rearm multiple banks at once.
13802  banks_full = 0;
13803  primary_banks_full = 0;
13804  if ( subsys_all_ok )
13805  {
13806  for (i = 0; i < swp->num_secondary_banks; i++ )
13807  {
13808  // Actual loading of missiles is preceded by a sound effect which is the missile
13809  // loading equipment moving into place
13810  if ( aip->rearm_first_missile == TRUE )
13811  {
13813 
13814  if (i == swp->num_secondary_banks - 1)
13815  aip->rearm_first_missile = FALSE;
13816  }
13817 
13818  if ( swp->secondary_bank_ammo[i] < swp->secondary_bank_start_ammo[i] )
13819  {
13820  float rearm_time;
13821 
13822  if ( objp == Player_obj )
13823  {
13825  }
13826 
13828  {
13829  rearm_time = Weapon_info[swp->secondary_bank_weapons[i]].rearm_rate;
13830  swp->secondary_bank_rearm_time[i] = timestamp((int)(rearm_time * 1000.0f));
13831 
13833  if (objp == Player_obj)
13835 
13837  if ( swp->secondary_bank_ammo[i] > swp->secondary_bank_start_ammo[i] )
13838  {
13840  }
13841  }
13842  else
13843  {
13844  }
13845  }
13846  else
13847  {
13848  banks_full++;
13849  }
13850 
13851  if ((aip->rearm_first_missile == TRUE) && (i == swp->num_secondary_banks - 1) && (banks_full != swp->num_secondary_banks))
13853  } // end for
13854 
13855  // rearm ballistic primaries - Goober5000
13856  if (sip->flags & SIF_BALLISTIC_PRIMARIES)
13857  {
13858  if ( aip->rearm_first_ballistic_primary == TRUE)
13859  {
13860  for (i = 1; i < swp->num_primary_banks; i++ )
13861  {
13863  last_ballistic_idx = i;
13864  }
13865  }
13866 
13867  for (i = 0; i < swp->num_primary_banks; i++ )
13868  {
13870  {
13871  // Actual loading of bullets is preceded by a sound effect which is the bullet
13872  // loading equipment moving into place
13873  if ( aip->rearm_first_ballistic_primary == TRUE )
13874  {
13875  // Goober5000
13876  int sound_index;
13877  if (Snds[SND_BALLISTIC_START_LOAD].id >= 0)
13878  sound_index = SND_BALLISTIC_START_LOAD;
13879  else
13880  sound_index = SND_MISSILE_START_LOAD;
13881 
13882  swp->primary_bank_rearm_time[i] = timestamp(snd_get_duration(Snds[sound_index].id));
13883 
13884  if (i == last_ballistic_idx)
13886  }
13887 
13888  if ( swp->primary_bank_ammo[i] < swp->primary_bank_start_ammo[i] )
13889  {
13890  float rearm_time;
13891 
13892  if ( objp == Player_obj )
13893  {
13895  }
13896 
13898  {
13899  rearm_time = Weapon_info[swp->primary_bank_weapons[i]].rearm_rate;
13900  swp->primary_bank_rearm_time[i] = timestamp( (int)(rearm_time * 1000.f) );
13901 
13902  // Goober5000
13903  int sound_index;
13904  if (Snds[SND_BALLISTIC_LOAD].id >= 0)
13905  sound_index = SND_BALLISTIC_LOAD;
13906  else
13907  sound_index = SND_MISSILE_LOAD;
13908 
13909  snd_play_3d( &Snds[sound_index], &objp->pos, &View_position );
13910 
13912  if ( swp->primary_bank_ammo[i] > swp->primary_bank_start_ammo[i] )
13913  {
13915  }
13916  }
13917  }
13918  else
13919  {
13920  primary_banks_full++;
13921  }
13922  }
13923  // if the bank is not a ballistic
13924  else
13925  {
13926  primary_banks_full++;
13927  }
13928 
13929  if ((aip->rearm_first_ballistic_primary == TRUE) && (i == swp->num_primary_banks - 1) && (primary_banks_full != swp->num_primary_banks))
13930  {
13931  // Goober5000
13932  int sound_index;
13933  if (Snds[SND_BALLISTIC_START_LOAD].id >= 0)
13934  sound_index = SND_BALLISTIC_START_LOAD;
13935  else
13936  sound_index = SND_MISSILE_START_LOAD;
13937 
13938  snd_play_3d( &Snds[sound_index], &objp->pos, &View_position );
13939  }
13940  } // end for
13941  } // end if - rearm ballistic primaries
13942  } // end if (subsys_all_ok)
13943 
13944  if ( banks_full == swp->num_secondary_banks )
13945  {
13946  aip->rearm_first_missile = TRUE;
13947  }
13948 
13949  if ( primary_banks_full == swp->num_primary_banks )
13950  {
13952  }
13953 
13954  int shields_full = 0;
13955  if ( (objp->flags & OF_NO_SHIELDS) ) {
13956  shields_full = 1;
13957  } else {
13958  if ( shield_get_strength(objp) >= shipp->ship_max_shield_strength )
13959  shields_full = 1;
13960  if (sip->sup_shield_repair_rate == 0.0f)
13961  shields_full = 1;
13962  }
13963 
13964  int hull_ok = 0;
13965  if(objp->hull_strength >= max_hull_repair)
13966  hull_ok = 1;
13967 
13968  if(sip->sup_hull_repair_rate == 0.0f) {
13969  subsys_all_ok = 1;
13970  hull_ok = 1;
13971  }
13972 
13973  // return 1 if at end of subsystem list, hull damage at 0, and shields full and all secondary banks full.
13974  if ( (subsys_all_ok && shields_full && (The_mission.flags & MISSION_FLAG_SUPPORT_REPAIRS_HULL) && hull_ok ) || (subsys_all_ok && shields_full && !(The_mission.flags & MISSION_FLAG_SUPPORT_REPAIRS_HULL) ) )
13975  {
13976  if ( objp == Player_obj ) {
13978  }
13979 
13980  if (!aip->rearm_release_delay)
13981  aip->rearm_release_delay = timestamp(1200);
13982 
13983  // check both primary and secondary banks are full
13984  if ( (banks_full == swp->num_secondary_banks) &&
13985  ( !(sip->flags & SIF_BALLISTIC_PRIMARIES) || ((sip->flags & SIF_BALLISTIC_PRIMARIES) && (primary_banks_full == swp->num_primary_banks)) ) )
13986  {
13988  return 1;
13989  }
13990  else
13991  {
13992  aip->rearm_release_delay = timestamp(1200);
13993  }
13994  }
13995 
13996  if (objp == Player_obj) Player_rearm_eta -= frametime;
13997 
13998  return 0;
13999 }
14000 
14001 // Goober5000 - modified the logic to clarify the various states
14002 // function which is used to find a repair ship to repair requester_obj. the way repair ships will work is:
14003 // if no ships in the mission at all, return 0
14004 // if a ship can immediately satisfy a repair request, return 1 and fill in the pointer
14005 // if no ships can satisfy a request, but we haven't reached either the concurrent or cumulative limit, return 2
14006 // if no ships can satisfy a request, and we've reached the limits, but a request can be queued, return 3 and fill in the pointer
14007 // if no ships can satisfy a request, we've reached the limits, and we can't queue anything, we're out of luck -- return 4
14008 int ship_find_repair_ship( object *requester_obj, object **ship_we_found )
14009 {
14010  object *objp;
14011  int num_support_ships = 0;
14012  float min_dist = -1.0f;
14013  object *nearest_support_ship = NULL;
14014  float min_time_till_available = -1.0f;
14015  object *soonest_available_support_ship = NULL;
14016 
14017  Assertion(requester_obj->type == OBJ_SHIP, "requester_obj not a ship. Has type of %08x", requester_obj->type);
14018  Assertion((requester_obj->instance >= 0) && (requester_obj->instance < MAX_SHIPS),
14019  "requester_obj does not have a valid pointer to a ship. Pointer is %d, which is smaller than 0 or bigger than %d",
14020  requester_obj->instance, MAX_SHIPS);
14021 
14022  ship *requester_ship = &Ships[requester_obj->instance];
14023  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
14024  {
14025  if ((objp->type == OBJ_SHIP) && !(objp->flags & OF_SHOULD_BE_DEAD))
14026  {
14027  ship *shipp;
14028  ship_info *sip;
14029  float dist;
14030 
14031  Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS),
14032  "objp does not have a valid pointer to a ship. Pointer is %d, which is smaller than 0 or bigger than %d",
14033  objp->instance, MAX_SHIPS);
14034 
14035  shipp = &Ships[objp->instance];
14036 
14037  if ( shipp->team != requester_ship->team ) {
14038  continue;
14039  }
14040 
14041  Assertion((shipp->ship_info_index >= 0) && (shipp->ship_info_index < static_cast<int>(Ship_info.size())),
14042  "Ship '%s' does not have a valid pointer to a ship class. Pointer is %d, which is smaller than 0 or bigger than %d",
14043  shipp->ship_name, shipp->ship_info_index, static_cast<int>(Ship_info.size()));
14044 
14045  sip = &Ship_info[shipp->ship_info_index];
14046 
14047  if ( !(sip->flags & SIF_SUPPORT) ) {
14048  continue;
14049  }
14050 
14051  // tally how many support ships actually exist
14052  num_support_ships++;
14053 
14054  // don't deal with dying or departing support ships
14055  if ( shipp->flags & (SF_DYING | SF_DEPARTING) ) {
14056  continue;
14057  }
14058 
14059  // Ship has been ordered to warpout but has not had a chance to process the order.
14060  Assertion( (shipp->ai_index >= 0) && (shipp->ai_index < MAX_AI_INFO),
14061  "Ship '%s' doesn't have a valid ai pointer. Pointer is %d, which is smaller than 0 or larger than %d",
14062  shipp->ship_name, shipp->ai_index, MAX_AI_INFO);
14063  ai_info* aip = &(Ai_info[shipp->ai_index]);
14064  if ( ai_find_goal_index( aip->goals, AI_GOAL_WARP ) != -1 ) {
14065  continue;
14066  }
14067 
14068  dist = vm_vec_dist_quick(&objp->pos, &requester_obj->pos);
14069 
14071  {
14072  // support ship is already busy, track the one that will be
14073  // done soonest by estimating how many seconds it will take for the support ship
14074  // to reach the requester.
14075  // The estimate is calculated by calculating how many seconds it will take the
14076  // support ship to travel from its current location to the requester at max velocity
14077  // We assume that every leg of the support ships journey will take the amount of time
14078  // for the support ship to fly from its current location to the requester. This is
14079  // a bit hacky but it penalizes further away support ships, so a futher support ship
14080  // will only be called if the closer ones are really busy. This is just a craps shoot
14081  // anyway because everything is moving around.
14082  float howlong = 0;
14083  for( int i = 0; i < MAX_AI_GOALS; i++ ) {
14084  if ( aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR ) {
14085  howlong += dist * objp->phys_info.max_vel.xyz.z;
14086  }
14087  }
14088  if ( min_time_till_available < 0.0f || howlong < min_time_till_available ) {
14089  min_time_till_available = howlong;
14090  soonest_available_support_ship = objp;
14091  }
14092  }
14093  else
14094  {
14095  // support ship not already busy, find the closest
14096  if ( min_dist < 0.0f || dist < min_dist )
14097  {
14098  min_dist = dist;
14099  nearest_support_ship = objp;
14100  }
14101  }
14102  }
14103  }
14104 
14105  // no ships present?
14106  // (be advised we may have an Arriving_support_ship in this case)
14107  if (num_support_ships == 0) {
14108  return 0;
14109  }
14110  // ship available?
14111  else if (nearest_support_ship != NULL) {
14112  // the nearest non-busy support ship is to service request
14113  if (ship_we_found != NULL)
14114  *ship_we_found = nearest_support_ship;
14115  return 1;
14116  }
14117  // no ships available; are we below the limits? (can we bring another ship in? -- and btw an Arriving_support_ship counts as being able to bring one in)
14118  else if ((num_support_ships < The_mission.support_ships.max_concurrent_ships)
14121  {
14122  // We are allowed more support ships in the mission; request another ship
14123  // to service this request.
14124  return 2;
14125  }
14126  // we're at the limit, but maybe a ship will become available
14127  else if (soonest_available_support_ship != NULL) {
14128  // found more support ships than should be in mission, so I can't ask for more,
14129  // instead I will give the player the ship that will be done soonest
14130  if (ship_we_found != NULL)
14131  *ship_we_found = soonest_available_support_ship;
14132  return 3;
14133  }
14134  // none of the above; we're out of luck
14135  else {
14136  return 4;
14137  }
14138 }
14139 
14145 int CLOAKMAP=-1;
14147 {
14148  int i;
14149 
14150  for (i=0; i<MAX_SHIPS; i++ ) {
14151  ship *shipp = &Ships[i];
14152 
14153  if (shipp->shield_integrity != NULL) {
14154  vm_free(shipp->shield_integrity);
14155  shipp->shield_integrity = NULL;
14156  }
14157 
14158  if (shipp->ship_replacement_textures != NULL) {
14160  shipp->ship_replacement_textures = NULL;
14161  }
14162 
14163  if(shipp->warpin_effect != NULL)
14164  delete shipp->warpin_effect;
14165  shipp->warpin_effect = NULL;
14166 
14167  if(shipp->warpout_effect != NULL)
14168  delete shipp->warpout_effect;
14169  shipp->warpout_effect = NULL;
14170  }
14171 
14172  // free this too! -- Goober5000
14173  ship_clear_subsystems();
14174 
14175  // free info from parsed table data
14176  Ship_info.clear();
14177 
14178  for (i = 0; i < (int)Ship_types.size(); i++) {
14179  Ship_types[i].ai_actively_pursues.clear();
14180  Ship_types[i].ai_actively_pursues_temp.clear();
14181  }
14182  Ship_types.clear();
14183 
14184  if(CLOAKMAP != -1)
14185  bm_release(CLOAKMAP);
14186 }
14187 
14192 {
14193  ship_info *sip;
14194  object *objp;
14195  vec3d engine_pos;
14196  ship_subsys *moveup;
14197 
14198  Assert( sp->objnum >= 0 );
14199  if(sp->objnum < 0){
14200  return;
14201  }
14202 
14203  objp = &Objects[sp->objnum];
14204  sip = &Ship_info[sp->ship_info_index];
14205 
14206  if ( sip->engine_snd != -1 ) {
14207  vm_vec_copy_scale(&engine_pos, &objp->orient.vec.fvec, -objp->radius/2.0f);
14208 
14209  obj_snd_assign(sp->objnum, sip->engine_snd, &engine_pos, 1);
14210  }
14211 
14212  // Do subsystem sounds
14213  moveup = GET_FIRST(&sp->subsys_list);
14214  while(moveup != END_OF_LIST(&sp->subsys_list)){
14215  // Check for any engine sounds
14216  if(strstr(moveup->system_info->name, "enginelarge")){
14218  } else if(strstr(moveup->system_info->name, "enginehuge")){
14220  }
14221 
14222  //Do any normal subsystem sounds
14223  if(moveup->current_hits > 0.0f)
14224  {
14225  if(moveup->system_info->alive_snd != -1)
14226  {
14227  obj_snd_assign(sp->objnum, moveup->system_info->alive_snd, &moveup->system_info->pnt, 0, OS_SUBSYS_ALIVE, moveup);
14228  moveup->subsys_snd_flags |= SSSF_ALIVE;
14229  }
14230  if(moveup->system_info->turret_base_rotation_snd != -1)
14231  {
14234  }
14235  if(moveup->system_info->turret_gun_rotation_snd != -1)
14236  {
14239  }
14240  if((moveup->system_info->rotation_snd != -1) && (moveup->flags & SSF_ROTATES))
14241  {
14242  obj_snd_assign(sp->objnum, moveup->system_info->rotation_snd, &moveup->system_info->pnt, 0, OS_SUBSYS_ROTATION, moveup);
14243  moveup->subsys_snd_flags |= SSSF_ROTATE;
14244  }
14245  }
14246  else
14247  {
14248  if(moveup->system_info->dead_snd != -1)
14249  {
14250  obj_snd_assign(sp->objnum, moveup->system_info->dead_snd, &moveup->system_info->pnt, 0, OS_SUBSYS_DEAD, moveup);
14251  moveup->subsys_snd_flags |= SSSF_DEAD;
14252  }
14253  }
14254 
14255  // next
14256  moveup = GET_NEXT(moveup);
14257  }
14258 }
14259 
14264 {
14265  object *objp;
14266  size_t idx;
14267  int has_sounds;
14268 
14269  if ( !Sound_enabled )
14270  return;
14271 
14272  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
14273  if ( objp->type == OBJ_SHIP && Player_obj != objp) {
14274  has_sounds = 0;
14275 
14276  // check to make sure this guy hasn't got sounds already assigned to him
14277  for(idx=0; idx<objp->objsnd_num.size(); idx++){
14278  if(objp->objsnd_num[idx] != -1){
14279  // skip
14280  has_sounds = 1;
14281  break;
14282  }
14283  }
14284 
14285  // actually assign the sound
14286  if(!has_sounds){
14287  ship_assign_sound(&Ships[objp->instance]);
14288  }
14289  }
14290  }
14291 }
14292 
14293 
14297 DCF(set_shield,"Change player ship shield strength")
14298 {
14299  float value;
14300 
14301  if (dc_optional_string_either("help", "--help")) {
14302  dc_printf ("Usage: set_shield [num]\n");
14303  dc_printf ("[num] -- shield percentage 0.0 -> 1.0 of max\n");
14304  return;
14305  }
14306 
14307  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
14308  dc_printf( "Shields are currently %.2f", shield_get_strength(Player_obj) );
14309  return;
14310  }
14311 
14312  dc_stuff_float(&value);
14313 
14314  CLAMP(value, 0.0f, 1.0f);
14315 
14317  dc_printf("Shields set to %.2f\n", shield_get_strength(Player_obj) );
14318 }
14319 
14323 DCF(set_hull, "Change player ship hull strength")
14324 {
14325  float value;
14326 
14327  if (dc_optional_string_either("help", "--help")) {
14328  dc_printf ("Usage: set_hull [num]\n");
14329  dc_printf ("[num] -- hull percentage 0.0 -> 1.0 of max\n");
14330  return;
14331  }
14332 
14333  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
14334  dc_printf( "Hull is currently %.2f", Player_obj->hull_strength );
14335  return;
14336  }
14337 
14338  dc_stuff_float(&value);
14339 
14340  CLAMP(value, 0.0f, 1.0f);
14341  Player_obj->hull_strength = value * Player_ship->ship_max_hull_strength;
14342  dc_printf("Hull set to %.2f\n", Player_obj->hull_strength );
14343 }
14344 
14348 //XSTR:OFF
14349 DCF(set_subsys, "Set the strength of a particular subsystem on player ship" )
14350 {
14351  SCP_string arg;
14352  int subsystem = SUBSYSTEM_NONE;
14353  float val_f;
14354 
14355  if (dc_optional_string_either("help", "--help")) {
14356  dc_printf( "Usage: set_subsys <type> [--status] <strength>\n");
14357  dc_printf("<type> is any of the following:\n");
14358  dc_printf("\tweapons\n");
14359  dc_printf("\tengine\n");
14360  dc_printf("\tsensors\n");
14361  dc_printf("\tcommunication\n");
14362  dc_printf("\tnavigation\n");
14363  dc_printf("\tradar\n\n");
14364 
14365  dc_printf("[--status] will display status of that subsystem\n\n");
14366 
14367  dc_printf("<strength> is any value between 0 and 1.0\n");
14368  return;
14369  }
14370 
14371  dc_stuff_string_white(arg);
14372 
14373  if (arg == "weapons") {
14374  subsystem = SUBSYSTEM_WEAPONS;
14375 
14376  } else if (arg == "engine") {
14377  subsystem = SUBSYSTEM_ENGINE;
14378 
14379  } else if (arg == "sensors") {
14380  subsystem = SUBSYSTEM_SENSORS;
14381 
14382  } else if (arg == "communication") {
14383  subsystem = SUBSYSTEM_COMMUNICATION;
14384 
14385  } else if (arg == "navigation") {
14386  subsystem = SUBSYSTEM_NAVIGATION;
14387 
14388  } else if (arg == "radar") {
14389  subsystem = SUBSYSTEM_RADAR;
14390 
14391  } else if ((arg == "status") || (arg == "--status") || (arg == "?") || (arg == "--?")) {
14392  dc_printf("Error: Must specify a subsystem.\n");
14393  return;
14394 
14395  } else {
14396  dc_printf("Error: Unknown argument '%s'\n", arg.c_str());
14397  return;
14398  }
14399 
14400  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
14401  dc_printf("Subsystem '%s' is at %f strength\n", arg.c_str(), ship_get_subsystem_strength(Player_ship, subsystem));
14402 
14403  } else {
14404  // Set the subsystem strength
14405  dc_stuff_float(&val_f);
14406 
14407  CLAMP(val_f, 0.0, 1.0);
14408  ship_set_subsystem_strength( Player_ship, subsystem, val_f );
14409 
14410  if (subsystem == SUBSYSTEM_ENGINE) {
14411  // If subsystem is an engine, set/clear the disabled flag
14412  (val_f < ENGINE_MIN_STR) ? (Player_ship->flags |= SF_DISABLED) : (Player_ship->flags &= (~SF_DISABLED));
14413  }
14414  }
14415 }
14416 //XSTR:ON
14417 
14418 // console function to toggle whether auto-repair for subsystems is active
14419 #ifndef NDEBUG
14420 DCF_BOOL( auto_repair, Ship_auto_repair )
14421 #endif
14422 
14423 // two functions to keep track of counting ships of particular types. Maybe we should be rolling this
14424 // thing into the stats section?? The first function adds a ship of a particular type to the overall
14425 // count of ships of that type (called from MissionParse.cpp). The second function adds to the kill total
14426 // of ships of a particular type. Note that we use the ship_info flags structure member to determine
14427 // what is happening.
14428 
14429 //WMC - ALERT!!!!!!!!!!!
14430 //These two functions did something weird with fighters/bombers. I don't
14431 //think that not doing this will break anything, but it might.
14432 //If it does, get me. OR someone smart.
14433 //G5K - Someone smart to the rescue! Fixed the functions so they don't
14434 //accidentally overwrite all the information.
14435 
14437 {
14438  // resize if we need to
14439  Ship_type_counts.resize(Ship_types.size());
14440 
14441  // clear all the stats
14442  for (size_t i = 0; i < Ship_type_counts.size(); i++)
14443  {
14444  Ship_type_counts[i].killed = 0;
14445  Ship_type_counts[i].total = 0;
14446  }
14447 }
14448 
14449 void ship_add_ship_type_count( int ship_info_index, int num )
14450 {
14451  int type = ship_class_query_general_type(ship_info_index);
14452 
14453  //Ship has no type or something
14454  if(type < 0) {
14455  return;
14456  }
14457 
14458  //Add it
14459  Ship_type_counts[type].total += num;
14460 }
14461 
14462 void ship_add_ship_type_kill_count( int ship_info_index )
14463 {
14464  int type = ship_class_query_general_type(ship_info_index);
14465 
14466  //Ship has no type or something
14467  if(type < 0) {
14468  return;
14469  }
14470 
14471  //Add it
14472  Ship_type_counts[type].killed++;
14473 }
14474 
14476 {
14477  return ship_query_general_type(&Ships[ship]);
14478 }
14479 
14481 {
14483 }
14484 
14486 {
14487  //This is quick
14488  return Ship_info[ship_class].class_type;
14489 }
14490 
14495 {
14496  // Goober5000
14497  // So many people have asked for this function to be extended that it's making less
14498  // and less sense to keep it around. We should probably just let any ship type
14499  // dock with any other ship type and assume the mission designer is smart enough not to
14500  // mess things up.
14501  return 1;
14502 }
14503 
14504 // function to return a random ship in a starting player wing. Returns -1 if a suitable
14505 // one cannot be found
14506 // input: max_dist => OPTIONAL PARAMETER (default value 0.0f) max range ship can be from player
14507 // input: persona => OPTIONAL PARAMETER (default to -1) which persona to get
14508 int ship_get_random_player_wing_ship( int flags, float max_dist, int persona_index, int get_first, int multi_team )
14509 {
14510  const int MAX_SIZE = MAX_SHIPS_PER_WING * MAX_SQUADRON_WINGS;
14511 
14512  int i, j, ship_index, count;
14513  int slist[MAX_SIZE], which_one;
14514 
14515  // iterate through starting wings of player. Add ship indices of ships which meet
14516  // given criteria
14517  count = 0;
14518  for (i = 0; i < Num_wings; i++ ) {
14519  if (count >= MAX_SIZE)
14520  break;
14521 
14522  int wingnum = -1;
14523 
14524  // multi-team?
14525  if(multi_team >= 0){
14526  if( i == TVT_wings[multi_team] ) {
14527  wingnum = i;
14528  } else {
14529  continue;
14530  }
14531  } else {
14532  // first check for a player starting wing
14533  for ( j = 0; j < MAX_STARTING_WINGS; j++ ) {
14534  if ( i == Starting_wings[j] ) {
14535  wingnum = i;
14536  break;
14537  }
14538  }
14539 
14540  // if not found, then check all squad wings (Goober5000)
14541  if ( wingnum == -1 ) {
14542  for ( j = 0; j < MAX_SQUADRON_WINGS; j++ ) {
14543  if ( i == Squadron_wings[j] ) {
14544  wingnum = i;
14545  break;
14546  }
14547  }
14548  }
14549 
14550  if ( wingnum == -1 ){
14551  continue;
14552  }
14553  }
14554 
14555  for ( j = 0; j < Wings[wingnum].current_count; j++ ) {
14556  if (count >= MAX_SIZE)
14557  break;
14558 
14559  ship_index = Wings[wingnum].ship_index[j];
14560  Assert( ship_index != -1 );
14561 
14562  if ( Ships[ship_index].flags & SF_DYING ) {
14563  continue;
14564  }
14565  // see if ship meets our criterea
14566  if ( (flags == SHIP_GET_NO_PLAYERS || flags == SHIP_GET_UNSILENCED) && (Objects[Ships[ship_index].objnum].flags & OF_PLAYER_SHIP) ){
14567  continue;
14568  }
14569 
14570  if ( (flags == SHIP_GET_UNSILENCED) && (Ships[ship_index].flags2 & SF2_NO_BUILTIN_MESSAGES) )
14571  {
14572  continue;
14573  }
14574 
14575  // don't process ships on a different team
14576  if(multi_team < 0){
14577  if ( Player_ship->team != Ships[ship_index].team ){
14578  continue;
14579  }
14580  }
14581 
14582  // see if ship is within max_dist units
14583  if ( (max_dist > 1.0f) && (multi_team < 0) ) {
14584  float dist;
14585  dist = vm_vec_dist_quick(&Objects[Ships[ship_index].objnum].pos, &Player_obj->pos);
14586  if ( dist > max_dist ) {
14587  continue;
14588  }
14589  }
14590 
14591  // if we should be checking persona's, then don't add ships that don't have the proper persona
14592  if ( persona_index != -1 ) {
14593  if ( Ships[ship_index].persona_index != persona_index ){
14594  continue;
14595  }
14596  }
14597 
14598  // return the first ship with correct persona
14599  if (get_first) {
14600  return ship_index;
14601  }
14602 
14603  slist[count] = ship_index;
14604  count++;
14605  }
14606  }
14607 
14608  if ( count == 0 ){
14609  return -1;
14610  }
14611 
14612  // now get a random one from the list
14613  which_one = (rand() % count);
14614  ship_index = slist[which_one];
14615 
14616  Assert ( Ships[ship_index].objnum != -1 );
14617 
14618  return ship_index;
14619 }
14620 
14621 // like above function, but returns a random ship in the given wing -- no restrictions
14622 // input: max_dist => OPTIONAL PARAMETER (default value 0.0f) max range ship can be from player
14623 int ship_get_random_ship_in_wing(int wingnum, int flags, float max_dist, int get_first)
14624 {
14625  int i, ship_index, slist[MAX_SHIPS_PER_WING], count, which_one;
14626 
14627  count = 0;
14628  for ( i = 0; i < Wings[wingnum].current_count; i++ ) {
14629  ship_index = Wings[wingnum].ship_index[i];
14630  Assert( ship_index != -1 );
14631 
14632  if ( Ships[ship_index].flags & SF_DYING ) {
14633  continue;
14634  }
14635 
14636  // see if ship meets our criterea
14637  if ( (flags == SHIP_GET_NO_PLAYERS || flags == SHIP_GET_UNSILENCED) && (Objects[Ships[ship_index].objnum].flags & OF_PLAYER_SHIP) )
14638  continue;
14639 
14640  if ( (flags == SHIP_GET_UNSILENCED) && (Ships[ship_index].flags2 & SF2_NO_BUILTIN_MESSAGES) )
14641  {
14642  continue;
14643  }
14644 
14645  // see if ship is within max_dist units
14646  if ( max_dist > 0 ) {
14647  float dist;
14648  dist = vm_vec_dist_quick(&Objects[Ships[ship_index].objnum].pos, &Player_obj->pos);
14649  if ( dist > max_dist ) {
14650  continue;
14651  }
14652  }
14653 
14654  // return the first ship in wing
14655  if (get_first) {
14656  return ship_index;
14657  }
14658 
14659  slist[count] = ship_index;
14660  count++;
14661  }
14662 
14663  if ( count == 0 ) {
14664  return -1;
14665  }
14666 
14667  // now get a random one from the list
14668  which_one = (rand() % count);
14669  ship_index = slist[which_one];
14670 
14671  Assert ( Ships[ship_index].objnum != -1 );
14672 
14673  return ship_index;
14674 }
14675 
14676 
14677 // this function returns a random index into the Ship array of a ship of the given team
14678 // cargo containers are not counted as ships for the purposes of this function. Why???
14679 // because now it is only used for getting a random ship for a message and cargo containers
14680 // can't send mesages. This function is an example of kind of bad coding :-(
14681 // input: max_dist => OPTIONAL PARAMETER (default value 0.0f) max range ship can be from player
14682 int ship_get_random_team_ship(int team_mask, int flags, float max_dist )
14683 {
14684  int num, which_one;
14685  object *objp, *obj_list[MAX_SHIPS];
14686 
14687  // for any allied, go through the ships list and find all of the ships on that team
14688  num = 0;
14689  for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
14690  if ( objp->type != OBJ_SHIP )
14691  continue;
14692 
14693  // series of conditionals one per line for easy reading
14694  // don't process ships on wrong team
14695  // don't process cargo's or navbuoys
14696  // don't process player ships if flags are set
14697  if (!iff_matches_mask(Ships[objp->instance].team, team_mask))
14698  continue;
14699  else if ( Ship_info[Ships[objp->instance].ship_info_index].flags & SIF_NOT_FLYABLE )
14700  continue;
14701  else if ( (flags == SHIP_GET_NO_PLAYERS) && (objp->flags & OF_PLAYER_SHIP) )
14702  continue;
14703  else if ( (flags == SHIP_GET_ONLY_PLAYERS) && !(objp->flags & OF_PLAYER_SHIP) )
14704  continue;
14705 
14706  if ( Ships[objp->instance].flags & SF_DYING ) {
14707  continue;
14708  }
14709 
14710  // see if ship is within max_dist units
14711  if ( max_dist > 0 ) {
14712  float dist;
14713  dist = vm_vec_dist_quick(&objp->pos, &Player_obj->pos);
14714  if ( dist > max_dist ) {
14715  continue;
14716  }
14717  }
14718 
14719  obj_list[num] = objp;
14720  num++;
14721  }
14722 
14723  if ( num == 0 )
14724  return -1;
14725 
14726  which_one = (rand() % num);
14727  objp = obj_list[which_one];
14728 
14729  Assert ( objp->instance != -1 );
14730 
14731  return objp->instance;
14732 }
14733 
14734 // -----------------------------------------------------------------------
14735 // ship_secondary_bank_has_ammo()
14736 //
14737 // check if currently selected secondary bank has ammo
14738 //
14739 // input: shipnum => index into Ships[] array for ship to check
14740 //
14742 {
14743  ship_weapon *swp;
14744 
14745  Assert(shipnum >= 0 && shipnum < MAX_SHIPS);
14746  swp = &Ships[shipnum].weapons;
14747 
14748  if ( swp->current_secondary_bank == -1 )
14749  return 0;
14750 
14752  if ( swp->secondary_bank_ammo[swp->current_secondary_bank] <= 0 )
14753  return 0;
14754 
14755  return 1;
14756 }
14757 
14758 // ship_primary_bank_has_ammo()
14759 //
14760 // check if currently selected primary bank has ammo
14761 //
14762 // input: shipnum => index into Ships[] array for ship to check
14763 //
14765 {
14766  ship_weapon *swp;
14767 
14768  Assert(shipnum >= 0 && shipnum < MAX_SHIPS);
14769  swp = &Ships[shipnum].weapons;
14770 
14771  if ( swp->current_primary_bank == -1 )
14772  {
14773  return 0;
14774  }
14775 
14777 
14778  return ( primary_out_of_ammo(swp, swp->current_primary_bank) == 0 );
14779 }
14780 
14781 // see if there is enough engine power to allow the ship to warp
14782 // returns 1 if ship is able to warp, otherwise return 0
14784 {
14785  // disabled ships can't warp
14786  if (sp->flags & SF_DISABLED)
14787  return 0;
14788 
14789  if (sp->flags & SF_WARP_BROKEN || sp->flags & SF_WARP_NEVER)
14790  return 0;
14791 
14792  float engine_strength = ship_get_subsystem_strength(sp, SUBSYSTEM_ENGINE);
14793 
14794  // if at 0% strength, can't warp
14795  if (engine_strength <= 0.0f)
14796  return 0;
14797 
14798  // player ships playing above Very Easy can't warp when below a threshold
14799  if ((sp == Player_ship) && (Game_skill_level > 0) && (engine_strength < SHIP_MIN_ENGINES_TO_WARP))
14800  return 0;
14801 
14802  // otherwise, warp is allowed
14803  return 1;
14804 }
14805 
14806 // Goober5000
14807 // see if there is enough navigation power to allow the ship to warp
14808 // returns 1 if ship is able to warp, otherwise return 0
14810 {
14811  // if not using the special flag, warp is always allowed
14813  return 1;
14814 
14815  float navigation_strength = ship_get_subsystem_strength(sp, SUBSYSTEM_NAVIGATION);
14816 
14817  // if at 0% strength, can't warp
14818  if (navigation_strength <= 0.0f)
14819  return 0;
14820 
14821  // player ships playing above Very Easy can't warp when below a threshold
14822  if ((sp == Player_ship) && (Game_skill_level > 0) && (navigation_strength < SHIP_MIN_NAV_TO_WARP))
14823  return 0;
14824 
14825  // otherwise, warp is allowed
14826  return 1;
14827 }
14828 
14829 // Calculate the normal vector from a subsystem position and its first path point
14830 // input: sp => pointer to ship that is parent of subsystem
14831 // ss => pointer to subsystem of interest
14832 // norm => output parameter... vector from subsys to first path point
14833 //
14834 // exit: 0 => a valid vector was placed in norm
14835 // !0 => an path normal could not be calculated
14836 //
14838 {
14839  if ( ss->system_info->path_num >= 0 ) {
14840  polymodel *pm = NULL;
14841  model_path *mp;
14842  vec3d *path_point;
14843  vec3d gpath_point;
14844  pm = model_get(Ship_info[shipp->ship_info_index].model_num);
14845  Assert( pm != NULL );
14846 
14847  // possibly a bad model?
14848  Assertion(ss->system_info->path_num <= pm->n_paths, "Too many paths in '%s'! Max is %i and the requested path was %i for subsystem '%s'!\n", pm->filename, pm->n_paths, ss->system_info->path_num, ss->system_info->subobj_name);
14849  if (ss->system_info->path_num > pm->n_paths)
14850  return 1;
14851 
14852  mp = &pm->paths[ss->system_info->path_num];
14853  if ( mp->nverts >= 2 ) {
14854  path_point = &mp->verts[0].pos;
14855  // get path point in world coords
14856  vm_vec_unrotate(&gpath_point, path_point, &Objects[shipp->objnum].orient);
14857  vm_vec_add2(&gpath_point, &Objects[shipp->objnum].pos);
14858  // get unit vector pointing from subsys pos to first path point
14859  vm_vec_normalized_dir(norm, &gpath_point, gsubpos);
14860  return 0;
14861  }
14862  }
14863  return 1;
14864 }
14865 
14866 
14867 // Determine if the subsystem can be viewed from eye_pos. The method is to check where the
14868 // vector from eye_pos to the subsystem hits the ship. If distance from the hit position and
14869 // the center of the subsystem is within a range (currently the subsystem radius) it is considered
14870 // in view (return true). If not in view, return false.
14871 //
14872 // input: objp => object that is the ship with the subsystem on it
14873 // subsys => pointer to the subsystem of interest
14874 // eye_pos => world coord for the eye looking at the subsystem
14875 // subsys_pos => world coord for the center of the subsystem of interest
14876 // do_facing_check => OPTIONAL PARAMETER (default value is 1), do a dot product check to see if subsystem fvec is facing
14877 // towards the eye position
14878 // dot_out => OPTIONAL PARAMETER, output parameter, will return dot between subsys fvec and subsys_to_eye_vec
14879 // (only filled in if do_facing_check is true)
14880 // vec_out => OPTIONAL PARAMETER, vector from eye_pos to absolute subsys_pos. (only filled in if do_facing_check is true)
14881 int ship_subsystem_in_sight(object* objp, ship_subsys* subsys, vec3d *eye_pos, vec3d* subsys_pos, int do_facing_check, float *dot_out, vec3d *vec_out)
14882 {
14883  float dist, dot;
14884  mc_info mc;
14885  vec3d terminus, eye_to_pos, subsys_fvec, subsys_to_eye_vec;
14886 
14887  if (objp->type != OBJ_SHIP)
14888  return 0;
14889 
14890  // See if we are at least facing the subsystem
14891  if ( do_facing_check ) {
14892  if ( ship_return_subsys_path_normal(&Ships[objp->instance], subsys, subsys_pos, &subsys_fvec) ) {
14893  // non-zero return value means that we couldn't generate a normal from path info... so use inaccurate method
14894  vm_vec_normalized_dir(&subsys_fvec, subsys_pos, &objp->pos);
14895  }
14896 
14897  vm_vec_normalized_dir(&subsys_to_eye_vec, eye_pos, subsys_pos);
14898  dot = vm_vec_dot(&subsys_fvec, &subsys_to_eye_vec);
14899  if ( dot_out ) {
14900  *dot_out = dot;
14901  }
14902 
14903  if (vec_out) {
14904  *vec_out = subsys_to_eye_vec;
14905  vm_vec_negate(vec_out);
14906  }
14907 
14908  if ( dot < 0 )
14909  return 0;
14910  }
14911 
14912  // See if ray from eye to subsystem actually hits close enough to the subsystem position
14913  vm_vec_normalized_dir(&eye_to_pos, subsys_pos, eye_pos);
14914  vm_vec_scale_add(&terminus, eye_pos, &eye_to_pos, 100000.0f);
14915 
14916  mc_info_init(&mc);
14918  mc.model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num; // Fill in the model to check
14919  mc.orient = &objp->orient; // The object's orientation
14920  mc.pos = &objp->pos; // The object's position
14921  mc.p0 = eye_pos; // Point 1 of ray to check
14922  mc.p1 = &terminus; // Point 2 of ray to check
14923  mc.flags = MC_CHECK_MODEL;
14924 
14925  model_collide(&mc);
14926 
14927  if ( !mc.num_hits ) {
14928  return 0;
14929  }
14930 
14931  // determine if hitpos is close enough to subsystem
14932  dist = vm_vec_dist(&mc.hit_point_world, subsys_pos);
14933 
14934  if ( dist <= subsys->system_info->radius ) {
14935  return 1;
14936  }
14937 
14938  return 0;
14939 }
14940 
14946 {
14947  ship_subsys *ssp;
14948 
14949  Assert ( type >= 0 && type < SUBSYSTEM_MAX );
14950 
14951  // If aggregate total is 0, that means no subsystem is alive of that type
14952  if ( shipp->subsys_info[type].aggregate_max_hits <= 0.0f )
14953  return NULL;
14954 
14955  // loop through all the subsystems, if we find a match that has some strength, return it
14956  ssp = ship_get_best_subsys_to_attack(shipp, type, attacker_pos);
14957 
14958  return ssp;
14959 }
14960 
14961 // Returns the closest subsystem of specified type that is in line of sight.
14962 // Returns null if all subsystems of that type are destroyed or none is in sight.
14963 ship_subsys *ship_get_closest_subsys_in_sight(ship *sp, int subsys_type, vec3d *attacker_pos)
14964 {
14965  Assert ( subsys_type >= 0 && subsys_type < SUBSYSTEM_MAX );
14966 
14967  // If aggregate total is 0, that means no subsystem is alive of that type
14968  if ( sp->subsys_info[subsys_type].aggregate_max_hits <= 0.0f )
14969  return NULL;
14970 
14971  ship_subsys *closest_in_sight_subsys;
14972  ship_subsys *ss;
14973  vec3d gsubpos;
14974  float closest_dist;
14975  float ss_dist;
14976 
14977  closest_in_sight_subsys = NULL;
14978  closest_dist = FLT_MAX;
14979 
14980  for (ss = GET_FIRST(&sp->subsys_list); ss != END_OF_LIST(&sp->subsys_list); ss = GET_NEXT(ss) ) {
14981  if ( (ss->system_info->type == subsys_type) && (ss->current_hits > 0) ) {
14982 
14983  // get world pos of subsystem
14984  vm_vec_unrotate(&gsubpos, &ss->system_info->pnt, &Objects[sp->objnum].orient);
14985  vm_vec_add2(&gsubpos, &Objects[sp->objnum].pos);
14986 
14987  if ( ship_subsystem_in_sight(&Objects[sp->objnum], ss, attacker_pos, &gsubpos) ) {
14988  ss_dist = vm_vec_dist_squared(attacker_pos, &gsubpos);
14989 
14990  if ( ss_dist < closest_dist ) {
14991  closest_dist = ss_dist;
14992  closest_in_sight_subsys = ss;
14993  }
14994  }
14995  }
14996  }
14997 
14998  return closest_in_sight_subsys;
14999 }
15000 
15002 {
15003  if( ss->sub_name[0] != '\0' )
15004  return ss->sub_name;
15005  else
15006  return ss->system_info->name;
15007 }
15008 
15010 {
15011  if( ss->sub_name[0] != '\0' )
15012  return true;
15013  else
15014  return false;
15015 }
15016 
15017 void ship_subsys_set_name(ship_subsys *ss, char* n_name)
15018 {
15019  strncpy(ss->sub_name, n_name, NAME_LENGTH-1);
15020 }
15021 
15022 // Return the shield strength in the quadrant hit on hit_objp, based on global hitpos
15023 //
15024 // input: hit_objp => object pointer to ship getting hit
15025 // hitpos => global position of impact
15026 //
15027 // exit: strength of shields in the quadrant that was hit as a percentage, between 0 and 1.0
15028 //
15029 // Assumes: that hitpos is a valid global hit position
15030 float ship_quadrant_shield_strength(object *hit_objp, vec3d *hitpos)
15031 {
15032  int quadrant_num, i;
15033  float max_quadrant;
15034  vec3d tmpv1, tmpv2;
15035 
15036  // If ship doesn't have shield mesh, then return
15037  if ( hit_objp->flags & OF_NO_SHIELDS ) {
15038  return 0.0f;
15039  }
15040 
15041  // Check if all the shield quadrants are all already 0, if so return 0
15042  for ( i = 0; i < 4; i++ ) {
15043  if ( hit_objp->shield_quadrant[i] > 0 )
15044  break;
15045  }
15046 
15047  if ( i == 4 ) {
15048  return 0.0f;
15049  }
15050 
15051  // convert hitpos to position in model coordinates
15052  vm_vec_sub(&tmpv1, hitpos, &hit_objp->pos);
15053  vm_vec_rotate(&tmpv2, &tmpv1, &hit_objp->orient);
15054  quadrant_num = get_quadrant(&tmpv2, hit_objp);
15055 
15056  if ( quadrant_num < 0 )
15057  quadrant_num = 0;
15058 
15059  max_quadrant = get_max_shield_quad(hit_objp);
15060  if ( max_quadrant <= 0 ) {
15061  return 0.0f;
15062  }
15063 
15064  if(hit_objp->shield_quadrant[quadrant_num] > max_quadrant)
15065  mprintf(("Warning: \"%s\" has shield quadrant strength of %f out of %f\n",
15066  Ships[hit_objp->instance].ship_name, hit_objp->shield_quadrant[quadrant_num], max_quadrant));
15067 
15068  return hit_objp->shield_quadrant[quadrant_num]/max_quadrant;
15069 }
15070 
15071 // Determine if a ship is threatened by any dumbfire projectiles (laser or missile)
15072 // input: sp => pointer to ship that might be threatened
15073 // exit: 0 => no dumbfire threats
15074 // 1 => at least one dumbfire threat
15075 //
15076 // NOTE: Currently this function is only called periodically from the HUD code for the
15077 // player ship.
15079 {
15081  return 0;
15082  }
15083 
15084  if (ai_endangered_by_weapon(&Ai_info[sp->ai_index]) > 0) {
15085  return 1;
15086  }
15087 
15088  return 0;
15089 }
15090 
15091 // Return !0 if there is a missile in the air homing on shipp
15093 {
15094  object *locked_objp, *A;
15095  weapon *wp;
15096  weapon_info *wip;
15097  missile_obj *mo;
15098 
15099  Assert(shipp->objnum >= 0 && shipp->objnum < MAX_OBJECTS);
15100  locked_objp = &Objects[shipp->objnum];
15101 
15102  // check for currently locked missiles (highest precedence)
15103  for ( mo = GET_NEXT(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
15104  Assert(mo->objnum >= 0 && mo->objnum < MAX_OBJECTS);
15105  A = &Objects[mo->objnum];
15106 
15107  if (A->type != OBJ_WEAPON)
15108  continue;
15109 
15110  Assert((A->instance >= 0) && (A->instance < MAX_WEAPONS));
15111  wp = &Weapons[A->instance];
15112  wip = &Weapon_info[wp->weapon_info_index];
15113 
15114  if ( wip->subtype != WP_MISSILE )
15115  continue;
15116 
15117  if ( !(wip->wi_flags & WIF_HOMING ) )
15118  continue;
15119 
15120  if (wp->homing_object == locked_objp) {
15121  return 1;
15122  }
15123  } // end for
15124 
15125  return 0;
15126 }
15127 
15128 // Return !0 if there is some ship attempting to lock onto shipp
15130 {
15131  ship_obj *so;
15132  object *objp;
15133  ai_info *aip;
15134 
15135  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
15136  objp = &Objects[so->objnum];
15137  aip = &Ai_info[Ships[objp->instance].ai_index];
15138 
15139  if ( aip->target_objnum == shipp->objnum ) {
15140  if ( aip->aspect_locked_time > 0.1f ) {
15141  float dist, wep_range;
15142  dist = vm_vec_dist_quick(&objp->pos, &Objects[shipp->objnum].pos);
15143  wep_range = ship_get_secondary_weapon_range(&Ships[objp->instance]);
15144  if ( wep_range > dist ) {
15145  nprintf(("Alan","AI ship is seeking lock\n"));
15146  return 1;
15147  }
15148  }
15149  }
15150  }
15151 
15152  return 0;
15153 }
15154 
15155 // Determine if a ship is threatened by attempted lock or actual lock
15156 // input: sp => pointer to ship that might be threatened
15157 // exit: 0 => no lock threats of any kind
15158 // 1 => at least one attempting lock (no actual locks)
15159 // 2 => at least one lock (possible other attempting locks)
15160 //
15161 // NOTE: Currently this function is only called periodically from the HUD code for the
15162 // player ship.
15164 {
15165  if ( ship_has_homing_missile_locked(sp) ) {
15166  return 2;
15167  }
15168 
15169  if ( ship_is_getting_locked(sp) ) {
15170  return 1;
15171  }
15172 
15173  return 0;
15174 }
15175 
15176 // converts a bitmask, such as 0x08, into the bit number this would be (3 in this case)
15177 // NOTE: Should move file to something like Math_utils.
15179 {
15180  int i;
15181 
15182  for (i=0; i<32; i++)
15183  if (num & (1 << i))
15184  return i;
15185 
15186  return -1;
15187 }
15188 
15189 // Get a text description of a ships orders.
15190 //
15191 // input: outbuf => buffer to hold orders string
15192 // sp => ship pointer to extract orders from
15193 //
15194 // exit: NULL => printable orders are not applicable
15195 // non-NULL => pointer to string that was passed in originally
15196 //
15197 // This function is called from HUD code to get a text description
15198 // of what a ship's orders are. Feel free to use this function if
15199 // it suits your needs for something.
15200 //
15201 char *ship_return_orders(char *outbuf, ship *sp)
15202 {
15203  ai_info *aip;
15204  ai_goal *aigp;
15205  const char *order_text;
15206  char ship_name[NAME_LENGTH];
15207 
15208  Assert(sp->ai_index >= 0);
15209  aip = &Ai_info[sp->ai_index];
15210 
15211  // The active goal is always in the first element of aip->goals[]
15212  aigp = &aip->goals[0];
15213 
15214  if ( aigp->ai_mode < 0 )
15215  return NULL;
15216 
15217  order_text = Ai_goal_text(bitmask_2_bitnum(aigp->ai_mode));
15218  if ( order_text == NULL )
15219  return NULL;
15220 
15221  strcpy(outbuf, order_text);
15222 
15223  if ( aigp->target_name ) {
15224  strcpy_s(ship_name, aigp->target_name);
15226  }
15227  switch (aigp->ai_mode ) {
15228 
15229  case AI_GOAL_FORM_ON_WING:
15230  case AI_GOAL_GUARD_WING:
15231  case AI_GOAL_CHASE_WING:
15232  if ( aigp->target_name ) {
15233  strcat(outbuf, ship_name);
15234  strcat(outbuf, XSTR( "'s Wing", 494));
15235  } else {
15236  strcpy(outbuf, XSTR( "no orders", 495));
15237  }
15238  break;
15239 
15240  case AI_GOAL_CHASE:
15241  case AI_GOAL_DOCK:
15242  case AI_GOAL_UNDOCK:
15243  case AI_GOAL_GUARD:
15244  case AI_GOAL_DISABLE_SHIP:
15245  case AI_GOAL_DISARM_SHIP:
15246  case AI_GOAL_EVADE_SHIP:
15247  case AI_GOAL_REARM_REPAIR:
15248  if ( aigp->target_name ) {
15249  strcat(outbuf, ship_name);
15250  } else {
15251  strcpy(outbuf, XSTR( "no orders", 495));
15252  }
15253  break;
15254 
15256  if ( aip->targeted_subsys != NULL ) {
15257  char subsys_name[NAME_LENGTH];
15258  strcpy_s(subsys_name, aip->targeted_subsys->system_info->subobj_name);
15260  sprintf(outbuf, XSTR( "atk %s %s", 496), ship_name, subsys_name);
15261  } else {
15262  strcpy(outbuf, XSTR( "no orders", 495) );
15263  }
15264  break;
15265  }
15266 
15267  case AI_GOAL_WAYPOINTS:
15269  // don't do anything, all info is in order_text
15270  break;
15271 
15272  case AI_GOAL_FLY_TO_SHIP:
15273  strcpy(outbuf, "Flying to ship");
15274  break;
15275 
15276 
15277  default:
15278  return NULL;
15279  }
15280 
15281  return outbuf;
15282 }
15283 
15284 // return the amount of time until ship reaches its goal (in MM:SS format)
15285 // input: outbuf => buffer to hold orders string
15286 // sp => ship pointer to extract orders from
15287 //
15288 // exit: NULL => printable orders are not applicable
15289 // non-NULL => pointer to string that was passed in originally
15290 //
15291 // This function is called from HUD code to get a text description
15292 // of what a ship's orders are. Feel free to use this function if
15293 // it suits your needs for something.
15294 char *ship_return_time_to_goal(char *outbuf, ship *sp)
15295 {
15296  ai_info *aip;
15297  int time, seconds, minutes;
15298  float dist = 0.0f;
15299  object *objp;
15300  float min_speed, max_speed;
15301 
15302  objp = &Objects[sp->objnum];
15303  aip = &Ai_info[sp->ai_index];
15304 
15305  min_speed = objp->phys_info.speed;
15306 
15307  // Goober5000 - handle cap
15308  if (aip->waypoint_speed_cap >= 0)
15309  max_speed = MIN(sp->current_max_speed, aip->waypoint_speed_cap);
15310  else
15311  max_speed = sp->current_max_speed;
15312 
15313  if ( aip->mode == AIM_WAYPOINTS ) {
15314  min_speed = 0.9f * max_speed;
15315  if (aip->wp_list != NULL) {
15317  dist += vm_vec_dist_quick(&objp->pos, aip->wp_list->get_waypoints()[aip->wp_index].get_pos());
15318 
15320  vec3d *prev_vec = NULL;
15321  for (ii = (aip->wp_list->get_waypoints().begin() + aip->wp_index); ii != aip->wp_list->get_waypoints().end(); ++ii) {
15322  if (prev_vec != NULL) {
15323  dist += vm_vec_dist_quick(ii->get_pos(), prev_vec);
15324  }
15325  prev_vec = ii->get_pos();
15326  }
15327  }
15328 
15329  if ( dist < 1.0f) {
15330  return NULL;
15331  }
15332 
15333  if ( (Objects[sp->objnum].phys_info.speed <= 0) || (max_speed <= 0.0f) ) {
15334  time = -1;
15335  } else {
15336  float speed;
15337 
15338  speed = objp->phys_info.speed;
15339 
15340  if (speed < min_speed)
15341  speed = min_speed;
15342  time = fl2i(dist/speed);
15343  }
15344 
15345  } else if ( (aip->mode == AIM_DOCK) && (aip->submode < AIS_DOCK_4) ) {
15346  time = hud_get_dock_time( objp );
15347  } else {
15348  // don't return anytime for time to except for waypoints and actual docking.
15349  return NULL;
15350  }
15351 
15352  if ( time >= 0 ) {
15353  minutes = time/60;
15354  seconds = time%60;
15355  if ( minutes > 99 ) {
15356  minutes = 99;
15357  seconds = 99;
15358  }
15359  sprintf(outbuf, NOX("%02d:%02d"), minutes, seconds);
15360  } else {
15361  strcpy( outbuf, XSTR( "Unknown", 497) );
15362  }
15363 
15364  return outbuf;
15365 }
15366 
15367 /* Karajorma - V decided not to use this function so I've commented it out so it isn't confused with code
15368 +that is actually in use. Someone might want to get it working using AI_Profiles at some point so I didn't
15369 +simply delete it.
15370 
15371 // Called to check if any AI ships might reveal the cargo of any cargo containers.
15372 //
15373 // This is called once a frame, but a global timer 'Ship_cargo_check_timer' will limit this
15374 // function to being called every SHIP_CARGO_CHECK_INTERVAL ms. I think that should be sufficient.
15375 //
15376 // NOTE: This function uses CARGO_REVEAL_DISTANCE from the HUD code... which is a multiple of
15377 // the ship radius that is used to determine when cargo is detected. AI ships do not
15378 // have to have the ship targeted to reveal cargo. The player is ignored in this function.
15379 #define SHIP_CARGO_CHECK_INTERVAL 1000
15380 void ship_check_cargo_all()
15381 {
15382  object *cargo_objp;
15383  ship_obj *cargo_so, *ship_so;
15384  ship *cargo_sp, *ship_sp;
15385  float dist_squared, limit_squared;
15386 
15387  // I don't want to do this check every frame, so I made a global timer to limit check to
15388  // every SHIP_CARGO_CHECK_INTERVAL ms.
15389  if ( !timestamp_elapsed(Ship_cargo_check_timer) ) {
15390  return;
15391  } else {
15392  Ship_cargo_check_timer = timestamp(SHIP_CARGO_CHECK_INTERVAL);
15393  }
15394 
15395  // Check all friendly fighter/bombers against all non-friendly cargo containers that don't have
15396  // cargo revealed
15397 
15398  // for now just locate a capital ship on the same team:
15399  cargo_so = GET_FIRST(&Ship_obj_list);
15400  while(cargo_so != END_OF_LIST(&Ship_obj_list)){
15401  cargo_sp = &Ships[Objects[cargo_so->objnum].instance];
15402  if ( (Ship_info[cargo_sp->ship_info_index].flags & SIF_CARGO) && (cargo_sp->team != Player_ship->team) ) {
15403 
15404  // If the cargo is revealed, continue on to next hostile cargo
15405  if ( cargo_sp->flags & SF_CARGO_REVEALED ) {
15406  goto next_cargo;
15407  }
15408 
15409  // check against friendly fighter/bombers + cruiser/freighter/transport
15410  // IDEA: could cull down to fighter/bomber if we want this to run a bit quicker
15411  for ( ship_so=GET_FIRST(&Ship_obj_list); ship_so != END_OF_LIST(&Ship_obj_list); ship_so=GET_NEXT(ship_so) )
15412  {
15413  ship_sp = &Ships[Objects[ship_so->objnum].instance];
15414  // only consider friendly ships
15415  if (ship_sp->team != Player_ship->team) {
15416  continue;
15417  }
15418 
15419  // ignore the player
15420  if ( ship_so->objnum == OBJ_INDEX(Player_obj) ) {
15421  continue;
15422  }
15423 
15424  // if this ship is a small or big ship
15425  if ( Ship_info[ship_sp->ship_info_index].flags & (SIF_SMALL_SHIP|SIF_BIG_SHIP) ) {
15426  cargo_objp = &Objects[cargo_sp->objnum];
15427  // use square of distance, faster than getting real distance (which will use sqrt)
15428  dist_squared = vm_vec_dist_squared(&cargo_objp->pos, &Objects[ship_sp->objnum].pos);
15429  limit_squared = (cargo_objp->radius+CARGO_RADIUS_DELTA)*(cargo_objp->radius+CARGO_RADIUS_DELTA);
15430  if ( dist_squared <= MAX(limit_squared, CARGO_REVEAL_MIN_DIST*CARGO_REVEAL_MIN_DIST) ) {
15431  ship_do_cargo_revealed( cargo_sp );
15432  break; // break out of for loop, move on to next hostile cargo
15433  }
15434  }
15435  } // end for
15436  }
15437 next_cargo:
15438  cargo_so = GET_NEXT(cargo_so);
15439  } // end while
15440 }
15441 */
15442 
15443 
15444 // Maybe warn player about this attacking ship. This is called once per frame, and the
15445 // information about the closest attacking ship comes for free, since this function is called
15446 // from HUD code which has already determined the closest enemy attacker and the distance.
15447 //
15448 // input: enemy_sp => ship pointer to the TEAM_ENEMY ship attacking the player
15449 // dist => the distance of the enemy to the player
15450 //
15451 // NOTE: there are no filters on enemy_sp, so it could be any ship type
15452 //
15453 #define PLAYER_CHECK_WARN_INTERVAL 300 // how often we check for warnings
15454 #define PLAYER_MIN_WARN_DIST 100 // minimum distance attacking ship can be from player and still allow warning
15455 #define PLAYER_MAX_WARN_DIST 1000 // maximum distance attacking ship can be from plyaer and still allow warning
15456 
15457 void ship_maybe_warn_player(ship *enemy_sp, float dist)
15458 {
15459  float fdot; //, rdot, udot;
15460  vec3d vec_to_target;
15461  int msg_type; //, on_right;
15462 
15463  // First check if the player has reached the maximum number of warnings for a mission
15465  return;
15466  }
15467 
15468  // Check if enough time has elapsed since last warning, if not - leave
15470  return;
15471  }
15472 
15473  // Check to see if check timer has elapsed. Necessary, since we don't want to check each frame
15475  return;
15476  }
15478 
15479  // only allow warnings if within a certain distance range
15480  if ( dist < PLAYER_MIN_WARN_DIST || dist > PLAYER_MAX_WARN_DIST ) {
15481  return;
15482  }
15483 
15484  // only warn if a fighter or bomber is attacking the player
15485  if ( !(Ship_info[enemy_sp->ship_info_index].flags & SIF_SMALL_SHIP) ) {
15486  return;
15487  }
15488 
15489  // get vector from player to target
15490  vm_vec_normalized_dir(&vec_to_target, &Objects[enemy_sp->objnum].pos, &Eye_position);
15491 
15492  // ensure that enemy fighter is oriented towards player
15493  fdot = vm_vec_dot(&Objects[enemy_sp->objnum].orient.vec.fvec, &vec_to_target);
15494  if ( fdot > -0.7 ) {
15495  return;
15496  }
15497 
15498  fdot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);
15499 
15500  msg_type = -1;
15501 
15502  // check if attacking ship is on six. return if not far enough behind player.
15503  if ( fdot > -0.7 )
15504  return;
15505 
15506  msg_type = MESSAGE_CHECK_6;
15507 
15508  if ( msg_type != -1 ) {
15509  int ship_index;
15510 
15511  // multiplayer tvt - this is client side.
15512  if(MULTI_TEAM && (Net_player != NULL)){
15514  } else {
15516  }
15517 
15518  if ( ship_index >= 0 ) {
15519  // multiplayer - make sure I just send to myself
15520  if(Game_mode & GM_MULTIPLAYER){
15522  } else {
15523  message_send_builtin_to_player(msg_type, &Ships[ship_index], MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, -1);
15524  }
15525  Player->allow_warn_timestamp = timestamp(Builtin_messages[MESSAGE_CHECK_6].min_delay);
15526  Player->warn_count++;
15527  }
15528  }
15529 }
15530 
15531 // player has just killed a ship, maybe offer send a 'good job' message
15533 {
15534  if ( myrand()&1 ) {
15535  return;
15536  }
15537 
15538  // First check if the player has reached the maximum number of praises for a mission
15540  return;
15541  }
15542 
15543  // Check if enough time has elapsed since last praise, if not - leave
15545  return;
15546  }
15547 
15548  // make sure player is not a traitor
15549  if (Player_ship->team == Iff_traitor) {
15550  return;
15551  }
15552 
15553  // only praise if killing an enemy!
15554  if ( deader_sp->team == Player_ship->team ) {
15555  return;
15556  }
15557 
15558  // don't praise the destruction of navbuoys, cargo or other non-flyable ship types
15559  if ( (Ship_info[deader_sp->ship_info_index].class_type > 0) && !(Ship_types[Ship_info[deader_sp->ship_info_index].class_type].message_bools & STI_MSG_PRAISE_DESTRUCTION) ) {
15560  return;
15561  }
15562 
15563  // There is already a praise pending
15564  if ( Player->praise_delay_timestamp ) {
15565  return;
15566  }
15567 
15568  // We don't want to praise the player right away.. it is more realistic to wait a moment
15570 }
15571 
15572 void ship_maybe_praise_self(ship *deader_sp, ship *killer_sp)
15573 {
15574  int j;
15575  bool wingman = false;
15576 
15577  if ( (int)(frand()*100) > Builtin_messages[MESSAGE_PRAISE_SELF].occurrence_chance ) {
15578  return;
15579  }
15580 
15581  if (Game_mode & GM_MULTIPLAYER) {
15582  return;
15583  }
15584 
15586  return;
15587  }
15588 
15590  return;
15591  }
15592 
15593  // only praise if killing an enemy so check they both attack each other!
15594  if (!((iff_x_attacks_y(deader_sp->team, killer_sp->team)) && (iff_x_attacks_y(killer_sp->team, deader_sp->team ))) ) {
15595  return;
15596  }
15597 
15598 
15599  // only send messages from the player's wingmen
15600  if (killer_sp->wingnum == -1) {
15601  return;
15602  }
15603  for ( j = 0; j < MAX_STARTING_WINGS; j++ ) {
15604  if ( Starting_wings[j] == killer_sp->wingnum) {
15605  wingman = true;
15606  break;
15607  }
15608  }
15609 
15610  if (!wingman) {
15611  return;
15612  }
15613 
15614  // don't praise the destruction of navbuoys, cargo or other non-flyable ship types
15615  if ( (Ship_info[deader_sp->ship_info_index].class_type > 0) && !(Ship_types[Ship_info[deader_sp->ship_info_index].class_type].message_bools & STI_MSG_PRAISE_DESTRUCTION) ) {
15616  return;
15617  }
15618 
15619  // ensure the ship isn't silenced
15620  if ( killer_sp->flags2 & SF2_NO_BUILTIN_MESSAGES ) {
15621  return;
15622  }
15623 
15624  message_send_builtin_to_player(MESSAGE_PRAISE_SELF, killer_sp, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_SOON, 0, 0, -1, -1);
15625  Player->praise_self_timestamp = timestamp(Builtin_messages[MESSAGE_PRAISE_SELF].min_delay);
15627 }
15628 
15629 #define ASK_HELP_SHIELD_PERCENT 0.1 // percent shields at which ship will ask for help
15630 #define ASK_HELP_HULL_PERCENT 0.3 // percent hull at which ship will ask for help
15631 #define AWACS_HELP_HULL_HI 0.75 // percent hull at which ship will ask for help
15632 #define AWACS_HELP_HULL_LOW 0.25 // percent hull at which ship will ask for help
15633 
15634 // -----------------------------------------------------------------------------
15635 void awacs_maybe_ask_for_help(ship *sp, int multi_team_filter)
15636 {
15637  // Goober5000 - bail if not in main fs2 campaign
15638  // (stupid coders... it's the FREDder's responsibility to add this message)
15639  if (stricmp(Campaign.filename, "freespace2") || !(Game_mode & GM_CAMPAIGN_MODE))
15640  return;
15641 
15642  object *objp;
15643  int message = -1;
15644  objp = &Objects[sp->objnum];
15645 
15646  if ( objp->hull_strength < ( (AWACS_HELP_HULL_LOW + 0.01f *(static_rand(objp-Objects) & 5)) * sp->ship_max_hull_strength) ) {
15647  // awacs ship below 25 + (0-4) %
15648  if (!(sp->awacs_warning_flag & AWACS_WARN_25)) {
15649  message = MESSAGE_AWACS_25;
15651  }
15652  } else if ( objp->hull_strength < ( (AWACS_HELP_HULL_HI + 0.01f*(static_rand(objp-Objects) & 5)) * sp->ship_max_hull_strength) ) {
15653  // awacs ship below 75 + (0-4) %
15654  if (!(sp->awacs_warning_flag & AWACS_WARN_75)) {
15655  message = MESSAGE_AWACS_75;
15657  }
15658  }
15659 
15660  if (message >= 0) {
15661  message_send_builtin_to_player(message, sp, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, multi_team_filter);
15664  }
15665 }
15666 
15667 // -----------------------------------------------------------------------------
15669 {
15670  object *objp;
15671  int multi_team_filter = -1;
15672 
15673  // First check if the player has reached the maximum number of ask_help's for a mission
15675  return;
15676 
15677  // Check if enough time has elapsed since last help request, if not - leave
15679  return;
15680 
15681  // make sure player is on their team and not a traitor
15682  if ((Player_ship->team != sp->team) || (Player_ship->team == Iff_traitor))
15683  return;
15684 
15685  objp = &Objects[sp->objnum];
15686 
15687  // don't let the player ask for help!
15688  if (objp->flags & OF_PLAYER_SHIP)
15689  return;
15690 
15691  // determine team filter if TvT
15692  if(MULTI_TEAM)
15693  multi_team_filter = sp->team;
15694 
15695  // handle awacs ship as a special case
15696  if (Ship_info[sp->ship_info_index].flags & SIF_HAS_AWACS)
15697  {
15698  awacs_maybe_ask_for_help(sp, multi_team_filter);
15699  return;
15700  }
15701 
15702  // for now, only have wingman ships request help
15703  if (!(sp->flags & SF_FROM_PLAYER_WING))
15704  return;
15705 
15706  // first check if hull is at a critical level
15708  goto play_ask_help;
15709 
15710  // check if shields are near critical level
15711  if (objp->flags & OF_NO_SHIELDS)
15712  return; // no shields on ship, no don't check shield levels
15713 
15715  return;
15716 
15717 play_ask_help:
15718 
15719  if (!(Ship_info[sp->ship_info_index].flags & (SIF_FIGHTER|SIF_BOMBER))) //If we're still here, only continue if we're a fighter or bomber.
15720  return;
15721 
15722  if (!(sp->flags2 & SF2_NO_BUILTIN_MESSAGES)) // Karajorma - Only unsilenced ships should ask for help
15723  {
15724  message_send_builtin_to_player(MESSAGE_HELP, sp, MESSAGE_PRIORITY_HIGH, MESSAGE_TIME_IMMEDIATE, 0, 0, -1, multi_team_filter);
15725  Player->allow_ask_help_timestamp = timestamp(Builtin_messages[MESSAGE_HELP].min_delay);
15726 
15727  // prevent overlap with death message
15730 
15732  }
15733 }
15734 
15739 {
15740  int ship_index;
15741 
15742  // no. because in multiplayer, its funny
15743  if (Game_mode & GM_MULTIPLAYER)
15744  return;
15745 
15746  if (rand() % 4 == 0)
15747  {
15749  if (ship_index >= 0)
15751  }
15752 }
15753 
15758 {
15759  int multi_team_filter = -1;
15760 
15761  // bogus
15762  if (sp == NULL)
15763  return;
15764 
15765  // multiplayer tvt
15766  if (MULTI_TEAM)
15767  multi_team_filter = sp->team;
15768 
15769  // Bail if the ship is silenced
15770  if (sp->flags2 & SF2_NO_BUILTIN_MESSAGES)
15771  {
15772  return;
15773  }
15774 
15777  Player->scream_count++;
15778 
15779  sp->flags |= SF_SHIP_HAS_SCREAMED;
15780 
15781  // prevent overlap with help messages
15784 }
15785 
15790 {
15791  // bail if screaming is disabled
15792  if (sp->flags2 & SF2_NO_DEATH_SCREAM)
15793  return;
15794 
15795  // if screaming is enabled, skip all checks
15796  if (!(sp->flags2 & SF2_ALWAYS_DEATH_SCREAM))
15797  {
15798  // only scream x% of the time
15799  if ( (int)(frand()*100) > Builtin_messages[MESSAGE_WINGMAN_SCREAM].occurrence_chance ) {
15800  return;
15801  }
15802 
15803  // check if enough time has elapsed since last scream; if not, leave
15805  return;
15806 
15807  // for WCSaga, only do a subset of the checks
15809  {
15810  // bail if this ship isn't from the player wing
15811  if (!(sp->flags & SF_FROM_PLAYER_WING))
15812  return;
15813 
15814  // first check if the player has reached the maximum number of screams for a mission
15816  return;
15817  }
15818 
15819  // if on different teams (i.e. team v. team games in multiplayer), no scream
15820  if (Player_ship->team != sp->team)
15821  return;
15822  }
15823  }
15824 
15825  ship_scream(sp);
15826 }
15827 
15828 // maybe tell player that we're running low on ammo
15829 #define PLAYER_LOW_AMMO_MSG_INTERVAL 250000
15830 #define PLAYER_REQUEST_REPAIR_MSG_INTERVAL 240000
15831 #define PLAYER_MAX_LOW_AMMO_MSGS 5
15832 
15838 {
15839  weapon_info *wip;
15840  int i;
15841  ship_weapon *swp;
15842  int multi_team_filter = -1;
15843 
15844  // we don't want a ship complaining about low ammo after it has just complained about needing support
15846  return;
15847 
15849  return;
15850 
15851  if (Player_ship->team == Iff_traitor)
15852  return;
15853 
15854  // Silent ships should remain just that
15855  if (sp->flags2 & SF2_NO_BUILTIN_MESSAGES) {
15856  return;
15857  }
15858 
15859  // don't mention low ammo if we're docked, for the same reason as in maybe_request_support
15860  if (object_is_docked(&Objects[sp->objnum]))
15861  return;
15862 
15863  // for now, each ship can only complain about low ammo once a mission to stop it getting repetitive
15864  if (sp->ammo_low_complaint_count) {
15865  return;
15866  }
15867 
15869  return;
15870  }
15871 
15872  swp = &sp->weapons;
15873 
15874  // stole the code for this from ship_maybe_tell_about_rearm()
15875  if (Ship_info[sp->ship_info_index].flags & SIF_BALLISTIC_PRIMARIES)
15876  {
15877  for (i = 0; i < swp->num_primary_banks; i++)
15878  {
15879  wip = &Weapon_info[swp->primary_bank_weapons[i]];
15880 
15881  if (wip->wi_flags2 & WIF2_BALLISTIC)
15882  {
15883  if (swp->primary_bank_start_ammo[i] > 0)
15884  {
15885  if ((float)swp->primary_bank_ammo[i] / (float)swp->primary_bank_start_ammo[i] < 0.3f)
15886  {
15887  // multiplayer tvt
15888  if(MULTI_TEAM) {
15889  multi_team_filter = sp->team;
15890  }
15891 
15893 
15895 
15896  // better reset this one too
15898 
15901  break;
15902  }
15903  }
15904  }
15905  }
15906  }
15907 }
15908 
15909 
15914 {
15915  weapon_info *wip;
15916 
15918  return;
15919 
15920  if (Player_ship->team == Iff_traitor)
15921  return;
15922 
15923  // Silent ships should remain just that
15924  if (sp->flags2 & SF2_NO_BUILTIN_MESSAGES)
15925  return;
15926 
15927  // AL 1-4-98: If ship integrity is low, tell player you want to get repaired. Otherwise, tell
15928  // the player you want to get re-armed.
15929 
15930  int message_type = -1;
15931  int heavily_damaged = (get_hull_pct(&Objects[sp->objnum]) < 0.4);
15932 
15933  if (heavily_damaged || (sp->flags & SF_DISABLED))
15934  {
15935  message_type = MESSAGE_REPAIR_REQUEST;
15936  }
15937  else
15938  {
15939  int i;
15940  ship_weapon *swp;
15941 
15942  swp = &sp->weapons;
15943  for (i = 0; i < swp->num_secondary_banks; i++)
15944  {
15945  if (swp->secondary_bank_start_ammo[i] > 0)
15946  {
15947  if ((float)swp->secondary_bank_ammo[i] / (float)swp->secondary_bank_start_ammo[i] < 0.5f)
15948  {
15949  message_type = MESSAGE_REARM_REQUEST;
15950  break;
15951  }
15952  }
15953  }
15954 
15955  // also check ballistic primaries - Goober5000
15956  if (Ship_info[sp->ship_info_index].flags & SIF_BALLISTIC_PRIMARIES)
15957  {
15958  for (i = 0; i < swp->num_primary_banks; i++)
15959  {
15960  wip = &Weapon_info[swp->primary_bank_weapons[i]];
15961 
15962  if (wip->wi_flags2 & WIF2_BALLISTIC)
15963  {
15964  if (swp->primary_bank_start_ammo[i] > 0)
15965  {
15966  if ((float)swp->primary_bank_ammo[i] / (float)swp->primary_bank_start_ammo[i] < 0.3f)
15967  {
15968  message_type = MESSAGE_REARM_PRIMARIES;
15969  break;
15970  }
15971  }
15972  }
15973  }
15974  }
15975  }
15976 
15977  int multi_team_filter = -1;
15978 
15979  // multiplayer tvt
15980  if(MULTI_TEAM)
15981  multi_team_filter = sp->team;
15982 
15983 
15984  if (message_type >= 0)
15985  {
15986  if (rand() & 1)
15987  message_send_builtin_to_player(message_type, sp, MESSAGE_PRIORITY_NORMAL, MESSAGE_TIME_SOON, 0, 0, -1, multi_team_filter);
15988 
15990  }
15991 }
15992 
15993 // The current primary weapon or link status for a ship has changed.. notify clients if multiplayer
15994 //
15995 // input: sp => pointer to ship that modified primaries
15997 {
15998  int i;
15999  ship_weapon *swp;
16000  swp = &sp->weapons;
16001 
16002 
16003  if (sp->flags & SF_PRIMARY_LINKED) {
16004  // if we are linked now find any body who is down and flip them up
16005  for (i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) {
16006  if (swp->primary_animation_position[i] == MA_POS_NOT_SET) {
16010  } else {
16012  }
16013  }
16014  }
16015  } else {
16016  // find anything that is up that shouldn't be
16017  for (i = 0; i < MAX_SHIP_PRIMARY_BANKS; i++) {
16018  if (i == swp->current_primary_bank) {
16019  // if the current bank is down raise it up
16020  if (swp->primary_animation_position[i] == MA_POS_NOT_SET) {
16024  } else {
16026  }
16027  }
16028  } else {
16029  // everyone else should be down, if they are not make them so
16030  if (swp->primary_animation_position[i] != MA_POS_NOT_SET) {
16033  }
16034  }
16035  }
16036  }
16037 
16038 #if 0
16039  // we only need to deal with multiplayer issues for now, so bail it not multiplayer
16040  if ( !(Game_mode & GM_MULTIPLAYER) )
16041  return;
16042 
16043  Assert(sp);
16044 
16045  if ( MULTIPLAYER_MASTER )
16047 #endif
16048 }
16049 
16050 // The current secondary weapon or dual-fire status for a ship has changed.. notify clients if multiplayer
16051 //
16052 // input: sp => pointer to ship that modified secondaries
16054 {
16055  Assert( sp != NULL );
16056 
16057  int i;
16058  ship_weapon *swp = &sp->weapons;
16059 
16060  // find anything that is up that shouldn't be
16061  if (timestamp() > 10) {
16062  for (i = 0; i < MAX_SHIP_SECONDARY_BANKS; i++) {
16063  if (i == swp->current_secondary_bank) {
16064  // if the current bank is down raise it up
16069  } else {
16071  }
16072  }
16073  } else {
16074  // everyone else should be down, if they are not make them so
16078  }
16079  }
16080  }
16081  }
16082 
16083 #if 0
16084  // we only need to deal with multiplayer issues for now, so bail it not multiplayer
16085  if ( !(Game_mode & GM_MULTIPLAYER) ){
16086  return;
16087  }
16088 
16089  Assert(sp);
16090 
16091  if ( MULTIPLAYER_MASTER )
16093 #endif
16094 }
16095 
16097 {
16098  return Ship_info[shipp->ship_info_index].flags;
16099 }
16100 
16101 int ship_get_SIF(int sh)
16102 {
16103  return Ship_info[Ships[sh].ship_info_index].flags;
16104 }
16105 
16106 int ship_get_by_signature(int signature)
16107 {
16108  ship_obj *so;
16109 
16110  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
16111  // if we found a matching ship object signature
16112  if((Objects[so->objnum].signature == signature) && (Objects[so->objnum].type == OBJ_SHIP)){
16113  return Objects[so->objnum].instance;
16114  }
16115  }
16116 
16117  // couldn't find the ship
16118  return -1;
16119 }
16120 
16122 {
16123  Assert(objp != NULL);
16124  Assert(objp->type == OBJ_SHIP);
16125  Assert(objp->instance > -1);
16126  Assert(Ships[objp->instance].ship_info_index > -1);
16127  Assert(Ship_info[Ships[objp->instance].ship_info_index].class_type > -1);
16128 
16129  return &Ship_types[Ship_info[Ships[objp->instance].ship_info_index].class_type];
16130 }
16131 
16138 void ship_do_cargo_revealed( ship *shipp, int from_network )
16139 {
16140  // don't do anything if we already know the cargo
16141  if ( shipp->flags & SF_CARGO_REVEALED ){
16142  return;
16143  }
16144 
16145  nprintf(("Network", "Revealing cargo for %s\n", shipp->ship_name));
16146 
16147  // send the packet if needed
16148  if ( (Game_mode & GM_MULTIPLAYER) && !from_network ){
16149  send_cargo_revealed_packet( shipp );
16150  }
16151 
16152  shipp->flags |= SF_CARGO_REVEALED;
16153  shipp->time_cargo_revealed = Missiontime;
16154 
16155  // if the cargo is something other than "nothing", then make a log entry
16156  if ( stricmp(Cargo_names[shipp->cargo1 & CARGO_INDEX_MASK], NOX("nothing")) ){
16157  mission_log_add_entry(LOG_CARGO_REVEALED, shipp->ship_name, NULL, (shipp->cargo1 & CARGO_INDEX_MASK) );
16158  }
16159 }
16160 
16161 void ship_do_cap_subsys_cargo_revealed( ship *shipp, ship_subsys *subsys, int from_network )
16162 {
16163  // don't do anything if we already know the cargo
16164  if (subsys->flags & SSF_CARGO_REVEALED) {
16165  return;
16166  }
16167 
16168  nprintf(("Network", "Revealing cap ship subsys cargo for %s\n", shipp->ship_name));
16169 
16170  // send the packet if needed
16171  if ( (Game_mode & GM_MULTIPLAYER) && !from_network ){
16172  int subsystem_index = ship_get_index_from_subsys(subsys, shipp->objnum);
16173  send_subsystem_cargo_revealed_packet( shipp, subsystem_index );
16174  }
16175 
16176  subsys->flags |= SSF_CARGO_REVEALED;
16178 
16179  // if the cargo is something other than "nothing", then make a log entry
16180  if ( stricmp(Cargo_names[subsys->subsys_cargo_name & CARGO_INDEX_MASK], NOX("nothing")) ){
16182  }
16183 }
16184 
16190 void ship_do_cargo_hidden( ship *shipp, int from_network )
16191 {
16192  // don't do anything if the cargo is already hidden
16193  if ( !(shipp->flags & SF_CARGO_REVEALED) )
16194  {
16195  return;
16196  }
16197 
16198  nprintf(("Network", "Hiding cargo for %s\n", shipp->ship_name));
16199 
16200  // send the packet if needed
16201  if ( (Game_mode & GM_MULTIPLAYER) && !from_network ){
16202  send_cargo_hidden_packet( shipp );
16203  }
16204 
16205  shipp->flags &= ~SF_CARGO_REVEALED;
16206 
16207  // don't log that the cargo was hidden and don't reset the time cargo revealed
16208 }
16209 
16210 void ship_do_cap_subsys_cargo_hidden( ship *shipp, ship_subsys *subsys, int from_network )
16211 {
16212  // don't do anything if the cargo is already hidden
16213  if (!(subsys->flags & SSF_CARGO_REVEALED))
16214  {
16215  return;
16216  }
16217 
16218  nprintf(("Network", "Hiding cap ship subsys cargo for %s\n", shipp->ship_name));
16219 
16220  // send the packet if needed
16221  if ( (Game_mode & GM_MULTIPLAYER) && !from_network ){
16222  int subsystem_index = ship_get_index_from_subsys(subsys, shipp->objnum);
16223  send_subsystem_cargo_hidden_packet( shipp, subsystem_index );
16224  }
16225 
16226  subsys->flags &= ~SSF_CARGO_REVEALED;
16227 
16228  // don't log that the cargo was hidden and don't reset the time cargo revealed
16229 }
16230 
16239 {
16240  float srange=0.0f;
16241 
16242  ship_weapon *swp;
16243  swp = &shipp->weapons;
16244  if ( swp->current_secondary_bank >= 0 ) {
16245  weapon_info *wip;
16246  int bank=swp->current_secondary_bank;
16247  if (swp->secondary_bank_weapons[bank] >= 0) {
16248  wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
16249  if ( swp->secondary_bank_ammo[bank] > 0 ) {
16250  srange = wip->max_speed * wip->lifetime;
16251  }
16252  }
16253  }
16254 
16255  return srange;
16256 }
16257 
16258 // Goober5000 - added for ballistic primaries
16262 int get_max_ammo_count_for_primary_bank(int ship_class, int bank, int ammo_type)
16263 {
16264  float capacity, size;
16265 
16266  if (!(Ship_info[ship_class].flags & SIF_BALLISTIC_PRIMARIES))
16267  {
16268  return 0;
16269  }
16270 
16271  capacity = (float) Ship_info[ship_class].primary_bank_ammo_capacity[bank];
16272  size = (float) Weapon_info[ammo_type].cargo_size;
16273  return fl2i((capacity / size)+0.5f);
16274 }
16275 
16279 int get_max_ammo_count_for_bank(int ship_class, int bank, int ammo_type)
16280 {
16281  float capacity, size;
16282 
16283  Assertion(ship_class < static_cast<int>(Ship_info.size()), "Invalid ship_class of %d is >= Ship_info.size() (%d); get a coder!\n", ship_class, static_cast<int>(Ship_info.size()));
16284  Assertion(bank < MAX_SHIP_SECONDARY_BANKS, "Invalid secondary bank of %d (max is %d); get a coder!\n", bank, MAX_SHIP_SECONDARY_BANKS - 1);
16285  Assertion(ammo_type < Num_weapon_types, "Invalid ammo_type of %d is >= Num_weapon_types (%d); get a coder!\n", ammo_type, Num_weapon_types);
16286 
16287  if (ship_class < 0 || bank < 0 || ammo_type < 0) {
16288  return 0;
16289  } else {
16290  capacity = (float) Ship_info[ship_class].secondary_bank_ammo_capacity[bank];
16291  size = (float) Weapon_info[ammo_type].cargo_size;
16292  return (int) (capacity / size);
16293  }
16294 }
16295 
16299 int get_max_ammo_count_for_turret_bank(ship_weapon *swp, int bank, int ammo_type)
16300 {
16301  float capacity, size;
16302 
16303  Assertion(bank < MAX_SHIP_SECONDARY_BANKS, "Invalid secondary bank of %d (max is %d); get a coder!\n", bank, MAX_SHIP_SECONDARY_BANKS - 1);
16304  Assertion(ammo_type < Num_weapon_types, "Invalid ammo_type of %d is >= Num_weapon_types (%d); get a coder!\n", ammo_type, Num_weapon_types);
16305 
16306  if (!swp || bank < 0 || ammo_type < 0) {
16307  return 0;
16308  } else {
16309  capacity = (float) swp->secondary_bank_capacity[bank];
16310  size = (float) Weapon_info[ammo_type].cargo_size;
16311  return (int) (capacity / size);
16312  }
16313 }
16314 
16318 void ship_page_in()
16319 {
16320  int i, j, k;
16321  int num_subsystems_needed = 0;
16322 
16323  int *ship_class_used = NULL;
16324 
16325  ship_class_used = new int[Ship_info.size()];
16326 
16327  Verify( ship_class_used != NULL );
16328 
16329  // Mark all ship classes as not used
16330  memset( ship_class_used, 0, Ship_info.size() * sizeof(int) );
16331 
16332  // Mark any support ship types as used
16333  for (auto sip = Ship_info.begin(); sip != Ship_info.end(); ++sip) {
16334  if (sip->flags & SIF_SUPPORT) {
16335  nprintf(( "Paging", "Found support ship '%s'\n", sip->name ));
16336  i = std::distance(Ship_info.begin(), sip);
16337  ship_class_used[i]++;
16338 
16339  num_subsystems_needed += sip->n_subsystems;
16340 
16341  // load the darn model and page in textures
16342  sip->model_num = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);
16343 
16344  if (sip->model_num >= 0) {
16345  model_page_in_textures(sip->model_num, i);
16346  }
16347  }
16348  }
16349 
16350  // Mark any ships in the mission as used
16351  for (i = 0; i < MAX_SHIPS; i++) {
16352  if (Ships[i].objnum < 0)
16353  continue;
16354 
16355  nprintf(( "Paging","Found ship '%s'\n", Ships[i].ship_name ));
16356  ship_class_used[Ships[i].ship_info_index]++;
16357 
16358  // check if we are going to use a Knossos device and make sure the special warp ani gets pre-loaded
16359  if ( Ship_info[Ships[i].ship_info_index].flags & SIF_KNOSSOS_DEVICE )
16360  Knossos_warp_ani_used = 1;
16361 
16362  // mark any weapons as being used, saves memory and time if we don't load them all
16363  ship_weapon *swp = &Ships[i].weapons;
16364 
16365  for (j = 0; j < swp->num_primary_banks; j++)
16366  weapon_mark_as_used(swp->primary_bank_weapons[j]);
16367 
16368  for (j = 0; j < swp->num_secondary_banks; j++)
16369  weapon_mark_as_used(swp->secondary_bank_weapons[j]);
16370 
16371  // get weapons for all capship subsystems (turrets)
16372  ship_subsys *ptr = GET_FIRST(&Ships[i].subsys_list);
16373 
16374  while (ptr != END_OF_LIST(&Ships[i].subsys_list)) {
16375  for (k = 0; k < MAX_SHIP_PRIMARY_BANKS; k++)
16376  weapon_mark_as_used(ptr->weapons.primary_bank_weapons[k]);
16377 
16378  for (k = 0; k < MAX_SHIP_SECONDARY_BANKS; k++)
16379  weapon_mark_as_used(ptr->weapons.secondary_bank_weapons[k]);
16380 
16381  ptr = GET_NEXT(ptr);
16382  }
16383 
16384  ship_info *sip = &Ship_info[Ships[i].ship_info_index];
16385 
16386  // page in all of the textures if the model is already loaded
16387  if (sip->model_num >= 0) {
16388  nprintf(( "Paging", "Paging in textures for ship '%s'\n", Ships[i].ship_name ));
16389  model_page_in_textures(sip->model_num, Ships[i].ship_info_index);
16390  // need to make sure and do this again, after we are sure that all of the textures are ready
16391  ship_init_afterburners( &Ships[i] );
16392  }
16393 
16394  //WMC - Since this is already in-mission, ignore the warpin effect.
16395  Ships[i].warpout_effect->pageIn();
16396 
16397  // don't need this one anymore, it's already been accounted for
16398  // num_subsystems_needed += Ship_info[Ships[i].ship_info_index].n_subsystems;
16399  }
16400 
16401  // Mark any ships that might warp in in the future as used
16402  for (p_object *p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp)) {
16403  nprintf(( "Paging", "Found future arrival ship '%s'\n", p_objp->name ));
16404  ship_class_used[p_objp->ship_class]++;
16405 
16406  // This will go through Subsys_index[] and grab all weapons: primary, secondary, and turrets
16407  for (i = p_objp->subsys_index; i < (p_objp->subsys_index + p_objp->subsys_count); i++) {
16408  for (j = 0; j < MAX_SHIP_PRIMARY_BANKS; j++) {
16409  if (Subsys_status[i].primary_banks[j] >= 0)
16410  weapon_mark_as_used(Subsys_status[i].primary_banks[j]);
16411  }
16412 
16413  for (j = 0; j < MAX_SHIP_SECONDARY_BANKS; j++) {
16414  if (Subsys_status[i].secondary_banks[j] >= 0)
16415  weapon_mark_as_used(Subsys_status[i].secondary_banks[j]);
16416  }
16417  }
16418 
16419  // page in any replacement textures
16420  if (Ship_info[p_objp->ship_class].model_num >= 0) {
16421  nprintf(( "Paging", "Paging in textures for future arrival ship '%s'\n", p_objp->name ));
16422  model_page_in_textures(Ship_info[p_objp->ship_class].model_num, p_objp->ship_class);
16423  }
16424 
16425  num_subsystems_needed += Ship_info[p_objp->ship_class].n_subsystems;
16426  }
16427 
16428  // pre-allocate the subsystems, this really only needs to happen for ships
16429  // which don't exist yet (ie, ships NOT in Ships[])
16430  if (!ship_allocate_subsystems(num_subsystems_needed, true)) {
16431  Error(LOCATION, "Attempt to page in new subsystems subsystems failed because mission file contains more than %d subsystems", (NUM_SHIP_SUBSYSTEM_SETS* NUM_SHIP_SUBSYSTEMS_PER_SET));
16432  }
16433 
16434  mprintf(("About to page in ships!\n"));
16435 
16436  // Page in all the ship classes that are used on this level
16437  int num_ship_types_used = 0;
16438  int test_id __UNUSED = -1;
16439 
16440  memset( fireball_used, 0, sizeof(int) * MAX_FIREBALL_TYPES );
16441 
16442  i = 0;
16443  for (auto sip = Ship_info.begin(); sip != Ship_info.end(); i++, ++sip) {
16444  if ( !ship_class_used[i] )
16445  continue;
16446 
16447  int model_previously_loaded = -1;
16448  int ship_previously_loaded = -1;
16449 
16450  num_ship_types_used++;
16451 
16452  // Page in the small hud icons for each ship
16453  hud_ship_icon_page_in(&(*sip));
16454 
16455  // See if this model was previously loaded by another ship
16456  for (auto it = Ship_info.begin(); it != Ship_info.end(); ++it) {
16457  if ( (it->model_num > -1) && !stricmp(sip->pof_file, it->pof_file) ) {
16458  // Model already loaded
16459  model_previously_loaded = it->model_num;
16460 
16461  if ((sip->n_subsystems > 0) && (sip->subsystems[0].model_num > -1)) {
16462  ship_previously_loaded = std::distance(Ship_info.begin(), it);
16463 
16464  // It is possible in some cases for sip->model_num to change, and for subsystems->model_num
16465  // to still point to the old model index; this makes sure it doesn't happen. -zookeeper
16466  for (k = 0; k < sip->n_subsystems; k++) {
16467  if (sip->model_num != sip->subsystems[k].model_num) {
16468  mprintf(("Ship %s has model_num %i but its subsystem %s has model_num %i, fixing...\n", sip->name, sip->model_num, sip->subsystems[k].name, sip->subsystems[k].model_num));
16469  sip->subsystems[k].model_num = sip->model_num;
16470  }
16471  }
16472  }
16473 
16474  // the model should already be loaded so this wouldn't take long, but
16475  // we need to make sure that the load count for the model is correct
16476  test_id = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);
16477  Assert( test_id == model_previously_loaded );
16478 
16479  break;
16480  }
16481  }
16482 
16483  // If the model is previously loaded...
16484  if (model_previously_loaded >= 0) {
16485  // If previously loaded model isn't the same ship class...)
16486  if (ship_previously_loaded != i) {
16487  // update the model number.
16488  sip->model_num = model_previously_loaded;
16489 
16490  for (j = 0; j < sip->n_subsystems; j++)
16491  sip->subsystems[j].model_num = -1;
16492 
16493  ship_copy_subsystem_fixup(&(*sip));
16494 
16495 #ifndef NDEBUG
16496  for (j = 0; j < sip->n_subsystems; j++) {
16497  if (sip->subsystems[j].model_num != sip->model_num) {
16498  polymodel *sip_pm = (sip->model_num >= 0) ? model_get(sip->model_num) : NULL;
16499  polymodel *subsys_pm = (sip->subsystems[j].model_num >= 0) ? model_get(sip->subsystems[j].model_num) : NULL;
16500  Warning(LOCATION, "After ship_copy_subsystem_fixup, ship '%s' does not have subsystem '%s' linked into the model file, '%s'.\n\n(Ship_info model is '%s' and subsystem model is '%s'.)", sip->name, sip->subsystems[j].subobj_name, sip->pof_file, (sip_pm != NULL) ? sip_pm->filename : "NULL", (subsys_pm != NULL) ? subsys_pm->filename : "NULL");
16501  }
16502  }
16503 #endif
16504  } else {
16505  // Just to be safe (I mean to check that my code works...)
16506  Assert( sip->model_num >= 0 );
16507  Assert( sip->model_num == model_previously_loaded );
16508 
16509 #ifndef NDEBUG
16510  for (j = 0; j < sip->n_subsystems; j++) {
16511  if (sip->subsystems[j].model_num != sip->model_num) {
16512  polymodel *sip_pm = (sip->model_num >= 0) ? model_get(sip->model_num) : NULL;
16513  polymodel *subsys_pm = (sip->subsystems[j].model_num >= 0) ? model_get(sip->subsystems[j].model_num) : NULL;
16514  Warning(LOCATION, "Without ship_copy_subsystem_fixup, ship '%s' does not have subsystem '%s' linked into the model file, '%s'.\n\n(Ship_info model is '%s' and subsystem model is '%s'.)", sip->name, sip->subsystems[j].subobj_name, sip->pof_file, (sip_pm != NULL) ? sip_pm->filename : "NULL", (subsys_pm != NULL) ? subsys_pm->filename : "NULL");
16515  }
16516  }
16517 #endif
16518  }
16519  } else {
16520  // Model not loaded, so load it
16521  sip->model_num = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);
16522 
16523  Assert( sip->model_num >= 0 );
16524 
16525 #ifndef NDEBUG
16526  // Verify that all the subsystem model numbers are updated
16527  for (j = 0; j < sip->n_subsystems; j++)
16528  Assertion( sip->subsystems[j].model_num == sip->model_num, "Model reference for subsystem %s (model num: %d) on model %s (model num: %d) is invalid.\n", sip->subsystems[j].name, sip->subsystems[j].model_num, sip->pof_file, sip->model_num ); // JAS
16529 #endif
16530  }
16531 
16532  // more weapon marking, the weapon info in Ship_info[] is the default
16533  // loadout which isn't specified by missionparse unless it's different
16534  for (j = 0; j < sip->num_primary_banks; j++)
16535  weapon_mark_as_used(sip->primary_bank_weapons[j]);
16536 
16537  for (j = 0; j < sip->num_secondary_banks; j++)
16538  weapon_mark_as_used(sip->secondary_bank_weapons[j]);
16539 
16540  weapon_mark_as_used(sip->cmeasure_type);
16541 
16542  for (j = 0; j < sip->n_subsystems; j++) {
16543  model_subsystem *msp = &sip->subsystems[j];
16544 
16545  for (k = 0; k < MAX_SHIP_PRIMARY_BANKS; k++)
16546  weapon_mark_as_used(msp->primary_banks[k]);
16547 
16548  for (k = 0; k < MAX_SHIP_SECONDARY_BANKS; k++)
16549  weapon_mark_as_used(msp->secondary_banks[k]);
16550  }
16551 
16552  // Page in the shockwave stuff. -C
16553  shockwave_create_info_load(&sip->shockwave);
16554  if(sip->explosion_bitmap_anims.size() > 0) {
16555  int num_fireballs = sip->explosion_bitmap_anims.size();
16556  for(j = 0; j < num_fireballs; j++){
16557  fireball_used[sip->explosion_bitmap_anims[j]] = 1;
16558  }
16559  } else if(sip->class_type >= 0 && Ship_types[sip->class_type].explosion_bitmap_anims.size() > 0) {
16560  int num_fireballs = Ship_types[sip->class_type].explosion_bitmap_anims.size();
16561  for(j = 0; j < num_fireballs; j++){
16562  fireball_used[Ship_types[sip->class_type].explosion_bitmap_anims[j]] = 1;
16563  }
16564  }
16565  }
16566 
16567  nprintf(( "Paging", "There are %d ship classes used in this mission.\n", num_ship_types_used ));
16568 
16569 
16570  // Page in the thruster effects
16571  // Make sure thrusters are loaded
16572  if (!Thrust_anim_inited)
16573  ship_init_thrusters();
16574 
16575  thrust_info *thruster;
16576  for (i = 0; i < (int)Species_info.size(); i++) {
16577  thruster = &Species_info[i].thruster_info;
16578 
16579  bm_page_in_texture( thruster->flames.normal.first_frame, thruster->flames.normal.num_frames );
16580  bm_page_in_texture( thruster->flames.afterburn.first_frame, thruster->flames.afterburn.num_frames );
16581 
16582  // glows are really not anims
16583  bm_page_in_texture( thruster->glow.normal.first_frame );
16584  bm_page_in_texture( thruster->glow.afterburn.first_frame );
16585  }
16586 
16587  // page in insignia bitmaps
16588  if(Game_mode & GM_MULTIPLAYER){
16589  for(i=0; i<MAX_PLAYERS; i++){
16590  if(MULTI_CONNECTED(Net_players[i]) && (Net_players[i].m_player != NULL) && (Net_players[i].m_player->insignia_texture >= 0)){
16591  bm_page_in_xparent_texture(Net_players[i].m_player->insignia_texture);
16592  }
16593  }
16594  } else {
16595  if((Player != NULL) && (Player->insignia_texture >= 0)){
16596  bm_page_in_xparent_texture(Player->insignia_texture);
16597  }
16598  }
16599 
16600  // page in wing insignia bitmaps - Goober5000
16601  for (i = 0; i < MAX_WINGS; i++)
16602  {
16603  if (Wings[i].wing_insignia_texture >= 0)
16604  bm_page_in_xparent_texture(Wings[i].wing_insignia_texture);
16605  }
16606 
16607  // page in replacement textures - Goober5000
16608  for (i = 0; i < MAX_SHIPS; i++)
16609  {
16610  // is this a valid ship?
16611  if (Ships[i].objnum >= 0)
16612  {
16613  // do we have any textures?
16614  if (Ships[i].ship_replacement_textures != NULL)
16615  {
16616  // page in replacement textures
16617  for (j=0; j<MAX_REPLACEMENT_TEXTURES; j++)
16618  {
16619  if (Ships[i].ship_replacement_textures[j] > -1)
16620  {
16621  bm_page_in_texture( Ships[i].ship_replacement_textures[j] );
16622  }
16623  }
16624  }
16625  }
16626  }
16627 
16628  // should never be NULL, this entire function wouldn't work
16629  delete[] ship_class_used;
16630  ship_class_used = NULL;
16631 
16632 }
16633 
16634 // Goober5000 - called from ship_page_in()
16635 void ship_page_in_textures(int ship_index)
16636 {
16637  int i;
16638  ship_info *sip;
16639 
16640  if ( (ship_index < 0) || (ship_index >= static_cast<int>(Ship_info.size())) )
16641  return;
16642 
16643 
16644  sip = &Ship_info[ship_index];
16645 
16646  // afterburner
16647  if ( !generic_bitmap_load(&sip->afterburner_trail) )
16648  bm_page_in_texture(sip->afterburner_trail.bitmap_id);
16649 
16650  // Wanderer - just copying over Bobboau's code...
16651  if ( !generic_anim_load(&sip->thruster_flame_info.normal) )
16652  bm_page_in_texture(sip->thruster_flame_info.normal.first_frame);
16653 
16654  if ( !generic_anim_load(&sip->thruster_flame_info.afterburn) )
16655  bm_page_in_texture(sip->thruster_flame_info.afterburn.first_frame);
16656 
16657  // Bobboau's thruster bitmaps
16658  // the first set has to be loaded a special way
16659  if ( !thruster_glow_anim_load(&sip->thruster_glow_info.normal) )
16660  bm_page_in_texture(sip->thruster_glow_info.normal.first_frame);
16661 
16662  if ( !thruster_glow_anim_load(&sip->thruster_glow_info.afterburn) )
16663  bm_page_in_texture(sip->thruster_glow_info.afterburn.first_frame);
16664 
16665  // everything else is loaded normally
16666  if ( !generic_bitmap_load(&sip->thruster_secondary_glow_info.normal) )
16667  bm_page_in_texture(sip->thruster_secondary_glow_info.normal.bitmap_id);
16668 
16669  if ( !generic_bitmap_load(&sip->thruster_secondary_glow_info.afterburn) )
16670  bm_page_in_texture(sip->thruster_secondary_glow_info.afterburn.bitmap_id);
16671 
16672  if ( !generic_bitmap_load(&sip->thruster_tertiary_glow_info.normal) )
16673  bm_page_in_texture(sip->thruster_tertiary_glow_info.normal.bitmap_id);
16674 
16675  if ( !generic_bitmap_load(&sip->thruster_tertiary_glow_info.afterburn) )
16676  bm_page_in_texture(sip->thruster_tertiary_glow_info.afterburn.bitmap_id);
16677 
16678  // splodeing bitmap
16679  if ( VALID_FNAME(sip->splodeing_texture_name) ) {
16680  sip->splodeing_texture = bm_load(sip->splodeing_texture_name);
16681  bm_page_in_texture(sip->splodeing_texture);
16682  }
16683 
16684  // thruster/particle bitmaps
16685  for (i = 0; i < (int)sip->normal_thruster_particles.size(); i++) {
16686  generic_anim_load(&sip->normal_thruster_particles[i].thruster_bitmap);
16687  bm_page_in_texture(sip->normal_thruster_particles[i].thruster_bitmap.first_frame);
16688  }
16689 
16690  for (i = 0; i < (int)sip->afterburner_thruster_particles.size(); i++) {
16691  generic_anim_load(&sip->afterburner_thruster_particles[i].thruster_bitmap);
16692  bm_page_in_texture(sip->afterburner_thruster_particles[i].thruster_bitmap.first_frame);
16693  }
16694 }
16695 
16696 
16697 #define PAGE_OUT_TEXTURE(x) { \
16698  if ( (x) >= 0 ) { \
16699  if (release) { \
16700  bm_release( (x) ); \
16701  (x) = -1; \
16702  } else { \
16703  bm_unload( (x) ); \
16704  } \
16705  } \
16706 }
16707 
16711 void ship_page_out_textures(int ship_index, bool release)
16712 {
16713  int i;
16714  ship_info *sip;
16715 
16716  if ( (ship_index < 0) || (ship_index >= static_cast<int>(Ship_info.size())) )
16717  return;
16718 
16719 
16720  sip = &Ship_info[ship_index];
16721 
16722  // afterburner
16723  PAGE_OUT_TEXTURE(sip->afterburner_trail.bitmap_id);
16724 
16725  // thruster bitmaps
16726  PAGE_OUT_TEXTURE(sip->thruster_flame_info.normal.first_frame);
16727  PAGE_OUT_TEXTURE(sip->thruster_flame_info.afterburn.first_frame);
16728  PAGE_OUT_TEXTURE(sip->thruster_glow_info.normal.first_frame);
16729  PAGE_OUT_TEXTURE(sip->thruster_glow_info.afterburn.first_frame);
16730  PAGE_OUT_TEXTURE(sip->thruster_secondary_glow_info.normal.bitmap_id);
16731  PAGE_OUT_TEXTURE(sip->thruster_secondary_glow_info.afterburn.bitmap_id);
16732  PAGE_OUT_TEXTURE(sip->thruster_tertiary_glow_info.normal.bitmap_id);
16733  PAGE_OUT_TEXTURE(sip->thruster_tertiary_glow_info.afterburn.bitmap_id);
16734 
16735  // slodeing bitmap
16736  PAGE_OUT_TEXTURE(sip->splodeing_texture);
16737 
16738  // thruster/particle bitmaps
16739  for (i = 0; i < (int)sip->normal_thruster_particles.size(); i++)
16740  PAGE_OUT_TEXTURE(sip->normal_thruster_particles[i].thruster_bitmap.first_frame);
16741 
16742  for (i = 0; i < (int)sip->afterburner_thruster_particles.size(); i++)
16743  PAGE_OUT_TEXTURE(sip->afterburner_thruster_particles[i].thruster_bitmap.first_frame);
16744 }
16745 
16746 // function to return true if support ships are allowed in the mission for the given object.
16747 // In single player, must be friendly and not Shivan. (Goober5000 - Shivans can now have support)
16748 // In multiplayer -- to be coded by Mark Allender after 5/4/98 -- MK, 5/4/98
16749 int is_support_allowed(object *objp, bool do_simple_check)
16750 {
16751  int result = -1;
16752 
16753  // check updated mission conditions to allow support
16754 
16755  // If running under autopilot support is not allowed
16756  if ( AutoPilotEngaged )
16757  return 0;
16758 
16759  // none allowed
16760  if (The_mission.support_ships.max_support_ships == 0)
16761  return 0;
16762 
16763  // ship_find_repair_ship is a little expensive, so let's not do it every frame
16764  if (!do_simple_check)
16765  {
16766  // check if all support ships are departing or dying
16767  result = ship_find_repair_ship(objp);
16768  if (result == 4) {
16769  return 0;
16770  }
16771 
16772  // restricted number allowed
16773  if (The_mission.support_ships.max_support_ships > 0)
16774  {
16775  // if all the allowed ships have been used up, can't rearm unless something's available in-mission or arriving
16776  if ((The_mission.support_ships.tally >= The_mission.support_ships.max_support_ships))
16777  {
16778  // this shouldn't happen because we've reached one of the limits
16779  Assert(result != 2);
16780 
16781  // nothing arriving and no ships available in mission
16782  if ((Arriving_support_ship == NULL) && (result == 0 || result == 3))
16783  return 0;
16784  }
16785  }
16786  }
16787 
16788  ship *shipp = &Ships[objp->instance];
16789 
16790  // this also looks a little more expensive
16791  if (!do_simple_check)
16792  {
16793  // make sure, if exiting from bay, that parent ship is in the mission!
16794  if ((result == 0 || result == 2) && (The_mission.support_ships.arrival_location == ARRIVE_FROM_DOCK_BAY))
16795  {
16796  Assert(The_mission.support_ships.arrival_anchor != -1);
16797 
16798  // ensure it's in-mission
16799  int temp = ship_name_lookup(Parse_names[The_mission.support_ships.arrival_anchor]);
16800  if (temp < 0)
16801  {
16802  return 0;
16803  }
16804 
16805  // make sure it's not leaving or blowing up
16806  if (Ships[temp].flags & (SF_DYING | SF_DEPARTING))
16807  {
16808  return 0;
16809  }
16810 
16811  // also make sure that parent ship's fighterbay hasn't been destroyed
16812  if (ship_fighterbays_all_destroyed(&Ships[temp]))
16813  {
16814  return 0;
16815  }
16816  }
16817  }
16818 
16819  if (Game_mode & GM_NORMAL)
16820  {
16821  if ( !(Iff_info[shipp->team].flags & IFFF_SUPPORT_ALLOWED) )
16822  {
16823  return 0;
16824  }
16825  }
16826  else
16827  {
16828  // multiplayer version behaves differently. Depending on mode:
16829  // 1) coop mode -- only available to friendly
16830  // 2) team v team mode -- availble to either side
16831  // 3) dogfight -- never
16832 
16833  if(Netgame.type_flags & NG_TYPE_DOGFIGHT)
16834  {
16835  return 0;
16836  }
16837 
16838  if (IS_MISSION_MULTI_COOP)
16839  {
16840  if ( !(Iff_info[shipp->team].flags & IFFF_SUPPORT_ALLOWED) )
16841  {
16842  return 0;
16843  }
16844  }
16845  }
16846 
16847  // Goober5000 - extra check for existence of support ship
16848  if ( (The_mission.support_ships.ship_class < 0) &&
16849  !(The_mission.support_ships.support_available_for_species & (1 << Ship_info[shipp->ship_info_index].species)) )
16850  {
16851  return 0;
16852  }
16853 
16854  // this is also somewhat expensive
16855  if (!do_simple_check)
16856  {
16857  // Goober5000 - extra check to make sure this guy has a rearming dockpoint
16858  if (model_find_dock_index(Ship_info[shipp->ship_info_index].model_num, DOCK_TYPE_REARM) < 0)
16859  {
16860  static bool warned_about_rearm_dockpoint = false;
16861  if (!warned_about_rearm_dockpoint)
16862  {
16863  Warning(LOCATION, "Support not allowed for %s because its model lacks a rearming dockpoint!", shipp->ship_name);
16864  warned_about_rearm_dockpoint = true;
16865  }
16866  return 0;
16867  }
16868  }
16869 
16870  // Goober5000 - if we got this far, we can request support
16871  return 1;
16872 }
16873 
16874 // returns random index of a visible ship
16875 // if no visible ships are generated in num_ships iterations, it returns -1
16876 int ship_get_random_targetable_ship()
16877 {
16878  int rand_ship;
16879  int idx = 0, target_list[MAX_SHIPS];
16880  ship_obj *so;
16881 
16882  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
16883  // make sure the instance is valid
16884  if ( (Objects[so->objnum].instance < 0) || (Objects[so->objnum].instance >= MAX_SHIPS) )
16885  continue;
16886 
16887  // skip if we aren't supposed to target it
16888  if ( Ships[Objects[so->objnum].instance].flags & TARGET_SHIP_IGNORE_FLAGS )
16889  continue;
16890 
16891  if (idx >= MAX_SHIPS) {
16892  idx = MAX_SHIPS;
16893  break;
16894  }
16895 
16896  target_list[idx] = Objects[so->objnum].instance;
16897  idx++;
16898  }
16899 
16900  if (idx == 0)
16901  return -1;
16902 
16903  rand_ship = (rand() % idx);
16904 
16905  return target_list[rand_ship];
16906 }
16907 
16911 void object_jettison_cargo(object *objp, object *cargo_objp)
16912 {
16913  // make sure we are docked
16914  Assert((objp != NULL) && (cargo_objp != NULL));
16915  Assert(dock_check_find_direct_docked_object(objp, cargo_objp));
16916 
16917  vec3d impulse, pos;
16918  ship *shipp = &Ships[objp->instance];
16919  ship *cargo_shipp = &Ships[cargo_objp->instance];
16920  int docker_index = dock_find_dockpoint_used_by_object(objp, cargo_objp);
16921  int dockee_index = dock_find_dockpoint_used_by_object(cargo_objp, objp);
16922 
16923  // undo all the docking animations
16924  model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
16925  model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
16926  model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
16927  model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_1, docker_index, -1);
16928  model_anim_start_type(cargo_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
16929  model_anim_start_type(cargo_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
16930  model_anim_start_type(cargo_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
16931  model_anim_start_type(cargo_shipp, TRIGGER_TYPE_DOCKING_STAGE_1, dockee_index, -1);
16932 
16933  // undock the objects
16934  ai_do_objects_undocked_stuff(objp, cargo_objp);
16935 
16936  // Goober5000 - add log
16937  mission_log_add_entry(LOG_SHIP_UNDOCKED, shipp->ship_name, cargo_shipp->ship_name);
16938 
16939  // physics stuff
16940  vm_vec_sub(&pos, &cargo_objp->pos, &objp->pos);
16941  impulse = pos;
16942  vm_vec_scale(&impulse, 100.0f);
16943  vm_vec_normalize(&pos);
16944 
16945  // whack the ship
16946  physics_apply_whack(&impulse, &pos, &cargo_objp->phys_info, &cargo_objp->orient, cargo_objp->phys_info.mass);
16947 }
16948 
16949 float ship_get_exp_damage(object* objp)
16950 {
16951  Assert(objp->type == OBJ_SHIP);
16952  float damage;
16953 
16954  ship *shipp = &Ships[objp->instance];
16955 
16956  if (shipp->special_exp_damage >= 0) {
16957  damage = i2fl(shipp->special_exp_damage);
16958  } else {
16959  damage = Ship_info[shipp->ship_info_index].shockwave.damage;
16960  }
16961 
16962  return damage;
16963 }
16964 
16965 int ship_get_exp_propagates(ship *sp)
16966 {
16967  return Ship_info[sp->ship_info_index].explosion_propagates;
16968 }
16969 
16970 float ship_get_exp_outer_rad(object *ship_objp)
16971 {
16972  float outer_rad;
16973  Assert(ship_objp->type == OBJ_SHIP);
16974 
16975  if (Ships[ship_objp->instance].special_exp_outer == -1) {
16976  outer_rad = Ship_info[Ships[ship_objp->instance].ship_info_index].shockwave.outer_rad;
16977  } else {
16978  outer_rad = (float)Ships[ship_objp->instance].special_exp_outer;
16979  }
16980 
16981  return outer_rad;
16982 }
16983 
16984 int valid_cap_subsys_cargo_list(char *subsys)
16985 {
16986  // Return 1 for all subsystems now, due to Mantis #2524.
16987  return 1;
16988  /*
16989  if (stristr(subsys, "nav")
16990  || stristr(subsys, "comm")
16991  || stristr(subsys, "engine")
16992  || stristr(subsys, "fighter") // fighter bays
16993  || stristr(subsys, "sensors")
16994  || stristr(subsys, "weapons")) {
16995 
16996  return 1;
16997  }
16998 
16999  return 0;
17000  */
17001 }
17002 
17008 int ship_get_turret_type(ship_subsys *subsys)
17009 {
17010  // not a turret at all
17011  if(subsys->system_info->type != SUBSYSTEM_TURRET){
17012  return 0;
17013  }
17014 
17015  // if it rotates
17016  if(subsys->system_info->turret_turning_rate > 0.0f){
17017  return 2;
17018  }
17019 
17020  // if its fixed
17021  return 1;
17022 }
17023 
17024 ship_subsys *ship_get_subsys(ship *shipp, char *subsys_name)
17025 {
17026  // sanity checks
17027  if ((shipp == NULL) || (subsys_name == NULL)) {
17028  return NULL;
17029  }
17030 
17031  ship_subsys *ss = GET_FIRST(&shipp->subsys_list);
17032  while (ss != END_OF_LIST(&shipp->subsys_list)) {
17033  // check subsystem name
17034  if (!subsystem_stricmp(ss->system_info->subobj_name, subsys_name)) {
17035  return ss;
17036  }
17037 
17038  // next
17039  ss = GET_NEXT(ss);
17040  }
17041 
17042  // didn't find it
17043  return NULL;
17044 }
17045 
17046 int ship_get_num_subsys(ship *shipp)
17047 {
17048  Assert(shipp != NULL);
17049 
17050  return Ship_info[shipp->ship_info_index].n_subsystems;
17051 }
17052 
17053 // returns 0 if no conflict, 1 if conflict, -1 on some kind of error with wing struct
17054 int wing_has_conflicting_teams(int wing_index)
17055 {
17056  int first_team, idx;
17057 
17058  // sanity checks
17059  Assert((wing_index >= 0) && (wing_index < Num_wings) && (Wings[wing_index].wave_count > 0));
17060  if((wing_index < 0) || (wing_index >= Num_wings) || (Wings[wing_index].wave_count <= 0)){
17061  return -1;
17062  }
17063 
17064  // check teams
17065  Assert(Wings[wing_index].ship_index[0] >= 0);
17066  if(Wings[wing_index].ship_index[0] < 0){
17067  return -1;
17068  }
17069  first_team = Ships[Wings[wing_index].ship_index[0]].team;
17070  for(idx=1; idx<Wings[wing_index].wave_count; idx++){
17071  // more sanity checks
17072  Assert(Wings[wing_index].ship_index[idx] >= 0);
17073  if(Wings[wing_index].ship_index[idx] < 0){
17074  return -1;
17075  }
17076 
17077  // if we've got a team conflict
17078  if(first_team != Ships[Wings[wing_index].ship_index[idx]].team){
17079  return 1;
17080  }
17081  }
17082 
17083  // no conflict
17084  return 0;
17085 }
17086 
17090 int ship_get_reinforcement_team(int r_index)
17091 {
17092  int wing_index;
17093  p_object *p_objp;
17094 
17095  // sanity checks
17096  Assert((r_index >= 0) && (r_index < Num_reinforcements));
17097  if ((r_index < 0) || (r_index >= Num_reinforcements))
17098  return -1;
17099 
17100  // if the reinforcement is a ship
17101  p_objp = mission_parse_get_arrival_ship(Reinforcements[r_index].name);
17102  if (p_objp != NULL)
17103  return p_objp->team;
17104 
17105  // if the reinforcement is a ship
17106  wing_index = wing_lookup(Reinforcements[r_index].name);
17107  if (wing_index >= 0)
17108  {
17109  // go through the ship arrival list and find any ship in this wing
17110  for (p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
17111  {
17112  // check by wingnum
17113  if (p_objp->wingnum == wing_index)
17114  return p_objp->team;
17115  }
17116  }
17117 
17118  // no team ?
17119  return -1;
17120 }
17121 
17125 int ship_get_texture(int bitmap)
17126 {
17127  // check all ship types
17128  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
17129  if ((it->model_num >= 0) && model_find_texture(it->model_num, bitmap) == 1) {
17130  return std::distance(Ship_info.cbegin(), it);
17131  }
17132  }
17133 
17134  // couldn't find the texture
17135  return -1;
17136 }
17137 
17138 // update artillery lock info
17139 #define CLEAR_ARTILLERY_AND_CONTINUE() { if(aip != NULL){ aip->artillery_objnum = -1; aip->artillery_sig = -1; aip->artillery_lock_time = 0.0f;} continue; }
17140 float artillery_dist = 10.0f;
17141 DCF(art, "Sets artillery disance")
17142 {
17143  dc_stuff_float(&artillery_dist);
17144 }
17145 
17146 void ship_update_artillery_lock()
17147 {
17148  ai_info *aip = NULL;
17149  mc_info *cinfo = NULL;
17150  int c_objnum;
17151  vec3d temp, local_hit;
17152  ship *shipp;
17153  ship_obj *so;
17154 
17155  // update all ships
17156  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ){
17157  // get the ship
17158  if((so->objnum >= 0) && (Objects[so->objnum].type == OBJ_SHIP) && (Objects[so->objnum].instance >= 0)){
17159  shipp = &Ships[Objects[so->objnum].instance];
17160  } else {
17161  continue;
17162  }
17163 
17164  // get ai info
17165  if(shipp->ai_index >= 0){
17166  aip = &Ai_info[shipp->ai_index];
17167  }
17168 
17169  // if the ship has no targeting laser firing
17170  if((shipp->targeting_laser_objnum < 0) || (shipp->targeting_laser_bank < 0)){
17171  CLEAR_ARTILLERY_AND_CONTINUE();
17172  }
17173 
17174  // if he didn't hit any objects this frame
17175  if(beam_get_num_collisions(shipp->targeting_laser_objnum) <= 0){
17176  CLEAR_ARTILLERY_AND_CONTINUE();
17177  }
17178 
17179  // get weapon info for the targeting laser he's firing
17180  Assert((shipp->weapons.current_primary_bank >= 0) && (shipp->weapons.current_primary_bank < 2));
17181  if((shipp->weapons.current_primary_bank < 0) || (shipp->weapons.current_primary_bank >= 2)){
17182  continue;
17183  }
17184  Assert(shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] >= 0);
17185  if(shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] < 0){
17186  continue;
17187  }
17188  Assert((Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].wi_flags & WIF_BEAM) && (Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].b_info.beam_type == BEAM_TYPE_C));
17189  if(!(Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].wi_flags & WIF_BEAM) || (Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].b_info.beam_type != BEAM_TYPE_C)){
17190  continue;
17191  }
17192 
17193  // get collision info
17194  if(!beam_get_collision(shipp->targeting_laser_objnum, 0, &c_objnum, &cinfo)){
17195  CLEAR_ARTILLERY_AND_CONTINUE();
17196  }
17197  if((c_objnum < 0) || (cinfo == NULL)){
17198  CLEAR_ARTILLERY_AND_CONTINUE();
17199  }
17200 
17201  // get the position we hit this guy with in his local coords
17202  vm_vec_sub(&temp, &cinfo->hit_point_world, &Objects[c_objnum].pos);
17203  vm_vec_rotate(&local_hit, &temp, &Objects[c_objnum].orient);
17204 
17205  // if we are hitting a different guy now, reset the lock
17206  if((c_objnum != aip->artillery_objnum) || (Objects[c_objnum].signature != aip->artillery_sig)){
17207  aip->artillery_objnum = c_objnum;
17208  aip->artillery_sig = Objects[c_objnum].signature;
17209  aip->artillery_lock_time = 0.0f;
17210  aip->artillery_lock_pos = local_hit;
17211 
17212  // done
17213  continue;
17214  }
17215 
17216  // otherwise we're hitting the same guy. check to see if we've strayed too far
17217  if(vm_vec_dist_quick(&local_hit, &aip->artillery_lock_pos) > artillery_dist){
17218  // hmmm. reset lock time, but don't reset the lock itself
17219  aip->artillery_lock_time = 0.0f;
17220  continue;
17221  }
17222 
17223  // finally - just increment the lock time
17224  aip->artillery_lock_time += flFrametime;
17225 
17226  // TEST CODE
17227  if(aip->artillery_objnum >= 0 && aip->artillery_lock_time >= 2.0f){
17228  ssm_create(&Objects[aip->artillery_objnum], &cinfo->hit_point_world, 0, NULL, shipp->team);
17229 
17230  // reset the artillery
17231  aip->artillery_lock_time = 0.0f;
17232  }
17233  }
17234 }
17235 
17241 int check_world_pt_in_expanded_ship_bbox(vec3d *world_pt, object *objp, float delta_box)
17242 {
17243  Assert(objp->type == OBJ_SHIP);
17244 
17245  vec3d temp, ship_pt;
17246  polymodel *pm;
17247  vm_vec_sub(&temp, world_pt, &objp->pos);
17248  vm_vec_rotate(&ship_pt, &temp, &objp->orient);
17249 
17250  pm = model_get(Ship_info[Ships[objp->instance].ship_info_index].model_num);
17251 
17252  return (
17253  (ship_pt.xyz.x > pm->mins.xyz.x - delta_box) && (ship_pt.xyz.x < pm->maxs.xyz.x + delta_box)
17254  && (ship_pt.xyz.y > pm->mins.xyz.y - delta_box) && (ship_pt.xyz.y < pm->maxs.xyz.y + delta_box)
17255  && (ship_pt.xyz.z > pm->mins.xyz.z - delta_box) && (ship_pt.xyz.z < pm->maxs.xyz.z + delta_box)
17256  );
17257 }
17258 
17259 
17263 int ship_is_tagged(object *objp)
17264 {
17265  ship *shipp;
17266  if (objp->type == OBJ_SHIP) {
17267  shipp = &Ships[objp->instance];
17268  if ( (shipp->tag_left > 0) || (shipp->level2_tag_left > 0) ) {
17269  return 1;
17270  }
17271  }
17272 
17273  return 0;
17274 }
17275 
17279 float ship_get_max_speed(ship *shipp)
17280 {
17281  float max_speed;
17282  ship_info *sip = &Ship_info[shipp->ship_info_index];
17283 
17284  // Goober5000 - maybe we're using cap-waypoint-speed
17285  ai_info *aip = &Ai_info[shipp->ai_index];
17286  if ((aip->mode == AIM_WAYPOINTS || aip->mode == AIM_FLY_TO_SHIP) && aip->waypoint_speed_cap > 0)
17287  return i2fl(aip->waypoint_speed_cap);
17288 
17289  // max overclock
17290  max_speed = sip->max_overclocked_speed;
17291 
17292  // normal max speed
17293  max_speed = MAX(max_speed, sip->max_vel.xyz.z);
17294 
17295  // afterburn if not locked
17296  if (!(shipp->flags2 & SF2_AFTERBURNER_LOCKED)) {
17297  max_speed = MAX(max_speed, sip->afterburner_max_vel.xyz.z);
17298  }
17299 
17300  return max_speed;
17301 }
17302 
17306 float ship_get_warpout_speed(object *objp)
17307 {
17308  Assert(objp->type == OBJ_SHIP);
17309 
17310  ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
17311  //WMC - Any speed is good for in place anims (aka BSG FTL effect)
17312  if(sip->warpout_type == WT_IN_PLACE_ANIM && sip->warpout_speed <= 0.0f)
17313  {
17314  return objp->phys_info.speed;
17315  }
17316  else if(sip->warpout_type == WT_SWEEPER || sip->warpout_type == WT_IN_PLACE_ANIM)
17317  {
17318  return sip->warpout_speed;
17319  }
17320  else if(sip->warpout_type == WT_HYPERSPACE)
17321  {
17322  if (objp->phys_info.speed > sip->warpout_speed)
17323  return objp->phys_info.speed;
17324  else
17325  return sip->warpout_speed;
17326  }
17327 
17328  return shipfx_calculate_warp_dist(objp) / shipfx_calculate_warp_time(objp, WD_WARP_OUT);
17329 }
17330 
17334 int ship_is_beginning_warpout_speedup(object *objp)
17335 {
17336  Assert(objp->type == OBJ_SHIP);
17337 
17338  ai_info *aip;
17339 
17340  aip = &Ai_info[Ships[objp->instance].ai_index];
17341 
17342  if (aip->mode == AIM_WARP_OUT) {
17343  if ( (aip->submode == AIS_WARP_3) || (aip->submode == AIS_WARP_4) || (aip->submode == AIS_WARP_5) ) {
17344  return 1;
17345  }
17346  }
17347 
17348  return 0;
17349 }
17350 
17354 float ship_class_get_length(ship_info *sip)
17355 {
17356  Assert(sip->model_num >= 0);
17357  polymodel *pm = model_get(sip->model_num);
17358  return (pm->maxs.xyz.z - pm->mins.xyz.z);
17359 }
17360 
17361 // Goober5000
17362 void ship_set_new_ai_class(int ship_num, int new_ai_class)
17363 {
17364  Assert(ship_num >= 0 && ship_num < MAX_SHIPS);
17365  Assert(new_ai_class >= 0);
17366 
17367  ai_info *aip = &Ai_info[Ships[ship_num].ai_index];
17368 
17369  // we hafta change a bunch of stuff here...
17370  aip->ai_class = new_ai_class;
17371  aip->behavior = AIM_NONE;
17372  init_aip_from_class_and_profile(aip, &Ai_classes[new_ai_class], The_mission.ai_profile);
17373 
17374  Ships[ship_num].weapons.ai_class = new_ai_class;
17375 
17376  // I think that's everything!
17377 }
17378 
17379 // Goober5000
17380 void ship_subsystem_set_new_ai_class(int ship_num, char *subsystem, int new_ai_class)
17381 {
17382  Assert(ship_num >= 0 && ship_num < MAX_SHIPS);
17383  Assert(subsystem);
17384  Assert(new_ai_class >= 0);
17385 
17386  ship_subsys *ss;
17387 
17388  // find the ship subsystem by searching ship's subsys_list
17389  ss = GET_FIRST( &Ships[ship_num].subsys_list );
17390  while ( ss != END_OF_LIST( &Ships[ship_num].subsys_list ) )
17391  {
17392  // if we found the subsystem
17393  if ( !subsystem_stricmp(ss->system_info->subobj_name, subsystem))
17394  {
17395  // set ai class
17396  ss->weapons.ai_class = new_ai_class;
17397  return;
17398  }
17399 
17400  ss = GET_NEXT( ss );
17401  }
17402 }
17403 
17404 // Goober5000 - will attempt to load an insignia bitmap and set it as active for the wing
17405 // copied more or less from managepilot.cpp
17406 void wing_load_squad_bitmap(wing *w)
17407 {
17408  // sanity check
17409  if(w == NULL)
17410  {
17411  return;
17412  }
17413 
17414  // make sure one is not already set?!?
17415  Assert (w->wing_insignia_texture == -1);
17416 
17417  // try and set the new one
17418  if( w->wing_squad_filename[0] != '\0' )
17419  {
17420  // load duplicate because it might be the same as the player's squad,
17421  // and we don't want to overlap and breed nasty errors when we unload
17422  w->wing_insignia_texture = bm_load_duplicate(w->wing_squad_filename);
17423 
17424  // lock is as a transparent texture
17425  if(w->wing_insignia_texture != -1)
17426  {
17427  bm_lock(w->wing_insignia_texture, 16, BMP_TEX_XPARENT);
17428  bm_unlock(w->wing_insignia_texture);
17429  }
17430  }
17431 }
17432 
17433 // Goober5000 - needed by new hangar depart code
17434 // check whether this ship has a docking bay
17435 bool ship_has_dock_bay(int shipnum)
17436 {
17437  Assert(shipnum >= 0 && shipnum < MAX_SHIPS);
17438 
17439  polymodel *pm;
17440 
17441  pm = model_get( Ship_info[Ships[shipnum].ship_info_index].model_num );
17442  Assert( pm );
17443 
17444  return ( pm->ship_bay && (pm->ship_bay->num_paths > 0) );
17445 }
17446 
17447 // Goober5000
17448 bool ship_useful_for_departure(int shipnum, int path_mask)
17449 {
17450  Assert( shipnum >= 0 && shipnum < MAX_SHIPS );
17451 
17452  // not valid if dying or departing
17453  if (Ships[shipnum].flags & (SF_DYING | SF_DEPARTING))
17454  return false;
17455 
17456  // no dockbay, can't depart to it
17457  if (!ship_has_dock_bay(shipnum))
17458  return false;
17459 
17460  // make sure that the bays are not all destroyed
17461  if (ship_fighterbays_all_destroyed(&Ships[shipnum]))
17462  return false;
17463 
17464  // in the future, we might want to check bay paths against destroyed fighterbays,
17465  // but that capability doesn't currently exist
17466  // (note, a mask of 0 indicates all paths are valid)
17467  //if (path_mask != 0)
17468  //{
17469  //}
17470 
17471  // ship is valid
17472  return true;
17473 }
17474 
17475 // Goober5000 - needed by new hangar depart code
17476 // get first ship in ship list with docking bay
17477 int ship_get_ship_for_departure(int team)
17478 {
17479  for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
17480  {
17481  Assert(so->objnum >= 0);
17482  int shipnum = Objects[so->objnum].instance;
17483  Assert(shipnum >= 0);
17484 
17485  if ( (Ships[shipnum].team == team) && ship_useful_for_departure(shipnum) )
17486  return shipnum;
17487  }
17488 
17489  // we didn't find anything
17490  return -1;
17491 }
17492 
17493 // Goober5000 - check if all fighterbays on a ship have been destroyed
17494 bool ship_fighterbays_all_destroyed(ship *shipp)
17495 {
17496  Assert(shipp);
17497  ship_subsys *subsys;
17498  int num_fighterbay_subsystems = 0;
17499 
17500  // check all fighterbay systems
17501  subsys = GET_FIRST(&shipp->subsys_list);
17502  while(subsys != END_OF_LIST(&shipp->subsys_list))
17503  {
17504  // look for fighterbays
17505  if (ship_subsys_is_fighterbay(subsys))
17506  {
17507  num_fighterbay_subsystems++;
17508 
17509  // if fighterbay doesn't take damage, we're good
17510  if (!ship_subsys_takes_damage(subsys))
17511  return false;
17512 
17513  // if fighterbay isn't destroyed, we're good
17514  if (subsys->current_hits > 0)
17515  return false;
17516  }
17517 
17518  // next item
17519  subsys = GET_NEXT(subsys);
17520  }
17521 
17522  // if the ship has no fighterbay subsystems at all, it must be an unusual case,
17523  // like the Faustus, so pretend it's okay...
17524  if (num_fighterbay_subsystems == 0)
17525  return false;
17526 
17527  // if we got this far, the ship has at least one fighterbay subsystem,
17528  // and all the ones it has are destroyed
17529  return true;
17530 }
17531 
17532 // moved here by Goober5000
17533 bool ship_subsys_is_fighterbay(ship_subsys *ss)
17534 {
17535  Assert(ss);
17536 
17537  if ( !strnicmp(NOX("fighter"), ss->system_info->name, 7) ) {
17538  return true;
17539  }
17540 
17541  return false;
17542 }
17543 
17544 // Goober5000
17545 bool ship_subsys_takes_damage(ship_subsys *ss)
17546 {
17547  Assert(ss);
17548 
17549  return (ss->max_hits > SUBSYS_MAX_HITS_THRESHOLD);
17550 }
17551 
17552 // Goober5000
17553 void ship_do_submodel_rotation(ship *shipp, model_subsystem *psub, ship_subsys *pss)
17554 {
17555  Assert(shipp);
17556  Assert(psub);
17557  Assert(pss);
17558 
17559  // check if we actually can rotate
17560  if ( !(pss->flags & SSF_ROTATES) ){
17561  return;
17562  }
17563 
17564  if (psub->flags & MSS_FLAG_TRIGGERED && pss->triggered_rotation_index >= 0) {
17565  Triggered_rotations[pss->triggered_rotation_index].process_queue();
17566  model_anim_submodel_trigger_rotate(psub, pss );
17567  return;
17568 
17569  }
17570 
17571  // check for rotating artillery
17572  if ( psub->flags & MSS_FLAG_ARTILLERY )
17573  {
17574  ship_weapon *swp = &shipp->weapons;
17575 
17576  // rotate only if trigger is down
17577  if ( !(shipp->flags & SF_TRIGGER_DOWN) )
17578  return;
17579 
17580  // check linked
17581  if ( shipp->flags & SF_PRIMARY_LINKED )
17582  {
17583  int i, ammo_tally = 0;
17584 
17585  // calculate ammo
17586  for (i=0; i<swp->num_primary_banks; i++)
17587  ammo_tally += swp->primary_bank_ammo[i];
17588 
17589  // do not rotate if out of ammo
17590  if (ammo_tally <= 0)
17591  return;
17592  }
17593  // check unlinked
17594  else
17595  {
17596  // do not rotate if this is not the firing bank or if we have no ammo in this bank
17597  if ((psub->weapon_rotation_pbank != swp->current_primary_bank) || (swp->primary_bank_ammo[swp->current_primary_bank] <= 0))
17598  return;
17599  }
17600  }
17601 
17602  // if we got this far, we can rotate - so choose which method to use
17603  if (psub->flags & MSS_FLAG_STEPPED_ROTATE ) {
17604  submodel_stepped_rotate(psub, &pss->submodel_info_1);
17605  } else {
17606  submodel_rotate(psub, &pss->submodel_info_1 );
17607  }
17608 }
17609 
17610 // Goober5000
17611 int ship_has_energy_weapons(ship *shipp)
17612 {
17613  // (to avoid round-off errors, weapon reserve is not tested for zero)
17614  return (Ship_info[shipp->ship_info_index].max_weapon_reserve > WEAPON_RESERVE_THRESHOLD);
17615 }
17616 
17617 // Goober5000
17618 int ship_has_engine_power(ship *shipp)
17619 {
17620  return (Ship_info[shipp->ship_info_index].max_speed > 0 );
17621 }
17622 
17623 // Goober5000
17624 int ship_starting_wing_lookup(const char *wing_name)
17625 {
17626  for (int i = 0; i < MAX_STARTING_WINGS; i++)
17627  {
17628  if (!stricmp(Starting_wing_names[i], wing_name))
17629  return i;
17630  }
17631 
17632  return -1;
17633 }
17634 
17635 // Goober5000
17636 int ship_squadron_wing_lookup(const char *wing_name)
17637 {
17638  // TvT uses a different set of wing names from everything else
17639  if (MULTI_TEAM)
17640  {
17641  for (int i = 0; i < MAX_TVT_WINGS; i++)
17642  {
17643  if (!stricmp(TVT_wing_names[i], wing_name))
17644  return i;
17645  }
17646  }
17647  else
17648  {
17649  for (int i = 0; i < MAX_SQUADRON_WINGS; i++)
17650  {
17651  if (!stricmp(Squadron_wing_names[i], wing_name))
17652  return i;
17653  }
17654  }
17655 
17656  return -1;
17657 }
17658 
17659 // Goober5000
17660 int ship_tvt_wing_lookup(const char *wing_name)
17661 {
17662  for (int i = 0; i < MAX_TVT_WINGS; i++)
17663  {
17664  if (!stricmp(TVT_wing_names[i], wing_name))
17665  return i;
17666  }
17667 
17668  return -1;
17669 }
17670 
17671 // Goober5000
17672 int ship_class_get_priority(int ship_class)
17673 {
17674  ship_info *sip = &Ship_info[ship_class];
17675 
17676  // biggest to smallest
17677  if (sip->flags & SIF_KNOSSOS_DEVICE)
17678  return 1;
17679  else if (sip->flags & SIF_SUPERCAP)
17680  return 2;
17681  else if (sip->flags & SIF_DRYDOCK)
17682  return 3;
17683  else if (sip->flags & SIF_CAPITAL)
17684  return 4;
17685  else if (sip->flags & SIF_CORVETTE)
17686  return 5;
17687  else if (sip->flags & SIF_CRUISER)
17688  return 6;
17689  else if (sip->flags & SIF_GAS_MINER)
17690  return 7;
17691  else if (sip->flags & SIF_AWACS)
17692  return 8;
17693  else if (sip->flags & SIF_FREIGHTER)
17694  return 9;
17695  else if (sip->flags & SIF_TRANSPORT)
17696  return 10;
17697  else if (sip->flags & SIF_BOMBER)
17698  return 11;
17699  else if (sip->flags & (SIF_FIGHTER | SIF_STEALTH))
17700  return 12;
17701  else if (sip->flags & SIF_ESCAPEPOD)
17702  return 13;
17703  else if (sip->flags & SIF_SENTRYGUN)
17704  return 14;
17705  else if (sip->flags & SIF_CARGO)
17706  return 15;
17707  else if (sip->flags & SIF_NAVBUOY)
17708  return 16;
17709 
17710  Warning(LOCATION, "Unknown priority for ship class '%s'!", sip->name);
17711  return 17 + ship_class;
17712 }
17713 
17714 // Goober5000
17715 int ship_class_compare(int ship_class_1, int ship_class_2)
17716 {
17717  // grab priorities
17718  int priority1 = ship_class_get_priority(ship_class_1);
17719  int priority2 = ship_class_get_priority(ship_class_2);
17720 
17721  // standard compare
17722  if (priority1 < priority2)
17723  return -1;
17724  else if (priority1 > priority2)
17725  return 1;
17726  else
17727  return 0;
17728 }
17729 
17734 int damage_type_get_idx(char *name)
17735 {
17736  //This should never be bigger than INT_MAX anyway
17737  for(int i = 0; i < (int)Damage_types.size(); i++)
17738  {
17739  if(!stricmp(name, Damage_types[i].name))
17740  return i;
17741  }
17742 
17743  return -1;
17744 }
17745 
17749 int damage_type_add(char *name)
17750 {
17751  int i = damage_type_get_idx(name);
17752  if(i != -1)
17753  return i;
17754 
17755  DamageTypeStruct dts;
17756 
17757  strncpy(dts.name, name, NAME_LENGTH-1);
17758 
17759  if(strlen(name) > NAME_LENGTH - 1)
17760  {
17761  Warning(LOCATION, "Damage type name '%s' is too long and has been truncated to '%s'", name, dts.name);
17762  }
17763 
17764  Damage_types.push_back(dts);
17765  return Damage_types.size()-1;
17766 }
17767 
17768 void ArmorDamageType::clear()
17769 {
17770  DamageTypeIndex = -1;
17771 
17772  Calculations.clear();
17773  Arguments.clear();
17774  altArguments.clear(); // Nuke: don't forget to delete it
17775 }
17776 
17777 //************
17778 // Wanderer - beam piercing type
17779 //************
17780 
17782  { "none", SADTF_PIERCING_NONE, 0},
17783  { "default", SADTF_PIERCING_DEFAULT, 0},
17784  { "retail", SADTF_PIERCING_RETAIL, 0},
17785 };
17786 
17788 
17789 int piercing_type_get(char *str)
17790 {
17791  int i;
17792  for(i = 0; i < Num_piercing_effect_types; i++)
17793  {
17794  if(!stricmp(PiercingTypes[i].name, str))
17795  return PiercingTypes[i].def;
17796  }
17797 
17798  // default to retail
17799  return SADTF_PIERCING_RETAIL;
17800 }
17801 
17802 // Nuke: handle difficulty scaling type
17804  { "first", ADT_DIFF_SCALE_FIRST, 0},
17805  { "last", ADT_DIFF_SCALE_LAST, 0},
17806  { "manual", ADT_DIFF_SCALE_MANUAL, 0},
17807 };
17808 
17810 
17812  int i;
17813  for(i = 0; i < Num_difficulty_scale_types; i++){
17814  if (!stricmp(DifficultyScaleTypes[i].name, str))
17815  return DifficultyScaleTypes[i].def;
17816  }
17817 
17818  // indicate error
17819  return ADT_DIFF_SCALE_BAD_VAL;
17820 }
17821 
17822 // Nuke: flag list for +constant: values
17824  { "base damage", AT_CONSTANT_BASE_DMG, 0},
17825  { "current damage", AT_CONSTANT_CURRENT_DMG, 0},
17826  { "difficulty factor", AT_CONSTANT_DIFF_FACTOR, 0},
17827  { "random", AT_CONSTANT_RANDOM, 0},
17828  { "pi", AT_CONSTANT_PI, 0},
17829 };
17830 
17832 
17834  int i;
17835  for (i = 0; i < Num_armor_type_constants; i++){
17836  if (!stricmp(ArmorTypeConstants[i].name, str))
17837  return ArmorTypeConstants[i].def;
17838  }
17839  // this shouldnt happen, but if it does theirs a define for that
17840  return AT_CONSTANT_BAD_VAL;
17841 }
17842 
17843 
17844 //**************************************************************
17845 //WMC - All the extra armor crap
17846 
17847 //****************************Calculation type addition
17848 //4 steps to add a new one
17849 
17850 //Armor types
17851 //STEP 1: Add a define
17852 #define AT_TYPE_ADDITIVE 0
17853 #define AT_TYPE_MULTIPLICATIVE 1
17854 #define AT_TYPE_EXPONENTIAL 2
17855 #define AT_TYPE_EXPONENTIAL_BASE 3
17856 #define AT_TYPE_CUTOFF 4
17857 #define AT_TYPE_REVERSE_CUTOFF 5
17858 #define AT_TYPE_INSTANT_CUTOFF 6
17859 #define AT_TYPE_INSTANT_REVERSE_CUTOFF 7
17860 // Added by Nuke
17861 #define AT_TYPE_CAP 8
17862 #define AT_TYPE_INSTANT_CAP 9
17863 #define AT_TYPE_SET 10
17864 #define AT_TYPE_STORE 11
17865 #define AT_TYPE_LOAD 12
17866 #define AT_TYPE_RANDOM 13
17867 
17868 // Nuke: this is the number of storage locations load/store calculations are allowed to use
17869 #define AT_NUM_STORAGE_LOCATIONS 8
17870 
17871 //STEP 2: Add the name string to the array
17872 char *TypeNames[] = {
17873  "additive",
17874  "multiplicative",
17875  "exponential",
17876  "exponential base",
17877  "cutoff",
17878  "reverse cutoff",
17879  "instant cutoff",
17880  "instant reverse cutoff",
17881  // Added by Nuke
17882  "cap",
17883  "instant cap",
17884  "set",
17885  "load",
17886  "store",
17887  "random"
17888 };
17889 
17890 //STEP 3: Add the default value
17892  0.0f, //additive
17893  1.0f, //multiplicatve
17894  1.0f, //exp
17895  1.0f, //exp base - Damage will always be one (No mathematical way to do better)
17896  0.0f, //cutoff
17897  0.0f, //reverse cutoff
17898  0.0f, //instant cutoff
17899  0.0f, //rev instant cutoff
17900  // Added by Nuke
17901  0.0f, // cap - caps are the same as reverse cutoffs, but sets damage to value instead of 0
17902  0.0f, // instant cap
17903  0.0f, // set - set the damage to value
17904  0.0f, // data storage index - load and store calculations allow you to dump and retrieve the current damage in one of a few memory locations (these only persist for the duration of the computation)
17905  0.0f, // data storage index
17906  0.0f // random min/max
17907 };
17908 
17909 const int Num_armor_calculation_types = sizeof(TypeNames)/sizeof(char*);
17910 
17911 int calculation_type_get(char *str)
17912 {
17913  for(int i = 0; i < Num_armor_calculation_types; i++)
17914  {
17915  if(!stricmp(TypeNames[i], str))
17916  return i;
17917  }
17918 
17919  return -1;
17920 }
17921 
17922 //STEP 4: Add the calculation to the switch statement.
17923 float ArmorType::GetDamage(float damage_applied, int in_damage_type_idx, float diff_dmg_scale)
17924 {
17925  // Nuke: If the weapon has no damage type, just return damage
17926  if (in_damage_type_idx < 0) {
17927  // multiply by difficulty scaler now, since it is no longer done where this is called
17928  return (damage_applied * diff_dmg_scale);
17929  }
17930 
17931  //Initialize vars
17932  uint i,num;
17933  ArmorDamageType *adtp = NULL;
17934 
17935  //Find the entry in the weapon that corresponds to the given weapon damage type
17936  num = DamageTypes.size();
17937  for(i = 0; i < num; i++)
17938  {
17939  if(DamageTypes[i].DamageTypeIndex == in_damage_type_idx)
17940  {
17941  adtp = &DamageTypes[i];
17942  break;
17943  }
17944  }
17945 
17946  //curr_arg is the current calculation type value
17947  float curr_arg;
17948 
17949  //Make sure that we _have_ an armor entry for this damage type
17950  if(adtp != NULL)
17951  {
17952  //How many calculations do we have to do?
17953  num = adtp->Calculations.size();
17954 
17955  // Used for instant cutoffs/cap, to instantly end the loop
17956  bool end_now = false;
17957  // used for load/store operations
17958  float storage[AT_NUM_STORAGE_LOCATIONS];
17959  int storage_idx;
17960  bool using_storage = false;
17961  // constant related stuff
17962  float constant_val;
17963  float base_damage;
17964  bool using_constant = false;
17965 
17966  // set storage locations to zero
17967  for (i = 0; i < AT_NUM_STORAGE_LOCATIONS; i++) {
17968  storage[i]=0.0f;
17969  }
17970 
17971  // check to see if we need to difficulty scale damage first
17972  if (adtp->difficulty_scale_type == ADT_DIFF_SCALE_FIRST) {
17973  damage_applied *= diff_dmg_scale;
17974  }
17975 
17976  // user may want to use base damage as a constant
17977  base_damage = damage_applied;
17978  // LOOP!
17979  for (i = 0; i < num; i++) {
17980  storage_idx = adtp->altArguments[i];
17981  //Set curr_arg
17982  // use storage index at +Stored Value:
17983  if ( (storage_idx >= 0) && (storage_idx < AT_NUM_STORAGE_LOCATIONS) ) {
17984  curr_arg = storage[storage_idx];
17985  using_storage = true;
17986  // using +value: (or error cases caught at parse, where this holda a 0.0f)
17987  } else if (storage_idx == AT_CONSTANT_NOT_USED) { // save time checking all possible constants when most of the time you will be using +value:
17988  curr_arg = adtp->Arguments[i];
17989  // maybe handle constants
17990  } else if (storage_idx == AT_CONSTANT_BASE_DMG) {
17991  curr_arg = base_damage;
17992  using_constant = true;
17993  } else if (storage_idx == AT_CONSTANT_CURRENT_DMG) {
17994  curr_arg = damage_applied;
17995  using_constant = true;
17996  } else if (storage_idx == AT_CONSTANT_DIFF_FACTOR) {
17997  curr_arg = diff_dmg_scale;
17998  using_constant = true;
17999  } else if (storage_idx == AT_CONSTANT_RANDOM) {
18000  constant_val = frand();
18001  curr_arg = constant_val;
18002  using_constant = true;
18003  } else if (storage_idx == AT_CONSTANT_PI) {
18004  constant_val = PI;
18005  curr_arg = constant_val;
18006  using_constant = true;
18007  } else { // fail
18008  constant_val = 0.0f;
18009  curr_arg = constant_val;
18010  }
18011  // new calcs go here
18012  switch(adtp->Calculations[i])
18013  {
18014  case AT_TYPE_ADDITIVE:
18015  damage_applied += curr_arg;
18016  break;
18018  damage_applied *= curr_arg;
18019  break;
18020  case AT_TYPE_EXPONENTIAL:
18021  damage_applied = powf(damage_applied, curr_arg);
18022  break;
18024  damage_applied = powf(curr_arg, damage_applied);
18025  break;
18026  case AT_TYPE_CUTOFF:
18027  if(damage_applied < curr_arg)
18028  damage_applied = 0;
18029  break;
18031  if(damage_applied > curr_arg)
18032  damage_applied = 0;
18033  break;
18035  if(damage_applied < curr_arg)
18036  {
18037  damage_applied = 0;
18038  end_now = true;
18039  }
18040  break;
18042  if(damage_applied > curr_arg)
18043  {
18044  damage_applied = 0;
18045  end_now = true;
18046  }
18047  break;
18048  case AT_TYPE_CAP:
18049  if (damage_applied > curr_arg)
18050  damage_applied = curr_arg;
18051  break;
18052  case AT_TYPE_INSTANT_CAP:
18053  if (damage_applied > curr_arg) {
18054  damage_applied = curr_arg;
18055  end_now = true;
18056  }
18057  break;
18058  case AT_TYPE_SET:
18059  damage_applied = curr_arg;
18060  break;
18061  case AT_TYPE_STORE:
18062  if (using_storage || using_constant) {
18063  Warning(LOCATION, "Cannot use +Stored Value: or +Constant: with +Store:, that would be bad. Skipping calculation.");
18064  } else {
18065  storage_idx = int(floorf(curr_arg));
18066  // Nuke: idiotproof this, no segfault 4 u
18067  if ( (storage_idx < 0) || (storage_idx >= AT_NUM_STORAGE_LOCATIONS) ) {
18068  Warning(LOCATION, "+Value: for +Store: calculation out of range. Should be between 0 and %i. Read: %i, Skipping calculation.", AT_NUM_STORAGE_LOCATIONS, storage_idx);
18069  storage_idx = 0;
18070  } else {
18071  storage[storage_idx] = damage_applied;
18072  }
18073  }
18074  break;
18075  case AT_TYPE_LOAD:
18076  if (using_storage || using_constant) {
18077  Warning(LOCATION, "Cannot use +Stored Value: or +Constant: with +Load:, that would be bad. Skipping calculation.");
18078  } else {
18079  storage_idx = int(floorf(curr_arg));
18080  // Nuke: idiotproof this, no segfault 4 u
18081  if ( (storage_idx < 0) || (storage_idx >= AT_NUM_STORAGE_LOCATIONS) ) {
18082  Warning(LOCATION, "+Value: for +Load: calculation out of range. Should be between 0 and %i. Read: %i, Skipping calculation.", AT_NUM_STORAGE_LOCATIONS, storage_idx);
18083  storage_idx = 0;
18084  } else {
18085  damage_applied = storage[storage_idx];
18086  }
18087  }
18088  break;
18089  case AT_TYPE_RANDOM: // Nuke: get a random number between damage_applied and +value:
18090  if (damage_applied > curr_arg) {
18091  damage_applied = frand_range( curr_arg, damage_applied );
18092  } else {
18093  damage_applied = frand_range( damage_applied, curr_arg );
18094  }
18095  break;
18096  }
18097 
18098  if(end_now)
18099  break;
18100  }
18101  // Nuke: check to see if we need to difficulty scale damage last
18102  if (adtp->difficulty_scale_type == ADT_DIFF_SCALE_LAST)
18103  damage_applied *= diff_dmg_scale;
18104 
18105  return damage_applied;
18106  }
18107  // fail return is fail
18108  return (damage_applied * diff_dmg_scale);
18109 }
18110 
18111 float ArmorType::GetShieldPiercePCT(int damage_type_idx)
18112 {
18113  if(damage_type_idx < 0)
18114  return 0.0f;
18115 
18116  //Initialize vars
18117  uint i,num;
18118  ArmorDamageType *adtp = NULL;
18119 
18120  //Find the entry in the weapon that corresponds to the given weapon damage type
18121  num = DamageTypes.size();
18122  for(i = 0; i < num; i++)
18123  {
18124  if(DamageTypes[i].DamageTypeIndex == damage_type_idx)
18125  {
18126  adtp = &DamageTypes[i];
18127  break;
18128  }
18129  }
18130  if(adtp != NULL){
18131  return adtp->shieldpierce_pct;
18132  }
18133 
18134  return 0.0f;
18135 }
18136 
18137 int ArmorType::GetPiercingType(int damage_type_idx)
18138 {
18139  if(damage_type_idx < 0)
18140  return 0;
18141 
18142  //Initialize vars
18143  uint i,num;
18144  ArmorDamageType *adtp = NULL;
18145 
18146  //Find the entry in the weapon that corresponds to the given weapon damage type
18147  num = DamageTypes.size();
18148  for(i = 0; i < num; i++)
18149  {
18150  if(DamageTypes[i].DamageTypeIndex == damage_type_idx)
18151  {
18152  adtp = &DamageTypes[i];
18153  break;
18154  }
18155  }
18156  if(adtp != NULL){
18157  return adtp->piercing_type;
18158  }
18159 
18160  return 0;
18161 }
18162 
18163 float ArmorType::GetPiercingLimit(int damage_type_idx)
18164 {
18165  if(damage_type_idx < 0)
18166  return 0.0f;
18167 
18168  //Initialize vars
18169  uint i,num;
18170  ArmorDamageType *adtp = NULL;
18171 
18172  //Find the entry in the weapon that corresponds to the given weapon damage type
18173  num = DamageTypes.size();
18174  for(i = 0; i < num; i++)
18175  {
18176  if(DamageTypes[i].DamageTypeIndex == damage_type_idx)
18177  {
18178  adtp = &DamageTypes[i];
18179  break;
18180  }
18181  }
18182  if(adtp != NULL){
18183  return adtp->piercing_start_pct;
18184  }
18185 
18186  return 0.0f;
18187 }
18188 
18189 //***********************************Member functions
18190 
18191 ArmorType::ArmorType(char* in_name)
18192 {
18193  uint len = strlen(in_name);
18194  if(len >= NAME_LENGTH) {
18195  Warning(LOCATION, "Armor name %s is %d characters too long, and will be truncated", in_name, len - NAME_LENGTH);
18196  }
18197 
18198  strncpy(Name, in_name, NAME_LENGTH-1);
18199 }
18200 
18202 {
18203  ArmorDamageType adt;
18204  char buf[NAME_LENGTH];
18205  float temp_float;
18206  int temp_int;
18207  int calc_type = -1;
18208 
18209  //Get the damage types
18210  required_string("$Damage Type:");
18211  do
18212  {
18213  //Get damage type name
18215 
18216  //Clear the struct and set the index
18217  adt.clear();
18218  adt.DamageTypeIndex = damage_type_add(buf);
18219  bool no_content = true;
18220 
18221  //Get calculation and argument
18222  while (optional_string("+Calculation:"))
18223  {
18224  //+Calculation
18226 
18227  calc_type = calculation_type_get(buf);
18228 
18229  //Make sure we have a valid calculation type
18230  if(calc_type == -1)
18231  {
18232  Warning(LOCATION, "Armor '%s': Armor calculation type '%s' is invalid, and has been skipped", Name, buf);
18233  // Nuke: guess we need to add this here too
18234  if (optional_string("+Stored Value:")) {
18235  stuff_int(&temp_int);
18236  } else if (optional_string("+Constant:")) {
18238  } else {
18239  required_string("+Value:");
18240  stuff_float(&temp_float);
18241  }
18242  }
18243  else
18244  {
18245  adt.Calculations.push_back(calc_type);
18246  // Nuke: maybe were using a stored location
18247  if (optional_string("+Stored Value:")) {
18248  stuff_int(&temp_int);
18249  // Nuke: idiot-proof
18250  if ( (temp_int < 0) || (temp_int >= AT_NUM_STORAGE_LOCATIONS) ) {
18251  Error(LOCATION, "+Stored Value: is out of range. Should be between 0 and %i. Read: %i, Using value 0.", AT_NUM_STORAGE_LOCATIONS-1, temp_int);
18252  temp_int = AT_CONSTANT_NOT_USED;
18253  }
18254  adt.altArguments.push_back(temp_int);
18255  adt.Arguments.push_back(0.0f); // this isnt used in this case, just take up space so the indices lign up, also a fallback value in case of bad altArguments
18256  } else if (optional_string("+Constant:")) { // use one of the pre-defined constants
18258  temp_int = armor_type_constants_get(buf);
18259  // Nuke: idiot proof some more
18260  if (temp_int == AT_CONSTANT_BAD_VAL) {
18261  Error(LOCATION, "Invalid +Constant: name, '%s'. Using value 0.", buf);
18262  temp_int = AT_CONSTANT_NOT_USED;
18263  }
18264  adt.altArguments.push_back(temp_int);
18265  adt.Arguments.push_back(0.0f); // this isnt used in this case, just take up space so the indices lign up, also a fallback value in case of bad altArguments
18266  } else { // Nuke: +Value, only required if storage location or constant is not used -nuke
18267  required_string("+Value:");
18268  stuff_float(&temp_float);
18269  adt.altArguments.push_back(AT_CONSTANT_NOT_USED); // set this to AT_CONSTANT_NOT_USED so we know to just use the value from adt.Arguments instead of constants/storage locations
18270  adt.Arguments.push_back(temp_float);
18271  }
18272  no_content = false;
18273  }
18274  }
18275 
18276  adt.shieldpierce_pct = 0.0f;
18277 
18278  if(optional_string("+Shield Piercing Percentage:")) {
18279  stuff_float(&temp_float);
18280  CLAMP(temp_float, 0.0f, 1.0f);
18281  adt.shieldpierce_pct = temp_float;
18282  no_content = false;
18283  }
18284 
18285  adt.piercing_start_pct = 0.1f;
18286  adt.piercing_type = -1;
18287 
18288  if(optional_string("+Weapon Piercing Effect Start Limit:")) {
18289  stuff_float(&temp_float);
18290  CLAMP(temp_float, 0.0f, 100.0f);
18291  temp_float /= 100.0f;
18292  adt.piercing_start_pct = temp_float;
18293  no_content = false;
18294  }
18295 
18296  if(optional_string("+Weapon Piercing Type:")) {
18298  adt.piercing_type = piercing_type_get(buf);
18299  no_content = false;
18300  }
18301 
18302  // Nuke: don't forget to init things
18303  adt.difficulty_scale_type = ADT_DIFF_SCALE_FIRST;
18304 
18305  if (optional_string("+Difficulty Scale Type:")) {
18307  temp_int = difficulty_scale_type_get(buf);
18308  if (temp_int == ADT_DIFF_SCALE_BAD_VAL) {
18309  Error(LOCATION, "Invalid +Difficulty Scale Type: name: '%s'. Reverting to default behavior.", buf);
18310  adt.difficulty_scale_type = ADT_DIFF_SCALE_FIRST;
18311  } else {
18312  adt.difficulty_scale_type = temp_int;
18313  }
18314  no_content = false;
18315  }
18316 
18317  //If we have calculations in this damage type, add it
18318  if(!no_content)
18319  {
18320  if(adt.Calculations.size() != adt.Arguments.size())
18321  {
18322  Warning(LOCATION, "Armor '%s', damage type " SIZE_T_ARG ": Armor has a different number of calculation types than arguments (" SIZE_T_ARG ", " SIZE_T_ARG ")",
18323  Name, DamageTypes.size(), adt.Calculations.size(), adt.Arguments.size());
18324  }
18325  DamageTypes.push_back(adt);
18326  }
18327  } while(optional_string("$Damage Type:"));
18328 }
18329 
18330 //********************************Global functions
18331 
18333 {
18334  int i, num;
18335  num = Armor_types.size();
18336  for(i = 0; i < num; i++)
18337  {
18338  if(Armor_types[i].IsName(name))
18339  return i;
18340  }
18341 
18342  //Didn't find anything.
18343  return -1;
18344 }
18345 
18347 {
18348  char name_buf[NAME_LENGTH];
18349  ArmorType tat("");
18350 
18351  required_string("$Name:");
18352  stuff_string(name_buf, F_NAME, NAME_LENGTH);
18353 
18354  tat = ArmorType(name_buf);
18355 
18356  //now parse the actual table (damage type/armor type pairs)
18357  tat.ParseData();
18358 
18359  //rest of the parse data
18360  if (optional_string("$Flags:"))
18361  parse_string_flag_list((int*)&tat.flags, Armor_flags, Num_armor_flags);
18362 
18363  //Add it to global armor types
18364  Armor_types.push_back(tat);
18365 }
18366 
18367 void armor_parse_table(const char *filename)
18368 {
18369  try
18370  {
18371  read_file_text(filename, CF_TYPE_TABLES);
18372  reset_parse();
18373 
18374  //Enumerate through all the armor types and add them.
18375  while (optional_string("#Armor Type")) {
18376  while (required_string_either("#End", "$Name:")) {
18377  parse_armor_type();
18378  continue;
18379  }
18380 
18381  required_string("#End");
18382  }
18383 
18384  // add tbl/tbm to multiplayer validation list
18385  fs2netd_add_table_validation(filename);
18386  }
18387  catch (const parse::ParseException& e)
18388  {
18389  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
18390  return;
18391  }
18392 }
18393 
18395 {
18396  if (!armor_inited) {
18397  armor_parse_table("armor.tbl");
18398 
18399  parse_modular_table(NOX("*-amr.tbm"), armor_parse_table);
18400 
18401  armor_inited = 1;
18402  }
18403 }
18404 
18405 //**************************************************************
18406 // AI targeting priority functions
18407 //**************************************************************
18409 {
18410  int i, j, num_strings;
18411  int n_entries = Ai_tp_list.size();
18412  SCP_vector <SCP_string> temp_strings;
18413 
18414  bool first_time = false;
18415  int already_exists = -1;
18416 
18417  if (n_entries == 0)
18418  first_time = true;
18419 
18420  required_string("$Name:");
18422 
18423  stuff_string(temp_priority.name, F_NAME, NAME_LENGTH);
18424  if (first_time == false) {
18425  for (i = 0; i < n_entries; i++) {
18426  if (!strnicmp(temp_priority.name, Ai_tp_list[i].name, NAME_LENGTH)) {
18427  already_exists = i;
18428  }
18429  }
18430  }
18431 
18432  if (optional_string("+Object Type:") ) {
18433  char tempname[NAME_LENGTH];
18434  stuff_string(tempname, F_NAME, NAME_LENGTH);
18435 
18436  for (j = 0; j < num_ai_tgt_objects; j++) {
18437  if ( !stricmp(ai_tgt_objects[j].name, tempname) ) {
18438  temp_priority.obj_type = ai_tgt_objects[j].def;
18439  }
18440  }
18441  }
18442 
18443  if (optional_string("+Weapon Class:") ) {
18444  temp_strings.clear();
18445  num_strings = stuff_string_list(temp_strings);
18446 
18447  for(i = 0; i < num_strings; i++) {
18448  for(j = 0; j < MAX_WEAPON_TYPES ; j++) {
18449  if ( !stricmp(Weapon_info[j].name, temp_strings[i].c_str()) ) {
18450  temp_priority.weapon_class.push_back(j);
18451  break;
18452  }
18453  }
18454  if (j == MAX_WEAPON_TYPES) {
18455  Warning(LOCATION, "Unidentified weapon class '%s' set for target priority group '%s'\n", temp_strings[i].c_str(), temp_priority.name);
18456  }
18457  }
18458  }
18459 
18460  if (optional_string("+Object Flags:") ) {
18461  temp_strings.clear();
18462  num_strings = stuff_string_list(temp_strings);
18463 
18464  for (i = 0; i < num_strings; i++) {
18465  for (j = 0; j < num_ai_tgt_obj_flags; j++) {
18466  if ( !stricmp(ai_tgt_obj_flags[j].name, temp_strings[i].c_str()) ) {
18467  temp_priority.obj_flags |= ai_tgt_obj_flags[j].def;
18468  break;
18469  }
18470  }
18471  if (j == num_ai_tgt_obj_flags) {
18472  Warning(LOCATION, "Unidentified object flag '%s' set for target priority group '%s'\n", temp_strings[i].c_str(), temp_priority.name);
18473  }
18474  }
18475  }
18476 
18477  if (optional_string("+Ship Class Flags:") ) {
18478  temp_strings.clear();
18479  num_strings = stuff_string_list(temp_strings);
18480 
18481  for (i = 0; i < num_strings; i++) {
18482  for (j = 0; j < num_ai_tgt_ship_flags; j++) {
18483  if ( !stricmp(ai_tgt_ship_flags[j].name, temp_strings[i].c_str()) ) {
18484  if (ai_tgt_ship_flags[j].var == 0) {
18485  temp_priority.sif_flags |= ai_tgt_ship_flags[j].def;
18486  } else {
18487  temp_priority.sif2_flags |= ai_tgt_ship_flags[j].def;
18488  }
18489  break;
18490  }
18491  }
18492  if (j == num_ai_tgt_ship_flags) {
18493  Warning(LOCATION, "Unidentified ship class flag '%s' set for target priority group '%s'\n", temp_strings[i].c_str(), temp_priority.name);
18494  }
18495  }
18496  }
18497 
18498  if (optional_string("+Weapon Class Flags:") ) {
18499  temp_strings.clear();
18500  num_strings = stuff_string_list(temp_strings);
18501 
18502  for (i = 0; i < num_strings; i++) {
18503  for (j = 0; j < num_ai_tgt_weapon_flags; j++) {
18504  if ( !stricmp(ai_tgt_weapon_flags[j].name, temp_strings[i].c_str()) ) {
18505  if (ai_tgt_weapon_flags[j].var == 0) {
18506  temp_priority.wif_flags |= ai_tgt_weapon_flags[j].def;
18507  } else {
18508  temp_priority.wif2_flags |= ai_tgt_weapon_flags[j].def;
18509  }
18510  break;
18511  }
18512  }
18513  if (j == num_ai_tgt_weapon_flags) {
18514  Warning(LOCATION, "Unidentified weapon class flag '%s' set for target priority group '%s'\n", temp_strings[i].c_str(), temp_priority.name);
18515  }
18516  }
18517  }
18518 
18519  temp_strings.clear();
18520 
18521  if (already_exists == -1) {
18522  Ai_tp_list.push_back(temp_priority);
18523  } else {
18524  Ai_tp_list[already_exists] = temp_priority;
18525  }
18526 }
18527 
18529 {
18530  ai_target_priority temp_priority;
18531 
18532  //initialize the entries
18533  temp_priority.obj_flags = 0;
18534  temp_priority.obj_type = -1;
18535  temp_priority.ship_class.clear();
18536  temp_priority.ship_type.clear();
18537  temp_priority.sif_flags = 0;
18538  temp_priority.sif2_flags = 0;
18539  temp_priority.weapon_class.clear();
18540  temp_priority.wif2_flags = 0;
18541  temp_priority.wif_flags = 0;
18542  temp_priority.name[0] = '\0';
18543 
18544  //return the initialized
18545  return temp_priority;
18546 }
18547 
18549 {
18550  char tempname[NAME_LENGTH];
18551  int i = 0;
18552  int j = 0;
18553  int k = 0;
18554 
18555  if (optional_string("$Name:")) {
18556  stuff_string(tempname, F_NAME, NAME_LENGTH);
18557 
18558  for(k = 0; k < MAX_WEAPON_TYPES ; k++) {
18559  if ( !stricmp(Weapon_info[k].name, tempname) ) {
18560  // found weapon, yay!
18561  // reset the list
18562 
18563  weapon_info *wip = &Weapon_info[k];
18564 
18565  wip->num_targeting_priorities = 0;
18566 
18567  if (optional_string("+Target Priority:")) {
18568  SCP_vector <SCP_string> tgt_priorities;
18569  int num_strings = stuff_string_list(tgt_priorities);
18570 
18571  if (num_strings > 32)
18572  num_strings = 32;
18573 
18574  int num_groups = Ai_tp_list.size();
18575 
18576  for(i = 0; i < num_strings; i++) {
18577  for(j = 0; j < num_groups; j++) {
18578  if ( !stricmp(Ai_tp_list[j].name, tgt_priorities[i].c_str())) {
18579  wip->targeting_priorities[i] = j;
18580  wip->num_targeting_priorities++;
18581  break;
18582  }
18583  }
18584  if(j == num_groups)
18585  Warning(LOCATION, "Unrecognized string '%s' found when setting weapon targeting priorities.\n", tgt_priorities[i].c_str());
18586  }
18587  }
18588  // no need to keep searching for more
18589  break;
18590  }
18591  }
18592  if(k == MAX_WEAPON_TYPES)
18593  Warning(LOCATION, "Unrecognized weapon '%s' found when setting weapon targeting priorities.\n", tempname);
18594  }
18595 }
18596 
18597 int ship_get_subobj_model_num(ship_info* sip, char* subobj_name)
18598 {
18599  for (int i = 0; i < sip->n_subsystems; i++) {
18600  if (!subsystem_stricmp(sip->subsystems[i].subobj_name, subobj_name))
18601  return sip->subsystems[i].subobj_num;
18602  }
18603 
18604  return -1;
18605 }
18606 
18608 {
18609  vm_vec_zero(&metadata.departure_rvec);
18610  metadata.arrive_speed_mult = FLT_MIN;
18611  metadata.depart_speed_mult = FLT_MIN;
18612 }
18613 
18615 {
18616  Assert( objp != NULL );
18617  Assert( id >= 0 && id < (int) Snds.size() );
18618 
18619  // ugh, it's possible that we're an observer at this point
18620  if (objp->type == OBJ_OBSERVER)
18621  return id;
18622 
18623  Assert( objp->type == OBJ_SHIP );
18624 
18625  ship *shipp = &Ships[objp->instance];
18626  ship_info *sip = &Ship_info[shipp->ship_info_index];
18627 
18628  SCP_map<GameSoundsIndex, int>::iterator element = sip->ship_sounds.find(id);
18629 
18630  if (element == sip->ship_sounds.end())
18631  return id;
18632  else
18633  return (*element).second;
18634 }
18635 
18637 {
18638  Assert( objp != NULL );
18639  Assert( id >= 0 && id < (int) Snds.size() );
18640 
18641  Assert( objp->type == OBJ_SHIP );
18642 
18643  ship *shipp = &Ships[objp->instance];
18644  ship_info *sip = &Ship_info[shipp->ship_info_index];
18645 
18646  SCP_map<GameSoundsIndex, int>::iterator element = sip->ship_sounds.find(id);
18647 
18648  if (element == sip->ship_sounds.end())
18649  return false;
18650  else
18651  return true;
18652 }
18653 
18664 int get_nearest_bbox_point(object *ship_objp, vec3d *start, vec3d *box_pt)
18665 {
18666  vec3d temp, rf_start;
18667  polymodel *pm;
18668  pm = model_get(Ship_info[Ships[ship_objp->instance].ship_info_index].model_num);
18669 
18670  // get start in ship rf
18671  vm_vec_sub(&temp, start, &ship_objp->pos);
18672  vm_vec_rotate(&rf_start, &temp, &ship_objp->orient);
18673 
18674  // find box_pt
18675  int inside = project_point_onto_bbox(&pm->mins, &pm->maxs, &rf_start, &temp);
18676 
18677  // get box_pt in world rf
18678  vm_vec_unrotate(box_pt, &temp, &ship_objp->orient);
18679  vm_vec_add2(box_pt, &ship_objp->pos);
18680 
18681  return inside;
18682 }
18683 
18685 {
18686  mst->length.xyz.z = obj->phys_info.forward_thrust;
18687  mst->length.xyz.x = obj->phys_info.side_thrust;
18688  mst->length.xyz.y = obj->phys_info.vert_thrust;
18689 
18690  // Maybe add noise to thruster geometry.
18691  if (!(sip->flags2 & SIF2_NO_THRUSTER_GEO_NOISE)) {
18692  mst->length.xyz.z *= (1.0f + frand()/5.0f - 0.1f);
18693  mst->length.xyz.y *= (1.0f + frand()/5.0f - 0.1f);
18694  mst->length.xyz.x *= (1.0f + frand()/5.0f - 0.1f);
18695  }
18696 
18697  CLAMP(mst->length.xyz.z, -1.0f, 1.0f);
18698  CLAMP(mst->length.xyz.y, -1.0f, 1.0f);
18699  CLAMP(mst->length.xyz.x, -1.0f, 1.0f);
18700 
18701  mst->primary_bitmap = shipp->thruster_bitmap;
18706 
18707  mst->use_ab = (obj->phys_info.flags & PF_AFTERBURNER_ON) || (obj->phys_info.flags & PF_BOOSTER_ON);
18709  mst->rotvel = Objects[shipp->objnum].phys_info.rotvel;
18710 
18717 
18718  mst->draw_distortion = sip->draw_distortion;
18719 }
18720 
18722 {
18723  int num = obj->instance;
18724  ship *shipp = &Ships[num];
18725  ship_info *sip = &Ship_info[Ships[num].ship_info_index];
18726 
18727  if ( Rendering_to_shadow_map ) return;
18728 
18729  physics_info *pi = &Objects[shipp->objnum].phys_info;
18730  float render_amount;
18731  fx_batcher.allocate(sip->num_maneuvering); //Act as if all thrusters are going.
18732 
18733  for ( int i = 0; i < sip->num_maneuvering; i++ ) {
18734  man_thruster *mtp = &sip->maneuvering[i];
18735 
18736  render_amount = 0.0f;
18737 
18738  //WMC - get us a steady value
18739  vec3d des_vel;
18740  vm_vec_rotate(&des_vel, &pi->desired_vel, &obj->orient);
18741 
18742  if(pi->desired_rotvel.xyz.x < 0 && (mtp->use_flags & MT_PITCH_UP)) {
18743  render_amount = fl_abs(pi->desired_rotvel.xyz.x) / pi->max_rotvel.xyz.x;
18744  } else if(pi->desired_rotvel.xyz.x > 0 && (mtp->use_flags & MT_PITCH_DOWN)) {
18745  render_amount = fl_abs(pi->desired_rotvel.xyz.x) / pi->max_rotvel.xyz.x;
18746  } else if(pi->desired_rotvel.xyz.y < 0 && (mtp->use_flags & MT_ROLL_RIGHT)) {
18747  render_amount = fl_abs(pi->desired_rotvel.xyz.y) / pi->max_rotvel.xyz.y;
18748  } else if(pi->desired_rotvel.xyz.y > 0 && (mtp->use_flags & MT_ROLL_LEFT)) {
18749  render_amount = fl_abs(pi->desired_rotvel.xyz.y) / pi->max_rotvel.xyz.y;
18750  } else if(pi->desired_rotvel.xyz.z < 0 && (mtp->use_flags & MT_BANK_RIGHT)) {
18751  render_amount = fl_abs(pi->desired_rotvel.xyz.z) / pi->max_rotvel.xyz.z;
18752  } else if(pi->desired_rotvel.xyz.z > 0 && (mtp->use_flags & MT_BANK_LEFT)) {
18753  render_amount = fl_abs(pi->desired_rotvel.xyz.z) / pi->max_rotvel.xyz.z;
18754  }
18755 
18756  //Backslash - show thrusters according to thrust amount, not speed
18757  if(pi->side_thrust > 0 && (mtp->use_flags & MT_SLIDE_RIGHT)) {
18758  render_amount = pi->side_thrust;
18759  } else if(pi->side_thrust < 0 && (mtp->use_flags & MT_SLIDE_LEFT)) {
18760  render_amount = -pi->side_thrust;
18761  } else if(pi->vert_thrust > 0 && (mtp->use_flags & MT_SLIDE_UP)) {
18762  render_amount = pi->vert_thrust;
18763  } else if(pi->vert_thrust < 0 && (mtp->use_flags & MT_SLIDE_DOWN)) {
18764  render_amount = -pi->vert_thrust;
18765  } else if(pi->forward_thrust > 0 && (mtp->use_flags & MT_FORWARD)) {
18766  render_amount = pi->forward_thrust;
18767  } else if(pi->forward_thrust < 0 && (mtp->use_flags & MT_REVERSE)) {
18768  render_amount = -pi->forward_thrust;
18769  }
18770 
18771  //Don't render small faraway thrusters (more than 10k * radius away)
18772  if ( vm_vec_dist(&Eye_position, &obj->pos) > (10000.0f * mtp->radius) ) {
18773  render_amount = 0.0f;
18774  }
18775 
18776  if ( render_amount > 0.0f ) {
18777  //Handle sounds and stuff
18778  if ( shipp->thrusters_start[i] <= 0 ) {
18779  shipp->thrusters_start[i] = timestamp();
18780  if(mtp->start_snd >= 0)
18781  snd_play_3d( &Snds[mtp->start_snd], &mtp->pos, &Eye_position, 0.0f, &obj->phys_info.vel );
18782  }
18783 
18784  //Only assign looping sound if
18785  //it is specified
18786  //it isn't assigned already
18787  //start sound doesn't exist or has finished
18789  if(mtp->loop_snd >= 0
18790  && shipp->thrusters_sounds[i] < 0
18791  && (mtp->start_snd < 0 || (snd_get_duration(mtp->start_snd) < timestamp() - shipp->thrusters_start[i]))
18792  )
18793  {
18794  shipp->thrusters_sounds[i] = obj_snd_assign(OBJ_INDEX(obj), mtp->loop_snd, &mtp->pos, 1);
18795  }
18796  }
18797 
18798  //Draw graphics
18799  //Skip invalid ones
18800  if ( mtp->tex_id >= 0 ) {
18801  float rad = mtp->radius;
18802  if(rad <= 0.0f)
18803  rad = 1.0f;
18804 
18805  float len = mtp->length;
18806  if(len == 0.0f)
18807  len = rad;
18808 
18809  vec3d start, tmpend, end;
18810  //Start
18811  vm_vec_unrotate(&start, &mtp->pos, &obj->orient);
18812  vm_vec_add2(&start, &obj->pos);
18813 
18814  //End
18815  vm_vec_scale_add(&tmpend, &mtp->pos, &mtp->norm, len * render_amount);
18816  vm_vec_unrotate(&end, &tmpend, &obj->orient);
18817  vm_vec_add2(&end, &obj->pos);
18818 
18819  //Draw
18820  fx_batcher.draw_beam(&start, &end, rad, 1.0f);
18821 
18822  int bmap_frame = mtp->tex_id;
18823  if(mtp->tex_nframes > 0)
18824  bmap_frame += (int)(((float)(timestamp() - shipp->thrusters_start[i]) / 1000.0f) * (float)mtp->tex_fps) % mtp->tex_nframes;
18825 
18826  man_thruster_renderer *mtr = man_thruster_get_slot(bmap_frame);
18827  mtr->man_batcher.add_allocate(1);
18828  mtr->man_batcher.draw_beam(&start, &end, rad, 1.0f);
18829  }
18830  } else if ( shipp->thrusters_start[i] > 0 ) {
18831  // We've stopped firing a thruster
18832 
18833  shipp->thrusters_start[i] = 0;
18834  if(shipp->thrusters_sounds[i] >= 0)
18835  {
18836  obj_snd_delete(OBJ_INDEX(obj), shipp->thrusters_sounds[i]);
18837  shipp->thrusters_sounds[i] = -1;
18838  }
18839 
18840  if ( mtp->stop_snd >= 0 ) {
18841  //Get world pos
18842  vec3d start;
18843  vm_vec_unrotate(&start, &mtp->pos, &obj->orient);
18844  vm_vec_add2(&start, &obj->pos);
18845 
18846  snd_play_3d( &Snds[mtp->stop_snd], &mtp->pos, &Eye_position, 0.0f, &obj->phys_info.vel );
18847  }
18848  }
18849  }
18850 }
18851 
18852 void ship_render_weapon_models(model_render_params *ship_render_info, draw_list *scene, object *obj, int render_flags)
18853 {
18854  int num = obj->instance;
18855  ship *shipp = &Ships[num];
18856  ship_info *sip = &Ship_info[Ships[num].ship_info_index];
18857 
18858  if ( !(sip->flags2 & SIF2_DRAW_WEAPON_MODELS) || (shipp->flags2 & SF2_CLOAKED) ) {
18859  return;
18860  }
18861 
18862  int i,k;
18863  ship_weapon *swp = &shipp->weapons;
18864 
18865  scene->push_transform(&obj->pos, &obj->orient);
18866 
18867  model_render_params render_info = *ship_render_info;
18868 
18869  render_flags &= ~MR_SHOW_THRUSTERS;
18870 
18871  //primary weapons
18872  for ( i = 0; i < swp->num_primary_banks; i++ ) {
18873  if ( Weapon_info[swp->primary_bank_weapons[i]].external_model_num == -1 || !sip->draw_primary_models[i] ) {
18874  continue;
18875  }
18876 
18877  w_bank *bank = &model_get(sip->model_num)->gun_banks[i];
18878  for ( k = 0; k < bank->num_slots; k++ ) {
18880 
18882 
18883  render_info.set_flags(render_flags);
18884 
18886 
18887  pm->gun_submodel_rotation = 0.0f;
18888  }
18889  }
18890 
18891  //secondary weapons
18892  int num_secondaries_rendered = 0;
18893  vec3d secondary_weapon_pos;
18894  w_bank* bank;
18895 
18896  for (i = 0; i < swp->num_secondary_banks; i++) {
18898  continue;
18899  }
18900 
18901  bank = &(model_get(sip->model_num))->missile_banks[i];
18902 
18904  for(k = 0; k < bank->num_slots; k++) {
18905  render_info.set_flags(render_flags);
18906 
18908  }
18909  } else {
18910  num_secondaries_rendered = 0;
18911 
18912  for ( k = 0; k < bank->num_slots; k++ ) {
18913  secondary_weapon_pos = bank->pnt[k];
18914 
18915  if ( num_secondaries_rendered >= shipp->weapons.secondary_bank_ammo[i] ) {
18916  break;
18917  }
18918 
18919  if ( shipp->secondary_point_reload_pct[i][k] <= 0.0 ) {
18920  continue;
18921  }
18922 
18923  num_secondaries_rendered++;
18924 
18926 
18927  render_info.set_flags(render_flags);
18928 
18929  model_render_queue(&render_info, scene, Weapon_info[swp->secondary_bank_weapons[i]].external_model_num, &vmd_identity_matrix, &secondary_weapon_pos);
18930  }
18931  }
18932  }
18933 
18934  scene->pop_transform();
18935 }
18936 
18938 {
18939  if ( Rendering_to_shadow_map ) {
18940  return -1;
18941  }
18942 
18943  if ( Game_mode & GM_MULTIPLAYER ) {
18944  // if its any player's object
18945  int np_index = multi_find_player_by_object( obj );
18946  if ( (np_index >= 0) && (np_index < MAX_PLAYERS) && MULTI_CONNECTED(Net_players[np_index]) && (Net_players[np_index].m_player != NULL) ) {
18947  return Net_players[np_index].m_player->insignia_texture;
18948  }
18949  }
18950 
18951  // in single player, we want to render model insignias on all ships in alpha beta and gamma
18952  // Goober5000 - and also on wings that have their logos set
18953 
18954  // if its an object in my squadron
18955  if ( ship_in_my_squadron(shipp) ) {
18956  return Player->insignia_texture;
18957  }
18958 
18959  // maybe it has a wing squad logo - Goober5000
18960  if ( shipp->wingnum >= 0 ) {
18961  // don't override the player's wing
18962  if ( shipp->wingnum != Player_ship->wingnum ) {
18963  // if we have a logo texture
18964  if ( Wings[shipp->wingnum].wing_insignia_texture >= 0 ) {
18965  return Wings[shipp->wingnum].wing_insignia_texture;
18966  }
18967  }
18968  }
18969 
18970  return -1;
18971 }
18972 
18974 {
18975  if ( !shipp->shader_effect_active || !is_minimum_GLSL_version() || Rendering_to_shadow_map ) {
18976  return;
18977  }
18978 
18979  float timer;
18980 
18981  ship_effect* sep = &Ship_effects[shipp->shader_effect_num];
18982 
18983  if ( sep->invert_timer ) {
18984  timer = 1.0f - ((timer_get_milliseconds() - shipp->shader_effect_start_time) / (float)shipp->shader_effect_duration);
18985  timer = MAX(timer,0.0f);
18986  } else {
18987  timer = ((timer_get_milliseconds() - shipp->shader_effect_start_time) / (float)shipp->shader_effect_duration);
18988  }
18989 
18990  render_info->set_animated_effect(sep->shader_effect, timer);
18991 
18993  shipp->flags2 |= SF2_CLOAKED;
18994  shipp->shader_effect_active = false;
18995  } else {
18996  shipp->flags2 &= ~SF2_CLOAKED;
18998  shipp->shader_effect_active = false;
18999  }
19000  }
19001 }
19002 
19003 void ship_render(object* obj, draw_list* scene)
19004 {
19005  int num = obj->instance;
19006  ship *shipp = &Ships[num];
19007  ship_info *sip = &Ship_info[Ships[num].ship_info_index];
19008  ship *warp_shipp = NULL;
19009  bool is_first_stage_arrival = false;
19010  bool show_thrusters = ((shipp->flags2 & SF2_NO_THRUSTERS) == 0) && !Rendering_to_shadow_map;
19011  dock_function_info dfi;
19012 
19013  MONITOR_INC( NumShipsRend, 1 );
19014 
19015  // look for a warping ship, whether for me or for anybody I'm docked with
19017 
19018  // if any docked objects are set to stage 1 arrival then set bool
19019  if ( dfi.maintained_variables.bool_value ) {
19020  warp_shipp = &Ships[dfi.maintained_variables.objp_value->instance];
19021 
19022  is_first_stage_arrival = ((warp_shipp->flags & SF_ARRIVING_STAGE_1) > 0);
19023 
19024  // This is a hack to make ships using the hyperspace warpin type to
19025  // render even in stage 1, which is used for collision detection
19026  // purposes -zookeeper
19027  if ( Ship_info[warp_shipp->ship_info_index].warpin_type == WT_HYPERSPACE ) {
19028  warp_shipp = NULL;
19029  is_first_stage_arrival = false;
19030  }
19031  }
19032 
19033  if ( is_first_stage_arrival ) {
19034  //WMC - Draw animated warp effect (ie BSG thingy)
19035  //WMC - based on Bobb's secondary thruster stuff
19036  //which was in turn based on the beam code.
19037  //I'm gonna need some serious acid to neutralize this base.
19038  if(shipp->flags & SF_ARRIVING) {
19039  shipp->warpin_effect->warpShipRender();
19040  } else if(shipp->flags & SF_DEPART_WARP) {
19041  shipp->warpout_effect->warpShipRender();
19042  }
19043 
19044  return;
19045  }
19046 
19047  if ( obj == Viewer_obj && !Rendering_to_shadow_map ) {
19048  if (!(Viewer_mode & VM_TOPDOWN))
19049  {
19050  return;
19051  }
19052  }
19053 
19055 
19056  // Only render electrical arcs if within 500m of the eye (for a 10m piece)
19057  if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f && !Rendering_to_shadow_map ) {
19058  for ( int i = 0; i < MAX_SHIP_ARCS; i++ ) {
19059  if ( timestamp_valid(shipp->arc_timestamp[i]) ) {
19060  model_add_arc(sip->model_num, -1, &shipp->arc_pts[i][0], &shipp->arc_pts[i][1], shipp->arc_type[i]);
19061  }
19062  }
19063  }
19064 
19065  uint render_flags = MR_NORMAL;
19066 
19067  if ( shipp->large_ship_blowup_index >= 0 ) {
19068  shipfx_large_blowup_queue_render(scene, shipp);
19069 
19070  //WMC - Draw animated warp effect (ie BSG thingy)
19071  //WMC - based on Bobb's secondary thruster stuff
19072  //which was in turn based on the beam code.
19073  //I'm gonna need some serious acid to neutralize this base.
19074  if(shipp->flags & SF_ARRIVING) {
19075  shipp->warpin_effect->warpShipRender();
19076  } else if(shipp->flags & SF_DEPART_WARP) {
19077  shipp->warpout_effect->warpShipRender();
19078  }
19079 
19080  return;
19081  }
19082 
19084 
19085  model_render_params render_info;
19086 
19087  if ( !(shipp->flags & SF_DISABLED) && !ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) && show_thrusters) {
19088  mst_info mst;
19089 
19090  ship_set_thruster_info(&mst, obj, shipp, sip);
19091 
19092  render_info.set_thruster_info(mst);
19093 
19094  render_flags |= MR_SHOW_THRUSTERS;
19095  }
19096 
19097  // Warp_shipp points to the ship that is going through a
19098  // warp... either this ship or the ship it is docked with.
19099  if ( warp_shipp != NULL ) {
19100  if ( warp_shipp->flags & SF_ARRIVING ) {
19101  warp_shipp->warpin_effect->warpShipClip(&render_info);
19102  } else if ( warp_shipp->flags & SF_DEPART_WARP ) {
19103  warp_shipp->warpout_effect->warpShipClip(&render_info);
19104  }
19105  }
19106 
19107  // maybe set squad logo bitmap
19108  render_info.set_insignia_bitmap(ship_render_get_insignia(obj, shipp));
19109 
19110  // Valathil - maybe do a scripting hook here to do some scriptable effects?
19111  ship_render_set_animated_effect(&render_info, shipp, &render_flags);
19112 
19113  if ( sip->uses_team_colors ) {
19114  team_color model_team_color;
19115 
19116  bool team_color_set = model_get_team_color(&model_team_color, shipp->team_name, shipp->secondary_team_name, shipp->team_change_timestamp, shipp->team_change_time);
19117 
19118  if ( team_color_set ) {
19119  render_info.set_team_color(model_team_color);
19120  }
19121  }
19122 
19123  if ( sip->flags2 & SIF2_NO_LIGHTING ) {
19124  render_flags |= MR_NO_LIGHTING;
19125  }
19126 
19127  if ( Rendering_to_shadow_map ) {
19128  render_flags = MR_NO_TEXTURING | MR_NO_LIGHTING;
19129  }
19130 
19131  if (shipp->flags2 & SF2_GLOWMAPS_DISABLED) {
19132  render_flags |= MR_NO_GLOWMAPS;
19133  }
19134 
19135  render_info.set_flags(render_flags);
19136 
19137  //draw weapon models
19138  ship_render_weapon_models(&render_info, scene, obj, render_flags);
19139 
19140  render_info.set_object_number(OBJ_INDEX(obj));
19142 
19143  // small ships
19144  if ( !( shipp->flags2 & SF2_CLOAKED ) ) {
19145  if ( ( The_mission.flags & MISSION_FLAG_FULLNEB ) && ( sip->flags & SIF_SMALL_SHIP ) ) {
19146  // force detail levels
19147  float fog_val = neb2_get_fog_intensity(obj);
19148  if ( fog_val >= 0.6f ) {
19149  render_info.set_detail_level_lock(2);
19150  }
19151  }
19152 
19153  model_render_queue(&render_info, scene, sip->model_num, &obj->orient, &obj->pos);
19154  }
19155 
19156  if (shipp->shield_hits && !Rendering_to_shadow_map) {
19158  shipp->shield_hits = 0;
19159  }
19160 
19161  //WMC - Draw animated warp effect (ie BSG thingy)
19162  //WMC - based on Bobb's secondary thruster stuff
19163  //which was in turn based on the beam code.
19164  //I'm gonna need some serious acid to neutralize this base.
19165  if(shipp->flags & SF_ARRIVING) {
19166  shipp->warpin_effect->warpShipRender();
19167  } else if(shipp->flags & SF_DEPART_WARP) {
19168  shipp->warpout_effect->warpShipRender();
19169  }
19170 }
void ct_ship_process(ship *shipp)
#define __UNUSED
Definition: clang.h:23
#define SF2_TOGGLE_SUBSYSTEM_SCANNING
Definition: ship.h:490
#define SSF_ROTATES
Definition: ship.h:292
void model_update_instance(int model_instance_num, int sub_model_num, submodel_instance_info *sii, int flags)
Definition: modelread.cpp:4796
void mc_info_init(mc_info *mc)
Definition: model.h:1138
#define BMP_FLAG_RENDER_TARGET_DYNAMIC
Texture is a dynamic type (animation)
Definition: bmpman.h:67
const int Num_player_orders
Definition: ship.cpp:228
float big_exp_visual_rad
Definition: ship.h:1239
void ship_wing_cleanup(int shipnum, wing *wingp)
Definition: ship.cpp:7640
#define AIM_FLAG_AUTOAIM
Definition: ship.h:961
bool uses_team_colors
Definition: ship.h:1365
const int Num_subsystem_flags
Definition: ship.cpp:265
#define MAX_SLOTS
Definition: model.h:430
#define SSF_MISSILES_IGNORE_IF_DEAD
Definition: ship.h:291
#define WIF_EMP
Definition: weapon.h:73
int ask_help_count
Definition: player.h:156
float max_rear_vel
Definition: physics.h:53
float lethality
Definition: ai.h:546
#define SUBSYSTEM_RADAR
Definition: model.h:55
char fg_filename[MAX_FILENAME_LEN]
Definition: ship.h:272
#define SHIP_VANISHED
Definition: ship.h:1622
float debris_max_rotspeed
Definition: ship.h:1262
int num_swarm_missiles_to_fire
Definition: ship.h:668
#define AWACS_WARN_NONE
Definition: ship.h:529
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
void parse_shiptype_tbl(const char *filename)
Definition: ship.cpp:4816
int model_collide(mc_info *mc_info_obj)
void armor_parse_table(const char *filename)
Definition: ship.cpp:18367
void radar_plot_object(object *objp)
Definition: radarsetup.cpp:146
int oo_interp_count[MAX_SHIPS]
Definition: multi_obj.cpp:45
#define MESSAGE_PRIORITY_NORMAL
size_t wp_index
Definition: ai.h:373
void hud_set_wingman_status_none(int wing_index, int wing_pos)
int turret_enemy_sig
Definition: ship.h:338
#define WT_SWEEPER
Definition: ship.h:1110
#define REARM_REPAIR_ME_ITEM
Definition: hudsquadmsg.h:49
bool model_anim_start_type(ship_subsys *pss, int animation_type, int subtype, int direction, bool instant)
Definition: modelanim.cpp:566
int muzzle_flash
Definition: weapon.h:463
char Starting_wing_names[MAX_STARTING_WINGS][NAME_LENGTH]
Definition: ship.cpp:139
float cur_glide_cap
Definition: physics.h:90
#define SHIP_GET_UNSILENCED
Definition: ship.h:1789
bsp_info * submodel
Definition: model.h:764
void ship_maybe_warn_player(ship *enemy_sp, float dist)
Definition: ship.cpp:15457
int shader_effect_duration
Definition: ship.h:767
#define MESSAGE_TIME_IMMEDIATE
int flags
Definition: ship.h:150
#define WIF_NO_DUMBFIRE
Definition: weapon.h:65
#define WEAPON_LIST_TYPE
Definition: parselo.h:51
int thruster_tertiary_glow_bitmap
Definition: ship.h:686
int timestamp(int delta_ms)
Definition: timer.cpp:226
int stamp
Definition: trails.h:29
#define SIF2_SURFACE_SHIELDS
Definition: ship.h:922
int n_paths
Definition: model.h:783
#define CYCLE_PRIMARY_PREV
Definition: ship.h:63
wing Wings[MAX_WINGS]
Definition: ship.cpp:128
int offset[2]
Definition: ship.h:262
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
#define AIF_REPAIRING
Definition: ai.h:41
int ship_info_lookup(const char *token)
Definition: ship.cpp:12772
void wing_bash_ship_name(char *ship_name, const char *wing_name, int index)
Definition: ship.cpp:12686
int launch_snd
Definition: weapon.h:414
#define MY_NET_PLAYER_NUM
Definition: multi.h:127
fix time_subsys_cargo_revealed
Definition: ship.h:374
void parse_ship_sound(char *name, GameSoundsIndex id, ship_info *sip)
Definition: ship.cpp:1843
bool use_newtonian_damp
Definition: ship.h:1410
#define SUBSYSTEM_NAVIGATION
Definition: model.h:56
int thruster_secondary_glow_bitmap
Definition: ship.h:685
void ship_obj_list_init()
Definition: ship.cpp:451
int Framecount
Definition: systemvars.cpp:22
#define MAX_TFP
Definition: model.h:69
void obj_set_flags(object *obj, uint new_flags)
Definition: object.cpp:1000
int i
Definition: multi_pxo.cpp:466
#define STI_AI_TURRETS_ATTACK
Definition: ship.h:1008
thrust_pair_bitmap thruster_secondary_glow_info
Definition: ship.h:1382
float get_max_shield_quad(object *objp)
Definition: object.cpp:260
fix Missiontime
Definition: systemvars.cpp:19
char wing_status_wing_pos
Definition: ship.h:553
#define WIF_BOMBER_PLUS
Definition: weapon.h:69
#define MSS_FLAG_NO_SS_TARGETING
Definition: model.h:122
#define STI_HUD_SHOW_ATTACK_DIRECTION
Definition: ship.h:993
vec3d deathroll_rotvel
Definition: ship.h:573
#define TRIGGER_TYPE_DOCKING_STAGE_2
Definition: modelanim.h:29
#define vm_free(ptr)
Definition: pstypes.h:548
SCP_vector< HudGauge * > hud_gauges
Definition: ship.h:1447
thrust_pair flames
Definition: species_defs.h:35
ubyte wash_killed
Definition: ship.h:548
fix time
Definition: ship.h:859
ubyte pre_death_explosion_happened
Definition: ship.h:547
#define AI_GOAL_UNDOCK
Definition: aigoals.h:36
int * turret_ids
Definition: model.h:410
float minimum_convergence_distance
Definition: ship.h:1436
#define STI_SHIP_WARP_PUSHES
Definition: ship.h:997
int n_textures
Definition: model.h:761
float aggregate_max_hits
Definition: ship.h:418
float p
Definition: pstypes.h:111
fix team_change_timestamp
Definition: ship.h:814
geometry_batcher fx_batcher
Definition: ship.cpp:6731
#define ENGINE_MIN_STR
Definition: subsysdamage.h:20
int foreground
Definition: ship.h:260
#define SF2_CLOAKED
Definition: ship.h:504
ubyte shield_icon_index
Definition: ship.h:1337
int stuff_string_list(SCP_vector< SCP_string > &slp)
Definition: parselo.cpp:2689
model_subsystem * system_info
Definition: ship.h:314
#define gr_clear
Definition: 2d.h:749
#define Verify(x)
Definition: pstypes.h:272
int Num_ai_goals
Definition: aigoals.cpp:90
weapon Weapons[MAX_WEAPONS]
Definition: weapons.cpp:78
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:103
#define MESSAGE_AWACS_25
SCP_vector< ArmorType > Armor_types
Definition: ship.cpp:170
#define STI_AI_PROTECTED_ON_CRIPPLE
Definition: ship.h:1010
int rotation_snd
Definition: model.h:204
#define SIF2_SHOW_SHIP_MODEL
Definition: ship.h:921
void ship_init_thrusters()
Definition: ship.cpp:8530
#define TM_BASE_TYPE
Definition: model.h:657
void hud_gauge_popup_start(int gauge_index, int time)
Start a gauge to pop-up.
Definition: hud.cpp:3036
int last_primary_fire_sound_stamp[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:118
#define SIF_NO_COLLIDE
Definition: ship.h:874
#define SF_DEPART_WARP
Definition: ship.h:449
float tag_total
Definition: ship.h:724
#define AIM_FLAG_AUTO_CONVERGENCE
Definition: ship.h:962
int ai_passive_dock
Definition: ship.h:1039
#define SSF_FOV_REQUIRED
Definition: ship.h:285
LARGE engine ambient.
Definition: gamesnd.h:139
vec3d turret_norm
Definition: model.h:186
#define MIN(a, b)
Definition: pstypes.h:296
Fully visible on the radar.
Definition: radarsetup.h:90
float Proj_fov
Definition: 3dsetup.cpp:31
#define AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP
Definition: ai_profiles.h:30
tried to fire lasers when not enough energy left
Definition: gamesnd.h:95
#define AT_CONSTANT_BASE_DMG
Definition: ship.h:181
#define MAX_SHIP_PRIMARY_BANKS
Definition: globals.h:62
#define SIF2_NO_PAIN_FLASH
Definition: ship.h:929
vec3d * pos
Definition: model.h:1113
EModelAnimationPosition turret_animation_position
Definition: ship.h:351
float fof_spread_rate
Definition: weapon.h:495
#define SSSF_ROTATE
Definition: ship.h:304
int cmeasure_fire_stamp
Definition: ship.h:654
int ts_index
Definition: ship.h:704
float max_weapon_reserve
Definition: ship.h:1276
float warpout_speed
Definition: ship.h:1220
geometry_batcher man_batcher
Definition: ship.h:1069
ai_info * Player_ai
Definition: ai.cpp:24
int lightning_stamp
Definition: ship.h:734
SCP_string secondary_team_name
Definition: ship.h:813
generic_bitmap normal
Definition: species_defs.h:24
float reorient_max_angle
Definition: ship.h:1141
int team
Definition: ship.h:606
int previous_primary_bank
Definition: ship.h:110
int Cmdline_old_collision_sys
Definition: cmdline.cpp:489
void ship_assign_sound_all()
Definition: ship.cpp:14263
#define WF_IGNORE_COUNT
Definition: ship.h:1503
void model_find_world_point(vec3d *outpnt, vec3d *mpnt, int model_num, int submodel_num, const matrix *objorient, const vec3d *objpos)
Definition: modelread.cpp:4099
int warpout_type
Definition: ship.h:1223
#define NUM_SUB_EXPL_HANDLES
Definition: ship.h:518
char * ship_subsys_get_name(ship_subsys *ss)
Definition: ship.cpp:15001
const int num_ai_tgt_ship_flags
Definition: ship.cpp:352
#define MSS_FLAG_ALLOW_LANDING
Definition: model.h:126
int ship_obj_list_add(int objnum)
Definition: ship.cpp:465
float debris_max_speed
Definition: ship.h:1260
SCP_vector< man_thruster_renderer > Man_thrusters
Definition: ship.cpp:6661
#define AIS_DOCK_4
Definition: ai.h:273
float vm_vec_mag_quick(const vec3d *v)
Definition: vecmat.cpp:371
int ship_engine_ok_to_warp(ship *sp)
Definition: ship.cpp:14783
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:1299
int flags
Definition: player.h:104
matrix * vm_matrix_x_matrix(matrix *dest, const matrix *src0, const matrix *src1)
Definition: vecmat.cpp:1006
float max_overclocked_speed
Definition: ship.h:1275
#define INTIAL_WEAPON_RECHARGE_INDEX
Definition: hudets.h:21
void ship_init_afterburners(ship *shipp)
Definition: ship.cpp:9624
#define AT_TYPE_STORE
Definition: ship.cpp:17864
#define AT_TYPE_INSTANT_CUTOFF
Definition: ship.cpp:17858
int beam_info_index
Definition: beam.h:57
thrust_pair_bitmap thruster_tertiary_glow_info
Definition: ship.h:1383
int thrusters_sounds[MAX_MAN_THRUSTERS]
Definition: ship.h:789
char name[NAME_LENGTH]
Definition: weapon.h:322
int ai_class
Definition: ship.h:148
bool draw_primary_models[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:1302
#define SSF_FOV_EDGE_CHECK
Definition: ship.h:286
void mission_log_add_entry(int type, char *pname, char *sname, int info_index)
Definition: missionlog.cpp:184
#define MR_NORMAL
Definition: model.h:858
vec3d vmd_z_vector
Definition: vecmat.cpp:27
np_update np_updates[MAX_PLAYERS]
Definition: ship.h:731
float awacs_intensity
Definition: ship.h:359
float slide_decel
Definition: ship.h:1204
vec3d View_position
Definition: 3dsetup.cpp:20
int num_target_priorities
Definition: ship.h:390
int Man_thruster_reset_timestamp
Definition: ship.cpp:5152
int num_primary_banks
Definition: ship.h:99
object * homing_object
Definition: weapon.h:177
~ship_info()
Definition: ship.cpp:1668
int check_for_string(const char *pstr)
Definition: parselo.cpp:517
set zero throttle
Definition: gamesnd.h:82
#define INTIAL_SHIELD_RECHARGE_INDEX
Definition: hudets.h:20
int objnum
Definition: ship.h:537
#define PROTECT_TARGET_ITEM
Definition: hudsquadmsg.h:41
float afterburner_trail_width_factor
Definition: ship.h:1370
int flags
Definition: ship.h:1483
#define SEF_BEEN_TAGGED
Definition: ship.h:850
float turn_rate
Definition: model.h:210
int parse_string_flag_list(int *dest, flag_def_list defs[], int defs_size)
Definition: parselo.cpp:2665
int score
Definition: ship.h:542
int warpin_type
Definition: ship.h:1213
int Game_mode
Definition: systemvars.cpp:24
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
float debris_arc_percent
Definition: ship.h:1267
void ship_model_stop(object *objp)
Definition: ship.cpp:13059
#define AIM_BAY_EMERGE
Definition: ai.h:183
vec3d rotvel
Definition: physics.h:78
shockwave_create_info shockwave
Definition: ship.h:1237
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
#define SIF_PLAYER_SHIP
Definition: ship.h:875
vec3d mins
Definition: model.h:746
int game_type
Definition: missionparse.h:138
int ai_paused
Definition: object.cpp:677
#define MISSION_FLAG_FULLNEB
Definition: missionparse.h:70
int wash_timestamp
Definition: ship.h:666
Visible but not fully.
Definition: radarsetup.h:91
const int Num_difficulty_scale_types
Definition: ship.cpp:17809
int ship_render_get_insignia(object *obj, ship *shipp)
Definition: ship.cpp:18937
#define ADT_DIFF_SCALE_FIRST
Definition: ship.h:173
int bii_index_ship_with_cargo
Definition: ship.h:1345
int alt_type_index
Definition: ship.h:556
int warpin_snd_start
Definition: ship.h:1208
#define SSF_AUTOREPAIR_IF_DISABLED
Definition: ship.h:297
void ship_set_thruster_info(mst_info *mst, object *obj, ship *shipp, ship_info *sip)
Definition: ship.cpp:18684
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
#define AIM_FLAG_STD_CONVERGENCE
Definition: ship.h:963
float debris_min_lifetime
Definition: ship.h:1257
SCP_vector< thruster_particles > normal_thruster_particles
Definition: ship.h:1376
int n_missiles
Definition: model.h:769
void model_set_instance(int model_num, int sub_model_num, submodel_instance_info *sii, int flags=0)
Definition: modelread.cpp:4726
#define MSS_FLAG2_TURRET_USE_AMMO
Definition: model.h:143
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
int external_model_num
Definition: weapon.h:331
ubyte bay_doors_launched_from
Definition: ship.h:780
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
void render_path_points(object *objp)
Definition: aicode.cpp:6230
"evaded" HUD popup
Definition: gamesnd.h:142
int ship_find_num_crewpoints(object *objp)
Definition: ship.cpp:13128
int Show_paths
Definition: ship.cpp:6626
#define SIF_SUPERCAP
Definition: ship.h:901
float thruster_glow_noise
Definition: weapon.h:192
#define SF2_SHIP_SELECTIVE_LINKING
Definition: ship.h:508
void ship_render_show_ship_cockpit(object *objp)
Definition: ship.cpp:7322
float shield_get_strength(object *objp)
ship_weapon weapons
Definition: ship.h:658
int ai_find_goal_index(ai_goal *aigp, int mode, int submode=-1, int priority=-1)
Definition: aigoals.cpp:1017
float radar_projection_size_mult
Definition: ship.h:1431
void do_dying_undock_physics(object *dying_objp, ship *dying_shipp)
Definition: ship.cpp:8037
#define MT_SLIDE_DOWN
Definition: ship.h:1085
void RemHookVar(char *name)
Definition: scripting.cpp:749
net_player * Net_player
Definition: multi.cpp:94
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
#define SIF_IN_TECH_DATABASE_M
Definition: ship.h:898
#define SIF2_SUBSYS_REPAIR_WHEN_DISABLED
Definition: ship.h:937
object * target
Definition: beam.h:62
char ship_name[NAME_LENGTH]
Definition: missionparse.h:324
float max_rad
Definition: ship.h:970
int scream_count
Definition: player.h:159
float fire_wait
Definition: weapon.h:359
char default_player_ship[255]
#define CARGO_INDEX_MASK
Definition: missionparse.h:220
void send_NEW_countermeasure_fired_packet(object *objp, int cmeasure_count, int rand_val)
Definition: multimsgs.cpp:7760
#define SIF_DEFAULT_VALUE
Definition: ship.h:939
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
Definition: trails.h:34
#define gr_end_view_matrix
Definition: 2d.h:896
fix time_cargo_revealed
Definition: ship.h:608
generic_anim laser_bitmap
Definition: weapon.h:346
#define PLAYER_LOW_AMMO_MSG_INTERVAL
Definition: ship.cpp:15829
#define SF2_NO_DISABLED_SELF_DESTRUCT
Definition: ship.h:511
int turret_gun_sobj
Definition: model.h:193
submodel_instance_info submodel_info_1
Definition: ship.h:368
#define FIREBALL_LARGE_EXPLOSION
Definition: fireballs.h:24
void model_copy_subsystems(int n_subsystems, model_subsystem *d_sp, model_subsystem *s_sp)
Definition: modelread.cpp:505
float flFrametime
Definition: fredstubs.cpp:22
#define SHIP_GET_NO_PLAYERS
Definition: ship.h:1787
int escort_priority
Definition: ship.h:541
bool Glowpoint_override
Definition: systemvars.cpp:75
float thruster_glow_noise
Definition: ship.h:683
float warpout_player_speed
Definition: ship.h:1225
int next_engine_stutter
Definition: ship.h:689
#define WIF2_CYCLE
Definition: weapon.h:89
GLsizei const GLfloat * value
Definition: Glext.h:5646
RadarVisibility radar_current_status
Definition: ship.h:810
int last_primary_fire_stamp[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:114
#define SF2_NO_SUBSPACE_DRIVE
Definition: ship.h:487
#define SF_IGNORE_COUNT
Definition: ship.h:436
float ff_multiplier
Definition: ship.h:1027
char icon_filename[MAX_FILENAME_LEN]
Definition: ship.h:1338
int required_string_one_of(int arg_count,...)
Checks for one of any of the given required strings.
Definition: parselo.cpp:708
char ** Ai_class_names
Definition: aicode.cpp:268
vec3d desired_vel
Definition: physics.h:70
#define REARM_NUM_MISSILES_PER_BATCH
Definition: ship.cpp:13531
Definition: weapon.h:163
GLuint index
Definition: Glext.h:5608
int Weapon_energy_cheat
Definition: hudets.cpp:27
#define MESSAGE_REPAIR_REQUEST
char wing_status_wing_index
Definition: ship.h:552
float afterburner_forward_accel_time_const
Definition: physics.h:60
#define CHECK_THEN_COPY(attribute)
Definition: ship.cpp:664
#define AI_GOAL_CHASE_WING
Definition: aigoals.h:37
#define SSF_PLAY_SOUND_FOR_PLAYER
Definition: ship.h:295
void show_ship_subsys_count()
Definition: ship.cpp:9606
#define AI_GOAL_DOCK
Definition: aigoals.h:30
ushort multi_get_next_network_signature(int what_kind)
Definition: multiutil.cpp:168
int weapon_create(vec3d *pos, matrix *orient, int weapon_type, int parent_obj, int group_id=-1, int is_locked=0, int is_spawned=0, float fof_cooldown=0.0f, ship_subsys *src_turret=NULL)
Definition: weapons.cpp:5246
#define SSF_NO_REPLACE
Definition: ship.h:288
void set_thruster_info(mst_info &info)
physics_info phys_info
Definition: object.h:157
player * m_player
Definition: multi.h:459
missile threat indicator flashes
Definition: gamesnd.h:122
int Fred_running
Definition: fred.cpp:44
matrix * vm_angles_2_matrix(matrix *m, const angles *a)
Definition: vecmat.cpp:752
void ship_model_change(int n, int ship_type)
Definition: ship.cpp:9888
#define WIF_HUGE
Definition: weapon.h:64
#define MAX_WINGS
Definition: globals.h:50
#define AI_GOAL_WAYPOINTS
Definition: aigoals.h:31
beam_info * beam_info_override
Definition: beam.h:83
int get_quadrant(vec3d *hit_pnt, object *shipobjp)
Definition: shield.cpp:988
int n_view_positions
Definition: model.h:752
#define SIF_HAS_AWACS
Definition: ship.h:906
float turn_rate
Definition: ship.h:400
ship_obj Ship_objs[MAX_SHIP_OBJS]
Definition: ship.cpp:161
bool use_newtonian_damp
Definition: physics.h:92
#define MAX_SHIPS
Definition: globals.h:37
#define MT_ROLL_LEFT
Definition: ship.h:1081
void parse_armor_type()
Definition: ship.cpp:18346
#define PLAYER_CHECK_WARN_INTERVAL
Definition: ship.cpp:15453
int turret_gun_rotation_snd
Definition: model.h:197
int piercing_type_get(char *str)
Definition: ship.cpp:17789
void ai_maybe_announce_shockwave_weapon(object *firing_objp, int weapon_index)
Definition: aicode.cpp:5939
void clear()
Definition: ship.cpp:5552
#define SF_AMMO_COUNT_RECORDED
Definition: ship.h:463
#define SIF2_GENERATE_HUD_ICON
Definition: ship.h:923
#define MSS_FLAG2_COLLIDE_SUBMODEL
Definition: model.h:141
#define WT_HYPERSPACE
Definition: ship.h:1111
int id
Definition: model.h:732
ship_subsys fighter_beam_turret_data
Definition: ship.h:743
SCP_vector< texture_replace > replacement_textures
Definition: missionparse.h:431
int ship_explode_area_calc_damage(vec3d *pos1, vec3d *pos2, float inner_rad, float outer_rad, float max_damage, float max_blast, float *damage, float *blast)
Definition: ship.cpp:7895
bool ship_subsys_has_instance_name(ship_subsys *ss)
Definition: ship.cpp:15009
#define STI_MSG_COUNTS_FOR_ALONE
Definition: ship.h:988
#define PLAYER_MAX_DIST_WARNING
Definition: ship.cpp:8856
int parent
Definition: model.h:595
#define MULTI_PRIMARY_CHANGED
Definition: multimsgs.h:60
GLsizei const GLfloat * points
Definition: Glext.h:7583
int allow_warn_timestamp
Definition: player.h:143
#define AI_GOAL_GUARD
Definition: aigoals.h:38
#define WF_WING_GONE
Definition: ship.h:1501
void obj_snd_delete(int objnum, int index)
Definition: objectsnd.cpp:780
int turret_max_target_ownage
Definition: ship.h:404
void ship_get_global_turret_gun_info(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, int use_angles, vec3d *targetp)
Definition: aiturret.cpp:1327
int corkscrew_missile_bank
Definition: ship.h:565
int departure_anchor
Definition: ship.h:618
int model_num
Definition: ship.h:1189
float ship_max_shield_strength
Definition: ship.h:596
int ai_player_orders
Definition: ship.h:1036
proximity warning (aspect)
Definition: gamesnd.h:124
angles model_icon_angles
Definition: ship.h:1339
thrust_pair thruster_glow_info
Definition: ship.h:1381
void shipfx_do_shockwave_stuff(ship *shipp, shockwave_create_info *sci)
Definition: shipfx.cpp:2776
int next_primary_fire_stamp[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:113
int arrival_location
Definition: ship.h:610
float thruster_glow_noise_mult
Definition: ship.h:1392
float forward_accel
Definition: ship.h:1201
#define AT_TYPE_CUTOFF
Definition: ship.cpp:17856
void shipfx_warpin_frame(object *objp, float frametime)
Definition: shipfx.cpp:605
#define MSS_FLAG2_DESTROYED_ROTATION
Definition: model.h:142
int ship_iff_color[MAX_IFFS][MAX_IFFS]
Definition: ship.h:793
float max_hits
Definition: ship.h:320
void ship_add_exited_ship(ship *sp, int reason)
Definition: ship.cpp:5298
int class_type
Definition: ship.h:1167
void stuff_malloc_string(char **dest, int type, char *terminators)
Definition: parselo.cpp:1419
int allowed_bank_restricted_weapons[MAX_SHIP_WEAPONS][MAX_WEAPON_TYPES]
Definition: ship.h:1335
void ct_ship_create(ship *shipp)
int weapon_info_lookup(const char *name=NULL)
Definition: weapons.cpp:467
#define PCM_NORMAL
Definition: player.h:58
#define MULTI_STANDALONE(np)
Definition: multi.h:139
#define SIF_CRUISER
Definition: ship.h:887
int model_instance_num
Definition: ship.h:802
ship_type_info * ship_get_type_info(object *objp)
Definition: ship.cpp:16121
float vm_vec_normalize_quick(vec3d *src)
Definition: vecmat.cpp:529
int Num_dock_type_names
Definition: modelread.cpp:122
#define MULTI_SECONDARY_CHANGED
Definition: multimsgs.h:61
int next_secondary_fire_stamp[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:115
#define PLAYER_MAX_LOW_AMMO_MSGS
Definition: ship.cpp:15831
int insignia_texture
Definition: player.h:195
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
#define PF_GLIDING
Definition: physics.h:32
waypoint_list * wp_list
Definition: ai.h:372
Assert(pm!=NULL)
uint flags2
Definition: model.h:170
int target_objnum
Definition: ai.h:339
int special_exp_blast
Definition: ship.h:586
int get_available_primary_weapons(object *objp, int *outlist, int *outbanklist)
Definition: ship.cpp:12641
int distortion_bitmap
Definition: model.h:1295
#define STI_AI_AUTO_ATTACKS
Definition: ship.h:1005
ship_obj * next
Definition: ship.h:1482
SCP_vector< vec3d > shield_points
Definition: ship.h:662
int submode
Definition: ai.h:394
#define MAX_MODEL_TEXTURES
Definition: globals.h:78
void _cdecl void void _cdecl void _cdecl void _cdecl WarningEx(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
engine_wash_info * get_engine_wash_pointer(char *engine_wash_name)
Definition: ship.cpp:4577
float reorient_min_angle
Definition: ship.h:1142
thrust_pair_bitmap thruster_distortion_info
Definition: species_defs.h:65
int detail[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:738
int departure_location
Definition: ship.h:617
void send_secondary_fired_packet(ship *shipp, ushort starting_sig, int starting_count, int num_fired, int allow_swarm)
Definition: multimsgs.cpp:2938
int bfi_flags
Definition: beam.h:71
int ct_count
Definition: ship.h:1355
int detonate_weapon_time
Definition: ship.h:147
Definition: pstypes.h:88
float detail_depth[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:739
#define MESSAGE_PRIMARIES_LOW
submodel_instance_info submodel_info_2
Definition: ship.h:369
int Ai_render_debug_flag
Definition: ship.cpp:113
void generic_bitmap_init(generic_bitmap *gb, const char *filename)
Definition: generic.cpp:124
int parent
Definition: model.h:359
#define mprintf(args)
Definition: pstypes.h:238
void dock_dead_undock_objects(object *objp1, object *objp2)
#define WIF_CORKSCREW
Definition: weapon.h:71
RadarVisibility radar_is_visible(object *objp)
Return if the specified object is visible on the radar.
Definition: radarsetup.cpp:498
#define MISSION_FLAG_SUPPORT_REPAIRS_HULL
Definition: missionparse.h:74
#define TRIGGER_TYPE_DOCKING_STAGE_1
Definition: modelanim.h:28
#define FRONT_QUAD
Definition: objectshield.h:16
#define PLAYER_REQUEST_REPAIR_MSG_INTERVAL
Definition: ship.cpp:15830
void stuff_boolean_flag(int *i, int flag, bool a_to_eol)
Definition: parselo.cpp:2529
int ai_index
Definition: ship.h:538
SCP_vector< triggered_rotation > Triggered_rotations
Definition: modelanim.cpp:20
int Player_weapon_precedence[MAX_WEAPON_TYPES]
Definition: weapons.cpp:125
int shockwave_count
Definition: ship.h:1246
#define NETINFO_FLAG_OBSERVER
Definition: multi.h:605
ship_weapon weapons
Definition: ship.h:362
char sub_name[NAME_LENGTH]
Definition: ship.h:318
vec3d center_of_mass
Definition: model.h:788
w_bank * gun_banks
Definition: model.h:772
int special_exp_inner
Definition: ship.h:587
int ship_fire_primary(object *obj, int stream_weapons, int force)
Definition: ship.cpp:10760
int total_vanished
Definition: ship.h:1535
#define SSF_NO_LIVE_DEBRIS
Definition: ship.h:289
#define MSS_FLAG_DAMAGE_AS_HULL
Definition: model.h:133
#define SF_ARRIVING_STAGE_2
Definition: ship.h:452
float level2_tag_left
Definition: ship.h:728
vec3d last_aim_enemy_pos
Definition: ship.h:395
float side_slip_time_const
Definition: physics.h:44
int weapon_recharge_index
Definition: ship.h:638
flag_def_list ai_tgt_objects[]
Definition: ship.cpp:331
#define OBJ_ASTEROID
Definition: object.h:44
void ship_subsys_set_disrupted(ship_subsys *ss, int time)
Definition: ship.cpp:9053
vec3d turret_big_attack_point
Definition: ship.h:349
#define MSS_FLAG_TRIGGERED
Definition: model.h:113
int subsystem_stricmp(const char *str1, const char *str2)
Definition: parselo.cpp:3648
hull_check p0
Definition: lua.cpp:5051
int ai_class
Definition: ai.h:369
#define WIF_STREAM
Definition: weapon.h:80
float srotation_time
Definition: ship.h:1199
#define OF_RENDERS
Definition: object.h:103
float player_autoaim_fov[NUM_SKILL_LEVELS]
Definition: ai_profiles.h:150
void ship_destroy_instantly(object *ship_objp, int shipnum)
Definition: ship.cpp:7761
int ship_stop_fire_primary(object *obj)
Definition: ship.cpp:10711
float turret_max_fov
Definition: model.h:189
#define MSS_FLAG_NO_AGGREGATE
Definition: model.h:135
float warpout_radius
Definition: ship.h:1216
vec3d leaning_position
Definition: systemvars.cpp:57
unsigned int mp_shots_fired
Definition: scoring.h:117
int stuff_float_optional(float *f, bool raw)
Definition: parselo.cpp:2343
#define SAF_IGNORE_SS_ARMOR
Definition: ship.h:243
matrix Eye_matrix
Definition: 3dsetup.cpp:26
void ship_render_set_animated_effect(model_render_params *render_info, ship *shipp, uint *render_flags)
Definition: ship.cpp:18973
#define SSF_UNTARGETABLE
Definition: ship.h:280
#define STAY_NEAR_TARGET_ITEM
Definition: hudsquadmsg.h:52
char wing_squad_filename[MAX_FILENAME_LEN]
Definition: ship.h:1518
void obj_snd_delete_type(int objnum, int sndnum, ship_subsys *ss)
Definition: objectsnd.cpp:812
float min_lethality
Definition: ship.cpp:9104
float total_time
Definition: generic.h:27
void send_cargo_hidden_packet(ship *shipp)
Definition: multimsgs.cpp:2881
int turret_next_enemy_check_stamp
Definition: ship.h:335
#define LOG_WING_DEPARTED
Definition: missionlog.h:25
void send_subsystem_cargo_revealed_packet(ship *shipp, int index)
Definition: multimsgs.cpp:4557
float untargeted_flak_range_penalty
Definition: weapon.h:376
#define SIF_CARGO
Definition: ship.h:884
int bm_get_info(int handle, int *w, int *h, ubyte *flags, int *nframes, int *fps)
Gets info on the bitmap indexed by handle.
Definition: bmpman.cpp:769
char name[MAX_FILENAME_LEN]
Definition: shockwave.h:74
ship_subsys * turret
Definition: beam.h:60
int subsys_guardian_threshold
Definition: ship.h:324
const int Num_armor_calculation_types
Definition: ship.cpp:17909
void set_flags(uint flags)
#define AT_TYPE_INSTANT_CAP
Definition: ship.cpp:17862
#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
const char * Ai_goal_text(int goal)
Definition: aigoals.cpp:96
int secondary_bank_start_ammo[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:135
struct vec3d::@225::@227 xyz
float arrive_speed_mult
Definition: ship.h:1154
flag_def_list ai_tgt_ship_flags[]
Definition: ship.cpp:346
float afterburner_fuel
Definition: ship.h:648
int generic_bitmap_load(generic_bitmap *gb)
Definition: generic.cpp:278
int afterburner_trail_faded_out_sections
Definition: ship.h:1373
int dead_snd
Definition: model.h:203
CButton * team
int next_hit_spark
Definition: ship.h:580
#define TMAP_HTL_3D_UNLIT
Definition: tmapper.h:63
#define SIF2_DYN_PRIMARY_LINKING
Definition: ship.h:933
ship_subsys * target_subsys
Definition: beam.h:63
void model_render_immediate(model_render_params *render_info, int model_num, matrix *orient, vec3d *pos, int render, bool sort)
short swarm_count
Definition: weapon.h:398
int hud_bools
Definition: ship.h:1019
#define STAY_NEAR_ME_ITEM
Definition: hudsquadmsg.h:51
#define STI_HUD_HOTKEY_ON_LIST
Definition: ship.h:991
void model_collide_preprocess(matrix *orient, int model_instance_num, int detail=0)
GLboolean GLuint group
Definition: Glext.h:10591
int physics_paused
Definition: object.cpp:677
int distance_warning_count
Definition: player.h:140
vec3d max_vel
Definition: physics.h:49
int shots
Definition: weapon.h:498
#define SF2_DONT_COLLIDE_INVIS
Definition: ship.h:486
float tertiary_glow_rad_factor
Definition: model.h:1304
GLclampf f
Definition: Glext.h:7097
#define MT_REVERSE
Definition: ship.h:1087
#define LOG_SHIP_DEPARTED
Definition: missionlog.h:24
float damp
Definition: ship.h:1193
char pof_file_hud[MAX_FILENAME_LEN]
Definition: ship.h:1184
vec3d * vm_vec_avg_n(vec3d *dest, int n, const vec3d src[])
Definition: vecmat.cpp:196
#define MSS_FLAG_NO_REPLACE
Definition: model.h:129
vec3d norm
Definition: model.h:441
#define MSS_FLAG_TURRET_ANIM_WAIT
Definition: model.h:136
#define MAX_OBJECTS
Definition: globals.h:83
const char * defaults_get_file(const char *filename)
Definition: def_files.cpp:103
#define SIZE_T_ARG
Definition: clang.h:61
int flags
Definition: ship.h:217
void polish_predicted_target_pos(weapon_info *wip, object *targetp, vec3d *enemy_pos, vec3d *predicted_enemy_pos, float dist_to_enemy, vec3d *last_delta_vec, int num_polish_steps)
Definition: hudtarget.cpp:3777
stepped_rotation_t * stepped_rotation
Definition: model.h:212
int ship_subsystem_in_sight(object *objp, ship_subsys *subsys, vec3d *eye_pos, vec3d *subsys_pos, int do_facing_check, float *dot_out, vec3d *vec_out)
Definition: ship.cpp:14881
int * Player_cockpit_textures
Definition: ship.cpp:125
float fof_reset_rate
Definition: weapon.h:496
void ship_obj_list_reset_slot(int index)
Definition: ship.cpp:418
int n_glow_point_banks
Definition: model.h:810
int subsys_disrupted_check_timestamp
Definition: ship.h:699
#define AI_GOAL_WARP
Definition: aigoals.h:33
#define TRUE
Definition: pstypes.h:399
#define CAPTURE_TARGET_ITEM
Definition: hudsquadmsg.h:46
#define NUM_SHIP_SUBSYSTEM_SETS
Definition: ship.cpp:87
float depart_speed_mult
Definition: ship.h:1155
#define MT_BANK_LEFT
Definition: ship.h:1077
#define WIF2_EXTERNAL_WEAPON_LNCH
Definition: weapon.h:109
void ship_do_cargo_revealed(ship *shipp, int from_network)
Definition: ship.cpp:16138
#define NUM_TURRET_ORDER_TYPES
Definition: ship.h:253
int ship_has_homing_missile_locked(ship *shipp)
Definition: ship.cpp:15092
#define OF_NO_SHIELDS
Definition: object.h:110
bool can_glide
Definition: ship.h:1406
#define SF2_FRIENDLY_STEALTH_INVIS
Definition: ship.h:484
#define STI_WEAP_BEAMS_EASILY_HIT
Definition: ship.h:1001
int special_exp_outer
Definition: ship.h:588
void send_NEW_primary_fired_packet(ship *shipp, int banks_fired)
Definition: multimsgs.cpp:7624
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
int Num_ship_subobj_types
Definition: ship.cpp:155
float afterburner_fuel_capacity
Definition: ship.h:1283
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
void ship_process_pre(object *objp, float frametime)
Definition: ship.cpp:9128
#define Assertion(expr, msg,...)
Definition: clang.h:41
#define SIF_BIG_DAMAGE
Definition: ship.h:905
float emp_decr
Definition: ship.h:718
#define WIF2_TAGGED_ONLY
Definition: weapon.h:88
void hud_set_wingman_status_departed(int wing_index, int wing_pos)
void model_add_arc(int model_num, int sub_model_num, vec3d *v1, vec3d *v2, int arc_type)
Definition: modelread.cpp:5003
object obj_used_list
Definition: object.cpp:53
EModelAnimationPosition bay_doors_status
Definition: ship.h:776
#define P_OF_NO_SHIELDS
Definition: missionparse.h:451
#define STI_AI_GUARDS_ATTACK
Definition: ship.h:1007
#define SF_ENGINES_ON
Definition: ship.h:454
#define CMEASURE_WAIT
Definition: cmeasure.h:20
vec3d maxs
Definition: model.h:746
#define AI_GOAL_DISARM_SHIP
Definition: aigoals.h:40
int status_update_stamp
Definition: multi_obj.h:41
int flags
Definition: ship.h:858
model_subsystem * subsystems
Definition: ship.h:1271
#define COVER_ME_ITEM
Definition: hudsquadmsg.h:44
void awacs_maybe_ask_for_help(ship *sp, int multi_team_filter)
Definition: ship.cpp:15635
float nr
Definition: lua.cpp:1945
fix t2
Definition: animplay.cpp:37
Definition: ship.h:1516
void init_ai_object(int objnum)
Definition: aicode.cpp:14300
float side_thrust
Definition: physics.h:73
int subsys_snd_flags
Definition: ship.h:383
bool Rendering_to_shadow_map
Definition: gropengltnl.cpp:88
int current_primary_bank
Definition: ship.h:106
void set_detail_level_lock(int detail_level_lock)
int update_stamp
Definition: multi_obj.h:40
virtual int warpShipRender()
Definition: shipfx.cpp:3496
ship_subsys * targeted_subsys
Definition: ai.h:472
#define SF_ARRIVING
Definition: ship.h:453
#define MR_DEPRECATED_ATTACHED_MODEL
Definition: model.h:924
float ship_get_secondary_weapon_range(ship *shipp)
Definition: ship.cpp:16238
void ship_init()
Definition: ship.cpp:5086
angles Viewer_slew_angles
Definition: systemvars.cpp:54
float ship_quadrant_shield_strength(object *hit_objp, vec3d *hitpos)
Definition: ship.cpp:15030
#define SSF_VANISHED
Definition: ship.h:290
vec3d pos
Definition: ship.h:1102
int ship_is_tagged(object *objp)
Definition: ship.cpp:17263
int ship_find_exited_ship_by_name(char *name)
Definition: ship.cpp:5338
float piercing_damage_draw_limit
Definition: ship.h:1442
target acquried
Definition: gamesnd.h:76
int n_quadrants
Definition: object.h:158
int turret_reset_delay
Definition: model.h:227
#define NUM_SUBSYSTEM_FLAGS
Definition: model.h:148
#define KAMIKAZE_HULL_ON_DEATH
Definition: ai.h:121
int wing_insignia_texture
Definition: ship.h:1566
Definition: model.h:432
float landing_rest_angle
Definition: ship.h:1147
#define SHIP_MIN_ENGINES_TO_WARP
Definition: subsysdamage.h:19
float angle
Definition: ship.h:1490
void set_insignia_bitmap(int bitmap)
float max_speed
Definition: weapon.h:354
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
void ship_process_post(object *obj, float frametime)
Definition: ship.cpp:9180
void update_ets(object *objp, float fl_frametime)
Definition: hudets.cpp:63
#define SIF2_INTRINSIC_NO_SHIELDS
Definition: ship.h:927
int bitmap_id
Definition: generic.h:53
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: Glext.h:5156
float afterburner_reverse_accel
Definition: physics.h:94
#define OF_COLLIDES
Definition: object.h:104
int burst_flags
Definition: weapon.h:534
int death_roll_base_time
Definition: ship.h:1244
Definition: ai.h:329
void ship_do_cap_subsys_cargo_revealed(ship *shipp, ship_subsys *subsys, int from_network)
Definition: ship.cpp:16161
#define MT_PITCH_UP
Definition: ship.h:1078
#define FIREBALL_EXPLOSION_LARGE1
Definition: fireballs.h:32
void ship_make_create_time_unique(ship *shipp)
Definition: ship.cpp:9550
float weapon_energy
Definition: ship.h:640
void ship_obj_list_rebuild()
Definition: ship.cpp:500
uint flags
Definition: ship.h:644
#define AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS
Definition: ai_profiles.h:58
int restricted_loadout_flag[MAX_SHIP_WEAPONS]
Definition: ship.h:1334
int ship_fire_secondary(object *obj, int allow_swarm)
Definition: ship.cpp:11799
#define AIPF2_PERFORM_FEWER_SCREAM_CHECKS
Definition: ai_profiles.h:56
int turret_next_fire_stamp
Definition: ship.h:336
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:1294
#define STI_HUD_TARGET_AS_THREAT
Definition: ship.h:992
#define SIF_NO_SHIP_TYPE
Definition: ship.h:894
#define WIF_HOMING_ASPECT
Definition: weapon.h:45
void ai_clear_ship_goals(ai_info *aip)
Definition: aigoals.cpp:251
int g3_draw_line(vertex *p0, vertex *p1)
Definition: 3ddraw.cpp:112
virtual int warpShipClip()
Definition: shipfx.cpp:3486
#define MT_ROLL_RIGHT
Definition: ship.h:1080
#define MAX_SHIPS_PER_WING
Definition: globals.h:52
hull_check orient
Definition: lua.cpp:5049
flag_def_list Dock_type_names[]
Definition: modelread.cpp:115
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
int flags
Definition: multi.h:463
#define OF_PLAYER_SHIP
Definition: object.h:109
char ship_name[NAME_LENGTH]
Definition: ship.h:854
#define AIPF_USE_ADDITIVE_WEAPON_VELOCITY
Definition: ai_profiles.h:34
float debris_max_hitpoints
Definition: ship.h:1265
int start_snd
Definition: ship.h:1092
float primary_rotate_rate[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:785
float min_rad
Definition: ship.h:979
int warpin_time
Definition: ship.h:1211
generic_anim afterburn
Definition: species_defs.h:31
#define PLAYER_MAX_DIST_END
Definition: ship.cpp:8858
object * objp
Definition: lua.cpp:3105
int ship_navigation_ok_to_warp(ship *sp)
Definition: ship.cpp:14809
int primary_bank_capacity[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:123
#define PLAYER_FLAGS_FORCE_MISSION_OVER
Definition: player.h:44
int red_alert_mission(void)
Definition: redalert.cpp:1031
#define ADT_DIFF_SCALE_LAST
Definition: ship.h:174
float optimum_range
Definition: ship.h:342
float vaporize_chance
Definition: ship.h:1044
GLenum GLenum GLenum GLenum GLenum scale
Definition: Glext.h:8503
#define PARTICLE_BITMAP
Definition: particle.h:49
#define OBJ_OBSERVER
Definition: object.h:43
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
Definition: 2d.cpp:2105
GLfloat GLfloat GLfloat v2
Definition: Glext.h:5640
int current_secondary_bank
Definition: ship.h:107
matrix I_body_inv
Definition: physics.h:41
GLsizeiptr size
Definition: Glext.h:5496
float ai_endangered_by_weapon(ai_info *aip)
Definition: aicode.cpp:6584
int thruster_glow_bitmap
Definition: ship.h:681
int subtype
Definition: weapon.h:326
#define Int3()
Definition: pstypes.h:292
int dock_find_dead_dockpoint_used_by_object(object *objp, object *other_objp)
vec3d max_rotvel
Definition: physics.h:52
int size[2]
Definition: ship.h:263
#define AT_TYPE_EXPONENTIAL
Definition: ship.cpp:17854
#define MAX_SUBSYS_ATTACKERS
Definition: ship.cpp:13277
float density
Definition: ship.h:1192
void ai_object_init(object *obj, int ai_index)
Definition: aicode.cpp:1330
int difficulty_scale_type_get(char *str)
Definition: ship.cpp:17811
void HUD_sourced_printf(int source, const char *format,...)
Definition: hudmessage.cpp:571
SCP_vector< ship_counts > Ship_type_counts
Definition: ship.cpp:401
ship_info()
Definition: ship.cpp:1304
int tracers[MAX_SHIPS][4][4]
Definition: ship.cpp:10750
#define AIF_KAMIKAZE
Definition: ai.h:55
float Noise[NOISE_NUM_FRAMES]
Definition: systemvars.cpp:83
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
GameSoundsIndex
Definition: gamesnd.h:67
float vaporize_chance
Definition: ship.h:1248
Definition: model.h:594
#define MAX_SQUADRON_WINGS
Definition: globals.h:55
int detail_distance[MAX_SHIP_DETAIL_LEVELS]
Definition: ship.h:1186
fix time_first_tagged
Definition: ship.h:726
int get_default_player_ship_index()
Returns the index of the default player ship.
Definition: ship.cpp:4862
GLuint in
Definition: Glext.h:9087
ship * shipp
Definition: lua.cpp:9162
int support_ship_objnum
Definition: ai.h:479
int turret_base_rotation_snd
Definition: model.h:195
int special_warpin_objnum
Definition: ship.h:740
float points_to_target
Definition: ship.h:378
int auto_shield_spread_from_lod
Definition: ship.h:1313
int n_thrusters
Definition: model.h:771
vec3d pos
Definition: object.h:152
#define VM_TOPDOWN
Definition: systemvars.h:43
int Default_ship_select_effect
Definition: mod_table.cpp:24
#define MAX_FIREBALL_TYPES
Definition: fireballs.h:35
Missle tracking to acquire a lock (looped)
Definition: gamesnd.h:68
float emp_intensity
Definition: ship.h:717
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
char pof_name[MAX_FILENAME_LEN]
Definition: shockwave.h:75
#define GR_RESIZE_NONE
Definition: 2d.h:681
ship_subsys_info subsys_info[SUBSYSTEM_MAX]
Definition: ship.h:632
#define MAX_TVT_WINGS
Definition: globals.h:59
void ship_apply_whack(vec3d *force, vec3d *hit_pos, object *objp)
Definition: shiphit.cpp:1740
#define DEFAULT_SHIP_PRIMITIVE_SENSOR_RANGE
Definition: ship.h:479
vec3d * p0
Definition: model.h:1114
int hull_strength
Definition: ship.h:860
int armor_type_constants_get(char *str)
Definition: ship.cpp:17833
void parse_weapon_bank(ship_info *sip, bool is_primary, int *num_banks, int *bank_default_weapons, int *bank_capacities)
Definition: ship.cpp:2056
#define SIF_GAS_MINER
Definition: ship.h:909
char tech_title[NAME_LENGTH]
Definition: ship.h:1175
#define SUBSYSTEM_GAS_COLLECT
Definition: model.h:61
flag_def_list Subsystem_flags[]
Definition: ship.cpp:231
int bm_release(int handle, int clear_render_targets)
Frees both a bitmap's data and it's associated slot.
Definition: bmpman.cpp:2603
vec3d turret_firing_point[MAX_TFP]
Definition: model.h:192
float awacs_radius
Definition: ship.h:360
int ai_flags
Definition: ai.h:330
void ship_find_warping_ship_helper(object *objp, dock_function_info *infop)
Definition: ship.cpp:6632
#define TRIGGER_TYPE_DOCKING_STAGE_3
Definition: modelanim.h:30
void obj_remove_collider(int obj_index)
float gun_submodel_rotation
Definition: model.h:813
#define IS_VEC_NULL(v)
Definition: vecmat.h:28
float vm_vec_mag_squared(const vec3d *v)
Definition: vecmat.cpp:339
void particle_emit(particle_emitter *pe, int type, int optional_data, float range)
Definition: particle.cpp:495
#define OS_SUBSYS_DEAD
Definition: objectsnd.h:21
int next_swarm_fire
Definition: ship.h:669
int maybe_detonate_weapon(ship_weapon *swp, object *src)
Definition: ship.cpp:11680
thruster_bank * thrusters
Definition: model.h:775
int calculation_type_get(char *str)
Definition: ship.cpp:17911
#define SIF_AFTERBURNER
Definition: ship.h:879
void ship_set_eye(object *obj, int eye_index)
Definition: ship.cpp:13197
script_state Script_system("FS2_Open Scripting")
#define gr_end_proj_matrix
Definition: 2d.h:894
float TypeDefaultValues[]
Definition: ship.cpp:17891
#define TM_NUM_TYPES
Definition: model.h:663
float base_rotation_rate_pct
Definition: ship.h:379
ship_subsys * last_fired_turret
Definition: ship.h:772
float turret_base_rotation_snd_mult
Definition: model.h:196
void ship_get_eye(vec3d *eye_pos, matrix *eye_orient, object *obj, bool do_slew, bool from_origin)
Definition: ship.cpp:13227
vec3d pnt[MAX_SLOTS]
Definition: model.h:434
int signature
Definition: object.h:145
flag_def_list ai_tgt_weapon_flags[]
Definition: ship.cpp:354
int subobj_num
Definition: model.h:175
int Ship_sphere_check
Definition: ship.cpp:115
void do_sub_expl_sound(float radius, vec3d *sound_pos, int *sound_handle)
Definition: shipfx.cpp:2190
std::deque< bool > glow_point_bank_active
Definition: ship.h:763
int parse_ship(const char *filename, bool replace)
Definition: ship.cpp:1688
int glide_start_snd
Definition: ship.h:1420
int model_num
Definition: model.h:1110
#define WP_BEAM
Definition: weapon.h:29
GLenum type
Definition: Gl.h:1492
void shipfx_do_damaged_arcs_frame(ship *shipp)
Definition: shipfx.cpp:2417
void ship_set(int ship_index, int objnum, int ship_type)
Definition: ship.cpp:5869
dock_bay * docking_bays
Definition: model.h:774
void stuff_float(float *f)
Definition: parselo.cpp:2328
#define SIF2_FLASH
Definition: ship.h:920
float thruster03_glow_rad_factor
Definition: ship.h:1388
#define MSS_FLAG_AWACS
Definition: model.h:111
int primary_banks[MAX_SHIP_PRIMARY_BANKS]
Definition: model.h:218
vec3d convergence_offset
Definition: ship.h:1438
cargo scanning (looped)
Definition: gamesnd.h:134
float mass
Definition: model.h:787
#define SHIP_GET_ONLY_PLAYERS
Definition: ship.h:1788
char * ship_return_time_to_goal(char *outbuf, ship *sp)
Definition: ship.cpp:15294
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 COLLISION_ROTATION_FACTOR
Definition: objcollide.h:43
int obj_snd_assign(int objnum, int sndnum, vec3d *pos, int main, int flags, ship_subsys *associated_sub)
Definition: objectsnd.cpp:705
#define WIF2_CAPITAL_PLUS
Definition: weapon.h:107
void send_cargo_revealed_packet(ship *shipp)
Definition: multimsgs.cpp:2829
#define CLAMP(x, min, max)
Definition: pstypes.h:488
int use_flags
Definition: ship.h:1090
int Load(char *filename=NULL, int specified_lods=MAX_WEAPON_EXPL_LOD)
Definition: weapons.cpp:179
int hotkey
Definition: ship.h:540
#define AIM_WAYPOINTS
Definition: ai.h:173
float forward_decel_time_const
Definition: physics.h:62
#define MT_SLIDE_LEFT
Definition: ship.h:1083
int lightningtype_match(char *p)
Definition: ship.cpp:648
void init_path_metadata(path_metadata &metadata)
Definition: ship.cpp:18607
void ship_actually_depart(int shipnum, int method)
Definition: ship.cpp:7748
int turret_max_bomb_ownage
Definition: model.h:239
int hud_get_dock_time(object *docker_objp)
Get the number of seconds until repair ship will dock with ther player.
Definition: hud.cpp:2582
int loop_snd
Definition: ship.h:1093
#define INTIAL_ENGINE_RECHARGE_INDEX
Definition: hudets.h:22
void backspace(char *src)
Definition: parselo.cpp:4069
#define WT_IN_PLACE_ANIM
Definition: ship.h:1109
#define SIF2_DEFAULT_IN_TECH_DATABASE
Definition: ship.h:918
#define MSS_FLAG_TURRET_LOCKED
Definition: model.h:134
int weapon_info_index
Definition: weapon.h:164
int beam_fire_targeting(fighter_beam_fire_info *fire_info)
Definition: beam.cpp:476
void pop_transform()
float GetShieldPiercePCT(int damage_type_idx)
Definition: ship.cpp:18111
#define SUBSYSTEM_COMMUNICATION
Definition: model.h:57
float lifetime
Definition: weapon.h:382
reinforcements Reinforcements[MAX_REINFORCEMENTS]
Definition: ship.cpp:165
vec3d topdown_offset
Definition: ship.h:1416
void g3_done_instance(bool set_api=false)
Definition: 3dsetup.cpp:341
void gr_set_color(int r, int g, int b)
Definition: 2d.cpp:1188
#define SHIP_DESTROYED
Definition: ship.h:1623
int get_available_secondary_weapons(object *objp, int *outlist, int *outbanklist)
Definition: ship.cpp:12667
#define AT_TYPE_CAP
Definition: ship.cpp:17861
int source
Definition: ship.h:259
float landing_max_angle
Definition: ship.h:1131
GLfloat angle
Definition: Glext.h:10324
SCP_vector< waypoint > & get_waypoints()
Definition: waypoint.cpp:89
int cs_num_fired
Definition: weapon.h:472
int ship_secondary_bank_has_ammo(int shipnum)
Definition: ship.cpp:14741
SCP_vector< cockpit_display > Player_displays
Definition: ship.cpp:126
int ship_type_name_lookup(const char *name)
Definition: ship.cpp:12923
int species
Definition: ship.h:1166
int rotation_timestamp
Definition: ship.h:385
ubyte num_corkscrew_to_fire
Definition: ship.h:564
int objnum
Definition: ship.h:1483
void ship_render_cockpit(object *objp)
Definition: ship.cpp:7272
int ship_get_num_ships()
Definition: ship.cpp:522
#define STI_HUD_NO_CLASS_DISPLAY
Definition: ship.h:994
#define OF_TARGETABLE_AS_BOMB
Definition: object.h:118
int rearm_first_missile
Definition: ai.h:499
#define PF_BOOSTER_ON
Definition: physics.h:31
int Squadron_wings[MAX_SQUADRON_WINGS]
Definition: ship.cpp:135
#define COLLISION_FRICTION_FACTOR
Definition: objcollide.h:42
ship_subsys subsys_list
Definition: ship.h:630
#define SIF_MASK
Definition: ship.h:955
#define MT_PITCH_DOWN
Definition: ship.h:1079
void ship_maybe_praise_player(ship *deader_sp)
Definition: ship.cpp:15532
int death_fx_count
Definition: ship.h:1245
int Cmdline_nohtl
Definition: cmdline.cpp:438
vec3d pnt
Definition: model.h:596
void ship_set_default_player_ship()
Definition: ship.cpp:4877
#define MESSAGE_PLAYER_DIED
int objnum
Definition: weapon.h:561
#define DISARM_TARGET_ITEM
Definition: hudsquadmsg.h:40
#define SIF_CAPITAL
Definition: ship.h:889
int turret_pick_big_attack_point_timestamp
Definition: ship.h:348
int object_is_docked(object *objp)
Definition: object.cpp:2019
fix time_cargo_revealed
Definition: ship.h:861
float t_rad
Definition: ship.cpp:10604
int ship_stop_fire_primary_bank(object *obj, int bank_to_stop)
Definition: ship.cpp:10674
#define gr_set_view_matrix
Definition: 2d.h:895
char alt_dmg_sub_name[NAME_LENGTH]
Definition: model.h:174
#define SIF2_NO_LIGHTING
Definition: ship.h:932
#define IGNORE_TARGET_ITEM
Definition: hudsquadmsg.h:42
unsigned int ms_shots_fired
Definition: scoring.h:118
thrust_pair_bitmap thruster_tertiary_glow_info
Definition: species_defs.h:64
int low_ammo_complaint_count
Definition: player.h:162
void ship_check_player_distance_sub(player *p, int multi_target=-1)
Definition: ship.cpp:8862
#define SIF_BOMBER
Definition: ship.h:886
#define CHA_ONWPDESELECTED
Definition: scripting.h:68
int ship_list_index
Definition: ship.h:676
ship_subsys * turret
Definition: beam.h:79
int orders_accepted
Definition: ship.h:624
thrust_info thruster_info
Definition: species_defs.h:60
int num_detail_levels
Definition: ship.h:1185
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
bool use_special_explosion
Definition: ship.h:584
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define MAX_SHIP_SECONDARY_BANKS
Definition: globals.h:63
EModelAnimationPosition secondary_animation_position[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:152
#define gr_reset_clip
Definition: 2d.h:745
vec3d big_attack_point
Definition: ai.h:524
void ship_do_weapon_thruster_frame(weapon *weaponp, object *objp, float frametime)
Definition: ship.cpp:8680
int instance
Definition: object.h:150
void obj_add_pairs(int objnum)
Definition: object.cpp:1901
beam_weapon_info b_info
Definition: weapon.h:456
int optional_data
Definition: particle.h:67
int waypoint_speed_cap
Definition: ai.h:375
SCP_vector< glow_point_bank_override > glowpoint_bank_overrides
Definition: modelread.cpp:124
int thruster_glow_bitmap
Definition: weapon.h:190
missle start load (during rearm/repair)
Definition: gamesnd.h:101
void turret_swarm_maybe_fire_missile(int shipnum)
Definition: swarm.cpp:522
void lethality_decay(ai_info *aip)
Definition: ship.cpp:9106
#define FIREBALL_MEDIUM_EXPLOSION
Definition: fireballs.h:23
#define WT_DEFAULT_THEN_KNOSSOS
Definition: ship.h:1108
void model_interp_set_team_color(const SCP_string &team, const SCP_string &secondaryteam, fix timestamp, int fadetime)
#define WIF_FLAK
Definition: weapon.h:75
#define ATTACK_TARGET_ITEM
Definition: hudsquadmsg.h:38
void shipfx_large_blowup_queue_render(draw_list *scene, ship *shipp)
Definition: shipfx.cpp:2393
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
#define SSF_NO_DISAPPEAR
Definition: ship.h:296
GLintptr offset
Definition: Glext.h:5497
int previous_secondary_bank
Definition: ship.h:111
Definition: player.h:85
float ship_get_subsystem_strength(ship *shipp, int type)
Definition: ship.cpp:13446
float core_radius
Definition: model.h:758
void ship_actually_depart_helper(object *objp, dock_function_info *infop)
Definition: ship.cpp:7733
float delta_bank_const
Definition: physics.h:47
const int Num_armor_flags
Definition: ship.cpp:177
p_object * mission_parse_get_arrival_ship(const char *name)
Returns the parse object on the ship arrival list associated with the given name. ...
object * target
Definition: beam.h:81
void find_submodel_instance_point_orient(vec3d *outpnt, matrix *outorient, int model_instance_num, int submodel_num, const vec3d *submodel_pnt, const matrix *submodel_orient)
Definition: modelread.cpp:4370
void parse_sound(const char *tag, int *idx_dest, const char *object_name, parse_sound_flags flags)
Definition: gamesnd.cpp:445
void weapon_set_tracking_info(int weapon_objnum, int parent_objnum, int target_objnum, int target_is_locked=0, ship_subsys *target_subsys=NULL)
Definition: weapons.cpp:5093
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
float a1d[3]
Definition: pstypes.h:93
#define GR_ALPHABLEND_FILTER
Definition: 2d.h:349
#define MSS_FLAG_TURRET_FIXED_FP
Definition: model.h:119
const float PI2
Definition: pstypes.h:305
char pof_file[MAX_FILENAME_LEN]
Definition: ship.h:1183
net_player_info p_info
Definition: multi.h:473
#define OBJ_START
Definition: object.h:35
float t_len
Definition: ship.cpp:10605
int shader_effect_start_time
Definition: ship.h:768
WarpEffect * warpout_effect
Definition: ship.h:576
vec3d last_pos
Definition: object.h:155
#define SIF2_ALLOW_LANDINGS
Definition: ship.h:930
#define gr_set_proj_matrix
Definition: 2d.h:893
float radius_mult
Definition: ship.h:1491
ubyte arc_type[MAX_SHIP_ARCS]
Definition: ship.h:713
int aiming_flags
Definition: ship.h:1435
void joy_ff_play_primary_shoot(int gain)
Definition: joy-unix.cpp:620
#define CHA_PRIMARYFIRE
Definition: scripting.h:71
class ship_subsys * prev
Definition: ship.h:313
int glide_end_snd
Definition: ship.h:1421
int cmeasure_max
Definition: ship.h:1291
void flak_muzzle_flash(vec3d *pos, vec3d *dir, physics_info *pip, int turret_weapon_class)
Definition: flak.cpp:120
#define SIF2_NO_THRUSTER_GEO_NOISE
Definition: ship.h:926
float level2_tag_total
Definition: ship.h:727
void model_delete_instance(int model_instance_num)
Definition: modelread.cpp:2907
ship_subsys * ship_get_indexed_subsys(ship *sp, int index, vec3d *attacker_pos)
Definition: ship.cpp:13340
void obj_add_collider(int obj_index)
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
void ship_set_subsystem_strength(ship *shipp, int type, float strength)
Definition: ship.cpp:13500
ship_spark sparks[MAX_SHIP_HITS]
Definition: ship.h:582
void ship_check_player_distance()
Definition: ship.cpp:8923
class ship_subsys * next
Definition: ship.h:313
#define SHIP_DEPARTED
Definition: ship.h:1626
RadarVisibility
Definition: radarsetup.h:87
float max_vel
Definition: ship.h:984
int flags
Definition: ship.h:322
void ship_maybe_tell_about_low_ammo(ship *sp)
Definition: ship.cpp:15837
object * dock_get_first_dead_docked_object(object *objp)
float t_min
Definition: ship.cpp:10607
#define AT_CONSTANT_RANDOM
Definition: ship.h:184
#define SIF_BIG_SHIP
Definition: ship.h:944
int ship_class_query_general_type(int ship_class)
Definition: ship.cpp:14485
missle load (during rearm/repair)
Definition: gamesnd.h:102
void queued_animation_init(queued_animation *qa)
Definition: modelanim.cpp:350
int flags
Definition: model.h:1116
#define STI_WEAP_NO_HUGE_IMPACT_EFF
Definition: ship.h:1002
vec3d desired_rotvel
Definition: physics.h:71
int target_priority[32]
Definition: ship.h:389
#define MSS_FLAG2_NO_AUTOREPAIR_IF_DISABLED
Definition: model.h:145
SCP_vector< alt_class > s_alt_classes
Definition: ship.h:791
#define MAX_SHIP_WEAPONS
Definition: globals.h:64
void afterburners_update(object *objp, float fl_frametime)
struct matrix::@228::@230 vec
bool auto_shield_spread_bypass
Definition: ship.h:1312
#define ANIMATION_SUBTYPE_ALL
Definition: modelanim.h:52
#define NETINFO_FLAG_AM_MASTER
Definition: multi.h:599
int armor_type_idx
Definition: ship.h:1403
#define SIF_NAVBUOY
Definition: ship.h:891
void model_anim_set_initial_states(ship *shipp)
Definition: modelanim.cpp:823
float neb2_get_fog_intensity(object *obj)
Definition: neb.cpp:1185
char * desc
Definition: ship.h:1173
unsigned int uint
Definition: pstypes.h:64
void model_anim_fix_reverse_times(ship_info *sip)
Definition: modelanim.cpp:705
#define DOGFIGHT_WEAPON
Definition: ship.h:959
#define LOG_WING_DESTROYED
Definition: missionlog.h:21
#define WIF_REMOTE
Definition: weapon.h:48
float mass
Definition: weapon.h:358
int bii_index_wing_with_cargo
Definition: ship.h:1347
void observer_process_post(object *objp)
Definition: ship.cpp:8947
float debris_min_speed
Definition: ship.h:1259
char dockee[NAME_LENGTH]
#define ENGAGE_ENEMY_ITEM
Definition: hudsquadmsg.h:45
int GetPiercingType(int damage_type_idx)
Definition: ship.cpp:18137
void swarm_maybe_fire_missile(int shipnum)
Definition: swarm.cpp:90
int subtype
Definition: lua.cpp:9763
#define PF_REDUCED_DAMP
Definition: physics.h:22
int Show_shield_mesh
Definition: shield.cpp:27
float ship_max_hull_strength
Definition: ship.h:597
#define AT_CONSTANT_NOT_USED
Definition: ship.h:179
int Num_warp_types
Definition: ship.cpp:627
#define AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV
Definition: ai_profiles.h:59
int message_bools
Definition: ship.h:1016
#define SEF_DESTROYED
Definition: ship.h:846
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
#define AWACS_HELP_HULL_LOW
Definition: ship.cpp:15632
void ship_start_targeting_laser(ship *shipp)
Definition: ship.cpp:11568
uint flags
Definition: model.h:169
int timestamp_until(int stamp)
Definition: timer.cpp:242
char * manufacturer_str
Definition: ship.h:1172
float afterburner_forward_accel
Definition: ship.h:1282
#define nprintf(args)
Definition: pstypes.h:239
void ship_end_render_cockpit_display(int cockpit_display_num)
Definition: ship.cpp:7539
float thruster_dist_rad_factor
Definition: ship.h:1390
#define TMAP_FLAG_GOURAUD
Definition: tmapper.h:40
#define GM_MULTIPLAYER
Definition: systemvars.h:18
int g3_draw_sphere(vertex *pnt, float rad)
Definition: 3ddraw.cpp:475
#define SIF2_GUN_CONVERGENCE
Definition: ship.h:925
float cargo_size
Definition: weapon.h:388
float afterburner_reverse_accel
Definition: ship.h:1288
bool use_ab
Definition: model.h:1297
SCP_vector< ship_info > Ship_templates
Definition: ship.cpp:166
int parse_ship_values(ship_info *sip, const bool is_template, const bool first_time, const bool replace)
Definition: ship.cpp:2148
int ship_in_my_squadron(ship *shipp)
Definition: ship.cpp:428
int first_frame
Definition: generic.h:19
void ship_render_batch_thrusters(object *obj)
Definition: ship.cpp:18721
void cmeasure_set_ship_launch_vel(object *objp, object *parent_objp, int arand)
Definition: cmeasure.cpp:28
#define MSS_FLAG_TURRET_RESET_IDLE
Definition: model.h:123
float rotdamp
Definition: physics.h:43
float glow_noise
Definition: model.h:1298
float max_life
Definition: trails.h:28
int primary_bank_ammo[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:121
ai_goal_list Ai_goal_names[]
Definition: aigoals.cpp:62
int primary_out_of_ammo(ship_weapon *swp, int bank)
Definition: ship.cpp:12291
float clip_aspect
Definition: 2d.h:372
#define WIF_SWARM
Definition: weapon.h:59
int Num_lightning_types
Definition: ship.cpp:646
void parse_ship_particle_effect(ship_info *sip, particle_effect *pe, char *id_string)
Definition: ship.cpp:1884
#define MR_NO_TEXTURING
Definition: model.h:868
SCP_vector< briefing_icon_info > Briefing_icon_info
#define SW_FLAG_TURRET_LOCK
Definition: ship.h:95
#define SHIP_DEPARTED_BAY
Definition: ship.h:1625
int * ship_replacement_textures
Definition: ship.h:751
#define WD_WARP_OUT
Definition: shipfx.h:156
#define AIPF_DISABLE_LINKED_FIRE_PENALTY
Definition: ai_profiles.h:32
int allow_ammo_timestamp
Definition: player.h:163
SCP_vector< int > ai_cripple_ignores
Definition: ship.h:1041
char name[NAME_LENGTH]
Definition: ship.h:1517
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
void clear()
Definition: ship.cpp:6164
int Ship_shadows
Definition: ship.cpp:6614
#define MAX_SHIP_CLASSES
Definition: globals.h:48
int secondary_bank_capacity[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:136
int pre_launch_snd_min_interval
Definition: weapon.h:413
float t_max
Definition: ship.cpp:10608
int fireball_ship_explosion_type(ship_info *sip)
Definition: fireballs.cpp:993
#define SF2_NO_DEATH_SCREAM
Definition: ship.h:495
#define OS_TURRET_BASE_ROTATION
Definition: objectsnd.h:18
float turret_y_fov
Definition: model.h:190
int cf_exists_full(const char *filename, int dir_type)
Definition: cfile.cpp:527
ai_target_priority init_ai_target_priorities()
Definition: ship.cpp:18528
int obj_create(ubyte type, int parent_obj, int instance, matrix *orient, vec3d *pos, float radius, uint flags)
Definition: object.cpp:467
bool topdown_offset_def
Definition: ship.h:1415
void ship_maybe_lament()
Definition: ship.cpp:15738
int shipfx_large_blowup_do_frame(ship *shipp, float frametime)
Definition: shipfx.cpp:2325
#define TRIGGER_TYPE_DOCKED
Definition: modelanim.h:31
vec3d * p1
Definition: model.h:1115
int armor_type_get_idx(char *name)
Definition: ship.cpp:18332
int get_max_ammo_count_for_bank(int ship_class, int bank, int ammo_type)
Definition: ship.cpp:16279
int ship_subsys_disrupted(ship_subsys *ss)
Definition: ship.cpp:9033
int flags
Definition: ship.h:1227
#define SADTF_PIERCING_DEFAULT
Definition: ship.h:246
ai_profile_t * ai_profile
Definition: missionparse.h:168
#define MSS_FLAG2_AUTOREPAIR_IF_DISABLED
Definition: model.h:144
float get_hull_pct(object *objp)
Definition: object.cpp:271
void model_clear_instance(int model_num)
Definition: modelread.cpp:4624
#define MSS_FLAG_ROTATES
Definition: model.h:106
char name[MAX_FILENAME_LEN]
Definition: ship.h:270
int reinforcement_index
Definition: ship.h:646
struct engine_wash_info * engine_wash_pointer
Definition: model.h:207
#define SIF_SMALL_SHIP
Definition: ship.h:943
char * filename
float slide_decel_time_const
Definition: physics.h:64
int ship_get_index_from_subsys(ship_subsys *ssp, int objnum, int error_bypass)
Definition: ship.cpp:13390
#define strnicmp(s1, s2, n)
Definition: config.h:272
int wingnum
Definition: ship.h:623
#define SIF2_DRAW_WEAPON_MODELS
Definition: ship.h:935
void joy_ff_play_reload_effect()
Definition: joy-unix.cpp:625
#define AIM_FLAG_AUTOAIM_CONVERGENCE
Definition: ship.h:964
int bay_doors_anim_done_time
Definition: ship.h:775
int ship_get_sound(object *objp, GameSoundsIndex id)
Returns a ship-specific sound index.
Definition: ship.cpp:18614
float target_shields_delta
Definition: ship.h:656
char Squadron_wing_names[MAX_SQUADRON_WINGS][NAME_LENGTH]
Definition: ship.cpp:140
float speed
Definition: physics.h:79
#define WF_WING_DEPARTING
Definition: ship.h:1502
void obj_remove_pairs(object *a)
Definition: object.cpp:1938
#define MAX_STARTING_WINGS
Definition: globals.h:54
int warn_count
Definition: player.h:145
vec3d rotvel
Definition: model.h:1299
int num_secondary_banks
Definition: ship.h:100
int ship_iff_info[MAX_IFFS][MAX_IFFS]
Definition: ship.h:1433
ship_info & operator=(ship_info &&other) NOEXCEPT
Definition: ship.cpp:1277
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 num_points
Definition: model.h:446
void ship_stop_targeting_laser(ship *shipp)
Definition: ship.cpp:11605
int mode
Definition: ai.h:336
int allow_praise_timestamp
Definition: player.h:153
texture_map maps[MAX_MODEL_TEXTURES]
Definition: model.h:762
heat-seeker launch warning
Definition: gamesnd.h:93
thrust_pair_bitmap thruster_secondary_glow_info
Definition: species_defs.h:63
int disruption_timestamp
Definition: ship.h:371
int subsys_disrupted_flags
Definition: ship.h:698
int explosion_propagates
Definition: ship.h:1238
#define SF2_HIDE_SHIP_NAME
Definition: ship.h:498
void ship_maybe_ask_for_help(ship *sp)
Definition: ship.cpp:15668
int shipnum
Definition: ai.h:331
afterburner engage
Definition: gamesnd.h:89
vec3d vel
Definition: particle.h:63
int armor_inited
Definition: ship.cpp:130
void ship_auto_repair_frame(int shipnum, float frametime)
Definition: ship.cpp:8763
generic_anim thruster_glow
Definition: weapon.h:538
float min_engine_vol
Definition: ship.h:1419
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
#define MULTI_SIG_NON_PERMANENT
Definition: multiutil.h:34
#define MESSAGE_REARM_REQUEST
#define PF_ACCELERATES
Definition: physics.h:18
int FindTexture(int bm_handle)
#define SSF_DAMAGE_AS_HULL
Definition: ship.h:293
int secondary_banks[MAX_SHIP_SECONDARY_BANKS]
Definition: model.h:220
#define MESSAGE_PRAISE
int point
Definition: beam.h:70
float hull_strength
Definition: object.h:160
#define SIF_SHIP_CLASS_DONT_COLLIDE_INVIS
Definition: ship.h:903
float Max_draw_distance
Definition: 2d.cpp:85
GLfloat v0
Definition: Glext.h:5638
int praise_delay_timestamp
Definition: player.h:154
void render_dock_bays(object *objp)
Definition: ship.cpp:6571
int reduced_damp_decay
Definition: physics.h:87
float min_speed
Definition: ship.h:1230
float length
Definition: ship.h:1492
char name[NAME_LENGTH]
Definition: ship.h:824
int bitmask_2_bitnum(int num)
Definition: ship.cpp:15178
int persona_index
Definition: ship.h:696
int shader_effect
Definition: ship.h:2005
void ship_render_weapon_models(model_render_params *ship_render_info, draw_list *scene, object *obj, int render_flags)
Definition: ship.cpp:18852
void engine_wash_ship_process(ship *shipp)
Definition: shipfx.cpp:2873
int ship_get_random_player_wing_ship(int flags, float max_dist, int persona_index, int get_first, int multi_team)
Definition: ship.cpp:14508
int primary_animation_done_time[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:153
void vm_orthogonalize_matrix(matrix *m_src)
Definition: vecmat.cpp:1247
void game_shudder_apply(int, float)
Definition: fredstubs.cpp:207
void ship_subsys_set_name(ship_subsys *ss, char *n_name)
Definition: ship.cpp:15017
#define w(p)
Definition: modelsinc.h:68
#define MAX_MODEL_SUBSYSTEMS
Definition: model.h:103
float ai_ship_fire_delay_scale_friendly
Definition: ai.h:449
#define CF_TYPE_TABLES
Definition: cfile.h:50
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
float variance
Definition: ship.h:973
int weapon_bools
Definition: ship.h:1026
void vm_set_identity(matrix *m)
Definition: vecmat.cpp:150
ship_subsys ship_subsys_free_list
Definition: ship.cpp:101
int ai_mode
Definition: ai.h:136
void set_team_color(team_color &clr)
#define WIF3_APPLY_RECOIL
Definition: weapon.h:125
float damage_ship[MAX_DAMAGE_SLOTS]
Definition: ship.h:694
int tag_level
Definition: weapon.h:460
#define AT_TYPE_EXPONENTIAL_BASE
Definition: ship.cpp:17855
trail_info ab_info[MAX_SHIP_CONTRAILS]
Definition: ship.h:759
flag_def_list Player_orders[]
Definition: ship.cpp:200
SCP_string default_team_name
Definition: ship.h:1366
#define WT_DEFAULT
Definition: ship.h:1106
void batch_render_man_thrusters()
Definition: ship.cpp:6668
int warpout_snd_end
Definition: ship.h:1218
float min_vel
Definition: ship.h:983
void joy_ff_explode()
Definition: joy-unix.cpp:600
int object_is_dead_docked(object *objp)
Definition: object.cpp:2025
#define MAX_AI_GOALS
Definition: ai.h:91
void ship_assign_sound(ship *sp)
Definition: ship.cpp:14191
float max_accel
Definition: ship.h:1230
int next_tertiary_fire_stamp
Definition: ship.h:117
ship explosion 2
Definition: gamesnd.h:117
#define AT_TYPE_SET
Definition: ship.cpp:17863
char name[MAX_FILENAME_LEN]
Definition: ship.h:264
#define MAX_SHIP_HITS
Definition: ship.h:56
void shipfx_warpout_frame(object *objp, float frametime)
Definition: shipfx.cpp:848
int num_turret_swarm_info
Definition: ship.h:671
#define SF_HIDDEN_FROM_SENSORS
Definition: ship.h:464
int n_subsystems
Definition: ship.h:1270
#define SSSF_TURRET_ROTATION
Definition: ship.h:305
#define REARM_NUM_BALLISTIC_PRIMARIES_PER_BATCH
Definition: ship.cpp:13532
generic_bitmap afterburner_trail
Definition: ship.h:1369
bool can_move
Definition: model.h:328
#define SIF_SENTRYGUN
Definition: ship.h:892
#define vm_vec_negate(v)
Definition: vecmat.h:70
#define SUBSYSTEM_TURRET
Definition: model.h:54
void ship_delete(object *obj)
Definition: ship.cpp:7585
float favor_current_facing
Definition: model.h:234
int sub_expl_sound_handle[NUM_SUB_EXPL_HANDLES]
Definition: ship.h:707
vec3d departure_rvec
Definition: ship.h:1153
void event_music_hostile_ship_destroyed()
int free_sexp2(int num)
Definition: sexp.cpp:1321
int Show_tnorms
Definition: ship.cpp:6623
char * ship_length
Definition: ship.h:1177
#define AT_CONSTANT_CURRENT_DMG
Definition: ship.h:182
int total_departed
Definition: ship.h:1534
#define MULTI_OBSERVER(np)
Definition: multi.h:140
int iff_lookup(char *iff_name)
Definition: iff_defs.cpp:540
float debris_max_lifetime
Definition: ship.h:1258
#define DEFAULT_DELTA_BANK_CONST
Definition: ship.cpp:662
int special_exp_deathroll_time
Definition: ship.h:591
trail * ABtrail_ptr[MAX_SHIP_CONTRAILS]
Definition: ship.h:758
float distortion_length_factor
Definition: model.h:1307
generic_anim normal
Definition: species_defs.h:30
float weapon_submodel_rotate_accell
Definition: weapon.h:516
object * Viewer_obj
Definition: object.cpp:57
int model_num
Definition: model.h:176
#define SSF_CARGO_REVEALED
Definition: ship.h:279
#define NETINFO_FLAG_INGAME_JOIN
Definition: multi.h:604
fix radar_last_contact
Definition: ship.h:807
float current_max_speed
Definition: ship.h:641
vec3d pt
Definition: trails.h:23
shield_info shield
Definition: model.h:778
ubyte g3_rotate_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:97
void physics_init(physics_info *pi)
Definition: physics.cpp:49
void emp_process_ship(ship *shipp)
Definition: emp.cpp:308
#define HUD_SOURCE_HIDDEN
Definition: hudmessage.h:23
hull_check p1
Definition: lua.cpp:5052
int Ship_auto_repair
Definition: ship.cpp:116
void armor_init()
Definition: ship.cpp:18394
char cargo1
Definition: ship.h:549
EModelAnimationPosition primary_animation_position[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:151
float reorient_max_rot_angle
Definition: ship.h:1143
model_subsystem beam_sys_info
Definition: ship.h:744
int warpout_snd_start
Definition: ship.h:1217
vec3d norm[MAX_DOCK_SLOTS]
Definition: model.h:531
void add_allocate(int quad, int n_tri=0)
Definition: grbatch.cpp:83
void engine_wash_info_init(engine_wash_info *ewi)
Definition: ship.cpp:534
bool draw_distortion
Definition: model.h:1308
#define SEF_RED_ALERT_CARRY
Definition: ship.h:851
int required_string(const char *pstr)
Definition: parselo.cpp:468
float primary_rotate_ang[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:786
queued_animation * triggers
Definition: model.h:225
int secondary_bank_capacity[MAX_SHIP_SECONDARY_BANKS]
Definition: model.h:221
int snd_play(game_snd *gs, float pan, float vol_scale, int priority, bool is_voice_msg)
Definition: sound.cpp:517
#define MAX_DAMAGE_SLOTS
Definition: ship.h:516
int ship_primary_bank_has_ammo(int shipnum)
Definition: ship.cpp:14764
float warpout_accel_exp
Definition: ship.h:1222
int cockpit_model_num
Definition: ship.h:1188
char * type_str
Definition: ship.h:1169
int engine_recharge_index
Definition: ship.h:639
int warpin_snd_end
Definition: ship.h:1209
#define SF_PRIMARY_LINKED
Definition: ship.h:458
#define fl_abs(fl)
Definition: floating.h:31
float max_shield_strength
Definition: ship.h:1310
int Num_wings
Definition: ship.cpp:120
#define MB_OK
Definition: config.h:179
void ai_ship_destroy(int shipnum, int method)
Definition: aicode.cpp:15234
#define PF_FORCE_GLIDE
Definition: physics.h:33
fix game_get_overall_frametime()
Definition: fredstubs.cpp:230
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:104
#define CHA_ONWPFIRED
Definition: scripting.h:66
int Num_ai_classes
Definition: aicode.cpp:195
char * target_name
Definition: ai.h:143
int nverts
Definition: model.h:418
void hud_start_flash_weapon(int index)
Definition: hudtarget.cpp:4534
void parse_allowed_weapons(ship_info *sip, const bool is_primary, const bool is_dogfight, const bool first_time)
Definition: ship.cpp:1987
GLdouble s
Definition: Glext.h:5321
int arc_timestamp[MAX_SHIP_ARCS]
Definition: ship.h:712
void model_anim_handle_multiplayer(ship *shipp)
Definition: modelanim.cpp:863
int get_max_ammo_count_for_primary_bank(int ship_class, int bank, int ammo_type)
Definition: ship.cpp:16262
int type_count
Definition: ship.h:417
int model_anim_get_time_type(ship_subsys *pss, int animation_type, int subtype)
Definition: modelanim.cpp:740
char * get_pointer_to_first_hash_symbol(char *src)
Definition: parselo.cpp:3868
float thruster_glow_frame
Definition: ship.h:682
#define SIF2_DEFAULT_VALUE
Definition: ship.h:940
int ship_show_velocity_dot
Definition: ship.cpp:4975
ship_subsys * ship_return_next_subsys(ship *shipp, int type, vec3d *attacker_pos)
Definition: ship.cpp:14945
float vm_vec_normalized_dir(vec3d *dest, const vec3d *end, const vec3d *start)
Definition: vecmat.cpp:591
void model_set_fog_level(float l)
int bay_doors_wanting_open
Definition: ship.h:777
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
#define DISABLE_TARGET_ITEM
Definition: hudsquadmsg.h:39
void ship_primary_changed(ship *sp)
Definition: ship.cpp:15996
#define MAX_PLAYERS
Definition: pstypes.h:32
int optional_string(const char *pstr)
Definition: parselo.cpp:539
void send_ship_weapon_change(ship *shipp, int what, int new_bank, int link_status)
Definition: multimsgs.cpp:4099
#define SSSF_ALIVE
Definition: ship.h:302
int primary_glow_bitmap
Definition: model.h:1292
#define LOG_CAP_SUBSYS_CARGO_REVEALED
Definition: missionlog.h:38
int current_count
Definition: ship.h:1530
int current_viewpoint
Definition: ship.h:756
float aggregate_current_hits
Definition: ship.h:419
matrix eye_orient
Definition: fredrender.cpp:112
int ship_class
Definition: ship.h:856
char name[MAX_NAME_LEN]
Definition: model.h:415
float max_rear_vel
Definition: ship.h:1200
float a_start
Definition: trails.h:26
void ship_maybe_scream(ship *sp)
Definition: ship.cpp:15789
float fireball_lifeleft(object *obj)
Definition: fireballs.cpp:669
const int num_ai_tgt_objects
Definition: ship.cpp:337
vec3d closeup_pos
Definition: ship.h:1327
char * Warp_types[]
Definition: ship.cpp:618
int collision_damage_type_idx
Definition: ship.h:798
void ship_subsystems_delete(ship *shipp)
Definition: ship.cpp:7568
#define SIF2_DEFAULT_IN_TECH_DATABASE_M
Definition: ship.h:919
float * shield_integrity
Definition: ship.h:634
int subsys_cargo_name
Definition: ship.h:373
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
vec3d offset
Definition: model.h:330
void player_maybe_start_repair_sound()
int callsign_index
Definition: ship.h:557
#define DEFAULT_SHIELD_SECTIONS
Definition: object.h:24
void model_do_intrinsic_rotations(int model_instance_num=-1)
Definition: modelread.cpp:4878
float landing_min_angle
Definition: ship.h:1132
float splode_level
float current_hits
Definition: ship.h:319
float fog_complete_dist
Definition: ship.h:1032
int turret_targeting_order[NUM_TURRET_ORDER_TYPES]
Definition: ship.h:341
int flags2
Definition: ship.h:1228
#define SADTF_PIERCING_RETAIL
Definition: ship.h:247
proximity warning (heat seeker)
Definition: gamesnd.h:123
#define RIGHT_QUAD
Definition: objectshield.h:19
bool scripting_target_override
Definition: ship.h:345
#define ASK_HELP_HULL_PERCENT
Definition: ship.cpp:15630
int large_ship_blowup_index
Definition: ship.h:706
int secondary_bank_ammo_capacity[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:1300
set 1/3 or 2/3 throttle (up)
Definition: gamesnd.h:83
int armor_type_idx
Definition: ship.h:325
Definition: ship.h:534
int wi_flags3
Definition: weapon.h:386
int num_nondark_colors
Definition: ship.h:1358
particle_effect regular_end_particles
Definition: ship.h:1254
GLenum GLuint id
Definition: Glext.h:5156
bool invert_timer
Definition: ship.h:2004
void ship_cleanup(int shipnum, int cleanup_mode)
Definition: ship.cpp:7786
#define SIF_BALLISTIC_PRIMARIES
Definition: ship.h:880
int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, int ferror=1, int duplicate=0)
Definition: modelread.cpp:2573
generic_bitmap afterburn
Definition: species_defs.h:25
int ship_get_random_ship_in_wing(int wingnum, int flags, float max_dist, int get_first)
Definition: ship.cpp:14623
void fs2netd_add_table_validation(const char *tblname)
void hud_targetbox_truncate_subsys_name(char *outstr)
vec3d eye_pos
Definition: fredrender.cpp:103
Beam Hit 1.
Definition: gamesnd.h:189
char filename[MAX_FILENAME_LEN]
Definition: ship.h:271
int ship_maybe_play_secondary_fail_sound(weapon_info *wip)
Definition: ship.cpp:10550
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
vec3d pos
Definition: particle.h:62
void SetHookObject(char *name, object *objp)
Definition: scripting.cpp:551
#define STI_SHIP_SCANNABLE
Definition: ship.h:996
int score
Definition: ship.h:1349
#define AI_GOAL_EVADE_SHIP
Definition: aigoals.h:44
int really_final_death_time
Definition: ship.h:572
#define PLAYER_FLAGS_DIST_TO_BE_KILLED
Definition: player.h:50
float max_subsys_strength
Definition: model.h:180
int skip_to_start_of_string_either(char *pstr1, char *pstr2, char *end)
Definition: parselo.cpp:433
#define ADT_DIFF_SCALE_BAD_VAL
Definition: ship.h:172
__inline void gr_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:760
#define MSS_FLAG_TURRET_ALT_MATH
Definition: model.h:124
int num_slots
Definition: model.h:433
float wash_intensity
Definition: ship.h:664
ship_subsys * ship_get_best_subsys_to_attack(ship *sp, int subsys_type, vec3d *attacker_pos)
Definition: ship.cpp:13278
ship_obj * prev
Definition: ship.h:1482
bool bm_set_render_target(int handle, int face)
(GR function) Calls gr_bm_set_render target for the given bitmap indexed by handle ...
Definition: bmpman.cpp:2810
SCP_vector< vec3d > shield_points
Definition: model.h:781
char bg_filename[MAX_FILENAME_LEN]
Definition: ship.h:273
int total_destroyed
Definition: ship.h:1533
const int Num_armor_type_constants
Definition: ship.cpp:17831
SCP_vector< texture_replace > replacement_textures
Definition: ship.h:1400
int beam_fire(beam_fire_info *fire_info)
Definition: beam.cpp:281
int splodeing_texture
Definition: ship.h:1396
const GLuint * textures
Definition: Glext.h:7569
void model_page_in_textures(int modelnum, int ship_info_index=-1)
tried to fire a missle when none are left
Definition: gamesnd.h:94
#define MAX_NONDARK_COLORS
Definition: palman.h:43
float slide_accel
Definition: ship.h:1203
float sup_subsys_repair_rate
Definition: ship.h:1325
bool Parsing_modular_table
Definition: parselo.cpp:34
#define delta
Definition: fvi.cpp:418
#define SIF_DEFAULT_PLAYER_SHIP
Definition: ship.h:876
#define SIF2_AUTO_SPREAD_SHIELDS
Definition: ship.h:934
int bii_index_wing
Definition: ship.h:1346
void flak_set_range(object *objp, float range)
Definition: flak.cpp:142
int turret_num_firing_points
Definition: model.h:191
#define NOEXCEPT
Definition: clang.h:64
fix time_created
Definition: ship.h:804
int idx
Definition: multiui.cpp:761
CJumpNode * jumpnode_get_which_in(object *objp)
Definition: jumpnode.cpp:448
#define AIF_AWAITING_REPAIR
Definition: ai.h:39
trail_info ct_info[MAX_SHIP_CONTRAILS]
Definition: ship.h:1354
void model_set_insignia_bitmap(int bmap)
int secondary_bank_ammo[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:134
vec3d norm[MAX_SLOTS]
Definition: model.h:435
GLdouble GLdouble t
Definition: Glext.h:5329
cycle secondary weapon
Definition: gamesnd.h:71
beam_info * beam_info_override
Definition: beam.h:67
void ship_set_new_ai_class(int ship_num, int new_ai_class)
Definition: ship.cpp:17362
int primary_bank_ammo_capacity[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:1296
#define SIF_IN_TECH_DATABASE
Definition: ship.h:897
#define MSS_FLAG_CARRY_NO_DAMAGE
Definition: model.h:115
#define SUBSYSTEM_WEAPONS
Definition: model.h:58
float assist_score_pct
Definition: ship.h:543
char cockpit_pof_file[MAX_FILENAME_LEN]
Definition: ship.h:1181
void ship_recalc_subsys_strength(ship *shipp)
Definition: ship.cpp:6020
#define MSS_FLAG_FIRE_ON_TARGET
Definition: model.h:121
builtin_message Builtin_messages[]
trail * trail_ptr[MAX_SHIP_CONTRAILS]
Definition: ship.h:721
int Sound_enabled
Definition: sound.cpp:51
#define WIF2_EXTERNAL_WEAPON_FP
Definition: weapon.h:108
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
int Num_engine_wash_types
Definition: ship.cpp:154
float min_life
Definition: ship.h:981
int n_triggers
Definition: model.h:224
float turret_gun_rotation_snd_mult
Definition: model.h:198
void parse_shiptbl(const char *filename)
Definition: ship.cpp:4910
void ship_subsys_disrupted_check(ship *sp)
Definition: ship.cpp:8988
vec3d norm
Definition: ship.h:1102
float vm_vec_dist_squared(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:344
void ship_apply_global_damage(object *ship_objp, object *other_obj, vec3d *force_center, float damage)
Definition: shiphit.cpp:2476
SCP_vector< thruster_particles > afterburner_thruster_particles
Definition: ship.h:1377
int ship_query_state(char *name)
Definition: ship.cpp:12945
char name[NAME_LENGTH]
Definition: ship.h:1013
int obj_signature
Definition: ship.h:855
#define SF_DISABLED
Definition: ship.h:448
#define MESSAGE_PRAISE_SELF
int num_targeting_priorities
Definition: weapon.h:543
#define PLAYER_DISTANCE_MAX_WARNINGS
Definition: ship.cpp:8857
int radar_image_size
Definition: ship.h:1430
int iff_x_attacks_y(int team_x, int team_y)
Definition: iff_defs.cpp:605
#define AI_GOAL_FLY_TO_SHIP
Definition: aigoals.h:56
int get_subsystem_pos(vec3d *pos, object *objp, ship_subsys *subsysp)
Definition: ship.cpp:12975
vec3d center_of_mass
Definition: physics.h:40
int num_target_priorities
Definition: model.h:231
vec3d rotation_time
Definition: ship.h:1198
int ship_select_next_primary(object *objp, int direction)
Definition: ship.cpp:12317
man_thruster_renderer * man_thruster_get_slot(int bmap_frame)
Definition: ship.cpp:6705
int primary_bank_capacity[MAX_SHIP_PRIMARY_BANKS]
Definition: model.h:219
void ship_subsys_disrupted_maybe_check(ship *shipp)
Definition: ship.cpp:9019
int damage_ship_id[MAX_DAMAGE_SLOTS]
Definition: ship.h:695
flag_def_list ai_tgt_obj_flags[]
Definition: ship.cpp:339
int snd_get_duration(int snd_id)
Definition: sound.cpp:1082
int Ship_subsys_hwm
Definition: ship.cpp:9604
const size_t INVALID_WAYPOINT_POSITION
Definition: waypoint.cpp:16
int shield_impact_explosion_anim
Definition: ship.h:1443
#define MSS_FLAG2_TURRET_ONLY_TARGET_IF_CAN_FIRE
Definition: model.h:139
int was_firing_last_frame[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:745
#define MODEL_RENDER_ALL
Definition: model.h:935
char name[NAME_LENGTH]
Definition: ship.h:1163
set 1/3 or 2/3 throttle (down)
Definition: gamesnd.h:84
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
for(int idx=0;idx< i;idx++)
Definition: multi_pxo.cpp:472
char alt_sub_name[NAME_LENGTH]
Definition: model.h:173
int turret_max_bomb_ownage
Definition: ship.h:403
float sup_hull_repair_rate
Definition: ship.h:1323
#define SIF_STEALTH
Definition: ship.h:900
int Num_ship_subobjects
Definition: ship.cpp:156
float awacs_radius
Definition: model.h:216
long fix
Definition: pstypes.h:54
void submodel_get_two_random_points(int model_num, int submodel_num, vec3d *v1, vec3d *v2, vec3d *n1=NULL, vec3d *n2=NULL)
GLclampd n
Definition: Glext.h:7286
#define MSS_FLAG2_SHARE_FIRE_DIRECTION
Definition: model.h:146
#define AIM_DOCK
Definition: ai.h:174
bool glide_dynamic_cap
Definition: ship.h:1408
#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
void ets_init_ship(object *obj)
Definition: hudets.cpp:34
float autoaim_fov
Definition: ship.h:1413
int radar_color_image_2d_idx
Definition: ship.h:1429
int Countermeasures_enabled
Definition: cmeasure.cpp:23
#define SLT_DEFAULT
Definition: ship.h:251
void ship_copy_subsystem_fixup(ship_info *sip)
Definition: ship.cpp:6121
void shield_add_strength(object *objp, float delta)
void stuff_vec3d(vec3d *vp)
Definition: parselo.cpp:3082
vec3d afterburner_max_vel
Definition: physics.h:50
int wi_flags
Definition: weapon.h:384
vec3d targeting_laser_offset
Definition: beam.h:59
#define vm_vec_zero(v)
Definition: vecmat.h:37
uint flags
Definition: physics.h:37
Destroyed by a beam (vaporized)
Definition: gamesnd.h:91
#define WD_WARP_IN
Definition: shipfx.h:155
int parse_and_add_briefing_icon_info()
Definition: ship.cpp:2103
#define SF_ARRIVING_STAGE_1
Definition: ship.h:451
SCP_vector< SCP_string > ai_actively_pursues_temp
Definition: ship.h:1050
#define AIM_FLAG_CONVERGENCE_OFFSET
Definition: ship.h:965
int ship_create(matrix *orient, vec3d *pos, int ship_type, char *ship_name)
Definition: ship.cpp:9690
float primary_bank_fof_cooldown[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:128
ubyte seq
Definition: multi_obj.h:39
#define AWACS_WARN_75
Definition: ship.h:531
int turret_swarm_num
Definition: ship.h:356
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
void set_replacement_textures(int *textures)
fix next_aim_pos_time
Definition: ship.h:394
void read_file_text_from_array(const char *array, char *processed_text, char *raw_text)
Definition: parselo.cpp:2022
ubyte shield_color[3]
Definition: ship.h:1362
#define AI_GOAL_WAYPOINTS_ONCE
Definition: aigoals.h:32
int objnum
Definition: player.h:124
#define SIF_DRYDOCK
Definition: ship.h:902
#define WF_DEPARTURE_ORDERED
Definition: ship.h:1512
char warpin_anim[MAX_FILENAME_LEN]
Definition: ship.h:1206
float max_life
Definition: ship.h:982
#define OBJ_INDEX(objp)
Definition: object.h:235
int cmeasure_type
Definition: ship.h:1290
#define MULTI_TEAM
Definition: multi.h:655
int next_corkscrew_fire
Definition: ship.h:566
float radius
Definition: model.h:442
int shield_armor_type_idx
Definition: ship.h:797
float glide_cap
Definition: physics.h:89
SCP_map< SCP_string, path_metadata > pathMetadata
Definition: ship.h:1453
vec3d hit_point_world
Definition: model.h:1124
ship * Player_ship
Definition: ship.cpp:124
const int num_ai_tgt_obj_flags
Definition: ship.cpp:344
void ship_maybe_praise_self(ship *deader_sp, ship *killer_sp)
Definition: ship.cpp:15572
float emp_resistance_mod
Definition: ship.h:1440
aspect launch warning
Definition: gamesnd.h:110
int num_waves
Definition: ship.h:1522
#define GM_IN_MISSION
Definition: systemvars.h:23
SCP_string team_name
Definition: ship.h:812
int ship_query_general_type(int ship)
Definition: ship.cpp:14475
void parse_ship_sounds(ship_info *sip)
Definition: ship.cpp:1855
int damage_ship_id[MAX_DAMAGE_SLOTS]
Definition: ship.h:864
#define gr_set_cull
Definition: 2d.h:838
void stuff_boolean(int *i, bool a_to_eol)
Definition: parselo.cpp:2519
RadarVisibility radar_last_status
Definition: ship.h:809
int ship_find_repair_ship(object *requester_obj, object **ship_we_found)
Definition: ship.cpp:14008
matrix orient
Definition: object.h:153
#define SIF2_NO_PRIMARY_LINKING
Definition: ship.h:928
#define WIF_HOMING_HEAT
Definition: weapon.h:44
int ship_guardian_threshold
Definition: ship.h:601
bool use_shockwave
Definition: ship.h:589
int wi_flags2
Definition: weapon.h:385
#define F_MESSAGE
Definition: parselo.h:42
int tertiary_glow_bitmap
Definition: model.h:1294
int hud_target_lod
Definition: ship.h:1191
#define AT_NUM_STORAGE_LOCATIONS
Definition: ship.cpp:17869
#define NOX(s)
Definition: pstypes.h:473
int last_secondary_fire_stamp[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:116
#define SUBSYSTEM_NONE
Definition: model.h:52
#define SND_PRIORITY_MUST_PLAY
Definition: sound.h:26
#define TMAP_FLAG_RGB
Definition: tmapper.h:39
int warptype_match(char *p)
Definition: ship.cpp:629
char * armor_str
Definition: ship.h:1171
vec3d targeting_laser_offset
Definition: beam.h:78
#define FIREBALL_NUM_LARGE_EXPLOSIONS
Definition: fireballs.h:38
float glow_length_factor
Definition: model.h:1305
bool end_string_at_first_hash_symbol(char *src)
Definition: parselo.cpp:3833
void ship_render_DEPRECATED(object *obj)
Definition: ship.cpp:6733
GLuint start
Definition: Gl.h:1502
#define SIF_PATH_FIXUP
Definition: ship.h:877
int do_facing_check(const vec3d *norm, vertex **vertlist, const vec3d *p)
Definition: 3ddraw.cpp:166
SCP_unordered_map< int, void * > glowpoint_bank_override_map
Definition: ship.h:1455
int TVT_wings[MAX_TVT_WINGS]
Definition: ship.cpp:136
ship_subsys * target_subsys
Definition: beam.h:82
bool splodeing
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
char * TypeNames[]
Definition: ship.cpp:17872
#define SADTF_PIERCING_NONE
Definition: ship.h:245
float target_weapon_energy_delta
Definition: ship.h:657
#define WIF_BOMB
Definition: weapon.h:63
#define WBF_FAST_FIRING
Definition: weapon.h:149
#define OBJ_SHIP
Definition: object.h:32
#define MR_DEPRECATED_ANIMATED_SHADER
Definition: model.h:923
GLfloat GLfloat v1
Definition: Glext.h:5639
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
float turret_rof_scaler
Definition: model.h:236
#define GM_STANDALONE_SERVER
Definition: systemvars.h:27
float intensity
Definition: ship.h:1493
float thruster01_glow_rad_factor
Definition: ship.h:1386
int targeting_laser_objnum
Definition: ship.h:561
#define TMAP_FLAG_CORRECT
Definition: tmapper.h:37
int rearm_first_ballistic_primary
Definition: ai.h:500
#define MT_BANK_RIGHT
Definition: ship.h:1076
flag_def_list PiercingTypes[]
Definition: ship.cpp:17781
#define AI_GOAL_GUARD_WING
Definition: aigoals.h:43
vec3d prev_fvec
Definition: physics.h:82
int special_warpout_objnum
Definition: ship.h:741
float max_speed
Definition: ship.h:1230
void dc_stuff_float(float *f)
Stuffs a float to the given variable.
void create_shield_explosion_all(object *objp)
Definition: shield.cpp:838
GLbitfield flags
Definition: Glext.h:6722
void vm_vec_rand_vec_quick(vec3d *rvec)
Definition: vecmat.cpp:1379
float tracer_length
Definition: particle.h:70
int collision_damage_type_idx
Definition: ship.h:1233
int ship_check_collision_fast(object *obj, object *other_obj, vec3d *hitpos)
Definition: ship.cpp:9521
int Show_shield_hits
Definition: ship.cpp:6620
int shield_point_augment_ctrls[4]
Definition: ship.h:1316
#define WIF3_NO_LINKED_PENALTY
Definition: weapon.h:119
Definition: 2d.h:109
bool newtonian_damp_override
Definition: ship.h:1411
int Num_weapon_types
Definition: weapons.cpp:105
#define vm_malloc(size)
Definition: pstypes.h:547
char cargo1
Definition: ship.h:862
void allocate(int quad, int n_tri=0)
Definition: grbatch.cpp:66
#define WIF2_PIERCE_SHIELDS
Definition: weapon.h:85
const int Num_man_types
Definition: ship.cpp:194
#define SIF_HUGE_SHIP
Definition: ship.h:945
#define SF2_NO_BUILTIN_MESSAGES
Definition: ship.h:491
int wing_name_lookup(const char *name, int ignore_count)
Definition: ship.cpp:12706
int turret_animation_done_time
Definition: ship.h:352
typedef void(APIENTRY *PFNGLARRAYELEMENTEXTPROC)(GLint i)
int Starting_wings[MAX_STARTING_WINGS]
Definition: ship.cpp:132
#define MSS_FLAG2_PLAYER_TURRET_SOUND
Definition: model.h:138
float Decay_rate
Definition: ship.cpp:9093
#define AWACS_WARN_25
Definition: ship.h:530
void reset_parse(char *text)
Definition: parselo.cpp:3305
#define SF2_NO_THRUSTERS
Definition: ship.h:505
#define AIF_BEING_REPAIRED
Definition: ai.h:40
#define MSS_FLAG2_NO_DISAPPEAR
Definition: model.h:140
char warpout_anim[MAX_FILENAME_LEN]
Definition: ship.h:1215
void hud_anim_init(hud_anim *ha, int sx, int sy, const char *filename)
Initialise the members of the hud_anim struct to default values.
Definition: hud.cpp:2169
int control_mode
Definition: player.h:134
void ship_radar_process(object *obj, ship *shipp, ship_info *sip)
Definition: ship.cpp:9136
int num_secondary_banks
Definition: ship.h:1298
GLuint const GLchar * name
Definition: Glext.h:5608
int RunCondition(int condition, char format='\0', void *data=NULL, class object *objp=NULL, int more_data=0)
Definition: scripting.cpp:924
void joy_ff_play_secondary_shoot(int gain)
Definition: joy-unix.cpp:630
int secondary_bank_rearm_time[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:138
void process_subobjects(int objnum)
Definition: aicode.cpp:11120
int alive_snd
Definition: model.h:202
float warpin_decel_exp
Definition: ship.h:1212
int Player_use_ai
vec3d turret_last_fire_direction
Definition: ship.h:334
float death_roll_time_mult
Definition: ship.h:1243
#define WIF_ELECTRONICS
Definition: weapon.h:46
int bii_index_ship
Definition: ship.h:1344
GLuint GLfloat * val
Definition: Glext.h:6741
#define AT_TYPE_INSTANT_REVERSE_CUTOFF
Definition: ship.cpp:17859
int final_death_time
Definition: ship.h:569
void SetHookObjects(int num,...)
Definition: scripting.cpp:556
man_thruster maneuvering[MAX_MAN_THRUSTERS]
Definition: ship.h:1426
#define CYCLE_PRIMARY_NEXT
Definition: ship.h:62
float thruster02_glow_len_factor
Definition: ship.h:1389
void ship_clear_ship_type_counts()
Definition: ship.cpp:14436
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
float debris_max_speed
Definition: ship.h:1023
#define SF_RED_ALERT_STORE_STATUS
Definition: ship.h:469
#define SUBSYSTEM_ENGINE
Definition: model.h:53
float gun_rotation_rate_pct
Definition: ship.h:380
vec3d vel
Definition: physics.h:77
#define vm_realloc(ptr, size)
Definition: pstypes.h:551
float fspeed
Definition: physics.h:80
cycle primary weapon
Definition: gamesnd.h:70
fix t1
Definition: animplay.cpp:37
int ai_valid_goals
Definition: ship.h:1035
p_object * Arriving_support_ship
float total_damage_received
Definition: ship.h:693
#define MISSION_TYPE_TRAINING
Definition: missionparse.h:63
#define SF_SCANNABLE
Definition: ship.h:465
int primary_bitmap
Definition: model.h:1291
#define SIF_SUPPORT
Definition: ship.h:878
#define SF2_PRIMARIES_LOCKED
Definition: ship.h:492
vec3d Eye_position
Definition: 3dsetup.cpp:27
int ship_fire_secondary_detonate(object *obj, ship_weapon *swp)
Definition: ship.cpp:11729
#define TM_GLOW_TYPE
Definition: model.h:658
#define SF_VAPORIZE
Definition: ship.h:470
#define WIF_SHUDDER
Definition: weapon.h:78
ship_flag_name Ship_flag_names[]
Definition: ship.cpp:372
void dc_stuff_string_white(char *out_str, size_t maxlen)
Stuffs a whitespace delimited string to out_str from the command line, stopping at the end of the com...
set full throttle
Definition: gamesnd.h:81
SCP_vector< SCP_string > ai_cripple_ignores_temp
Definition: ship.h:1051
#define AWACS_HELP_HULL_HI
Definition: ship.cpp:15631
int bm_load(const char *real_filename)
Loads a bitmap so we can draw with it later.
Definition: bmpman.cpp:1119
thrust_pair glow
Definition: species_defs.h:36
#define MSS_FLAG_TURRET_HULL_CHECK
Definition: model.h:118
#define SIF_FREIGHTER
Definition: ship.h:888
thrust_pair thruster_flame_info
Definition: ship.h:1380
SCP_vector< cockpit_display_info > displays
Definition: ship.h:1451
int num_hits
Definition: model.h:1121
int target
Definition: ship.h:258
int shield_hits
Definition: ship.h:660
int iff_init_color(int r, int g, int b)
Definition: iff_defs.cpp:62
int ship_info_lookup_sub(const char *token)
Definition: ship.cpp:12749
void stuff_int(int *i)
Definition: parselo.cpp:2372
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
#define SIF_ESCAPEPOD
Definition: ship.h:893
int weapon_rotation_pbank
Definition: model.h:211
int next_manage_ets
Definition: ship.h:642
int allow_scream_timestamp
Definition: player.h:160
#define SSF_NO_AUTOREPAIR_IF_DISABLED
Definition: ship.h:298
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
int num_maneuvering
Definition: ship.h:1425
float turret_turning_rate
Definition: model.h:194
#define SF_DEPARTING
Definition: ship.h:475
#define MT_SLIDE_RIGHT
Definition: ship.h:1082
void send_ship_depart_packet(object *objp, int method)
Definition: multimsgs.cpp:2774
#define MESSAGE_PRIORITY_HIGH
float turret_time_enemy_in_range
Definition: ship.h:340
int death_roll_snd
Definition: ship.h:675
#define STI_AI_CAN_FORM_WING
Definition: ship.h:1009
vec3d get_submodel_offset(int model, int submodel)
Definition: ship.cpp:5489
#define SHIP_MIN_NAV_TO_WARP
Definition: subsysdamage.h:58
SCP_vector< ship_effect > Ship_effects
Definition: ship.cpp:412
#define MR_DEPRECATED_NO_TEXTURING
Definition: model.h:902
#define BEAM_TYPE_C
Definition: beam.h:34
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
#define SF_EXPLODED
Definition: ship.h:467
int special_shield
Definition: ship.h:594
void shipfx_do_lightning_frame(ship *shipp)
Definition: shipfx.cpp:2648
int parent_objnum
Definition: ship.h:316
int total_arrived_count
Definition: ship.h:1528
int ship_get_by_signature(int signature)
Definition: ship.cpp:16106
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
GLuint GLuint num
Definition: Glext.h:9089
#define SIF2_DISABLE_WEAPON_DAMAGE_SCALING
Definition: ship.h:924
#define WING_INDEX(wingp)
Definition: ship.h:1601
float warpin_speed
Definition: ship.h:1210
char alt_name[NAME_LENGTH]
Definition: ship.h:1164
void shockwave_create_info_init(shockwave_create_info *sci)
Definition: shockwave.cpp:811
int ship_select_next_valid_secondary_bank(ship_weapon *swp)
Definition: ship.cpp:11762
#define MAX_REPLACEMENT_TEXTURES
Definition: model.h:690
int damage_lightning_type
Definition: ship.h:1445
float power_output
Definition: ship.h:1274
captial ship explosion
Definition: gamesnd.h:127
#define MR_DEPRECATED_NORMAL
Definition: model.h:892
int allow_ask_help_timestamp
Definition: player.h:157
void hud_shield_assign_info(ship_info *sip, char *filename)
Definition: hudshield.cpp:339
#define DCF_BOOL(function_name, bool_variable)
Definition: console.h:71
int ship_get_subobj_model_num(ship_info *sip, char *subobj_name)
Definition: ship.cpp:18597
int primitive_sensor_range
Definition: ship.h:748
int attached_sig
Definition: particle.h:72
int ship_launch_countermeasure(object *objp, int rand_val)
Definition: ship.cpp:10421
vec3d pnt
Definition: model.h:178
fix base_texture_anim_frametime
Definition: ship.h:691
void ship_model_start(object *objp)
Definition: ship.cpp:13012
int initial_velocity
Definition: missionparse.h:365
int ship_dumbfire_threat(ship *sp)
Definition: ship.cpp:15078
#define BFIF_IS_FIGHTER_BEAM
Definition: beam.h:50
int next_fireball
Definition: ship.h:578
void CAP(T &v, T mn, T mx)
Definition: pstypes.h:478
int secondary_next_slot[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:137
float turret_fov
Definition: model.h:188
float debris_damage_mult
Definition: ship.h:1266
#define MESSAGE_CHECK_6
#define MAX_AI_INFO
Definition: ai.h:564
int ship_find_num_turrets(object *objp)
Definition: ship.cpp:13164
int turret_next_fire_pos
Definition: ship.h:339
campaign Campaign
int turret_max_target_ownage
Definition: model.h:240
float emp_multiplier
Definition: ship.h:1028
float tag_left
Definition: ship.h:725
float vm_vec_delta_ang(const vec3d *v0, const vec3d *v1, const vec3d *fvec)
Definition: vecmat.cpp:687
float favor_current_facing
Definition: ship.h:343
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
char anim_filename[MAX_FILENAME_LEN]
Definition: ship.h:1340
vec3d last_aim_enemy_vel
Definition: ship.h:396
#define MSS_FLAG_UNTARGETABLE
Definition: model.h:114
char old_texture[MAX_FILENAME_LEN]
Definition: missionparse.h:325
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)
#define SF_WARP_BROKEN
Definition: ship.h:460
#define SF2_NO_ETS
Definition: ship.h:503
int ship_get_exp_propagates(ship *sp)
Definition: ship.cpp:16965
#define OS_SUBSYS_ALIVE
Definition: objectsnd.h:20
int model_num_hud
Definition: ship.h:1190
#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
#define SF_SECONDARY_DUAL_FIRE
Definition: ship.h:459
char splodeing_texture_name[MAX_FILENAME_LEN]
Definition: ship.h:1397
#define AT_TYPE_RANDOM
Definition: ship.cpp:17866
#define LEFT_QUAD
Definition: objectshield.h:18
#define WP_MISSILE
Definition: weapon.h:28
#define AI_GOAL_DISABLE_SHIP
Definition: aigoals.h:39
int engine_snd
Definition: ship.h:1418
int ship_docking_valid(int docker, int dockee)
Definition: ship.cpp:14494
float rad
Definition: model.h:757
int request_repair_timestamp
Definition: player.h:169
float lssm_lock_range
Definition: weapon.h:492
bool shipfx_in_shadow(object *src_obj)
Definition: shipfx.cpp:926
int tex_nframes
Definition: ship.h:1097
float ai_ship_fire_delay_scale_hostile
Definition: ai.h:450
int Cmdline_freespace_no_sound
Definition: cmdline.cpp:272
#define SSF_NO_AGGREGATE
Definition: ship.h:294
#define STI_TURRET_TGT_SHIP_TGT
Definition: ship.h:999
bool hud_enabled
Definition: ship.h:1448
int ship_weapon_maybe_fail(ship *sp)
Definition: ship.cpp:10572
float t_vel
Definition: ship.cpp:10606
void submodel_get_two_random_points_better(int model_num, int submodel_num, vec3d *v1, vec3d *v2)
void ship_render(object *obj, draw_list *scene)
Definition: ship.cpp:19003
void ship_init_cockpit_displays(ship *shipp)
Definition: ship.cpp:7349
#define KEEP_SAFE_DIST_ITEM
Definition: hudsquadmsg.h:53
#define SUBSYSTEM_SENSORS
Definition: model.h:59
#define fl2i(fl)
Definition: floating.h:33
int ship_template_lookup(const char *token)
Definition: ship.cpp:12761
#define MULTI_CONNECTED(np)
Definition: multi.h:136
#define SUBSYSTEM_UNKNOWN
Definition: model.h:63
#define AIPF_USE_NEWTONIAN_DAMPENING
Definition: ai_profiles.h:35
char short_name[NAME_LENGTH]
Definition: ship.h:1165
int submodel
Definition: lua.cpp:5007
void ship_scream(ship *sp)
Definition: ship.cpp:15757
ubyte awacs_warning_flag
Definition: ship.h:737
player * Player
#define MESSAGE_REARM_PRIMARIES
ushort orient_chksum
Definition: multi_obj.h:44
int distance_warning_time
Definition: player.h:141
p_object * mission_parse_get_parse_object(ushort net_signature)
void shipfx_flash_light_model(object *objp, int model_num)
Definition: shipfx.cpp:1314
#define MC_CHECK_MODEL
Definition: model.h:1169
int tex_fps
Definition: ship.h:1098
void message_send_builtin_to_player(int type, ship *shipp, int priority, int timing, int group, int delay, int multi_target, int multi_team_filter)
#define AT_CONSTANT_DIFF_FACTOR
Definition: ship.h:183
#define SIF_SHIP_COPY
Definition: ship.h:896
GLenum target
Definition: Glext.h:6872
#define MESSAGE_STRAY_WARNING
int last_fired_point[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:771
int external_model_fp_counter[MAX_SHIP_PRIMARY_BANKS+MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:157
vec3d wash_rot_axis
Definition: ship.h:665
void ship_do_thruster_frame(ship *shipp, object *objp, float frametime)
Definition: ship.cpp:8567
struct dock_function_info::@258 parameter_variables
#define HUD_WEAPONS_GAUGE
Definition: hudgauges.h:34
float prop_exp_rad_mult
Definition: ship.h:1240
struct dock_function_info::@258 maintained_variables
screen gr_screen
Definition: 2d.cpp:46
void ship_maybe_tell_about_rearm(ship *sp)
Definition: ship.cpp:15913
#define STI_MSG_PRAISE_DESTRUCTION
Definition: ship.h:989
#define DEPART_ITEM
Definition: hudsquadmsg.h:56
float lifetime
Definition: particle.h:64
float Min_draw_distance
Definition: 2d.cpp:84
#define WIF_BEAM
Definition: weapon.h:76
void generic_anim_init(generic_anim *ga)
Definition: generic.cpp:80
float forward_accel_time_const
Definition: physics.h:59
glow_point * points
Definition: model.h:447
float weapon_model_draw_distance
Definition: ship.h:1304
#define MT_SLIDE_UP
Definition: ship.h:1084
matrix last_rotmat
Definition: physics.h:83
int ship_do_rearm_frame(object *objp, float frametime)
Definition: ship.cpp:13664
void model_set_instance_info(submodel_instance_info *sii, float turn_rate, float turn_accel)
Definition: modelread.cpp:4708
ship_subsys * ship_get_closest_subsys_in_sight(ship *sp, int subsys_type, vec3d *attacker_pos)
Definition: ship.cpp:14963
#define MAX_SHIP_ARCS
Definition: ship.h:517
HUGE engine ambient.
Definition: gamesnd.h:143
void ai_deathroll_start(object *ship_obj)
Definition: aicode.cpp:15299
float both_small_bounce
Definition: ship.h:1117
int warpout_engage_time
Definition: ship.h:1219
object * objp_value
Definition: objectdock.h:38
void ship_chase_shield_energy_targets(ship *shipp, object *obj, float frametime)
Definition: ship.cpp:8461
void ship_dying_frame(object *objp, int ship_num)
Definition: ship.cpp:8101
#define SF2_GLOWMAPS_DISABLED
Definition: ship.h:494
void shipfx_blow_up_model(object *obj, int model, int submodel, int ndebris, vec3d *exp_center)
Definition: shipfx.cpp:374
void hud_set_wingman_status_dead(int wing_index, int wing_pos)
int current_wave
Definition: ship.h:1522
int CLOAKMAP
Definition: ship.cpp:14145
ubyte nondark_colors[MAX_NONDARK_COLORS][3]
Definition: ship.h:1359
unsigned short ushort
Definition: pstypes.h:63
ship_subsys * targeted_subsys
Definition: ship.h:344
void ship_obj_list_remove(int index)
Definition: ship.cpp:490
char subobj_name[MAX_NAME_LEN]
Definition: model.h:172
float max_weapon_regen_per_second
Definition: ship.h:1278
afterburner fail (no fuel when aburn pressed)
Definition: gamesnd.h:92
int ship_return_subsys_path_normal(ship *shipp, ship_subsys *ss, vec3d *gsubpos, vec3d *norm)
Definition: ship.cpp:14837
void ship_do_cargo_hidden(ship *shipp, int from_network)
Definition: ship.cpp:16190
float vm_vec_copy_normalize(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:427
void clone(const ship_info &other)
Definition: ship.cpp:670
float model_get_radius(int modelnum)
Definition: modelread.cpp:3105
void physics_apply_whack(vec3d *impulse, vec3d *pos, physics_info *pi, matrix *orient, float mass)
Definition: physics.cpp:776
bool shader_effect_active
Definition: ship.h:769
#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 dock_evaluate_all_docked_objects(object *objp, dock_function_info *infop, void(*function)(object *, dock_function_info *))
Definition: objectdock.cpp:285
float fog_start_dist
Definition: ship.h:1031
void RemHookVars(unsigned int num,...)
Definition: scripting.cpp:754
#define OF_PHYSICS
Definition: object.h:105
float thruster_frame
Definition: weapon.h:189
int splodeingtexture
void ship_secondary_changed(ship *sp)
Definition: ship.cpp:16053
int ship_info_index
Definition: ship.h:539
float death_fx_r_mult
Definition: ship.h:1242
GLfloat GLfloat p
Definition: Glext.h:8373
char name[NAME_LENGTH]
Definition: ship.h:1489
float slide_accel_time_const
Definition: physics.h:63
#define MULTIPLAYER_MASTER
Definition: multi.h:130
#define MAX_REINFORCEMENTS
Definition: ship.h:58
void queued_animation_correct(queued_animation *qa)
Definition: modelanim.cpp:372
char * missile_banks
Definition: ship.h:1179
#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
Definition: ai.h:198
texture_info textures[TM_NUM_TYPES]
Definition: model.h:671
GLenum src
Definition: Glext.h:5917
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
void ship_clear_cockpit_displays()
Definition: ship.cpp:7385
#define MSS_FLAG_TURRET_SALVO
Definition: model.h:120
int Player_ship_class
Definition: ship.cpp:157
void ship_add_cockpit_display(cockpit_display_info *display, int cockpit_model_num)
Definition: ship.cpp:7409
#define SIF_KNOSSOS_DEVICE
Definition: ship.h:912
int secondary_animation_done_time[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:154
#define ASK_HELP_SHIELD_PERCENT
Definition: ship.cpp:15629
#define SIF_TRANSPORT
Definition: ship.h:890
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
float glide_cap
Definition: ship.h:1407
vec3d afterburner_max_vel
Definition: ship.h:1281
#define SIF_AWACS
Definition: ship.h:910
ship_subsys * last_targeted_subobject[MAX_PLAYERS]
Definition: ship.h:631
int bay_doors_parent_shipnum
Definition: ship.h:782
#define PF_DEAD_DAMP
Definition: physics.h:24
int MessageBox(HWND h, const char *s1, const char *s2, int i)
#define SF2_AFTERBURNER_LOCKED
Definition: ship.h:499
int departure_delay
Definition: ship.h:621
float afterburner_max_reverse_vel
Definition: physics.h:93
#define SIF_FIGHTER
Definition: ship.h:885
void g3_start_instance_matrix(const vec3d *pos, const matrix *orient, bool set_api=true)
Definition: 3dsetup.cpp:249
int num_turrets_attacking(object *turret_parent, int target_objnum)
Definition: aicode.cpp:2137
#define TMAP_FLAG_TEXTURED
Definition: tmapper.h:36
float burst_delay
Definition: weapon.h:533
particle_effect damage_spew
Definition: ship.h:1251
int Viewer_mode
Definition: systemvars.cpp:28
int bank
Definition: beam.h:69
#define NUM_SHIP_SUBSYSTEMS_PER_SET
Definition: ship.cpp:90
char TVT_wing_names[MAX_TVT_WINGS][NAME_LENGTH]
Definition: ship.cpp:141
void gamesnd_play_error_beep()
Definition: gamesnd.cpp:1159
int model_anim_match_type(char *p)
Definition: modelanim.cpp:38
matrix moment_of_inertia
Definition: model.h:789
#define MSS_FLAG_FOV_EDGE_CHECK
Definition: model.h:127
#define CHA_SECONDARYFIRE
Definition: scripting.h:72
int static_rand(int num)
Return a pseudo random 32 bit value given a reasonably small number.
Definition: staticrand.cpp:38
void model_set_thrust(int model_num=-1, mst_info *mst=NULL)
#define MESSAGE_WINGMAN_SCREAM
#define WIF_HOMING
Definition: weapon.h:129
#define timestamp_elapsed(stamp)
Definition: timer.h:102
SCP_vector< DamageTypeStruct > Damage_types
Definition: ship.cpp:171
float debris_min_hitpoints
Definition: ship.h:1264
SCP_vector< float > shield_quadrant
Definition: object.h:159
SCP_vector< species_info > Species_info
float Player_rearm_eta
Definition: hud.cpp:179
float GetPiercingLimit(int damage_type_idx)
Definition: ship.cpp:18163
float normal_variance
Definition: particle.h:114
#define PF_SLIDE_ENABLED
Definition: physics.h:21
void draw_beam(vec3d *start, vec3d *end, float width, float intensity=1.0f, float offset=0.0f)
Definition: grbatch.cpp:362
DCF(t_rad,"Sets weapon tracer radius")
Definition: ship.cpp:10609
#define LOG_CARGO_REVEALED
Definition: missionlog.h:37
#define MAX_MAN_THRUSTERS
Definition: ship.h:521
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
SCP_vector< exited_ship > Ships_exited
Definition: ship.cpp:152
vec3d * get_subsystem_world_pos(object *parent_obj, ship_subsys *subsys, vec3d *world_pos)
Definition: hudtarget.cpp:4395
float afterburner_max_reverse_vel
Definition: ship.h:1287
void model_interp_set_animated_effect_and_timer(int effect_num=0, float effect_timer=0.0f)
int ab_count
Definition: ship.h:760
int ship_get_default_orders_accepted(ship_info *sip)
Definition: ship.cpp:5480
#define PI
Definition: pstypes.h:303
#define WIF_PUNCTURE
Definition: weapon.h:49
char docker[NAME_LENGTH]
int ship_is_getting_locked(ship *shipp)
Definition: ship.cpp:15129
#define MAX_WEAPONS
Definition: globals.h:71
void ship_add_ship_type_kill_count(int ship_info_index)
Definition: ship.cpp:14462
hull_check pos
Definition: lua.cpp:5050
#define STI_SHIP_WARP_PUSHABLE
Definition: ship.h:998
#define PLAYER_FLAGS_DIST_WARNING
Definition: player.h:43
char * maneuverability_str
Definition: ship.h:1170
int thruster_bitmap
Definition: ship.h:678
void error_display(int error_level, char *format,...)
Definition: parselo.cpp:308
int Game_skill_level
Definition: fredstubs.cpp:170
void parse_weapon_targeting_priorities()
Definition: ship.cpp:18548
int secondary_glow_bitmap
Definition: model.h:1293
const GLfloat * m
Definition: Glext.h:10319
#define SIF2_MODEL_POINT_SHIELDS
Definition: ship.h:936
void ship_draw_shield(object *objp)
Definition: shield.cpp:879
#define SF2_ALWAYS_DEATH_SCREAM
Definition: ship.h:496
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
float ship_recoil_modifier
Definition: ship.h:1307
float thruster_dist_len_factor
Definition: ship.h:1391
float warpin_radius
Definition: ship.h:1207
void free_strings()
Definition: ship.cpp:1264
int model_instance_num
Definition: model.h:1109
#define VALID_FNAME(x)
Definition: pstypes.h:418
int armor_type_idx
Definition: ship.h:796
int Iff_traitor
Definition: iff_defs.cpp:22
#define SWARM_DEFAULT_NUM_MISSILES_FIRED
Definition: swarm.h:49
int debris_damage_type_idx
Definition: ship.h:1263
void parse_engine_wash(bool replace)
Definition: ship.cpp:546
ship_obj * get_ship_obj_ptr_from_index(int index)
Definition: ship.cpp:513
#define SND_PRIORITY_TRIPLE_INSTANCE
Definition: sound.h:29
void change_ship_type(int n, int ship_type, int by_sexp)
Definition: ship.cpp:9983
#define AI_GOAL_CHASE
Definition: aigoals.h:29
int turret_best_weapon
Definition: ship.h:333
int n_guns
Definition: model.h:768
int n_high
Definition: ship.h:978
void ship_process_targeting_lasers()
Definition: ship.cpp:11611
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
vec3d pos
Definition: model.h:408
void ai_process(object *obj, int ai_index, float frametime)
Definition: aicode.cpp:14232
void shield_set_strength(object *objp, float strength)
#define CHA_ONWPSELECTED
Definition: scripting.h:67
#define ETS_RECHARGE_RATE
Definition: hudets.h:38
float auto_shield_spread
Definition: ship.h:1311
void ship_add_ship_type_count(int ship_info_index, int num)
Definition: ship.cpp:14449
int subsys_update_stamp
Definition: multi_obj.h:42
int departure_path_mask
Definition: ship.h:619
#define SIF_NOT_FLYABLE
Definition: ship.h:946
#define STI_AI_ACCEPT_PLAYER_ORDERS
Definition: ship.h:1004
int ai_active_dock
Definition: ship.h:1038
#define i2fl(i)
Definition: floating.h:32
const int Num_piercing_effect_types
Definition: ship.cpp:17787
int arc_next_time
Definition: ship.h:714
void asteroid_hit(object *pasteroid_obj, object *other_obj, vec3d *hitpos, float damage)
Definition: asteroid.cpp:1368
void vm_vec_scale_sub2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:293
float max_rad
Definition: ship.h:980
particle_effect knossos_end_particles
Definition: ship.h:1253
void model_clear_submodel_instances(int model_instance_num)
Definition: modelread.cpp:4696
#define MESSAGE_HELP
char * ship_return_orders(char *outbuf, ship *sp)
Definition: ship.cpp:15201
bool draw_secondary_models[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:1303
#define MAX_SHIP_CONTRAILS
Definition: ship.h:520
GLint GLsizei count
Definition: Gl.h:1491
int parse_modular_table(const char *name_check, void(*parse_callback)(const char *filename), int path_type, int sort_type)
Definition: parselo.cpp:4205
int team
Definition: ship.h:857
SCP_vector< int > ai_actively_pursues
Definition: ship.h:1040
#define timestamp_rand(a, b)
Definition: timer.h:92
#define SUBSYSTEM_SOLAR
Definition: model.h:60
void ai_free_slot(int ai_index)
Frees a currently used AI slot.
Definition: ai.cpp:50
void gr_bitmap(int _x, int _y, int resize_mode)
Definition: 2d.cpp:1303
#define AT_TYPE_LOAD
Definition: ship.cpp:17865
float rearm_rate
Definition: weapon.h:389
flag_def_list DifficultyScaleTypes[]
Definition: ship.cpp:17803
float energy_consumed
Definition: weapon.h:383
int arrival_anchor
Definition: ship.h:612
mp_vert * verts
Definition: model.h:419
#define GR_BITBLT_MODE_NORMAL
Definition: 2d.h:351
#define MSS_FLAG_ALLOW_VANISHING
Definition: model.h:132
#define SIF2_MASK
Definition: ship.h:956
int ai_get_slot(int shipnum)
Returns index of free AI slot.
Definition: ai.cpp:30
#define MSS_FLAG_IGNORE_IF_DEAD
Definition: model.h:131
matrix * A
Definition: lua.cpp:444
const float PI_2
Definition: pstypes.h:307
float shockwave_shake_amp
Definition: physics.h:65
float secondary_glow_rad_factor
Definition: model.h:1303
#define AT_TYPE_REVERSE_CUTOFF
Definition: ship.cpp:17857
SCP_vector< int > weapon_class
Definition: ship.h:829
#define WT_KNOSSOS
Definition: ship.h:1107
#define SHIPS_LIMIT
Definition: globals.h:38
eye view_positions[MAX_EYES]
Definition: model.h:753
int ammo_low_complaint_count
Definition: ship.h:795
int path_num
Definition: model.h:222
GLenum GLsizei len
Definition: Glext.h:6283
SCP_vector< int > ship_type
Definition: ship.h:827
object * Player_obj
Definition: object.cpp:56
weapon_explosions Weapon_explosions
Definition: weapons.cpp:101
flag_def_list ArmorTypeConstants[]
Definition: ship.cpp:17823
matrix world_to_turret_matrix
Definition: ship.h:386
void player_stop_repair_sound()
void set_animated_effect(int effect_num, float timer)
#define SUBSYSTEM_ACTIVATION
Definition: model.h:62
void flak_pick_range(object *objp, vec3d *firing_pos, vec3d *predicted_target_pos, float weapon_subsys_strength)
Definition: flak.cpp:37
void ParseData()
Definition: ship.cpp:18201
int triggered_rotation_index
Definition: ship.h:376
float damage_ship[MAX_DAMAGE_SLOTS]
Definition: ship.h:863
void shipfx_large_blowup_level_init()
Definition: shipfx.cpp:2009
int thruster_glow_anim_load(generic_anim *ga)
Definition: ship.cpp:8506
int ships_inited
Definition: ship.cpp:129
#define SF_CARGO_REVEALED
Definition: ship.h:456
ushort debris_net_sig
Definition: ship.h:800
#define WIF_HOMING_JAVELIN
Definition: weapon.h:55
int Num_reinforcements
Definition: ship.cpp:121
Definition: ai.h:134
uint flags2
Definition: ship.h:645
#define AI_GOAL_REARM_REPAIR
Definition: aigoals.h:49
vec3d prev_ramp_vel
Definition: physics.h:69
#define MAX_IFFS
Definition: globals.h:34
#define MSS_FLAG_FOV_REQUIRED
Definition: model.h:128
vec3d arc_pts[MAX_SHIP_ARCS][2]
Definition: ship.h:711
#define SF_DYING
Definition: ship.h:447
float recoil_modifier
Definition: weapon.h:449
int praise_self_count
Definition: player.h:165
char filename[MAX_FILENAME_LEN]
bool ship_has_sound(object *objp, GameSoundsIndex id)
Specifies if a ship has a custom sound for the specified id.
Definition: ship.cpp:18636
int temp
Definition: lua.cpp:4996
float val_f
Definition: multilag.cpp:561
int kamikaze_damage
Definition: ai.h:523
void dc_printf(const char *format,...)
Prints the given char string to the debug console.
Definition: console.cpp:358
int special_hitpoints
Definition: ship.h:593
#define PF_AFTERBURNER_ON
Definition: physics.h:20
void stuff_ubyte(ubyte *i)
Definition: parselo.cpp:2646
float w_start
Definition: trails.h:24
void render(int flags, float radius=0.0f)
Definition: grbatch.cpp:523
int nturrets
Definition: model.h:409
int ship_index[MAX_SHIPS_PER_WING]
Definition: ship.h:1531
bool hud_retail
Definition: ship.h:1449
SCP_vector< int > explosion_bitmap_anims
Definition: ship.h:1047
ship_collision_physics collision_physics
Definition: ship.h:1234
int team_change_time
Definition: ship.h:815
float radius
Definition: ship.h:1100
#define P2_OF_FORCE_SHIELDS_ON
Definition: missionparse.h:504
bool is_minimum_GLSL_version()
Definition: gropengl.cpp:2064
#define WIF2_BALLISTIC
Definition: weapon.h:84
polymodel * pm
Definition: lua.cpp:1598
void model_clear_instance_info(submodel_instance_info *sii)
Definition: modelread.cpp:4669
void find_and_stuff_optional(char *id, int *addr, int f_type, char *strlist[], int max, char *description)
Definition: parselo.cpp:3229
float max_delay
Definition: weapon.h:360
WarpEffect * warpin_effect
Definition: ship.h:575
void shipfx_large_blowup_render(ship *shipp)
Definition: shipfx.cpp:2374
w_bank * missile_banks
Definition: model.h:773
float rad
Definition: particle.h:65
float forward_decel
Definition: ship.h:1202
int special_exp_damage
Definition: ship.h:585
float subsys_repair_rate
Definition: ship.h:1321
int departure_cue
Definition: ship.h:620
int primary_bank_rearm_time[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:125
int ship_get_subsys_index(ship *sp, char *ss_name, int error_bypass)
Definition: ship.cpp:13421
int stuff_bool_list(bool *blp, int max_bools)
Definition: parselo.cpp:2591
#define MAX(a, b)
Definition: pstypes.h:299
#define MR_DEPRECATED_NO_LIGHTING
Definition: model.h:901
int thruster_distortion_bitmap
Definition: ship.h:687
void ship_set_warp_effects(object *objp, ship_info *sip)
Definition: ship.cpp:5500
float closeup_zoom
Definition: ship.h:1328
int shader_effect_num
Definition: ship.h:766
float awacs_intensity
Definition: model.h:215
SCP_map< SCP_string, team_color > Team_Colors
Definition: alphacolors.cpp:15
#define OS_TURRET_GUN_ROTATION
Definition: objectsnd.h:19
int arrival_path_mask
Definition: ship.h:613
int iff_matches_mask(int team, int mask)
Definition: iff_defs.cpp:628
char filename[MAX_FILENAME_LEN]
Definition: generic.h:52
float delta_bank_const
Definition: ship.h:1195
int shockwave_decay
Definition: physics.h:86
#define SF2_PRIMITIVE_SENSORS
Definition: ship.h:483
SCP_vector< int > explosion_bitmap_anims
Definition: ship.h:1247
void light_set_shadow(int state)
Definition: lighting.cpp:638
float variance
Definition: ship.h:985
float glide_accel_mult
Definition: ship.h:1409
int respawn_priority
Definition: ship.h:544
int primary_bank_start_ammo[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:122
int subsys_set(int objnum, int ignore_subsys_info)
Definition: ship.cpp:6253
int bm_unload(int handle, int clear_render_targets, bool nodebug)
Unloads a bitmap's data, but not the bitmap info.
Definition: bmpman.cpp:2890
char filename[MAX_FILENAME_LEN]
Definition: generic.h:18
int scan_time
Definition: ship.h:1351
#define OBJ_NONE
Definition: object.h:31
int turret_swarm_info_index[MAX_TFP]
Definition: ship.h:355
float mass
Definition: physics.h:39
char targeting_laser_bank
Definition: ship.h:560
int parse_ship_template()
Definition: ship.cpp:1788
void cscrew_maybe_fire_missile(int shipnum)
Definition: corkscrew.cpp:71
int shield_armor_type_idx
Definition: ship.h:1404
void shipfx_flash_create(object *objp, int model_num, vec3d *gun_pos, vec3d *gun_dir, int is_primary, int weapon_info_index)
Definition: shipfx.cpp:1231
uint create_time
Definition: ship.h:701
float afterburner_trail_life
Definition: ship.h:1372
#define DISABLE_SUBSYSTEM_ITEM
Definition: hudsquadmsg.h:59
int ship_name_lookup(const char *name, int inc_players)
Definition: ship.cpp:12900
void ship_model_update_instance(object *objp)
Definition: ship.cpp:13072
void ship_do_cap_subsys_cargo_hidden(ship *shipp, ship_subsys *subsys, int from_network)
Definition: ship.cpp:16210
#define WIF3_NOLINK
Definition: weapon.h:117
#define FIREBALL_EXPLOSION_MEDIUM
Definition: fireballs.h:28
int arrival_cue
Definition: ship.h:614
#define MT_FORWARD
Definition: ship.h:1086
float max_hull_strength
Definition: ship.h:1309
int swarm_missile_bank
Definition: ship.h:672
float vel_inherit_amount
Definition: weapon.h:356
#define OS_SUBSYS_ROTATION
Definition: objectsnd.h:23
int ship_render_mode
Definition: ship.cpp:414
float a_end
Definition: trails.h:27
#define SHIP_MULTITEXT_LENGTH
Definition: ship.cpp:661
void ship_fire_tracer(int weapon_objnum)
Definition: ship.cpp:10647
float length
Definition: ship.h:1099
#define ABORT_REARM_REPAIR_ITEM
Definition: hudsquadmsg.h:50
#define REGULAR_WEAPON
Definition: ship.h:958
int ship_get_random_team_ship(int team_mask, int flags, float max_dist)
Definition: ship.cpp:14682
#define SF2_STEALTH
Definition: ship.h:485
#define TRIGGER_TYPE_PRIMARY_BANK
Definition: modelanim.h:32
uint flags
Definition: object.h:151
int last_fired_weapon_signature
Definition: ship.h:146
float radius
Definition: object.h:154
#define SF_SHIP_HAS_SCREAMED
Definition: ship.h:468
particle * particle_create(particle_info *pinfo)
Definition: particle.cpp:105
model_path * paths
Definition: model.h:784
float optimum_range
Definition: model.h:233
#define SUBSYSTEM_MAX
Definition: model.h:64
int current_tertiary_bank
Definition: ship.h:108
char * GetName()
Definition: jumpnode.cpp:117
int ship_find_exited_ship_by_signature(int signature)
Definition: ship.cpp:5353
void set_predicted_enemy_pos(vec3d *predicted_enemy_pos, object *pobjp, vec3d *enemy_pos, vec3d *enemy_vel, ai_info *aip)
Definition: aicode.cpp:6397
void snd_stop(int sig)
Definition: sound.cpp:875
int model_create_instance(bool is_ship, int model_num)
Definition: modelread.cpp:2855
bool bay_doors_need_open
Definition: ship.h:781
#define PLAYER_DEATH_DELTA_TIME
Definition: ship.cpp:8860
#define TRIGGER_TYPE_SECONDARY_BANK
Definition: modelanim.h:33
float min_delay
Definition: weapon.h:361
float w_end
Definition: trails.h:25
#define FORMATION_ITEM
Definition: hudsquadmsg.h:43
mission The_mission
missile_obj Missile_obj_list
Definition: weapons.cpp:84
#define MSS_FLAG_CARRY_SHOCKWAVE
Definition: model.h:125
int tex_id
Definition: ship.h:1096
#define MESSAGE_AWACS_75
int ship_select_next_secondary(object *objp)
Definition: ship.cpp:12550
#define SHIP_REPAIR_SUBSYSTEM_RATE
Definition: ship.cpp:8761
char * Lightning_types[]
Definition: ship.cpp:641
int check_warn_timestamp
Definition: player.h:137
#define AI_GOAL_DESTROY_SUBSYSTEM
Definition: aigoals.h:34
vec3d pnt
Definition: model.h:440
int collision_lod
Definition: ship.h:1187
int stop_snd
Definition: ship.h:1094
float rotdamp
Definition: ship.h:1194
fix time_gone
Definition: ship.h:1525
#define SF_TRIGGER_DOWN
Definition: ship.h:462
Definition: shipfx.h:233
void ship_close()
Definition: ship.cpp:14146
void ct_ship_delete(ship *shipp)
float h
Definition: pstypes.h:111
#define WIF2_LOCAL_SSM
Definition: weapon.h:87
int turret_enemy_objnum
Definition: ship.h:337
int model_num
Definition: lua.cpp:4996
int model_instance_num
Definition: lua.cpp:4996
int bm_make_render_target(int width, int height, int flags)
Creates a render target as close to the desired resolution as possible.
Definition: bmpman.cpp:2267
float thruster_frame
Definition: ship.h:679
int current_cmeasure
Definition: ship.h:652
void set_object_number(int num)
int ship_lock_threat(ship *sp)
Definition: ship.cpp:15163
int stuff_float_list(float *flp, int max_floats)
Definition: parselo.cpp:2988
char type
Definition: object.h:146
flag_def_list Armor_flags[]
Definition: ship.cpp:173
void find_submodel_instance_world_point(vec3d *outpnt, int model_instance_num, int submodel_num, const matrix *objorient, const vec3d *objpos)
Definition: modelread.cpp:4431
void compute_slew_matrix(matrix *orient, angles *a)
Definition: ship.cpp:6546
#define MSS_FLAG_USE_MULTIPLE_GUNS
Definition: model.h:116
void parse_ai_target_priorities()
Definition: ship.cpp:18408
vec3d max_rotvel
Definition: ship.h:1197
int Show_fpaths
Definition: ship.cpp:6629
int background
Definition: ship.h:261
int target_priority[32]
Definition: model.h:230
vec3d vmd_zero_vector
Definition: vecmat.cpp:24
support_ship_info support_ships
Definition: missionparse.h:143
vec3d max_vel
Definition: ship.h:1196
float distortion_rad_factor
Definition: model.h:1306
void diag_printf(char *format,...)
Definition: parselo.cpp:229
#define NOISE_NUM_FRAMES
Definition: systemvars.h:130
#define PARTICLE_SMOKE2
Definition: particle.h:53
int ship_start_render_cockpit_display(int cockpit_display_num)
Definition: ship.cpp:7494
SCP_vector< int > objsnd_num
Definition: object.h:162
#define MR_NO_GLOWMAPS
Definition: model.h:886
float damage
Definition: weapon.h:363
generic_bitmap texture
Definition: trails.h:30
int rearm_release_delay
Definition: ai.h:501
int warpout_time
Definition: ship.h:1221
void ship_set_hud_cockpit_targets()
Definition: ship.cpp:7479
int oo_arrive_time_count[MAX_SHIPS]
Definition: multi_obj.cpp:40
#define STI_AI_ATTEMPT_BROADSIDE
Definition: ship.h:1006
char overhead_filename[MAX_FILENAME_LEN]
Definition: ship.h:1341
float glide_accel_mult
Definition: physics.h:91
#define FALSE
Definition: pstypes.h:400
#define SF_FROM_PLAYER_WING
Definition: ship.h:457
float death_roll_r_mult
Definition: ship.h:1241
float autoaim_fov
Definition: ship.h:817
float afterburner_recover_rate
Definition: ship.h:1285
object * shooter
Definition: beam.h:77
float landing_max_rot_angle
Definition: ship.h:1133
int multi_find_player_by_object(object *objp)
Definition: multiutil.cpp:500
char filename[FILESPEC_LENGTH]
Definition: model.h:734
#define wp(p)
Definition: modelsinc.h:69
ship explosion 1
Definition: gamesnd.h:75
#define MC_ONLY_SPHERE
Definition: model.h:1171
int radar_image_2d_idx
Definition: ship.h:1428
#define SF2_SECONDARIES_LOCKED
Definition: ship.h:493
#define MAX_NAME_LEN
Definition: model.h:29
#define MSS_FLAG_TURRET_MATRIX
Definition: model.h:110
char * Cargo_names[]
ubyte reverse
Definition: particle.h:73
void ship_parse_post_cleanup()
Definition: ship.cpp:4983
#define PLAYER_MAX_WARN_DIST
Definition: ship.cpp:15455
net_player Net_players[MAX_PLAYERS]
Definition: multi.cpp:93
int ship_bools
Definition: ship.h:1022
float armor_factor
Definition: weapon.h:378
float max_shield_recharge
Definition: ship.h:599
#define AT_TYPE_MULTIPLICATIVE
Definition: ship.cpp:17853
int n_fade_out_sections
Definition: trails.h:31
int praise_count
Definition: player.h:152
int num_hits
Definition: ship.h:581
int attached_objnum
Definition: particle.h:71
void parse_ship_type()
Definition: ship.cpp:4591
int targeting_priorities[32]
Definition: weapon.h:542
ushort pos_chksum
Definition: multi_obj.h:43
int death_time
Definition: ship.h:570
int timer_get_milliseconds()
Definition: timer.cpp:150
SCP_vector< ai_target_priority > Ai_tp_list
Definition: ship.cpp:396
void gameseq_post_event(int event)
void clear()
Definition: ship.cpp:17768
#define CHECK_THEN_FREE(attribute)
Definition: ship.cpp:1256
bool disables_rendering
Definition: ship.h:2003
#define SUBSYS_WEAPONS_STR_FIRE_OK
Definition: subsysdamage.h:26
float max_shield_recharge
Definition: ship.h:1318
#define MR_NO_FOGGING
Definition: model.h:884
vec3d pnt[MAX_DOCK_SLOTS]
Definition: model.h:530
#define F_MULTITEXT
Definition: parselo.h:43
void ship_blow_up_area_apply_blast(object *exp_objp)
Definition: ship.cpp:7926
int shield_recharge_index
Definition: ship.h:637
particle_effect impact_spew
Definition: ship.h:1250
matrix * orient
Definition: model.h:1112
#define GM_CAMPAIGN_MODE
Definition: systemvars.h:29
int burst_counter[MAX_SHIP_PRIMARY_BANKS+MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:156
float ship_calculate_rearm_duration(object *objp)
Definition: ship.cpp:13537
#define stricmp(s1, s2)
Definition: config.h:271
#define SIF2_NO_ETS
Definition: ship.h:931
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
int weapon_create_group_id()
Definition: weapons.cpp:6481
SCP_vector< glow_point_bank_override >::iterator get_glowpoint_bank_override_by_name(const char *name)
Definition: modelread.cpp:5550
void ship_reset_disabled_physics(object *objp, int ship_class)
Definition: ship.cpp:8974
const GLdouble * v
Definition: Glext.h:5322
char * Mp
Definition: parselo.cpp:48
#define OBJ_GHOST
Definition: object.h:39
int primary_bank_slot_count[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:131
matrix vmd_identity_matrix
Definition: vecmat.cpp:28
flag_def_list Man_types[]
Definition: ship.cpp:179
void weapon_detonate(object *objp)
Definition: weapons.cpp:6450
#define timestamp_valid(stamp)
Definition: timer.h:104
const int num_ai_tgt_weapon_flags
Definition: ship.cpp:394
#define AI_GOAL_FORM_ON_WING
Definition: aigoals.h:35
float max_subsys_repair_val
Definition: missionparse.h:107
SCP_vector< engine_wash_info > Engine_wash_info
Definition: ship.cpp:143
int wing_lookup(const char *name)
Definition: ship.cpp:12736
#define SIF_NO_FRED
Definition: ship.h:914
int cmeasure_count
Definition: ship.h:651
int ntris
Definition: model.h:568
int armor_type_idx
Definition: model.h:181
#define CF_TYPE_MODELS
Definition: cfile.h:49
float weapon_submodel_rotate_vel
Definition: weapon.h:517
int praise_self_timestamp
Definition: player.h:166
int parent_sig
Definition: object.h:148
int end_death_time
Definition: ship.h:571
int damage_type_add(char *name)
Definition: ship.cpp:17749
#define AT_TYPE_ADDITIVE
Definition: ship.cpp:17852
char ship_name[NAME_LENGTH]
Definition: ship.h:604
int allowed_weapons[MAX_WEAPON_TYPES]
Definition: ship.h:1330
int ai_class
Definition: ship.h:1229
fix radar_visible_since
Definition: ship.h:806
#define MR_DEPRECATED_SHOW_THRUSTERS
Definition: model.h:898
#define PLAYER_WARN_DELTA_TIME
Definition: ship.cpp:8859
int special_exp_shockwave_speed
Definition: ship.h:590
const int Num_ship_flags
Definition: ship.cpp:322
int arrival_distance
Definition: ship.h:611
vec3d cockpit_offset
Definition: ship.h:1182
void push_transform(vec3d *pos, matrix *orient)
float afterburner_burn_rate
Definition: ship.h:1284
#define SF_WARP_NEVER
Definition: ship.h:461
bool model_get_team_color(team_color *clr, const SCP_string &team, const SCP_string &secondaryteam, fix timestamp, int fadetime)
#define SF2_NO_SECONDARY_LOCKON
Definition: ship.h:510
generic_anim thruster_flame
Definition: weapon.h:537
thrust_pair_bitmap thruster_distortion_info
Definition: ship.h:1384
int selection_effect
Definition: ship.h:1342
int last_fired_weapon_index
Definition: ship.h:145
int Num_player_weapon_precedence
Definition: weapons.cpp:124
float vert_thrust
Definition: physics.h:74
int myrand()
Definition: systemvars.cpp:102
void physics_ship_init(object *objp)
Definition: ship.cpp:5366
#define SUBSYS_WEAPONS_STR_FIRE_FAIL
Definition: subsysdamage.h:27
float GetDamage(float damage_applied, int in_damage_type_idx, float diff_dmg_scale)
Definition: ship.cpp:17923
float heading
Definition: physics.h:81
float thruster02_glow_rad_factor
Definition: ship.h:1387
SCP_vector< ship_type_info > Ship_types
Definition: ship.cpp:168
void model_set_detail_level(int n)
float rof_scaler
Definition: ship.h:399
#define TRIGGER_TYPE_INITIAL
Definition: modelanim.h:27
unsigned int obj_flags
Definition: ship.h:831
void hud_save_restore_camera_data(int save)
Called to save and restore the 3D camera settings.
Definition: hud.cpp:3656
#define SHIP_OBJ_USED
Definition: ship.cpp:159
float sup_shield_repair_rate
Definition: ship.h:1324
#define LOG_SELF_DESTRUCTED
Definition: missionlog.h:39
float convergence_distance
Definition: ship.h:1437
GLuint GLuint end
Definition: Gl.h:1502
int debris_damage_type_idx
Definition: ship.h:799
int Default_cmeasure_index
Definition: weapons.cpp:117
int thrusters_start[MAX_MAN_THRUSTERS]
Definition: ship.h:788
void shipfx_large_blowup_init(ship *shipp)
Definition: shipfx.cpp:2019
int n_detail_levels
Definition: model.h:737
int last_fired_weapon_info_index
Definition: ship.h:346
#define AT_CONSTANT_PI
Definition: ship.h:185
Missle lock (non-looping)
Definition: gamesnd.h:69
engine sound (as heard in cockpit)
Definition: gamesnd.h:72
char * gun_mounts
Definition: ship.h:1178
int burst_shots
Definition: weapon.h:532
char name[MAX_NAME_LEN]
Definition: model.h:171
#define SSF_NO_SS_TARGETING
Definition: ship.h:281
bool draw_distortion
Definition: ship.h:1394
int ship_fire_primary_debug(object *objp)
Definition: ship.cpp:10386
float b
Definition: pstypes.h:111
#define SIF_CORVETTE
Definition: ship.h:908
SCP_map< GameSoundsIndex, int > ship_sounds
Definition: ship.h:1423
#define ADT_DIFF_SCALE_MANUAL
Definition: ship.h:175
void model_unload(int modelnum, int force=0)
Definition: modelread.cpp:162
particle_effect split_particles
Definition: ship.h:1252
float secondary_point_reload_pct[MAX_SHIP_SECONDARY_BANKS][MAX_SLOTS]
Definition: ship.h:784
void send_subsystem_cargo_hidden_packet(ship *shipp, int index)
Definition: multimsgs.cpp:4626
int num_slots
Definition: model.h:525
char sub_name[NAME_LENGTH]
Definition: modelanim.h:78
float afterburner_trail_alpha_factor
Definition: ship.h:1371
GLuint res
Definition: Glext.h:9084
int current_target_is_locked
Definition: ai.h:490
int arrival_delay
Definition: ship.h:615
float auto_shield_spread_min_span
Definition: ship.h:1314
int project_point_onto_bbox(const vec3d *mins, const vec3d *maxs, const vec3d *start, vec3d *box_pt)
Definition: fvi.cpp:1107
char new_texture[MAX_FILENAME_LEN]
Definition: missionparse.h:326
float aspect_locked_time
Definition: ai.h:476
Not visible on the radar.
Definition: radarsetup.h:89
float hull_repair_rate
Definition: ship.h:1320
int num_primary_banks
Definition: ship.h:1293
int flags
Definition: ship.h:1556
#define RAW_INTEGER_TYPE
Definition: parselo.h:52
#define MESSAGE_TIME_SOON
float forward_thrust
Definition: physics.h:72
float max_shield_regen_per_second
Definition: ship.h:1277
afterburner burn sound (looped)
Definition: gamesnd.h:90
#define MSS_FLAG_FIRE_ON_NORMAL
Definition: model.h:117
#define AT_CONSTANT_BAD_VAL
Definition: ship.h:180
scoring_struct stats
Definition: player.h:127
#define MESSAGE_STRAY_WARNING_FINAL
#define MAX_SHIP_OBJS
Definition: ship.cpp:160
#define MSS_FLAG_NO_LIVE_DEBRIS
Definition: model.h:130
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
void ship_set_default_weapons(ship *shipp, ship_info *sip)
Definition: ship.cpp:9392
int ai_bools
Definition: ship.h:1037
flag_def_list Ship_flags[]
Definition: ship.cpp:272
#define strcpy_s(...)
Definition: safe_strings.h:67
ArmorType(char *in_name)
Definition: ship.cpp:18191
int Is_standalone
Definition: systemvars.cpp:59
int next_swarm_path
Definition: ship.h:670
void ship_maybe_play_primary_fail_sound()
Definition: ship.cpp:10524
int ship_get_type(char *output, ship_info *sip)
Definition: ship.cpp:5464
float min_rad
Definition: ship.h:969
float field_of_fire
Definition: weapon.h:494
#define SEF_CARGO_KNOWN
Definition: ship.h:848
generic_anim thruster_bitmap
Definition: ship.h:968
void ship_level_init()
Definition: ship.cpp:5226
#define SSSF_DEAD
Definition: ship.h:303
#define CHA_DEATH
Definition: scripting.h:45
#define REAR_QUAD
Definition: objectshield.h:17
#define MAX_SHIP_DETAIL_LEVELS
Definition: ship.h:57
char * tech_desc
Definition: ship.h:1174
#define SEF_DEPARTED
Definition: ship.h:847
float debris_min_rotspeed
Definition: ship.h:1261
#define MSS_FLAG_CREWPOINT
Definition: model.h:109
void shipfx_emit_spark(int n, int sn)
Definition: shipfx.cpp:1417
SCP_vector< int > ship_class
Definition: ship.h:828