FS2_Open
Open source remastering of the Freespace 2 engine
missionparse.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #ifdef _WIN32
13 #include <windows.h>
14 #endif
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <assert.h>
20 #include <stdarg.h>
21 #include <setjmp.h>
22 
23 
24 #include "ai/aigoals.h"
25 #include "asteroid/asteroid.h"
26 #include "bmpman/bmpman.h"
27 #include "cfile/cfile.h"
28 #include "cmdline/cmdline.h"
29 #include "debris/debris.h"
30 #include "gamesnd/eventmusic.h"
31 #include "globalincs/alphacolors.h"
32 #include "globalincs/linklist.h"
33 #include "hud/hudescort.h"
34 #include "hud/hudets.h"
35 #include "hud/hudwingmanstatus.h"
36 #include "iff_defs/iff_defs.h"
37 #include "io/timer.h"
38 #include "jumpnode/jumpnode.h"
39 #include "lighting/lighting.h"
40 #include "localization/localize.h"
41 #include "math/fvi.h"
42 #include "math/staticrand.h"
45 #include "mission/missiongoals.h"
46 #include "mission/missionhotkey.h"
47 #include "mission/missionlog.h"
48 #include "mission/missionmessage.h"
49 #include "mission/missionparse.h"
52 #include "missionui/redalert.h"
53 #include "mod_table/mod_table.h"
54 #include "nebula/neb.h"
55 #include "nebula/neblightning.h"
56 #include "network/multi.h"
57 #include "network/multi_endgame.h"
58 #include "network/multi_respawn.h"
59 #include "network/multimsgs.h"
60 #include "network/multiutil.h"
61 #include "object/parseobjectdock.h"
62 #include "object/waypoint.h"
63 #include "parse/generic_log.h"
64 #include "parse/parselo.h"
65 #include "parse/scripting.h"
66 #include "playerman/player.h"
67 #include "popup/popup.h"
68 #include "popup/popupdead.h"
69 #include "ship/ship.h"
70 #include "ship/shipfx.h"
71 #include "ship/shiphit.h"
72 #include "sound/ds.h"
73 #include "starfield/nebula.h"
74 #include "starfield/starfield.h"
75 #include "weapon/weapon.h"
76 
77 LOCAL struct {
83 
85 
88 
89 int Mission_palette; // index into Nebula_palette_filenames[] of palette file to use for mission
90 int Nebula_index; // index into Nebula_filenames[] of nebula to use in mission.
92 int Num_cargo = 0;
97 int Player_starts = 1;
100 
104 
108 
109 // alternate ship type names
112 
113 // callsigns
116 
117 #define SHIP_WARP_TIME 5.0f // how many seconds it takes for ship to warp in
118 
119 // the ship arrival list will contain a list of ships that are yet to arrive. This
120 // list could also include ships that are part of wings!
121 p_object Ship_arrival_list; // for linked list of ships to arrive later
122 
123 // all the ships that we parse
125 
126 
127 // list for arriving support ship
132 
133 #define MIN_SUBSYS_STATUS_SIZE 25
137 
139 
141 
142 // variables for player start in single player
146 
147 // name of all ships to use while parsing a mission (since a ship might be referenced by
148 // something before that ship has even been loaded yet)
151 
153 
156 
157 //XSTR:OFF
158 
160  "Nebula01",
161  "Nebula02",
162  "Nebula03"
163 };
164 
166  "Nebfull01",
167  "Nebfull02",
168  "Nebfull03"
169 };
170 
171 // Note: Nebula_colors[] and Nebula_palette_filenames are linked via index numbers
173  "Red",
174  "Blue",
175  "Gold",
176  "Purple",
177  "Maroon",
178  "Green",
179  "Grey blue",
180  "Violet",
181  "Grey Green",
182 };
183 
185  "Chase",
186  "Evade",
187  "Get behind",
188  "Stay Near",
189  "Still",
190  "Guard",
191  "Avoid",
192  "Waypoints",
193  "Dock",
194  "None",
195  "Big Ship",
196  "Path",
197  "Be Rearmed",
198  "Safety",
199  "Evade Weapon",
200  "Strafe",
201  "Play Dead",
202  "Bay Emerge",
203  "Bay Depart",
204  "Sentry Gun",
205  "Warp Out",
206 };
207 
210 
211 char *Ship_class_names[MAX_SHIP_CLASSES]; // to be filled in from Ship_info array
212 
214  "Fighter", "Fighter Wing", "Cargo", "Cargo Wing", "Largeship",
215  "Largeship Wing", "Capital", "Planet", "Asteroid Field", "Waypoint",
216  "Support Ship", "Freighter(no cargo)", "Freighter(has cargo)",
217  "Freighter Wing(no cargo)", "Freighter Wing(has cargo)", "Installation",
218  "Bomber", "Bomber Wing", "Cruiser", "Cruiser Wing", "Unknown", "Unknown Wing",
219  "Player Fighter", "Player Fighter Wing", "Player Bomber", "Player Bomber Wing",
220  "Knossos Device", "Transport Wing", "Corvette", "Gas Miner", "Awacs", "Supercap", "Sentry Gun", "Jump Node", "Transport"
221 };
222 
224  "Shields Critical", "Engines Damaged", "Fully Operational",
225 };
226 
228  "Damaged", "Disabled", "Corroded",
229 };
230 
232  "Weapons", "Engines", "Cable TV",
233 };
234 
235 // definitions for arrival locations for ships/wings
237  "Hyperspace", "Near Ship", "In front of ship", "Docking Bay",
238 };
239 
241  "Hyperspace", "Docking Bay",
242 };
243 
245  "Primary", "Secondary", "Bonus",
246 };
247 
249  "Attack/Protect",
250  "Repair/Rearm",
251 };
252 
254  "Single Player Only",
255  "Multiplayer Only",
256  "Single/Multi Player",
257  "Training mission"
258 };
259 
261  "cargo-known",
262  "ignore-count",
263  "protect-ship",
264  "reinforcement",
265  "no-shields",
266  "escort",
267  "player-start",
268  "no-arrival-music",
269  "no-arrival-warp",
270  "no-departure-warp",
271  "locked",
272  "invulnerable",
273  "hidden-from-sensors",
274  "scannable",
275  "kamikaze",
276  "no-dynamic",
277  "red-alert-carry",
278  "beam-protect-ship",
279  "flak-protect-ship",
280  "laser-protect-ship",
281  "missile-protect-ship",
282  "guardian",
283  "special-warp",
284  "vaporize",
285  "stealth",
286  "friendly-stealth-invisible",
287  "don't-collide-invisible",
288 };
289 
291  "primitive-sensors",
292  "no-subspace-drive",
293  "nav-carry-status",
294  "affected-by-gravity",
295  "toggle-subsystem-scanning",
296  "targetable-as-bomb",
297  "no-builtin-messages",
298  "primaries-locked",
299  "secondaries-locked",
300  "no-death-scream",
301  "always-death-scream",
302  "nav-needslink",
303  "hide-ship-name",
304  "set-class-dynamically",
305  "lock-all-turrets",
306  "afterburners-locked",
307  "force-shields-on",
308  "immobile",
309  "no-ets",
310  "cloaked",
311  "ship-locked",
312  "weapons-locked",
313  "scramble-messages",
314  "no-collide",
315  "no-disabled-self-destruct",
316 };
317 
319  "true",
320  "false",
321  "always true", // disabled
322  "always false",
323  "first repeat",
324  "last repeat",
325  "first trigger",
326  "last trigger",
327  "state change",
328 };
329 
330 
331 //XSTR:ON
332 
334 
337 
339 
340 // definitions for timestamps for eval'ing arrival/departure cues
344 
345 #define ARRIVAL_TIMESTAMP 2000 // every 2 seconds
346 #define DEPARTURE_TIMESTAMP 2200 // every 2.2 seconds -- just to be a little different
347 
348 // calculates a "unique" file signature as a ushort (checksum) and an int (file length)
349 // the amount of The_mission we're going to checksum
350 // WARNING : do NOT call this function on the server - it will overwrite goals, etc
351 #define MISSION_CHECKSUM_SIZE (NAME_LENGTH + NAME_LENGTH + 4 + DATE_TIME_LENGTH + DATE_TIME_LENGTH)
352 
353 // timers used to limit arrival messages and music
354 #define ARRIVAL_MUSIC_MIN_SEPARATION 60000
355 #define ARRIVAL_MESSAGE_MIN_SEPARATION 30000
356 
357 #define ARRIVAL_MESSAGE_DELAY_MIN 2000
358 #define ARRIVAL_MESSAGE_DELAY_MAX 3000
359 
360 static int Allow_arrival_music_timestamp;
361 static int Allow_arrival_message_timestamp;
362 static int Arrival_message_delay_timestamp;
363 
364 // multi TvT
365 static int Allow_arrival_music_timestamp_m[2];
366 static int Allow_arrival_message_timestamp_m[2];
367 static int Arrival_message_delay_timestamp_m[2];
368 
369 extern fix game_get_overall_frametime(); // for texture animation
370 
371 // local prototypes
373 void post_process_mission();
377 int mission_set_arrival_location(int anchor, int location, int distance, int objnum, int path_mask, vec3d *new_pos, matrix *new_orient);
378 int get_anchor(char *name);
381 void mission_set_wing_arrival_location( wing *wingp, int num_to_set );
382 int parse_lookup_alt_name(char *name);
383 void parse_init(bool basic = false);
388 
389 static bool Warned_about_team_out_of_range;
390 
391 // Goober5000
395 
396 // Goober5000 - FRED import
397 void convertFSMtoFS2();
398 
399 
400 MONITOR(NumShipArrivals)
401 MONITOR(NumShipDepartures)
402 
403 
404 // Goober5000
405 void parse_custom_bitmap(const char *expected_string_640, const char *expected_string_1024, char *string_field_640, char *string_field_1024)
406 {
407  int found640 = 0, found1024 = 0;
408  strcpy(string_field_640, "");
409  strcpy(string_field_1024, "");
410 
411  // custom mission loading background, or whatever
412  if (optional_string(expected_string_640))
413  {
414  found640 = 1;
415  stuff_string(string_field_640, F_NAME, MAX_FILENAME_LEN);
416  }
417  if (optional_string(expected_string_1024))
418  {
419  found1024 = 1;
420  stuff_string(string_field_1024, F_NAME, MAX_FILENAME_LEN);
421  }
422 
423  // error testing
424  if (Fred_running && (found640) && !(found1024))
425  {
426  Warning(LOCATION, "Mission: found an entry for %s but not a corresponding entry for %s!", expected_string_640, expected_string_1024);
427  }
428  if (Fred_running && !(found640) && (found1024))
429  {
430  Warning(LOCATION, "Mission: found an entry for %s but not a corresponding entry for %s!", expected_string_1024, expected_string_640);
431  }
432 }
433 
434 void parse_mission_info(mission *pm, bool basic = false)
435 {
436  int i;
437  char game_string[NAME_LENGTH];
438 
439  // Goober5000
440  skip_to_start_of_string("#Mission Info");
441 
442  required_string("#Mission Info");
443 
444  required_string("$Version:");
445  stuff_float(&pm->version);
446  if (pm->version != MISSION_VERSION)
447  mprintf(("Older mission, should update it (%.2f<-->%.2f)\n", pm->version, MISSION_VERSION));
448 
449  required_string("$Name:");
451 
452  required_string("$Author:");
454 
455  required_string("$Created:");
457 
458  required_string("$Modified:");
460 
461  required_string("$Notes:");
463 
464  if (optional_string("$Mission Desc:"))
466  else
467  strcpy_s(pm->mission_desc, NOX("No description\n"));
468 
469  pm->game_type = MISSION_TYPE_SINGLE; // default to single player only
470  if ( optional_string("+Game Type:")) {
471  // HACK HACK HACK -- stuff_string was changed to *not* ignore carriage returns. Since the
472  // old style missions may have carriage returns, deal with it here.
474  stuff_string(game_string, F_NAME, NAME_LENGTH);
475  for ( i = 0; i < OLD_MAX_GAME_TYPES; i++ ) {
476  if ( !stricmp(game_string, Old_game_types[i]) ) {
477 
478  // this block of code is now old mission compatibility code. We specify game
479  // type in a different manner than before.
480  if ( i == OLD_GAME_TYPE_SINGLE_ONLY )
482  else if ( i == OLD_GAME_TYPE_MULTI_ONLY )
484  else if ( i == OLD_GAME_TYPE_SINGLE_MULTI )
486  else if ( i == OLD_GAME_TYPE_TRAINING )
488  else
489  Int3();
490 
491  if ( pm->game_type & MISSION_TYPE_MULTI )
493 
494  break;
495  }
496  }
497  }
498 
499  if ( optional_string("+Game Type Flags:") ) {
500  stuff_int(&pm->game_type);
501  }
502 
503  pm->flags = 0;
504  if (optional_string("+Flags:")){
505  stuff_int(&pm->flags);
506  }
507 
508  // nebula mission stuff
509  Neb2_awacs = -1.0f;
510  if(optional_string("+NebAwacs:")){
512  }
513  if(optional_string("+Storm:")){
515 
516  if (!basic)
518  }
519  Neb2_fog_near_mult = 1.0f;
520  Neb2_fog_far_mult = 1.0f;
521  if(optional_string("+Fog Near Mult:")){
523  }
524  if(optional_string("+Fog Far Mult:")){
526  }
527 
528  // Goober5000 - ship contrail speed threshold
530  if (optional_string("$Contrail Speed Threshold:")){
532  }
533 
534  // get the number of players if in a multiplayer mission
535  pm->num_players = 1;
536  if ( pm->game_type & MISSION_TYPE_MULTI ) {
537  if ( optional_string("+Num Players:") ) {
538  stuff_int( &(pm->num_players) );
539  }
540  }
541 
542  // get the number of respawns
543  pm->num_respawns = 0;
544  if ( pm->game_type & MISSION_TYPE_MULTI ) {
545  if ( optional_string("+Num Respawns:") ){
546  stuff_int( (int*)&(pm->num_respawns) );
547  }
548  }
549 
550  The_mission.max_respawn_delay = -1;
551  if ( pm->game_type & MISSION_TYPE_MULTI ) {
552  if ( optional_string("+Max Respawn Time:") ){
553  stuff_int( &The_mission.max_respawn_delay );
554  }
555  }
556 
557  if ( optional_string("+Red Alert:")) {
558  int temp;
559  stuff_int(&temp);
560 
561  if (temp)
563  else
565  }
567 
568  if ( optional_string("+Scramble:")) {
569  int temp;
570  stuff_int(&temp);
571 
572  if (temp)
574  else
576  }
577 
578  // if we are just requesting basic info then skip everything else. the reason
579  // for this is to make sure that we don't modify things outside of the mission struct
580  // that might not get reset afterwards (like what can happen in the techroom) - taylor
581  //
582  // NOTE: this can be dangerous so be sure that any get_mission_info() call (defaults to basic info) will
583  // only reference data parsed before this point!! (like current FRED2 and game code does)
584  if (basic)
585  return;
586 
587 
588  // set up support ships
590  pm->support_ships.arrival_anchor = -1;
594  pm->support_ships.max_subsys_repair_val = 100.0f; //ASSUMPTION: full repair capabilities
595  pm->support_ships.max_support_ships = -1; // infinite
597  pm->support_ships.ship_class = -1;
598  pm->support_ships.tally = 0;
600 
601  // for each species, store whether support is available
602  for (int species = 0; species < (int)Species_info.size(); species++)
603  {
604  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it)
605  {
606  if ((it->flags & SIF_SUPPORT) && (it->species == species))
607  {
608  pm->support_ships.support_available_for_species |= (1 << species);
609  break;
610  }
611  }
612  }
613 
614  if ( optional_string("+Disallow Support:"))
615  {
616  int temp;
617  stuff_int(&temp);
618 
619  pm->support_ships.max_support_ships = (temp > 0) ? 0 : -1;
620  }
621 
622  if ( optional_string("+Hull Repair Ceiling:"))
623  {
624  float temp;
625  stuff_float(&temp);
626 
627  //ONLY set max_hull_repair_val if the value given is valid -C
628  if (temp <= 100.0f && temp >= 0.0f) {
630  }
631  }
632 
633  if ( optional_string("+Subsystem Repair Ceiling:"))
634  {
635  float temp;
636  stuff_float(&temp);
637 
638  //ONLY set max_subsys_repair_val if the value given is valid -C
639  if (temp <= 100.0f && temp >= 0.0f) {
641  }
642  }
643 
644  if (optional_string("+All Teams Attack")){
645  Mission_all_attack = 1;
646  } else {
647  Mission_all_attack = 0;
648  }
649 
650  // Maybe delay the player's entry.
651  if (optional_string("+Player Entry Delay:")) {
652  float temp;
653 
654  stuff_float(&temp);
655  Assert(temp >= 0.0f);
656  Entry_delay_time = fl2f(temp);
657  }
658  else
659  {
660  Entry_delay_time = 0;
661  }
662 
663  if (optional_string("+Viewer pos:")){
664  stuff_vec3d(&Parse_viewer_pos);
665  }
666 
667  if (optional_string("+Viewer orient:")){
668  stuff_matrix(&Parse_viewer_orient);
669  }
670 
671  // possible squadron reassignment
672  strcpy_s(pm->squad_name, "");
673  strcpy_s(pm->squad_filename, "");
674  if(optional_string("+SquadReassignName:")){
676  if(optional_string("+SquadReassignLogo:")){
678  }
679  }
680  // always clear out squad reassignments if not single player
682  strcpy_s(pm->squad_name, "");
683  strcpy_s(pm->squad_filename, "");
684  }
685  // reassign the player
686  else {
687  if(!Fred_running && (Player != NULL) && (pm->squad_name[0] != '\0') && (Game_mode & GM_CAMPAIGN_MODE)){
688  mprintf(("Reassigning player to squadron %s\n", pm->squad_name));
691  }
692  }
693 
694 
695  // wing stuff by Goober5000 ------------------------------------------
696  // the wing name arrays are initialized in ship_level_init
697  if (optional_string("$Starting wing names:"))
698  {
700  }
701 
702  if (optional_string("$Squadron wing names:"))
703  {
705  }
706 
707  if (optional_string("$Team-versus-team wing names:"))
708  {
710  }
711  // end of wing stuff -------------------------------------------------
712 
713 
714  // set up the Num_teams variable accoriding to the game_type variable'
715  Num_teams = 1; // assume 1
716 
717  // multiplayer team v. team games have two teams. If we have three teams, we need to use
718  // a new mission mode!
720  Num_teams = 2;
721  }
722 
723  // Goober5000 - made this into a function since we use much the same technique for the briefing background
724  parse_custom_bitmap("$Load Screen 640:", "$Load Screen 1024:", pm->loading_screen[GR_640], pm->loading_screen[GR_1024]);
725 
726  strcpy_s(pm->skybox_model, "");
727  if (optional_string("$Skybox Model:"))
728  {
730  }
731 
733  if (optional_string("+Skybox Orientation:"))
734  {
736  }
737 
738  if (optional_string("+Skybox Flags:")){
739  pm->skybox_flags = 0;
740  stuff_int(&pm->skybox_flags);
741  }else{
743  }
744 
745  // Goober5000 - AI on a per-mission basis
746  The_mission.ai_profile = &Ai_profiles[Default_ai_profile];
747  if (optional_string("$AI Profile:"))
748  {
749  int index;
750  char temp[NAME_LENGTH];
751 
753  index = ai_profile_lookup(temp);
754 
755  if (index >= 0)
756  The_mission.ai_profile = &Ai_profiles[index];
757  else
758  WarningEx(LOCATION, "Mission: %s\nUnknown AI profile %s!", pm->name, temp );
759  }
760 
761  Assert( The_mission.ai_profile != NULL );
762 
763  // Kazan - player use AI at start?
765  Player_use_ai = 1;
766 
767  pm->sound_environment.id = -1;
768  if (optional_string("$Sound Environment:")) {
769  char preset[65] = { '\0' };
770  stuff_string(preset, F_NAME, sizeof(preset)-1);
771 
772  int preset_id = ds_eax_get_preset_id(preset);
773 
774  if (preset_id >= 0) {
775  sound_env_get(&pm->sound_environment, preset_id);
776  }
777 
778  // NOTE: values will be clamped properly when the effect is actually set
779 
780  if (optional_string("+Volume:")) {
782  }
783 
784  if (optional_string("+Damping:")) {
786  }
787 
788  if (optional_string("+Decay Time:")) {
790  }
791  }
792 }
793 
795 {
796  char temp[NAME_LENGTH];
797  Assert(pm != NULL);
798 
799  // alternate type names begin here
801  if(optional_string("#Alternate Types:")){
802  // read them all in
803  while(!optional_string("#end")){
804  required_string("$Alt:");
806 
807  // maybe store it
808  mission_parse_add_alt(temp);
809  }
810  }
811 
812  // callsigns begin here
814  if(optional_string("#Callsigns:")){
815  // read them all in
816  while(!optional_string("#end")){
817  required_string("$Callsign:");
819 
820  // maybe store it
822  }
823  }
824 
825  Player_starts = 0;
826  required_string("#Players");
827 
828  while (required_string_either("#Objects", "$")){
829  parse_player_info2(pm);
830  }
831 }
832 
834 {
835  char str[NAME_LENGTH];
836  int nt, i, total, list[MAX_SHIP_CLASSES * 4], list2[MAX_WEAPON_TYPES * 4];
837  team_data *ptr;
838 
839  // read in a ship/weapon pool for each team.
840  for ( nt = 0; nt < Num_teams; nt++ ) {
841  int num_choices;
842 
843  ptr = &Team_data[nt];
844  // get the shipname for single player missions
845  // MWA -- make this required later!!!!
846  if ( optional_string("$Starting Shipname:") )
848 
849  required_string("$Ship Choices:");
851 
852  // make sure we have a count which is divisible by four since four values are added for each ship
853  Assert((total%4) == 0);
854 
855  num_choices = 0;
856 
857  // only every 4th entry is actually a ship class.
858  for (i=0; i<total; i += 4) {
859  // in a campaign, see if the player is allowed the ships or not. Remove them from the
860  // pool if they are not allowed
862  if ( !Campaign.ships_allowed[list[i]] )
863  continue;
864  }
865 
866  ptr->ship_list[num_choices] = list[i];
867  // if the list isn't set by a variable leave the variable name empty
868  if (list[i+1] == -1) {
869  strcpy_s(ptr->ship_list_variables[num_choices], "") ;
870  }
871  else {
872  strcpy_s(ptr->ship_list_variables[num_choices],Sexp_variables[list[i+1]].variable_name);
873  }
874  ptr->ship_count[num_choices] = list[i+2];
875  ptr->loadout_total += list[i+2];
876 
877  // if the list isn't set by a variable leave the variable name empty
878  if (list[i+3] == -1) {
879  strcpy_s(ptr->ship_count_variables[num_choices], "");
880  }
881  else {
882  strcpy_s(ptr->ship_count_variables[num_choices], Sexp_variables[list[i+3]].variable_name);
883  }
884  num_choices++;
885  }
886  ptr->num_ship_choices = num_choices;
887 
888  ptr->default_ship = -1;
889  if (optional_string("+Default_ship:")) {
891  ptr->default_ship = ship_info_lookup(str);
892  if (-1 == ptr->default_ship) {
893  WarningEx(LOCATION, "Mission: %s\nUnknown default ship %s! Defaulting to %s.", pm->name, str, Ship_info[ptr->ship_list[0]].name );
894  ptr->default_ship = ptr->ship_list[0]; // default to 1st in list
895  }
896  // see if the player's default ship is an allowable ship (campaign only). If not, then what
897  // do we do? choose the first allowable one?
899  if ( !(Campaign.ships_allowed[ptr->default_ship]) ) {
900  for (i = 0; i < static_cast<int>(Ship_info.size()); i++ ) {
901  if ( Campaign.ships_allowed[i] ) {
902  ptr->default_ship = i;
903  break;
904  }
905  }
906  Assertion( i < static_cast<int>(Ship_info.size()), "Mission: %s: Could not find a valid default ship.\n", pm->name );
907  }
908  }
909  }
910 
911  if (ptr->default_ship == -1) // invalid or not specified, make first in list
912  ptr->default_ship = ptr->ship_list[0];
913 
914  required_string("+Weaponry Pool:");
916 
917  // make sure we have a count which is divisible by four since four values are added for each ship
918  Assert((total%4) == 0);
919  num_choices = 0;
920 
921  for (i = 0; i < total; i += 4) {
922  // in a campaign, see if the player is allowed the weapons or not. Remove them from the
923  // pool if they are not allowed
925  if ( !Campaign.weapons_allowed[list2[i]] ) {
926  continue;
927  }
928  }
929 
930  if ( (list2[i] >= 0) && (list2[i] < MAX_WEAPON_TYPES) ) {
931  // always allow the pool to be added in FRED, it is a verbal warning
932  // to let the mission dev know about the problem
933  if ( (Weapon_info[list2[i]].wi_flags & WIF_PLAYER_ALLOWED) || Fred_running ) {
934  ptr->weaponry_pool[num_choices] = list2[i];
935  ptr->weaponry_count[num_choices] = list2[i+2];
936 
937  // if the list isn't set by a variable leave the variable name empty
938  if (list2[i+1] == -1) {
939  strcpy_s(ptr->weaponry_pool_variable[num_choices], "");
940  }
941  else {
942  strcpy_s(ptr->weaponry_pool_variable[num_choices], Sexp_variables[list2[i+1]].variable_name);
943  }
944 
945  // if the list isn't set by a variable leave the variable name empty
946  if (list2[i+3] == -1) {
947  strcpy_s(ptr->weaponry_amount_variable[num_choices], "");
948  }
949  else {
950  strcpy_s(ptr->weaponry_amount_variable[num_choices], Sexp_variables[list2[i+3]].variable_name);
951  }
952  num_choices++;
953  }
954  else {
955  WarningEx(LOCATION, "Weapon '%s' in weapon pool isn't allowed on player loadout! Ignoring it ...\n", Weapon_info[i].name);
956  }
957  }
958  }
959  ptr->num_weapon_choices = num_choices;
960 
961  memset(ptr->weapon_required, 0, MAX_WEAPON_TYPES * sizeof(bool));
962  if (optional_string("+Required for mission:"))
963  {
964  int num_weapons;
965  int weapon_list_buf[MAX_WEAPON_TYPES];
966  num_weapons = stuff_int_list(weapon_list_buf, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
967 
968  for (i = 0; i < num_weapons; i++)
969  ptr->weapon_required[weapon_list_buf[i]] = true;
970  }
971  }
972 
973  if ( nt != Num_teams )
974  Error(LOCATION, "Not enough ship/weapon pools for mission. There are %d teams and only %d pools.", Num_teams, nt);
975 }
976 
978 {
979  pm->cutscenes.clear();
980 
981  if (optional_string("#Cutscenes"))
982  {
983  mission_cutscene scene;
984 
985  while (!optional_string("#end"))
986  {
987  // this list should correspond to the MOVIE_* #defines
988  scene.type = optional_string_one_of(6,
989  "$Fiction Viewer Cutscene:",
990  "$Command Brief Cutscene:",
991  "$Briefing Cutscene:",
992  "$Pre-game Cutscene:",
993  "$Debriefing Cutscene:",
994  "$Campaign End Cutscene:");
995 
996  // no more cutscenes specified?
997  if (scene.type < 0)
998  break;
999 
1000  // get the cutscene file
1002 
1003  // get the sexp if we have one
1004  if (optional_string("+formula:"))
1005  scene.formula = get_sexp_main();
1006  else
1007  scene.formula = Locked_sexp_true;
1008 
1009  // add it
1010  pm->cutscenes.push_back(scene);
1011  }
1012  }
1013 }
1014 
1016 {
1017  if (optional_string("#Plot Info"))
1018  {
1019  char dummy_filespec[FILESPEC_LENGTH];
1020  char dummy_name[NAME_LENGTH];
1021 
1022  required_string("$Tour:");
1023  stuff_string(dummy_name, F_NAME, NAME_LENGTH);
1024 
1025  required_string("$Pre-Briefing Cutscene:");
1026  stuff_string(dummy_filespec, F_FILESPEC, FILESPEC_LENGTH);
1027 
1028  required_string("$Pre-Mission Cutscene:");
1029  stuff_string(dummy_filespec, F_FILESPEC, FILESPEC_LENGTH);
1030 
1031  required_string("$Next Mission Success:");
1032  stuff_string(dummy_name, F_NAME, NAME_LENGTH);
1033 
1034  required_string("$Next Mission Partial:");
1035  stuff_string(dummy_name, F_NAME, NAME_LENGTH);
1036 
1037  required_string("$Next Mission Failure:");
1038  stuff_string(dummy_name, F_NAME, NAME_LENGTH);
1039  }
1040 }
1041 
1043 {
1044  char junk[4096];
1045 
1046  if ( !optional_string("#Briefing Info") )
1047  return;
1048 
1049  required_string("$Briefing Voice 1:");
1050  stuff_string(junk, F_FILESPEC, sizeof(junk));
1051 
1052  required_string("$Briefing Text 1:");
1053  stuff_string(junk, F_MULTITEXTOLD, sizeof(junk));
1054 
1055  required_string("$Briefing Voice 2:");
1056  stuff_string(junk, F_FILESPEC, sizeof(junk));
1057 
1058  required_string("$Briefing Text 2:");
1059  stuff_string(junk, F_MULTITEXTOLD, sizeof(junk));
1060 
1061  required_string("$Briefing Voice 3:");
1062  stuff_string(junk, F_FILESPEC, sizeof(junk));
1063 
1064  required_string("$Briefing Text 3:");
1065  stuff_string(junk, F_MULTITEXTOLD, sizeof(junk));
1066 
1067  required_string("$Debriefing Voice 1:");
1068  stuff_string(junk, F_FILESPEC, sizeof(junk));
1069 
1070  required_string("$Debriefing Text 1:");
1071  stuff_string(junk, F_MULTITEXTOLD, sizeof(junk));
1072 
1073  required_string("$Debriefing Voice 2:");
1074  stuff_string(junk, F_FILESPEC, sizeof(junk));
1075 
1076  required_string("$Debriefing Text 2:");
1077  stuff_string(junk, F_MULTITEXTOLD, sizeof(junk));
1078 
1079  required_string("$Debriefing Voice 3:");
1080  stuff_string(junk, F_FILESPEC, sizeof(junk));
1081 
1082  required_string("$Debriefing Text 3:");
1083  stuff_string(junk, F_MULTITEXTOLD, sizeof(junk));
1084 }
1085 
1090 {
1091  int i, index, num;
1092  char *ch;
1093  char temp[NAME_LENGTH];
1094 
1096 
1097  if ( !optional_string("#Music") ) {
1098  return;
1099  }
1100 
1101  required_string("$Event Music:");
1103 
1104  // Goober5000
1105  if (optional_string("$Substitute Event Music:"))
1107 
1108  required_string("$Briefing Music:");
1110 
1111  // Goober5000
1112  if (optional_string("$Substitute Briefing Music:"))
1114 
1115  // old stuff, apparently
1116  if (optional_string("$Debriefing Success Music:"))
1117  {
1120  if ((index >= 0) && ((Spooled_music[index].flags & SMF_VALID) || Fred_running)) {
1122  }
1123  }
1124 
1125  // not old, just added since it makes sense
1126  if (optional_string("$Debriefing Average Music:"))
1127  {
1130  if ((index >= 0) && ((Spooled_music[index].flags & SMF_VALID) || Fred_running)) {
1132  }
1133  }
1134 
1135  // old stuff
1136  if (optional_string("$Debriefing Fail Music:"))
1137  {
1140  if ((index >= 0) && ((Spooled_music[index].flags & SMF_VALID) || Fred_running)) {
1142  }
1143  }
1144 
1145  // new stuff
1146  if (optional_string("$Fiction Viewer Music:"))
1147  {
1150  }
1151 
1152  // Goober5000 - if briefing not specified in import, default to BRIEF1
1153  if (!stricmp(pm->briefing_music_name, "none") && (flags & MPF_IMPORT_FSM))
1154  strcpy_s(pm->briefing_music_name, "BRIEF1");
1155 
1156  // Goober5000 - old way of grabbing substitute music, but here for reverse compatibility
1157  if (optional_string("$Substitute Music:"))
1158  {
1160  Mp++;
1162  }
1163 
1164  // Goober5000 - if the mission is being imported, the substitutes are the specified tracks
1165  // (with FS1 prefixes) and we generate new specified tracks
1166  if (flags & MPF_IMPORT_FSM)
1167  {
1168  // no specified music?
1169  if (!stricmp(pm->event_music_name, "none"))
1170  goto done_event_music;
1171 
1172  // set the FS1 equivalent as the substitute
1175 
1176  // if we have Marauder, it's in FS2 as Deuteronomy, so we're done
1177  if (!stricmp(pm->event_music_name, "7: Marauder") && event_music_get_soundtrack_index("5: Deuteronomy") >= 0)
1178  {
1179  strcpy_s(pm->event_music_name, "5: Deuteronomy");
1180  goto done_event_music;
1181  }
1182 
1183  // search for something with the same track number
1184  strcpy_s(temp, pm->event_music_name);
1185  ch = strchr(temp, ':');
1186  if (ch != NULL)
1187  {
1188  *(ch + 1) = '\0';
1189 
1190  for (i = 0; i < Num_soundtracks; i++)
1191  {
1192  if (!strncmp(temp, Soundtracks[i].name, strlen(temp)))
1193  {
1195  goto done_event_music;
1196  }
1197  }
1198  }
1199 
1200  // last resort: pick a random track out of the 7 FS2 soundtracks
1201  num = (Num_soundtracks < 7) ? Num_soundtracks : 7;
1202  strcpy_s(pm->event_music_name, Soundtracks[rand() % num].name);
1203 
1204 
1205 done_event_music:
1206 
1207 
1208  // no specified music?
1209  if (!stricmp(pm->briefing_music_name, "none"))
1210  goto done_briefing_music;
1211 
1212  // set the FS1 equivalent as the substitute
1215 
1216  // Choco Mousse is the FS1 title soundtrack, so use Aquitaine in FS2
1217  if (!stricmp(pm->briefing_music_name, "Choco Mousse") && event_music_get_spooled_music_index("Aquitaine") >= 0)
1218  {
1219  strcpy_s(pm->briefing_music_name, "Aquitaine");
1220  goto done_briefing_music;
1221  }
1222 
1223  // we might have a match with the same track number
1225  goto done_briefing_music;
1226 
1227  // last resort: pick a random track out of the first 7 FS2 briefings (the regular ones)...
1228  num = (Num_music_files < 7) ? Num_music_files : 7;
1229  strcpy_s(pm->briefing_music_name, Spooled_music[rand() % num].name);
1230 
1231 
1232 done_briefing_music:
1233 
1234  /* NO-OP */ ;
1235  }
1236 
1237 
1238  // set the soundtrack, preferring the substitute in FS2 (not FRED!)
1240  if ((index >= 0) && (Soundtracks[index].flags & EMF_VALID) && !Fred_running)
1241  {
1243  }
1244  else
1245  {
1247  }
1248 
1249  // set the briefing, preferring the substitute in FS2 (not FRED!)
1251  if ((index >= 0) && (Spooled_music[index].flags & SMF_VALID) && !Fred_running)
1252  {
1254  }
1255  else
1256  {
1258  }
1259 }
1260 
1265 {
1267 
1268  if (optional_string("#Fiction Viewer"))
1269  {
1270  bool fiction_viewer_loaded = false;
1271 
1272  while (check_for_string("$File:"))
1273  {
1274  fiction_viewer_stage stage;
1275  memset(&stage, 0, sizeof(fiction_viewer_stage));
1276  stage.formula = Locked_sexp_true;
1277 
1278  required_string("$File:");
1280 
1281  if (optional_string("$Font:"))
1283 
1284  if (optional_string("$Voice:"))
1286 
1287  if (optional_string("$UI:"))
1289 
1290  parse_custom_bitmap("$Background 640:", "$Background 1024:", stage.background[GR_640], stage.background[GR_1024]);
1291 
1292  // get the sexp if we have one
1293  if (optional_string("$Formula:"))
1294  stage.formula = get_sexp_main();
1295 
1296  // now, store this stage
1297  Fiction_viewer_stages.push_back(stage);
1298 
1299  // see if this is the stage we want to display, then display it
1300  if (!Fred_running && !fiction_viewer_loaded && is_sexp_true(stage.formula))
1301  {
1303  fiction_viewer_loaded = true;
1304  }
1305  }
1306  }
1307 }
1308 
1313 {
1314  int stage;
1315 
1317  stage = 0;
1318 
1319  required_string("#Command Briefing");
1320 
1321  // Yarn - use the same code as for mission loading screens
1322  parse_custom_bitmap("$Background 640:", "$Background 1024:", Cur_cmd_brief->background[GR_640], Cur_cmd_brief->background[GR_1024]);
1323 
1324  while (optional_string("$Stage Text:")) {
1325  Assert(stage < CMD_BRIEF_STAGES_MAX);
1327 
1328  required_string("$Ani Filename:");
1330  if (optional_string("+Wave Filename:"))
1332  else
1333  Cur_cmd_brief->stage[stage].wave_filename[0] = 0;
1334 
1335  stage++;
1336  }
1337 
1338  Cur_cmd_brief->num_stages = stage;
1339 }
1340 
1342 {
1343  int i;
1344 
1345  cmd_brief_reset();
1346  // a hack follows because old missions don't have a command briefing
1347  if (required_string_either("#Command Briefing", "#Briefing"))
1348  return;
1349 
1350  for (i=0; i<Num_teams; i++) {
1352  parse_cmd_brief(pm);
1353  }
1354 }
1355 
1362 {
1363  int nt, i, j, stage_num = 0, icon_num = 0;
1364  brief_stage *bs;
1365  brief_icon *bi;
1366  briefing *bp;
1367 
1368  char not_used_text[MAX_ICON_TEXT_LEN];
1369 
1370  brief_reset();
1371 
1372  // MWA -- 2/3/98. we can now have multiple briefing and debriefings in a mission
1373  for ( nt = 0; nt < Num_teams; nt++ ) {
1374  if ( !optional_string("#Briefing") )
1375  break;
1376 
1377  bp = &Briefings[nt];
1378  required_string("$start_briefing");
1379 
1380  // Goober5000 - use the same code as for mission loading screens
1381  parse_custom_bitmap("$briefing_background_640:", "$briefing_background_1024:", bp->background[GR_640], bp->background[GR_1024]);
1382  parse_custom_bitmap("$ship_select_background_640:", "$ship_select_background_1024:", bp->ship_select_background[GR_640], bp->ship_select_background[GR_1024]);
1383  parse_custom_bitmap("$weapon_select_background_640:", "$weapon_select_background_1024:", bp->weapon_select_background[GR_640], bp->weapon_select_background[GR_1024]);
1384 
1385  required_string("$num_stages:");
1386  stuff_int(&bp->num_stages);
1388 
1389  stage_num = 0;
1390  while (required_string_either("$end_briefing", "$start_stage")) {
1391  required_string("$start_stage");
1392  Assert(stage_num < MAX_BRIEF_STAGES);
1393  bs = &bp->stages[stage_num++];
1394  required_string("$multi_text");
1395  stuff_string(bs->text, F_MULTITEXT, NULL);
1396  required_string("$voice:");
1398  required_string("$camera_pos:");
1399  stuff_vec3d(&bs->camera_pos);
1400  required_string("$camera_orient:");
1402  required_string("$camera_time:");
1403  stuff_int(&bs->camera_time);
1404 
1405  if ( optional_string("$num_lines:") ) {
1406  stuff_int(&bs->num_lines);
1407 
1408  if ( Fred_running ) {
1409  Assert(bs->lines!=NULL);
1410  } else {
1411  if ( bs->num_lines > 0 ) {
1412  bs->lines = (brief_line *)vm_malloc(sizeof(brief_line)*bs->num_lines);
1413  Assert(bs->lines!=NULL);
1414  }
1415  }
1416 
1417  for (i=0; i<bs->num_lines; i++) {
1418  required_string("$line_start:");
1419  stuff_int(&bs->lines[i].start_icon);
1420  required_string("$line_end:");
1421  stuff_int(&bs->lines[i].end_icon);
1422  }
1423  }
1424  else {
1425  bs->num_lines = 0;
1426  }
1427 
1428  required_string("$num_icons:");
1429  stuff_int(&bs->num_icons);
1430 
1431  if ( Fred_running ) {
1432  Assert(bs->icons!=NULL);
1433  } else {
1434  if ( bs->num_icons > 0 ) {
1435  bs->icons = (brief_icon *)vm_malloc(sizeof(brief_icon)*bs->num_icons);
1436  Assert(bs->icons!=NULL);
1437  }
1438  }
1439 
1440  if ( optional_string("$flags:") )
1441  stuff_int(&bs->flags);
1442  else
1443  bs->flags = 0;
1444 
1445  if ( optional_string("$formula:") )
1446  bs->formula = get_sexp_main();
1447  else
1448  bs->formula = Locked_sexp_true;
1449 
1450  Assert(bs->num_icons <= MAX_STAGE_ICONS );
1451 
1452  // static alias stuff - stupid, but it seems to be necessary
1453  static char *temp_team_names[MAX_IFFS];
1454  for (i = 0; i < Num_iffs; i++)
1455  temp_team_names[i] = Iff_info[i].iff_name;
1456 
1457  while (required_string_either("$end_stage", "$start_icon"))
1458  {
1459  required_string("$start_icon");
1460  Assert(icon_num < MAX_STAGE_ICONS);
1461  bi = &bs->icons[icon_num++];
1462 
1463  required_string("$type:");
1464  stuff_int(&bi->type);
1465 
1466  // Goober5000 - import
1467  if (flags & MPF_IMPORT_FSM)
1468  {
1469  // someone changed the jump node icon to a Knossos, so change it back
1470  if (bi->type == ICON_KNOSSOS_DEVICE)
1471  bi->type = ICON_JUMP_NODE;
1472 
1473  // change largeship to transport
1474  else if (bi->type == ICON_LARGESHIP)
1475  bi->type = ICON_TRANSPORT;
1476 
1477  // ditto
1478  else if (bi->type == ICON_LARGESHIP_WING)
1479  bi->type = ICON_TRANSPORT_WING;
1480  }
1481 
1482  find_and_stuff("$team:", &bi->team, F_NAME, temp_team_names, Num_iffs, "team name");
1483 
1484  find_and_stuff("$class:", &bi->ship_class, F_NAME, Ship_class_names, Ship_info.size(), "ship class");
1485 
1486  // Goober5000 - import
1487  if (flags & MPF_IMPORT_FSM)
1488  {
1489  // the Faustus is a largeship
1490  if (!strnicmp(Ship_info[bi->ship_class].name, "GTSC Faustus", 12))
1491  {
1492  if (bi->type == ICON_CRUISER)
1493  bi->type = ICON_LARGESHIP;
1494 
1495  else if (bi->type == ICON_CRUISER_WING)
1496  bi->type = ICON_LARGESHIP_WING;
1497  }
1498  // the Demon is a support ship :p
1499  else if (!strnicmp(Ship_info[bi->ship_class].name, "SD Demon", 8))
1500  {
1501  bi->type = ICON_SUPPORT_SHIP;
1502  }
1503  // the Hades is a supercap
1504  else if (!strnicmp(Ship_info[bi->ship_class].name, "GTD Hades", 9))
1505  {
1506  bi->type = ICON_SUPERCAP;
1507  }
1508  }
1509 
1510  required_string("$pos:");
1511  stuff_vec3d(&bi->pos);
1512 
1513  bi->label[0] = 0;
1514  if (optional_string("$label:"))
1516 
1517  if (optional_string("+id:")) {
1518  stuff_int(&bi->id);
1519  if (bi->id >= Cur_brief_id)
1520  Cur_brief_id = bi->id + 1;
1521 
1522  } else {
1523  bi->id = -1;
1524  for (i=0; i<stage_num-1; i++)
1525  for (j=0; j < bp->stages[i].num_icons; j++)
1526  {
1527  if (!stricmp(bp->stages[i].icons[j].label, bi->label))
1528  bi->id = bp->stages[i].icons[j].id;
1529  }
1530 
1531  if (bi->id < 0)
1532  bi->id = Cur_brief_id++;
1533  }
1534 
1535  bi->flags=0;
1536  int val;
1537  required_string("$hlight:");
1538  stuff_int(&val);
1539  if ( val>0 ) {
1540  bi->flags |= BI_HIGHLIGHT;
1541  }
1542 
1543  if (optional_string("$mirror:"))
1544  {
1545  stuff_int(&val);
1546  if ( val>0 ) {
1547  bi->flags |= BI_MIRROR_ICON;
1548  }
1549  }
1550 
1551  if (optional_string("$use wing icon:"))
1552  {
1553  stuff_int(&val);
1554  if ( val>0 ) {
1555  bi->flags |= BI_USE_WING_ICON;
1556  }
1557  }
1558 
1559  required_string("$multi_text");
1560  stuff_string(not_used_text, F_MULTITEXT, MAX_ICON_TEXT_LEN);
1561  required_string("$end_icon");
1562  } // end while
1563  Assert(bs->num_icons == icon_num);
1564  icon_num = 0;
1565  required_string("$end_stage");
1566  } // end while
1567 
1568  Assert(bp->num_stages == stage_num);
1569  required_string("$end_briefing");
1570  }
1571 
1572  if ( nt != Num_teams )
1573  Error(LOCATION, "Not enough briefings in mission file. There are %d teams and only %d briefings.", Num_teams, nt );
1574 }
1575 
1580 {
1581  int stage_num, nt;
1582  debriefing *db;
1583  debrief_stage *dbs;
1584 
1585  debrief_reset();
1586 
1587  // 2/3/98 -- MWA. We can now have multiple briefings and debriefings on a team
1588  for ( nt = 0; nt < Num_teams; nt++ ) {
1589 
1590  if ( !optional_string("#Debriefing_info") )
1591  break;
1592 
1593  stage_num = 0;
1594 
1595  db = &Debriefings[nt];
1596 
1597  // Yarn - use the same code as for mission loading screens
1598  parse_custom_bitmap("$Background 640:", "$Background 1024:", db->background[GR_640], db->background[GR_1024]);
1599 
1600  required_string("$Num stages:");
1601  stuff_int(&db->num_stages);
1603 
1604  while (required_string_either("#", "$Formula")) {
1605  Assert(stage_num < MAX_DEBRIEF_STAGES);
1606  dbs = &db->stages[stage_num++];
1607  required_string("$Formula:");
1608  dbs->formula = get_sexp_main();
1609  required_string("$multi text");
1610  stuff_string(dbs->text, F_MULTITEXT, NULL);
1611  required_string("$Voice:");
1613  required_string("$Recommendation text:");
1615  } // end while
1616 
1617  Assert(db->num_stages == stage_num);
1618  }
1619 
1620  if ( nt != Num_teams )
1621  Error(LOCATION, "Not enough debriefings for mission. There are %d teams and only %d debriefings;\n", Num_teams, nt );
1622 }
1623 
1625 {
1626  object *objp = p_objp->created_object;
1627  ship *shipp = &Ships[objp->instance];
1628  object *knossos_objp = NULL;
1629 
1630  // Assume no valid knossos device
1631  shipp->special_warpin_objnum = -1;
1632 
1633  // find knossos device
1634  for (ship_obj *so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so))
1635  {
1636  object *ship_objp = &Objects[so->objnum];
1637 
1638  if (Ship_info[Ships[ship_objp->instance].ship_info_index].flags & SIF_KNOSSOS_DEVICE)
1639  {
1640  // be close to the right device (allow multiple knossoses)
1641  if ( vm_vec_dist_quick(&ship_objp->pos, &p_objp->pos) < 2.0f*(ship_objp->radius + objp->radius) )
1642  {
1643  knossos_objp = ship_objp;
1644  break;
1645  }
1646  }
1647  }
1648 
1649  if (knossos_objp == NULL)
1650  return;
1651 
1652  // set ship special_warpin_objnum
1653  shipp->special_warpin_objnum = OBJ_INDEX(knossos_objp);
1654 
1655  // position self for warp on plane of device
1656  vec3d new_point;
1657  polymodel *pm = model_get(Ship_info[shipp->ship_info_index].model_num);
1658 
1659  float dist = fvi_ray_plane(&new_point, &knossos_objp->pos, &knossos_objp->orient.vec.fvec, &p_objp->pos, &p_objp->orient.vec.fvec, 0.0f);
1660  float desired_dist = -pm->mins.xyz.z;
1661  vm_vec_scale_add2(&objp->pos, &objp->orient.vec.fvec, (dist - desired_dist));
1662 
1663  // if ship is BIG or HUGE, make it go through the center of the knossos
1664  if (Ship_info[shipp->ship_info_index].flags & SIF_HUGE_SHIP)
1665  {
1666  vec3d offset;
1667  vm_vec_sub(&offset, &knossos_objp->pos, &new_point);
1668  vm_vec_add2(&knossos_objp->pos, &offset);
1669  }
1670 }
1671 
1676 {
1677  int dockpoint, parent_dockpoint;
1678  char *dockpoint_name, *parent_dockpoint_name;
1679  object *objp, *parent_objp;
1680 
1681  // get the actual in-game objects that will be docked
1682  objp = pobjp->created_object;
1683  parent_objp = parent_pobjp->created_object;
1684 
1685  // check valid
1686  if (!objp || !parent_objp)
1687  {
1688  Int3();
1689  return;
1690  }
1691 
1692  // get dockpoint names
1693  dockpoint_name = dock_find_dockpoint_used_by_object(pobjp, parent_pobjp);
1694  parent_dockpoint_name = dock_find_dockpoint_used_by_object(parent_pobjp, pobjp);
1695 
1696  // check valid
1697  if (!dockpoint_name || !parent_dockpoint_name)
1698  {
1699  Int3();
1700  return;
1701  }
1702 
1703  // resolve names to dockpoints
1704  dockpoint = model_find_dock_name_index(Ship_info[Ships[objp->instance].ship_info_index].model_num, dockpoint_name);
1705  parent_dockpoint = model_find_dock_name_index(Ship_info[Ships[parent_objp->instance].ship_info_index].model_num, parent_dockpoint_name);
1706 
1707  // check valid
1708  if ((dockpoint < 0) || (parent_dockpoint < 0))
1709  {
1710  Int3();
1711  return;
1712  }
1713 
1714  // dock them
1715  nprintf(("AI", "Initially docked: %s to parent %s\n", Ships[objp->instance].ship_name, Ships[parent_objp->instance].ship_name));
1716  ai_dock_with_object(objp, dockpoint, parent_objp, parent_dockpoint, AIDO_DOCK_NOW);
1717 }
1718 
1720 
1721 // Goober5000
1723 {
1724  // create the object
1725  parse_create_object_sub(pobjp);
1726 
1727  // remove the object from the arrival list
1728  // (don't remove the leader, because he'll be removed the usual way)
1729  if (pobjp != infop->parameter_variables.objp_value)
1730  {
1731  // If an object is present at the beginning of the mission, it may not have been put on the arrival
1732  // list. This is totally dependent on the order the objects are parsed in the mission file because
1733  // that is the order in which they are created. All the objects in a docked group are created
1734  // simultaneously when and only when the leader is created.
1735 
1736  // if it's on the list, remove it
1737  if (parse_object_on_arrival_list(pobjp))
1738  list_remove(&Ship_arrival_list, pobjp);
1739  }
1740 }
1741 
1747 {
1748  object *objp;
1749 
1750  // if this guy is part of a dock group, create the entire group, starting with the leader
1751  if (object_is_docked(pobjp))
1752  {
1754 
1755  // we should only be calling this for dock leaders, because the dock leader
1756  // governs the creation of his entire group
1757  Assert((pobjp->flags & P_SF_DOCK_LEADER));
1758 
1759  // if the leader will be destroyed before the mission starts, then *only* create the leader;
1760  // don't create the rest of the group (this is what retail did)
1761  if (pobjp->destroy_before_mission_time >= 0)
1762  return parse_create_object_sub(pobjp);
1763 
1764  // store the leader as a parameter
1765  dfi.parameter_variables.objp_value = pobjp;
1766 
1767  // Just as we couldn't create the parse dock trees until we had parsed them all,
1768  // we can't dock the in-game objects until we have created them all. :p
1769 
1770  // create all the objects
1772 
1773  // dock all the objects
1774  dock_dock_docked_objects(pobjp);
1775 
1776  // now clear the handled flags
1778  }
1779  // create normally
1780  else
1781  {
1782  parse_create_object_sub(pobjp);
1783  }
1784 
1785  // get the main object
1786  objp = pobjp->created_object;
1787 
1788  // warp it in (moved from parse_create_object_sub)
1789  if ((Game_mode & GM_IN_MISSION) && (!Fred_running) && (!Game_restoring))
1790  {
1791  if ((Ships[objp->instance].wingnum < 0) && (pobjp->arrival_location != ARRIVE_FROM_DOCK_BAY))
1792  {
1793  shipfx_warpin_start(objp);
1794  }
1795  }
1796 
1797  // return the main object's objnum
1798  return OBJ_INDEX(objp);
1799 }
1800 
1801 void parse_bring_in_docked_wing(p_object *p_objp, int wingnum, int shipnum);
1802 
1808 {
1809  int i, j, k, objnum, shipnum;
1810  int anchor_objnum = -1;
1811  ai_info *aip;
1812  ship_subsys *ptr;
1813  ship *shipp;
1814  ship_info *sip;
1815  subsys_status *sssp;
1816  ship_weapon *wp;
1817 
1818  // texture replacements
1819  polymodel *pm;
1820 
1821  MONITOR_INC(NumShipArrivals, 1);
1822 
1823  // base level creation - need ship name in case of duplicate textures
1824  objnum = ship_create(&p_objp->orient, &p_objp->pos, p_objp->ship_class, p_objp->name);
1825  Assert(objnum != -1);
1826  shipnum = Objects[objnum].instance;
1827 
1828  shipp = &Ships[shipnum];
1829  sip = &Ship_info[shipp->ship_info_index];
1830 
1831  // Goober5000 - make the parse object aware of what it was created as
1832  p_objp->created_object = &Objects[objnum];
1833 
1834  // Goober5000 - if this object is being created because he's docked to something,
1835  // and he's in a wing, then mark the wing as having arrived
1836  if (object_is_docked(p_objp) && !(p_objp->flags & P_SF_DOCK_LEADER) && (p_objp->wingnum >= 0))
1837  {
1838  if (!Fred_running)
1839  parse_bring_in_docked_wing(p_objp, p_objp->wingnum, shipnum);
1840  }
1841 
1842  // if arriving through knossos, adjust objpj->pos to plane of knossos and set flag
1843  // special warp is single player only
1844  if ((p_objp->flags & P_KNOSSOS_WARP_IN) && !(Game_mode & GM_MULTIPLAYER))
1845  {
1846  if (!Fred_running)
1848  }
1849 
1850  shipp->group = p_objp->group;
1851  shipp->team = p_objp->team;
1852  strcpy_s(shipp->ship_name, p_objp->name);
1853  shipp->escort_priority = p_objp->escort_priority;
1855  shipp->special_exp_damage = p_objp->special_exp_damage;
1856  shipp->special_exp_blast = p_objp->special_exp_blast;
1857  shipp->special_exp_inner = p_objp->special_exp_inner;
1858  shipp->special_exp_outer = p_objp->special_exp_outer;
1859  shipp->use_shockwave = p_objp->use_shockwave;
1862 
1863  shipp->special_hitpoints = p_objp->special_hitpoints;
1864  shipp->special_shield = p_objp->special_shield;
1865 
1866  for (i=0;i<MAX_IFFS;i++)
1867  {
1868  for (j=0;j<MAX_IFFS;j++)
1869  {
1870  shipp->ship_iff_color[i][j] = p_objp->alt_iff_color[i][j];
1871  }
1872  }
1873 
1876  shipp->max_shield_recharge = p_objp->max_shield_recharge;
1877 
1878  // Goober5000 - ugh, this is really stupid having to do this here; if the
1879  // ship creation code was better organized this wouldn't be necessary
1880  if (shipp->special_hitpoints > 0)
1881  {
1882  float hull_factor = shipp->ship_max_hull_strength / sip->max_hull_strength;
1883  ship_subsys *ss;
1884 
1885  for (ss = GET_FIRST(&shipp->subsys_list); ss != END_OF_LIST(&shipp->subsys_list) && ss != NULL; ss = GET_NEXT(ss))
1886  {
1887  ss->max_hits *= hull_factor;
1888 
1889  if (Fred_running)
1890  ss->current_hits = 0.0f;
1891  else
1892  ss->current_hits = ss->max_hits;
1893  }
1894 
1896  }
1897 
1898  // Goober5000 - this is also stupid; this is in ship_set but it needs to be done here because of the special hitpoints mod
1899  Objects[objnum].hull_strength = shipp->ship_max_hull_strength;
1900 
1901  shipp->respawn_priority = p_objp->respawn_priority;
1902 
1903  // if this is a multiplayer dogfight game, and its from a player wing, make it team traitor
1904  if (MULTI_DOGFIGHT && (p_objp->wingnum >= 0))
1905  {
1906  for (i = 0; i < MAX_STARTING_WINGS; i++)
1907  {
1908  if (!stricmp(Starting_wing_names[i], Wings[p_objp->wingnum].name))
1909  shipp->team = Iff_traitor;
1910  }
1911  }
1912 
1913  if (!Fred_running)
1914  {
1915  ship_assign_sound(&Ships[shipnum]);
1916  }
1917 
1918  aip = &(Ai_info[shipp->ai_index]);
1919  aip->behavior = p_objp->behavior;
1920  aip->mode = aip->behavior;
1921 
1922  // make sure aim_safety has its submode defined
1923  if (aip->mode == AIM_SAFETY) {
1924  aip->submode = AISS_1;
1925  }
1926 
1927  // alternate stuff
1928  shipp->alt_type_index = p_objp->alt_type_index;
1929  shipp->callsign_index = p_objp->callsign_index;
1930 
1931  aip->ai_class = p_objp->ai_class;
1932  shipp->weapons.ai_class = p_objp->ai_class; // Fred uses this instead of above.
1933  //Fixes a bug where the AI class attributes were not copied if the AI class was set in the mission.
1934  if (The_mission.ai_profile->flags & AIPF_FIX_AI_CLASS_BUG)
1935  ship_set_new_ai_class(shipnum, p_objp->ai_class);
1936 
1937  // must reset the number of ai goals when the object is created
1938  for (i = 0; i < MAX_AI_GOALS; i++)
1939  {
1940  aip->goals[i].ai_mode = AI_GOAL_NONE;
1941  aip->goals[i].signature = -1;
1942  aip->goals[i].priority = -1;
1943  aip->goals[i].flags = 0;
1944  }
1945 
1946  shipp->cargo1 = p_objp->cargo1;
1947 
1948  shipp->arrival_location = p_objp->arrival_location;
1949  shipp->arrival_distance = p_objp->arrival_distance;
1950  shipp->arrival_anchor = p_objp->arrival_anchor;
1951  shipp->arrival_path_mask = p_objp->arrival_path_mask;
1952  shipp->arrival_cue = p_objp->arrival_cue;
1953  shipp->arrival_delay = p_objp->arrival_delay;
1954  shipp->departure_location = p_objp->departure_location;
1955  shipp->departure_anchor = p_objp->departure_anchor;
1956  shipp->departure_path_mask = p_objp->departure_path_mask;
1957  shipp->departure_cue = p_objp->departure_cue;
1958  shipp->departure_delay = p_objp->departure_delay;
1959  shipp->wingnum = p_objp->wingnum;
1960  shipp->hotkey = p_objp->hotkey;
1961  shipp->score = p_objp->score;
1962  shipp->assist_score_pct = p_objp->assist_score_pct;
1963  shipp->persona_index = p_objp->persona_index;
1964  if (Ship_info[shipp->ship_info_index].uses_team_colors && !p_objp->team_color_setting.empty())
1965  shipp->team_name = p_objp->team_color_setting;
1966 
1967  // reset texture animations
1969 
1970  // handle the replacement textures
1971  if (!p_objp->replacement_textures.empty())
1972  {
1973  shipp->ship_replacement_textures = (int *) vm_malloc( MAX_REPLACEMENT_TEXTURES * sizeof(int));
1974 
1975  for (i = 0; i < MAX_REPLACEMENT_TEXTURES; i++)
1976  shipp->ship_replacement_textures[i] = -1;
1977  }
1978 
1979  // now fill them in
1980  for (SCP_vector<texture_replace>::iterator tr = p_objp->replacement_textures.begin(); tr != p_objp->replacement_textures.end(); ++tr)
1981  {
1982  pm = model_get(sip->model_num);
1983 
1984  // look for textures
1985  for (j = 0; j < pm->n_textures; j++)
1986  {
1987  texture_map *tmap = &pm->maps[j];
1988 
1989  int tnum = tmap->FindTexture(tr->old_texture);
1990  if(tnum > -1)
1991  shipp->ship_replacement_textures[j * TM_NUM_TYPES + tnum] = tr->new_texture_id;
1992  }
1993  }
1994 
1995  // Copy across the alt classes (if any) for FRED
1996  if (Fred_running) {
1997  shipp->s_alt_classes = p_objp->alt_classes;
1998  }
1999 
2000  // check the parse object's flags for possible things to set on this newly created ship
2001  resolve_parse_flags(&Objects[objnum], p_objp->flags, p_objp->flags2);
2002 
2003 
2004  // other flag checks
2006 
2007  // forcing the shields on or off depending on flags -- but only if shield strength supports it
2008 
2009  // no strength means we can't have shields, period
2010  if (p_objp->ship_max_shield_strength == 0.0f)
2011  Objects[objnum].flags |= OF_NO_SHIELDS;
2012  // force shields on means we have them regardless of other flags; per r5332 this ranks above the next check
2013  else if (p_objp->flags2 & P2_OF_FORCE_SHIELDS_ON)
2014  Objects[objnum].flags &= ~OF_NO_SHIELDS;
2015  // intrinsic no-shields means we have them off in-game
2016  else if (!Fred_running && (sip->flags2 & SIF2_INTRINSIC_NO_SHIELDS))
2017  Objects[objnum].flags |= OF_NO_SHIELDS;
2018 
2019  // don't set the flag if the mission is ongoing in a multiplayer situation. This will be set by the players in the
2020  // game only before the game or during respawning.
2021  // MWA -- changed the next line to remove the !(Game_mode & GM_MULTIPLAYER). We shouldn't be setting
2022  // this flag in single player mode -- it gets set in post process mission.
2023  if ((p_objp->flags & P_OF_PLAYER_START) && (Fred_running || ((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION))))
2024  Objects[objnum].flags |= OF_PLAYER_SHIP;
2025 
2026  // a couple of ai_info flags. Also, do a reasonable default for the kamikaze damage regardless of
2027  // whether this flag is set or not
2028  if (p_objp->flags & P_AIF_KAMIKAZE)
2029  {
2031  Ai_info[shipp->ai_index].kamikaze_damage = p_objp->kamikaze_damage;
2032  }
2033 
2034  if (p_objp->flags & P_AIF_NO_DYNAMIC)
2036 
2037  if (p_objp->flags & P_SF_RED_ALERT_STORE_STATUS)
2038  {
2039  if (!(Game_mode & GM_MULTIPLAYER)) {
2040  shipp->flags |= SF_RED_ALERT_STORE_STATUS;
2041  }
2042  }
2043 
2044  if (p_objp->flags & P_KNOSSOS_WARP_IN)
2045  {
2046  Objects[objnum].flags |= OF_SPECIAL_WARPIN;
2048  }
2049 
2050  // set the orders that this ship will accept. It will have already been set to default from the
2051  // ship create code, so only set them if the parse object flags say they are unique
2052  if (p_objp->flags & P_SF_USE_UNIQUE_ORDERS)
2053  {
2054  shipp->orders_accepted = p_objp->orders_accepted;
2055 
2056  // MWA 5/15/98 -- Added the following debug code because some orders that ships
2057  // will accept were apparently written out incorrectly with Fred. This Int3() should
2058  // trap these instances.
2059 #ifndef NDEBUG
2060  if (Fred_running)
2061  {
2062  int default_orders, remaining_orders;
2063 
2064  default_orders = ship_get_default_orders_accepted(&Ship_info[shipp->ship_info_index]);
2065  remaining_orders = p_objp->orders_accepted & ~default_orders;
2066  if (remaining_orders)
2067  {
2068  Warning(LOCATION, "Ship %s has orders which it will accept that are\nnot part of default orders accepted.\n\nPlease reedit this ship and change the orders again\n", shipp->ship_name);
2069  }
2070  }
2071 #endif
2072  }
2073 
2074  if (p_objp->flags & P_SF_DOCK_LEADER)
2075  shipp->flags |= SF_DOCK_LEADER;
2076 
2077  if (p_objp->flags & P_SF_WARP_BROKEN)
2078  shipp->flags |= SF_WARP_BROKEN;
2079 
2080  if (p_objp->flags & P_SF_WARP_NEVER)
2081  shipp->flags |= SF_WARP_NEVER;
2083 
2084 
2085  // if ship is in a wing, and the wing's no_warp_effect flag is set, then set the equivalent
2086  // flag for the ship
2087  if ((shipp->wingnum != -1) && (Wings[shipp->wingnum].flags & WF_NO_ARRIVAL_WARP))
2088  shipp->flags |= SF_NO_ARRIVAL_WARP;
2089 
2090  if ((shipp->wingnum != -1) && (Wings[shipp->wingnum].flags & WF_NO_DEPARTURE_WARP))
2091  shipp->flags |= SF_NO_DEPARTURE_WARP;
2092 
2093  // ditto for Kazan
2094  if ((shipp->wingnum != -1) && (Wings[shipp->wingnum].flags & WF_NAV_CARRY))
2095  shipp->flags2 |= SF2_NAVPOINT_CARRY;
2096 
2097  // if the wing index and wing pos are set for this parse object, set them for the ship. This
2098  // is useful in multiplayer when ships respawn
2100  shipp->wing_status_wing_pos = p_objp->wing_status_wing_pos;
2101 
2102 
2103  // set up the ai_goals for this object -- all ships created here are AI controlled.
2104  if (p_objp->ai_goals != -1)
2105  {
2106  int sexp;
2107 
2108  // set up the ai goals for this object.
2109  for (sexp = CDR(p_objp->ai_goals); sexp != -1; sexp = CDR(sexp))
2111 
2112  // free the sexpression nodes only for non-wing ships. wing code will handle its own case
2113  if (p_objp->wingnum < 0)
2114  free_sexp2(p_objp->ai_goals); // free up sexp nodes for reuse, since they aren't needed anymore.
2115  }
2116 
2117  Assert(sip->model_num != -1);
2118 
2119  // initialize subsystem statii here. The subsystems are given a percentage damaged. So a percent value
2120  // of 20% means that the subsystem is 20% damaged (*not* 20% of max hits). This is opposite the way
2121  // that the initial velocity/hull strength/shields work
2122  i = p_objp->subsys_count;
2123  while (i--)
2124  {
2125  sssp = &Subsys_status[p_objp->subsys_index + i];
2126  if (!stricmp(sssp->name, NOX("Pilot")))
2127  {
2128  wp = &shipp->weapons;
2129  if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
2130  {
2131  for (j=k=0; j<MAX_SHIP_PRIMARY_BANKS; j++)
2132  {
2133  if ((sssp->primary_banks[j] >= 0) || Fred_running)
2134  wp->primary_bank_weapons[k++] = sssp->primary_banks[j];
2135  }
2136 
2137  if (Fred_running)
2139  else
2140  wp->num_primary_banks = k;
2141  }
2142 
2143  if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
2144  {
2145  for (j = k = 0; j < MAX_SHIP_SECONDARY_BANKS; j++)
2146  {
2147  if ((sssp->secondary_banks[j] >= 0) || Fred_running)
2148  wp->secondary_bank_weapons[k++] = sssp->secondary_banks[j];
2149  }
2150 
2151  if (Fred_running)
2153  else
2154  wp->num_secondary_banks = k;
2155  }
2156 
2157  // primary weapons too - Goober5000
2158  for (j = 0; j < wp->num_primary_banks; j++)
2159  {
2160  if (Fred_running)
2161  {
2162  wp->primary_bank_ammo[j] = sssp->primary_ammo[j];
2163  }
2165  {
2167  "Primary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
2168  shipp->ship_name, sssp->name, j, Weapon_info[wp->primary_bank_weapons[j]].name);
2169 
2170  int capacity = fl2i(sssp->primary_ammo[j]/100.0f * sip->primary_bank_ammo_capacity[j] + 0.5f);
2171  wp->primary_bank_ammo[j] = fl2i(capacity / Weapon_info[wp->primary_bank_weapons[j]].cargo_size + 0.5f);
2172  }
2173  }
2174 
2175  for (j = 0; j < wp->num_secondary_banks; j++)
2176  {
2177  if (Fred_running)
2178  {
2179  wp->secondary_bank_ammo[j] = sssp->secondary_ammo[j];
2180  }
2181  else if (wp->secondary_bank_weapons[j] >= 0)
2182  {
2184  "Secondary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
2185  shipp->ship_name, sssp->name, j, Weapon_info[wp->secondary_bank_weapons[j]].name);
2186 
2187  int capacity = fl2i(sssp->secondary_ammo[j]/100.0f * sip->secondary_bank_ammo_capacity[j] + 0.5f);
2188  wp->secondary_bank_ammo[j] = fl2i(capacity / Weapon_info[wp->secondary_bank_weapons[j]].cargo_size + 0.5f);
2189  }
2190  }
2191 
2192  continue;
2193  }
2194 
2195  ptr = GET_FIRST(&shipp->subsys_list);
2196  while (ptr != END_OF_LIST(&shipp->subsys_list))
2197  {
2198  // check the mission flag to possibly free all beam weapons - Goober5000, taken from SEXP.CPP
2199  if (The_mission.flags & MISSION_FLAG_BEAM_FREE_ALL_BY_DEFAULT)
2200  {
2201  // mark all turrets as beam free
2202  if(ptr->system_info->type == SUBSYSTEM_TURRET)
2203  {
2205  ptr->turret_next_fire_stamp = timestamp((int) frand_range(50.0f, 4000.0f));
2206  }
2207  }
2208 
2210  {
2211  // mark all turrets as locked
2212  if(ptr->system_info->type == SUBSYSTEM_TURRET)
2213  {
2215  }
2216  }
2217 
2218  if (!subsystem_stricmp(ptr->system_info->subobj_name, sssp->name))
2219  {
2220  if (Fred_running)
2221  {
2222  ptr->current_hits = sssp->percent;
2223  ptr->max_hits = 100.0f;
2224  }
2225  else
2226  {
2228 
2229  float new_hits = ptr->max_hits * (100.0f - sssp->percent) / 100.f;
2230  if (!(ptr->flags & SSF_NO_AGGREGATE)) {
2231  shipp->subsys_info[ptr->system_info->type].aggregate_current_hits -= (ptr->max_hits - new_hits);
2232  }
2233 
2234  if ((100.0f - sssp->percent) < 0.5)
2235  {
2236  ptr->current_hits = 0.0f;
2237  ptr->submodel_info_1.blown_off = 1;
2238  }
2239  else
2240  {
2241  ptr->current_hits = new_hits;
2242  }
2243  }
2244 
2245  if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
2246  for (j=0; j<MAX_SHIP_PRIMARY_BANKS; j++)
2247  ptr->weapons.primary_bank_weapons[j] = sssp->primary_banks[j];
2248 
2250  for (j=0; j<MAX_SHIP_SECONDARY_BANKS; j++)
2251  ptr->weapons.secondary_bank_weapons[j] = sssp->secondary_banks[j];
2252 
2253  // Goober5000
2254  for (j = 0; j < ptr->weapons.num_primary_banks; j++)
2255  {
2256  if (Fred_running) {
2257  ptr->weapons.primary_bank_ammo[j] = sssp->primary_ammo[j];
2260  "Primary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
2261  shipp->ship_name, sssp->name, j, Weapon_info[ptr->weapons.primary_bank_weapons[j]].name);
2262 
2263  int capacity = fl2i(sssp->primary_ammo[j]/100.0f * ptr->weapons.primary_bank_capacity[j] + 0.5f);
2264  ptr->weapons.primary_bank_ammo[j] = fl2i(capacity / Weapon_info[ptr->weapons.primary_bank_weapons[j]].cargo_size + 0.5f);
2265  }
2266  }
2267 
2268  for (j = 0; j < ptr->weapons.num_secondary_banks; j++)
2269  {
2270  if (Fred_running) {
2271  ptr->weapons.secondary_bank_ammo[j] = sssp->secondary_ammo[j];
2272  } else if (ptr->weapons.secondary_bank_weapons[j] >= 0) {
2274  "Secondary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
2275  shipp->ship_name, sssp->name, j, Weapon_info[ptr->weapons.secondary_bank_weapons[j]].name);
2276 
2277  int capacity = fl2i(sssp->secondary_ammo[j]/100.0f * ptr->weapons.secondary_bank_capacity[j] + 0.5f);
2279  }
2280  }
2281 
2282  ptr->subsys_cargo_name = sssp->subsys_cargo_name;
2283 
2284  if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
2285  ptr->weapons.ai_class = sssp->ai_class;
2286 
2287  ptr->turret_best_weapon = -1;
2288  ptr->turret_animation_position = MA_POS_NOT_SET; // model animation position is not set
2289  ptr->turret_animation_done_time = 0;
2290  }
2291 
2292  ptr = GET_NEXT(ptr);
2293  }
2294  }
2295 
2296  // initial hull strength, shields, and velocity are all expressed as a percentage of the max value/
2297  // so a initial_hull value of 90% means 90% of max. This way is opposite of how subsystems are dealt
2298  // with
2299  if (Fred_running)
2300  {
2301  Objects[objnum].phys_info.speed = (float) p_objp->initial_velocity;
2302  Objects[objnum].hull_strength = (float) p_objp->initial_hull;
2303  Objects[objnum].shield_quadrant[0] = (float) p_objp->initial_shields;
2304 
2305  }
2306  else
2307  {
2308  int max_allowed_sparks, num_sparks, iLoop;
2309 
2310  Objects[objnum].hull_strength = p_objp->initial_hull * shipp->ship_max_hull_strength / 100.0f;
2311  for (iLoop = 0; iLoop<Objects[objnum].n_quadrants; iLoop++)
2312  {
2313  Objects[objnum].shield_quadrant[iLoop] = (float) (shipp->max_shield_recharge * p_objp->initial_shields * get_max_shield_quad(&Objects[objnum]) / 100.0f);
2314  }
2315 
2316  // initial velocities now do not apply to ships which warp in after mission starts
2317  // WMC - Make it apply for ships with IN_PLACE_ANIM type
2318  // zookeeper - Also make it apply for hyperspace warps
2319  if (!(Game_mode & GM_IN_MISSION) || (sip->warpin_type == WT_IN_PLACE_ANIM || sip->warpin_type == WT_HYPERSPACE))
2320  {
2321  Objects[objnum].phys_info.speed = (float) p_objp->initial_velocity * sip->max_speed / 100.0f;
2322  Objects[objnum].phys_info.vel.xyz.z = Objects[objnum].phys_info.speed;
2323  Objects[objnum].phys_info.prev_ramp_vel = Objects[objnum].phys_info.vel;
2324  Objects[objnum].phys_info.desired_vel = Objects[objnum].phys_info.vel;
2325  }
2326 
2327  // recalculate damage of subsystems
2329 
2330  // create sparks on a ship whose hull is damaged. We will create two sparks for every 20%
2331  // of hull damage done. 100 means no sparks. between 80 and 100 do two sparks. 60 and 80 is
2332  // four, etc.
2333  pm = model_get(sip->model_num);
2334  max_allowed_sparks = get_max_sparks(&Objects[objnum]);
2335  num_sparks = (int)((100.0f - p_objp->initial_hull) / 5.0f);
2336  if (num_sparks > max_allowed_sparks)
2337  num_sparks = max_allowed_sparks;
2338 
2339  for (iLoop = 0; iLoop < num_sparks; iLoop++)
2340  {
2341  vec3d v1, v2;
2342 
2343  // DA 10/20/98 - sparks must be chosen on the hull and not any submodel
2344  if ( Cmdline_old_collision_sys ) {
2345  submodel_get_two_random_points(sip->model_num, pm->detail[0], &v1, &v2);
2346  } else {
2347  submodel_get_two_random_points_better(sip->model_num, pm->detail[0], &v1, &v2);
2348  }
2349  ship_hit_sparks_no_rotate(&Objects[objnum], &v1);
2350  }
2351  }
2352 
2353  // in mission, we add a log entry -- set ship positions for ships not in wings, and then do
2354  // warpin effect
2355  if ((Game_mode & GM_IN_MISSION) && (!Fred_running))
2356  {
2358 
2359  if (!Game_restoring)
2360  {
2361  // if this ship isn't in a wing, determine its arrival location
2362  if (shipp->wingnum == -1)
2363  {
2364  int location;
2365 
2366  // multiplayer clients set the arrival location of ships to be at location since their
2367  // position has already been determined. Don't actually set the variable since we
2368  // don't want the warp effect to show if coming from a dock bay.
2369  location = p_objp->arrival_location;
2370 
2371  if (MULTIPLAYER_CLIENT)
2372  location = ARRIVE_AT_LOCATION;
2373 
2374  anchor_objnum = mission_set_arrival_location(p_objp->arrival_anchor, location, p_objp->arrival_distance, objnum, p_objp->arrival_path_mask, NULL, NULL);
2375 
2376  // Goober5000 - warpin start moved to parse_create_object
2377  }
2378  }
2379 
2380  // possibly add this ship to a hotkey set
2381  // Ships can now have both a ship-hotkey and a wing-hotkey -- FSF
2382  if (shipp->hotkey != -1)
2384  if ((shipp->wingnum != -1) && (Wings[shipp->wingnum].hotkey != -1))
2386 
2387  // possibly add this ship to the hud escort list
2388  if (shipp->flags & SF_ESCORT)
2389  hud_add_remove_ship_escort(objnum, 1);
2390  }
2391 
2392  // for multiplayer games, make a call to the network code to assign the object signature
2393  // of the newly created object. The network host of the netgame will always assign a signature
2394  // to a newly created object. The network signature will get to the clients of the game in
2395  // different manners depending on whether or not an individual ship or a wing was created.
2396  if (Game_mode & GM_MULTIPLAYER)
2397  {
2398  Objects[objnum].net_signature = p_objp->net_signature;
2399 
2400  // Goober5000 - for an initially docked group, only send the packet for the dock leader... this is necessary so that the
2401  // docked hierarchy of objects can be created in the right order on the client side
2402  if (!object_is_docked(p_objp) || (p_objp->flags & P_SF_DOCK_LEADER))
2403  {
2404  if ((Game_mode & GM_IN_MISSION) && MULTIPLAYER_MASTER && (p_objp->wingnum == -1))
2405  send_ship_create_packet(&Objects[objnum], (p_objp == Arriving_support_ship) ? 1 : 0);
2406  }
2407  }
2408 
2409  if (Game_mode & GM_IN_MISSION) {
2410  if (anchor_objnum >= 0)
2411  Script_system.SetHookObjects(2, "Ship", &Objects[objnum], "Parent", &Objects[anchor_objnum]);
2412  else
2413  Script_system.SetHookObjects(2, "Ship", &Objects[objnum], "Parent", NULL);
2414 
2415  Script_system.RunCondition(CHA_ONSHIPARRIVE, 0, NULL, &Objects[objnum]);
2416  Script_system.RemHookVars(2, "Ship", "Parent");
2417  }
2418 
2419  return objnum;
2420 }
2421 
2428 void parse_bring_in_docked_wing(p_object *p_objp, int wingnum, int shipnum)
2429 {
2430  Assert(!Fred_running);
2431  Assert(p_objp != NULL);
2432  Assert(wingnum >= 0);
2433  Assert(shipnum >= 0);
2434  int j, index;
2435  wing *wingp = &Wings[wingnum];
2436 
2437  // link ship and wing together
2438  // (do this first because mission log relies on ship_index)
2439  wingp->ship_index[p_objp->pos_in_wing] = shipnum;
2440  Ships[shipnum].wingnum = wingnum;
2441 
2442  // has this wing arrived at all yet?
2443  if (wingp->current_wave == 0)
2444  {
2445  wingp->current_wave++;
2446  mission_log_add_entry( LOG_WING_ARRIVED, wingp->name, NULL, wingp->current_wave );
2447  wingp->wave_delay_timestamp = timestamp(-1);
2448  }
2449  // how did we get more than one wave here?
2450  else if (wingp->current_wave > 1)
2451  Error(LOCATION, "Wing %s was created from docked ships but somehow has more than one wave!", wingp->name);
2452 
2453  // increment tallies
2454  wingp->total_arrived_count++;
2455  wingp->current_count++;
2456  // make sure we haven't created too many ships
2458 
2459  // at this point the wing has arrived, so handle the stuff for this particular ship
2460 
2461  // set up wingman status index
2462  hud_wingman_status_set_index(wingp, &Ships[shipnum], p_objp);
2463 
2464  // copy to parse object
2466  p_objp->wing_status_wing_pos = Ships[shipnum].wing_status_wing_pos;
2467 
2468  // set flag if necessary
2469  for (j = 0; j < MAX_STARTING_WINGS; j++)
2470  {
2471  if (!stricmp(Starting_wing_names[j], wingp->name))
2472  Ships[shipnum].flags |= SF_FROM_PLAYER_WING;
2473  }
2474 
2475  // handle AI
2476  ai_info *aip = &Ai_info[Ships[shipnum].ai_index];
2477  aip->wing = wingnum;
2478 
2479  if (wingp->flags & WF_NO_DYNAMIC)
2480  aip->ai_flags |= AIF_NO_DYNAMIC;
2481 
2482  // copy any goals from the wing to the newly created ship
2483  for (index = 0; index < MAX_AI_GOALS; index++)
2484  {
2485  if (wingp->ai_goals[index].ai_mode != AI_GOAL_NONE)
2486  ai_copy_mission_wing_goal(&wingp->ai_goals[index], aip);
2487  }
2488 }
2489 
2490 // Goober5000
2491 void resolve_parse_flags(object *objp, int parse_flags, int parse_flags2)
2492 {
2493  Assert(objp != NULL);
2494  ship *shipp = &Ships[objp->instance];
2495 
2496  if (parse_flags & P_SF_CARGO_KNOWN)
2497  shipp->flags |= SF_CARGO_REVEALED;
2498 
2499  if (parse_flags & P_SF_IGNORE_COUNT)
2500  shipp->flags |= SF_IGNORE_COUNT;
2501 
2502  if (parse_flags & P_OF_PROTECTED)
2503  objp->flags |= OF_PROTECTED;
2504 
2505  if (parse_flags & P_SF_REINFORCEMENT)
2506  {
2507  //Individual ships in wings can't be reinforcements - FUBAR
2508  if(shipp->wingnum >= 0)
2509  {
2510  Warning(LOCATION, "Ship %s is a reinforcement unit but is a member of a wing. Ignoring reinforcement flag.", shipp->ship_name);
2511  }
2512  else
2513  {
2514  shipp->flags |= SF_REINFORCEMENT;
2515  }
2516  }
2517 
2518  if ((parse_flags & P_OF_NO_SHIELDS) && (parse_flags2 & P2_OF_FORCE_SHIELDS_ON))
2519  {
2520  Warning(LOCATION, "The parser found a ship with both the \"force-shields-on\" and \"no-shields\" flags; this is inconsistent!");
2521  }
2522  if (parse_flags & P_OF_NO_SHIELDS)
2523  objp->flags |= OF_NO_SHIELDS;
2524 
2525  if (parse_flags & P_SF_ESCORT)
2526  shipp->flags |= SF_ESCORT;
2527 
2528  // P_OF_PLAYER_START is handled in parse_create_object_sub
2529 
2530  if (parse_flags & P_SF_NO_ARRIVAL_MUSIC)
2531  shipp->flags |= SF_NO_ARRIVAL_MUSIC;
2532 
2533  if (parse_flags & P_SF_NO_ARRIVAL_WARP)
2534  shipp->flags |= SF_NO_ARRIVAL_WARP;
2535 
2536  if (parse_flags & P_SF_NO_DEPARTURE_WARP)
2537  shipp->flags |= SF_NO_DEPARTURE_WARP;
2538 
2539  if (parse_flags & P_SF_LOCKED) {
2540  shipp->flags2 |= SF2_SHIP_LOCKED;
2541  shipp->flags2 |= SF2_WEAPONS_LOCKED;
2542  }
2543 
2544  if (parse_flags & P_OF_INVULNERABLE)
2545  objp->flags |= OF_INVULNERABLE;
2546 
2547  if (parse_flags & P_SF_HIDDEN_FROM_SENSORS)
2548  shipp->flags |= SF_HIDDEN_FROM_SENSORS;
2549 
2550  if (parse_flags & P_SF_SCANNABLE)
2551  shipp->flags |= SF_SCANNABLE;
2552 
2553  // P_AIF_KAMIKAZE, P_AIF_NO_DYNAMIC, and P_SF_RED_ALERT_CARRY are handled in parse_create_object_sub
2554 
2555  if (parse_flags & P_OF_BEAM_PROTECTED)
2556  objp->flags |= OF_BEAM_PROTECTED;
2557 
2558  if (parse_flags & P_OF_FLAK_PROTECTED)
2559  objp->flags |= OF_FLAK_PROTECTED;
2560 
2561  if (parse_flags & P_OF_LASER_PROTECTED)
2562  objp->flags |= OF_LASER_PROTECTED;
2563 
2564  if (parse_flags & P_OF_MISSILE_PROTECTED)
2565  objp->flags |= OF_MISSILE_PROTECTED;
2566 
2567  if (parse_flags & P_SF_GUARDIAN)
2569 
2570  if (parse_flags & P_SF_VAPORIZE)
2571  shipp->flags |= SF_VAPORIZE;
2572 
2573  if (parse_flags & P_SF2_STEALTH)
2574  shipp->flags2 |= SF2_STEALTH;
2575 
2576  if (parse_flags & P_SF2_FRIENDLY_STEALTH_INVIS)
2578 
2579  if (parse_flags & P_SF2_DONT_COLLIDE_INVIS)
2580  shipp->flags2 |= SF2_DONT_COLLIDE_INVIS;
2581 
2582  if (parse_flags2 & P2_SF2_PRIMITIVE_SENSORS)
2583  shipp->flags2 |= SF2_PRIMITIVE_SENSORS;
2584 
2585  if (parse_flags2 & P2_SF2_NO_SUBSPACE_DRIVE)
2586  shipp->flags2 |= SF2_NO_SUBSPACE_DRIVE;
2587 
2588  if (parse_flags2 & P2_SF2_NAV_CARRY_STATUS)
2589  shipp->flags2 |= SF2_NAVPOINT_CARRY;
2590 
2591  if (parse_flags2 & P2_SF2_AFFECTED_BY_GRAVITY)
2592  shipp->flags2 |= SF2_AFFECTED_BY_GRAVITY;
2593 
2594  if (parse_flags2 & P2_SF2_TOGGLE_SUBSYSTEM_SCANNING)
2596 
2597  if (parse_flags2 & P2_OF_TARGETABLE_AS_BOMB)
2598  objp->flags |= OF_TARGETABLE_AS_BOMB;
2599 
2600  if (parse_flags2 & P2_SF2_NO_BUILTIN_MESSAGES)
2601  shipp->flags2 |= SF2_NO_BUILTIN_MESSAGES;
2602 
2603  if (parse_flags2 & P2_SF2_PRIMARIES_LOCKED)
2604  shipp->flags2 |= SF2_PRIMARIES_LOCKED;
2605 
2606  if (parse_flags2 & P2_SF2_SECONDARIES_LOCKED)
2607  shipp->flags2 |= SF2_SECONDARIES_LOCKED;
2608 
2609  if (parse_flags2 & P2_SF2_SET_CLASS_DYNAMICALLY)
2611 
2612  if (parse_flags2 & P2_SF2_NO_DEATH_SCREAM)
2613  shipp->flags2 |= SF2_NO_DEATH_SCREAM;
2614 
2615  if (parse_flags2 & P2_SF2_ALWAYS_DEATH_SCREAM)
2616  shipp->flags2 |= SF2_ALWAYS_DEATH_SCREAM;
2617 
2618  if (parse_flags2 & P2_SF2_NAV_NEEDSLINK)
2619  shipp->flags2 |= SF2_NAVPOINT_NEEDSLINK;
2620 
2621  if (parse_flags2 & P2_SF2_HIDE_SHIP_NAME)
2622  shipp->flags2 |= SF2_HIDE_SHIP_NAME;
2623 
2624  if (parse_flags2 & P2_SF2_LOCK_ALL_TURRETS_INITIALLY)
2626 
2627  if (parse_flags2 & P2_SF2_AFTERBURNER_LOCKED)
2628  shipp->flags2 |= SF2_AFTERBURNER_LOCKED;
2629 
2630  if (parse_flags2 & P2_OF_FORCE_SHIELDS_ON)
2631  shipp->flags2 |= SF2_FORCE_SHIELDS_ON;
2632 
2633  if (parse_flags2 & P2_OF_IMMOBILE)
2634  objp->flags |= OF_IMMOBILE;
2635 
2636  if (parse_flags2 & P2_SF2_NO_ETS)
2637  shipp->flags2 |= SF2_NO_ETS;
2638 
2639  if (parse_flags2 & P2_SF2_CLOAKED)
2640  shipp->flags2 |= SF2_CLOAKED;
2641 
2642  if (parse_flags2 & P2_SF2_SHIP_LOCKED)
2643  shipp->flags2 |= SF2_SHIP_LOCKED;
2644 
2645  if (parse_flags2 & P2_SF2_WEAPONS_LOCKED)
2646  shipp->flags2 |= SF2_WEAPONS_LOCKED;
2647 
2648  if (parse_flags2 & P2_SF2_SCRAMBLE_MESSAGES)
2649  shipp->flags2 |= SF2_SCRAMBLE_MESSAGES;
2650 
2651  if (parse_flags2 & P2_SF2_NO_DISABLED_SELF_DESTRUCT)
2653 
2654  // don't remove no-collide if not set in the mission
2655  if (parse_flags2 & P2_OF_NO_COLLIDE)
2656  obj_set_flags(objp, objp->flags & ~OF_COLLIDES);
2657 }
2658 
2659 void fix_old_special_explosions(p_object *p_objp, int variable_index)
2660 {
2661  int i;
2662 
2663  Assertion(!(p_objp->use_special_explosion), "Mission appears to be using both the new and old method of special explosions for %s. Old method values used", p_objp->name);
2664 
2665  // check all the variables are valid
2666  for ( i = variable_index; i < (variable_index + BLOCK_EXP_SIZE); i++ ) {
2667  if (!( Block_variables[i].type & SEXP_VARIABLE_BLOCK )) {
2668  Warning (LOCATION, "%s is using the old special explosions method but does not appear to have variables for all the values", p_objp->name);
2669  return;
2670  }
2671  }
2672 
2673  p_objp->use_special_explosion = true;
2674 
2675  p_objp->special_exp_damage = atoi(Block_variables[variable_index+DAMAGE].text);
2676  p_objp->special_exp_blast = atoi(Block_variables[variable_index+BLAST].text);
2677  p_objp->special_exp_inner = atoi(Block_variables[variable_index+INNER_RAD].text);
2678  p_objp->special_exp_outer = atoi(Block_variables[variable_index+OUTER_RAD].text);
2679  p_objp->use_shockwave = (atoi(Block_variables[variable_index+PROPAGATE].text) ? 1:0);
2680  p_objp->special_exp_shockwave_speed = atoi(Block_variables[variable_index+SHOCK_SPEED].text);
2681  p_objp->special_exp_deathroll_time = 0;
2682 }
2683 
2684 void fix_old_special_hits(p_object *p_objp, int variable_index)
2685 {
2686  int i;
2687 
2688  Assertion( ((p_objp->special_hitpoints == 0) && (p_objp->special_shield == -1)),"Mission appears to be using both the new and old method of special hitpoints for %s", p_objp->name);
2689 
2690  // check all the variables are valid
2691  for ( i = variable_index; i < (variable_index + BLOCK_HIT_SIZE); i++ ) {
2692  if (!( Block_variables[i].type & SEXP_VARIABLE_BLOCK )) {
2693  Warning (LOCATION, "%s is using the old special hitpoints method but does not appear to have variables for all the values", p_objp->name);
2694  return;
2695  }
2696  }
2697 
2698  p_objp->special_hitpoints = atoi(Block_variables[variable_index+HULL_STRENGTH].text);
2699  p_objp->special_shield = atoi(Block_variables[variable_index+SHIELD_STRENGTH].text);
2700 }
2701 
2703  : next(NULL), prev(NULL), dock_list(NULL), created_object(NULL)
2704 {}
2705 
2706 // this will be called when Parse_objects is cleared between missions and upon shutdown
2708 {
2709  dock_free_dock_list(this);
2710 }
2711 
2721 int parse_object(mission *pm, int flag, p_object *p_objp)
2722 {
2723  int i, j, count, delay;
2724  char name[NAME_LENGTH], flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
2725  char flag_strings_2[MAX_PARSE_OBJECT_FLAGS_2][NAME_LENGTH];
2726 
2727  Assert(pm != NULL);
2728 
2729  // Goober5000
2730  p_objp->created_object = NULL;
2731  p_objp->next = NULL;
2732  p_objp->prev = NULL;
2733 
2734  required_string("$Name:");
2735  stuff_string(p_objp->name, F_NAME, NAME_LENGTH);
2736  if (mission_parse_get_parse_object(p_objp->name))
2737  error_display(0, NOX("Redundant ship name: %s\n"), p_objp->name);
2738 
2739 
2740  find_and_stuff("$Class:", &p_objp->ship_class, F_NAME, Ship_class_names, Ship_info.size(), "ship class");
2741  if (p_objp->ship_class < 0)
2742  {
2743  if (Fred_running) {
2744  Warning(LOCATION, "Ship \"%s\" has an invalid ship type (ships.tbl probably changed). Making it type 0\n", p_objp->name);
2745  }
2746  else {
2747  mprintf(("MISSIONS: Ship \"%s\" has an invalid ship type (ships.tbl probably changed). Making it type 0\n", p_objp->name));
2748  }
2749 
2750  p_objp->ship_class = 0;
2752  }
2753 
2754  // Karajorma - See if there are any alternate classes specified for this ship.
2755  p_objp->alt_classes.clear();
2756  // The alt class can either be a variable or a ship class name
2757  char alt_ship_class[TOKEN_LENGTH > NAME_LENGTH ? TOKEN_LENGTH : NAME_LENGTH];
2758  int is_variable;
2759 
2760  while (optional_string("$Alt Ship Class:")) {
2761  alt_class new_alt_class;
2762 
2763  is_variable = get_string_or_variable(alt_ship_class);
2764 
2765  if (is_variable) {
2766  new_alt_class.variable_index = get_index_sexp_variable_name(alt_ship_class);
2767  if(new_alt_class.variable_index >= 0) {
2768  new_alt_class.ship_class = ship_info_lookup(Sexp_variables[new_alt_class.variable_index].text);
2769  }
2770  else {
2771  new_alt_class.ship_class = -1;
2772  }
2773  }
2774  else {
2775  new_alt_class.variable_index = -1;
2776  new_alt_class.ship_class = ship_info_lookup(alt_ship_class);
2777  }
2778 
2779  if (new_alt_class.ship_class < 0 ) {
2780  if (!Fred_running) {
2781  Warning(LOCATION, "Ship \"%s\" has an invalid Alternate Ship Class type (ships.tbl probably changed). Skipping this entry", p_objp->name);
2782  continue;
2783  }
2784  else {
2785  // incorrect initial values for a variable can be fixed in FRED
2786  if (new_alt_class.variable_index != -1) {
2787  Warning(LOCATION, "Ship \"%s\" has an invalid Alternate Ship Class type.", p_objp->name);
2788  }
2789  // but there is little we can do if someone spelled a ship class incorrectly
2790  else {
2791  Warning(LOCATION, "Ship \"%s\" has an invalid Alternate Ship Class type. Skipping this entry", p_objp->name);
2792  continue;
2793  }
2794  }
2795  }
2796 
2797  if (optional_string("+Default Class:")) {
2798  new_alt_class.default_to_this_class = true;
2799  }
2800  else {
2801  new_alt_class.default_to_this_class = false;
2802  }
2803 
2804  p_objp->alt_classes.push_back(new_alt_class);
2805  }
2806 
2807  // if this is a multiplayer dogfight mission, skip support ships
2808  if(MULTI_DOGFIGHT && (Ship_info[p_objp->ship_class].flags & SIF_SUPPORT))
2809  return 0;
2810 
2811  // optional alternate name type
2812  p_objp->alt_type_index = -1;
2813  if(optional_string("$Alt:"))
2814  {
2815  // alternate name
2817 
2818  // try and find the alternate name
2819  p_objp->alt_type_index = mission_parse_lookup_alt(name);
2820  if(p_objp->alt_type_index < 0)
2821  WarningEx(LOCATION, "Mission %s\nError looking up alternate ship type name %s!\n", pm->name, name);
2822  else
2823  mprintf(("Using alternate ship type name: %s\n", name));
2824  }
2825 
2826  // optional callsign
2827  p_objp->callsign_index = -1;
2828  if(optional_string("$Callsign:"))
2829  {
2830  // alternate callsign
2832 
2833  // try and find the callsign
2835  if(p_objp->callsign_index < 0)
2836  WarningEx(LOCATION, "Mission %s\nError looking up callsign %s!\n", pm->name, name);
2837  else
2838  mprintf(("Using callsign: %s\n", name));
2839  }
2840 
2841  // static alias stuff - stupid, but it seems to be necessary
2842  static char *temp_team_names[MAX_IFFS];
2843  for (i = 0; i < Num_iffs; i++)
2844  temp_team_names[i] = Iff_info[i].iff_name;
2845 
2846  find_and_stuff("$Team:", &p_objp->team, F_NAME, temp_team_names, Num_iffs, "team name");
2847 
2848  if (optional_string("$Team Color Setting:")) {
2849  char temp[NAME_LENGTH];
2851  p_objp->team_color_setting = temp;
2852 
2853  if (Team_Colors.find(p_objp->team_color_setting) == Team_Colors.end()) {
2854  mprintf(("Invalid team color specified in mission file for ship %s, resetting to default\n", p_objp->name));
2855  p_objp->team_color_setting = Ship_info[p_objp->ship_class].default_team_name;
2856  }
2857  }
2858 
2859  required_string("$Location:");
2860  stuff_vec3d(&p_objp->pos);
2861 
2862  required_string("$Orientation:");
2863  stuff_matrix(&p_objp->orient);
2864 
2865  // legacy code, not even used in FS1
2866  if (optional_string("$IFF:"))
2867  {
2869  }
2870 
2871  find_and_stuff("$AI Behavior:", &p_objp->behavior, F_NAME, Ai_behavior_names, Num_ai_behaviors, "AI behavior");
2872  p_objp->ai_goals = -1;
2873 
2874  if (optional_string("+AI Class:"))
2875  {
2876  p_objp->ai_class = match_and_stuff(F_NAME, Ai_class_names, Num_ai_classes, "AI class");
2877 
2878  if (p_objp->ai_class < 0)
2879  {
2880  Warning(LOCATION, "AI Class for ship %s does not exist in ai.tbl. Setting to first available class.\n", p_objp->name);
2881  p_objp->ai_class = 0;
2882  }
2883  }
2884  else
2885  {
2886  p_objp->ai_class = Ship_info[p_objp->ship_class].ai_class;
2887  }
2888 
2889  if (optional_string("$AI Goals:"))
2890  p_objp->ai_goals = get_sexp_main();
2891 
2892  if (!required_string_either("$AI Goals:", "$Cargo 1:"))
2893  {
2894  required_string("$AI Goals:");
2895  p_objp->ai_goals = get_sexp_main();
2896  }
2897 
2898  p_objp->cargo1 = -1;
2899  int temp;
2900  find_and_stuff_or_add("$Cargo 1:", &temp, F_NAME, Cargo_names, &Num_cargo, MAX_CARGO, "cargo");
2901  p_objp->cargo1 = char(temp);
2902  if (optional_string("$Cargo 2:"))
2903  {
2905  }
2906 
2907  parse_common_object_data(p_objp); // get initial conditions and subsys status
2908  count = 0;
2909  while (required_string_either("$Arrival Location:", "$Status Description:")) {
2910  Assert(count < MAX_OBJECT_STATUS);
2911 
2912  find_and_stuff("$Status Description:", &p_objp->status_type[count], F_NAME, Status_desc_names, Num_status_names, "Status Description");
2913  find_and_stuff("$Status:", &p_objp->status[count], F_NAME, Status_type_names, Num_status_names, "Status Type");
2914  find_and_stuff("$Target:", &p_objp->target[count], F_NAME, Status_target_names, Num_status_names, "Target");
2915  count++;
2916  }
2917  p_objp->status_count = count;
2918 
2919  p_objp->arrival_anchor = -1;
2920  p_objp->arrival_distance = 0;
2921  p_objp->arrival_path_mask = -1; // -1 only until resolved
2922 
2923  find_and_stuff("$Arrival Location:", &p_objp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
2924 
2925  if (optional_string("+Arrival Distance:"))
2926  {
2927  stuff_int(&p_objp->arrival_distance);
2928 
2929  // Goober5000
2930  if ((p_objp->arrival_distance <= 0) && ((p_objp->arrival_location == ARRIVE_NEAR_SHIP) || (p_objp->arrival_location == ARRIVE_IN_FRONT_OF_SHIP)))
2931  {
2932  Warning(LOCATION, "Arrival distance for ship %s cannot be %d. Setting to 1.\n", p_objp->name, p_objp->arrival_distance);
2933  p_objp->arrival_distance = 1;
2934  }
2935  }
2936 
2937  if (p_objp->arrival_location != ARRIVE_AT_LOCATION)
2938  {
2939  required_string("$Arrival Anchor:");
2941  p_objp->arrival_anchor = get_anchor(name);
2942  }
2943 
2944  if (optional_string("+Arrival Paths:"))
2945  {
2946  // temporarily use mask to point to the restriction index
2948  }
2949 
2950  delay = 0;
2951  if (optional_string("+Arrival Delay:"))
2952  {
2953  stuff_int(&delay);
2954  if (delay < 0)
2955  Error(LOCATION, "Cannot have arrival delay < 0 (ship %s)", p_objp->name);
2956  }
2957 
2958  if (!Fred_running)
2959  p_objp->arrival_delay = -delay; // use negative numbers to mean we haven't set up a timer yet
2960  else
2961  p_objp->arrival_delay = delay;
2962 
2963  required_string("$Arrival Cue:");
2964  p_objp->arrival_cue = get_sexp_main();
2965  if (!Fred_running && (p_objp->arrival_cue >= 0))
2966  {
2967  // eval the arrival cue. if the cue is true, set up the timestamp for the arrival delay
2968  Assert (p_objp->arrival_delay <= 0);
2969 
2970  // don't eval arrival_cues when just looking for player information.
2971  // evaluate to determine if sexp is always false.
2972  if (eval_sexp(p_objp->arrival_cue))
2973  p_objp->arrival_delay = timestamp(-p_objp->arrival_delay * 1000);
2974  }
2975 
2976  p_objp->departure_anchor = -1;
2977  p_objp->departure_path_mask = -1; // -1 only until resolved
2978 
2979  find_and_stuff("$Departure Location:", &p_objp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
2980 
2981  if (p_objp->departure_location != DEPART_AT_LOCATION)
2982  {
2983  required_string("$Departure Anchor:");
2985  p_objp->departure_anchor = get_anchor(name);
2986  }
2987 
2988  if (optional_string("+Departure Paths:"))
2989  {
2990  // temporarily use mask to point to the restriction index
2992  }
2993 
2994  delay = 0;
2995  if (optional_string("+Departure Delay:"))
2996  {
2997  stuff_int(&delay);
2998  if (delay < 0)
2999  Error(LOCATION, "Cannot have departure delay < 0 (ship %s)", p_objp->name);
3000  }
3001 
3002  if (!Fred_running)
3003  p_objp->departure_delay = -delay;
3004  else
3005  p_objp->departure_delay = delay;
3006 
3007  required_string("$Departure Cue:");
3008  p_objp->departure_cue = get_sexp_main();
3009 
3010  if (optional_string("$Misc Properties:"))
3011  stuff_string(p_objp->misc, F_NAME, NAME_LENGTH);
3012 
3013  required_string("$Determination:");
3014  int dummy;
3015  stuff_int(&dummy);
3016 
3017  // set flags
3018  p_objp->flags = 0;
3019  if (optional_string("+Flags:"))
3020  {
3021  count = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
3022  for (i=0; i<count; i++)
3023  {
3024  for (j=0; j<MAX_PARSE_OBJECT_FLAGS; j++)
3025  {
3026  if (!stricmp(flag_strings[i], Parse_object_flags[j]))
3027  {
3028  p_objp->flags |= (1 << j);
3029  break;
3030  }
3031  }
3032 
3033  if (j == MAX_PARSE_OBJECT_FLAGS)
3034  Warning(LOCATION, "Unknown flag in mission file: %s\n", flag_strings[i]);
3035  }
3036  }
3037 
3038  // second set - Goober5000
3039  p_objp->flags2 = 0;
3040  if (optional_string("+Flags2:"))
3041  {
3042  count = stuff_string_list(flag_strings_2, MAX_PARSE_OBJECT_FLAGS_2);
3043  for (i=0; i<count; i++)
3044  {
3045  for (j=0; j<MAX_PARSE_OBJECT_FLAGS_2; j++)
3046  {
3047  if (!stricmp(flag_strings_2[i], Parse_object_flags_2[j]))
3048  {
3049  p_objp->flags2 |= (1 << j);
3050  break;
3051  }
3052  }
3053 
3054  if (j == MAX_PARSE_OBJECT_FLAGS_2)
3055  Warning(LOCATION, "Unknown flag2 in mission file: %s\n", flag_strings_2[i]);
3056  }
3057  }
3058 
3059 
3060  // always store respawn priority, just for ease of implementation
3061  p_objp->respawn_priority = 0;
3062  if(optional_string("+Respawn Priority:"))
3063  stuff_int(&p_objp->respawn_priority);
3064 
3065  p_objp->escort_priority = 0;
3066  if (optional_string("+Escort Priority:"))
3067  {
3068  Assert(p_objp->flags & P_SF_ESCORT);
3069  stuff_int(&p_objp->escort_priority);
3070  }
3071 
3072  if (p_objp->flags & P_OF_PLAYER_START)
3073  {
3074  p_objp->flags |= P_SF_CARGO_KNOWN; // make cargo known for players
3075  Player_starts++;
3076  }
3077 
3078  p_objp->use_special_explosion = false;
3079  p_objp->special_exp_damage = -1;
3080  p_objp->special_exp_blast = -1;
3081  p_objp->special_exp_inner = -1;
3082  p_objp->special_exp_outer = -1;
3083  p_objp->use_shockwave = false;
3084  p_objp->special_exp_shockwave_speed = 0;
3085  p_objp->special_exp_deathroll_time = 0;
3086 
3087  p_objp->special_hitpoints = 0;
3088  p_objp->special_shield = -1;
3089 
3090  if (optional_string("$Special Explosion:")) {
3091  p_objp->use_special_explosion = true;
3092  bool period_detected = false;
3093 
3094  if (required_string("+Special Exp Damage:")) {
3095  stuff_int(&p_objp->special_exp_damage);
3096 
3097  if (*Mp == '.') {
3098  period_detected = true;
3099  advance_to_eoln(NULL);
3100  }
3101  }
3102 
3103  if (required_string("+Special Exp Blast:")) {
3104  stuff_int(&p_objp->special_exp_blast);
3105 
3106  if (*Mp == '.') {
3107  period_detected = true;
3108  advance_to_eoln(NULL);
3109  }
3110  }
3111 
3112  if (required_string("+Special Exp Inner Radius:")) {
3113  stuff_int(&p_objp->special_exp_inner);
3114 
3115  if (*Mp == '.') {
3116  period_detected = true;
3117  advance_to_eoln(NULL);
3118  }
3119  }
3120 
3121  if (required_string("+Special Exp Outer Radius:")) {
3122  stuff_int(&p_objp->special_exp_outer);
3123 
3124  if (*Mp == '.') {
3125  period_detected = true;
3126  advance_to_eoln(NULL);
3127  }
3128  }
3129 
3130  if (optional_string("+Special Exp Shockwave Speed:")) {
3132  p_objp->use_shockwave = true;
3133 
3134  if (*Mp == '.') {
3135  period_detected = true;
3136  advance_to_eoln(NULL);
3137  }
3138  }
3139 
3140  if (optional_string("+Special Exp Death Roll Time:")) {
3142  }
3143 
3144  if (period_detected) {
3145  nprintf(("Warning", "Special explosion attributes have been returned to integer format"));
3146  }
3147  }
3148 
3149  if (optional_string("+Special Hitpoints:")) {
3150  stuff_int(&p_objp->special_hitpoints);
3151  }
3152 
3153  if (optional_string("+Special Shield Points:")) {
3154  stuff_int(&p_objp->special_shield);
3155  }
3156 
3157  if (optional_string("+Special Exp index:")) {
3158  int variable_index;
3159  stuff_int(&variable_index);
3160  fix_old_special_explosions(p_objp, variable_index);
3161  }
3162 
3163  if (optional_string("+Special Hitpoint index:")) {
3164  int variable_index;
3165  stuff_int(&variable_index);
3166  fix_old_special_hits(p_objp, variable_index);
3167  }
3168 
3169  // set custom shield value
3170  if (p_objp->special_shield != -1) {
3171  p_objp->ship_max_shield_strength = (float) p_objp->special_shield;
3172  }
3173  else {
3174  p_objp->ship_max_shield_strength = Ship_info[p_objp->ship_class].max_shield_strength;
3175  }
3176 
3177  // set custom hitpoint value
3178  if (p_objp->special_hitpoints > 0) {
3179  p_objp->ship_max_hull_strength = (float) p_objp->special_hitpoints;
3180  }
3181  else {
3182  p_objp->ship_max_hull_strength = Ship_info[p_objp->ship_class].max_hull_strength;
3183  }
3184 
3185  Assert(p_objp->ship_max_hull_strength > 0.0f); // Goober5000: div-0 check (not shield because we might not have one)
3186  p_objp->max_shield_recharge = Ship_info[p_objp->ship_class].max_shield_recharge;
3187 
3188 
3189  // if the kamikaze flag is set, we should have the next flag
3190  if (optional_string("+Kamikaze Damage:"))
3191  {
3192  int damage;
3193 
3194  stuff_int(&damage);
3195  p_objp->kamikaze_damage = damage;
3196  }
3197 
3198  p_objp->hotkey = -1;
3199  if (optional_string("+Hotkey:"))
3200  {
3201  stuff_int(&p_objp->hotkey);
3202  Assert((p_objp->hotkey >= 0) && (p_objp->hotkey < 10));
3203  }
3204 
3205  // Goober5000
3206  p_objp->dock_list = NULL;
3207  while (optional_string("+Docked With:"))
3208  {
3209  char docked_with[NAME_LENGTH];
3210  char docker_point[NAME_LENGTH];
3211  char dockee_point[NAME_LENGTH];
3212 
3213  // grab docking information
3214  // (whoever designed the original docking system
3215  // reversed the dockpoints in the mission file)
3216  stuff_string(docked_with, F_NAME, NAME_LENGTH);
3217  required_string("$Docker Point:");
3218  stuff_string(dockee_point, F_NAME, NAME_LENGTH);
3219  required_string("$Dockee Point:");
3220  stuff_string(docker_point, F_NAME, NAME_LENGTH);
3221 
3222  // make sure we don't overflow the limit
3224  {
3225  mprintf(("Too many initially docked instances; skipping...\n"));
3226  continue;
3227  }
3228 
3229  // put this information into the Initially_docked array
3232  strcpy_s(Initially_docked[Total_initially_docked].docker_point, docker_point);
3233  strcpy_s(Initially_docked[Total_initially_docked].dockee_point, dockee_point);
3235  }
3236 
3237  // check the optional parameter for destroying the ship before the mission starts. If this parameter is
3238  // here, then we need to destroy the ship N seconds before the mission starts (for debris purposes).
3239  // store the time value here. We want to create this object for sure. Set the arrival cue and arrival
3240  // delay to bogus values
3241  p_objp->destroy_before_mission_time = -1;
3242  if (optional_string("+Destroy At:"))
3243  {
3245  Assert (p_objp->destroy_before_mission_time >= 0);
3246  p_objp->arrival_cue = Locked_sexp_true;
3247  p_objp->arrival_delay = timestamp(0);
3248  }
3249 
3250  // check for the optional "orders accepted" string which contains the orders from the default
3251  // set that this ship will actually listen to
3252  if (optional_string("+Orders Accepted:"))
3253  {
3254  stuff_int(&p_objp->orders_accepted);
3255  if (p_objp->orders_accepted != -1)
3256  p_objp->flags |= P_SF_USE_UNIQUE_ORDERS;
3257  }
3258 
3259  p_objp->group = 0;
3260  if (optional_string("+Group:"))
3261  stuff_int(&p_objp->group);
3262 
3263  bool table_score = false;
3264  if (optional_string("+Use Table Score:")) {
3265  table_score = true;
3266  }
3267 
3268  if (optional_string("+Score:")) {
3269  if (!table_score) {
3270  stuff_int(&p_objp->score);
3271  }
3272  // throw away the value the mission file has and use the table value.
3273  else {
3274  int temp_score;
3275  stuff_int(&temp_score);
3276  }
3277  }
3278  else {
3279  table_score = true;
3280  }
3281 
3282  if (table_score) {
3283  p_objp->score = Ship_info[p_objp->ship_class].score;
3284  }
3285 
3286  if (optional_string("+Assist Score Percentage:")) {
3287  stuff_float(&p_objp->assist_score_pct);
3288  // value must be a percentage
3289  if (p_objp->assist_score_pct < 0) {
3290  p_objp->assist_score_pct = 0;
3291  }
3292  else if (p_objp->assist_score_pct > 1) {
3293  p_objp->assist_score_pct = 1;
3294  }
3295  }
3296  else {
3297  p_objp->assist_score_pct = 0;
3298  }
3299 
3300  // parse the persona index if present
3301  p_objp->persona_index = -1;
3302  if (optional_string("+Persona Index:"))
3303  stuff_int(&p_objp->persona_index);
3304 
3305  // texture replacement - Goober5000
3306  p_objp->replacement_textures = Ship_info[p_objp->ship_class].replacement_textures; // initialize our set with the ship class set, which may be empty
3307  if (optional_string("$Texture Replace:") || optional_string("$Duplicate Model Texture Replace:"))
3308  {
3309  texture_replace tr;
3310  char *p;
3311 
3312  while (optional_string("+old:"))
3313  {
3314  strcpy_s(tr.ship_name, p_objp->name);
3315  tr.new_texture_id = -1;
3316 
3318  required_string("+new:");
3320 
3321  // get rid of extensions
3322  p = strchr(tr.old_texture, '.');
3323  if (p)
3324  {
3325  mprintf(("Extraneous extension found on replacement texture %s!\n", tr.old_texture));
3326  *p = 0;
3327  }
3328  p = strchr(tr.new_texture, '.');
3329  if (p)
3330  {
3331  mprintf(("Extraneous extension found on replacement texture %s!\n", tr.new_texture));
3332  *p = 0;
3333  }
3334 
3335  // add it if we aren't over the limit
3336  if (p_objp->replacement_textures.size() < MAX_MODEL_TEXTURES)
3337  p_objp->replacement_textures.push_back(tr);
3338  else
3339  mprintf(("Too many replacement textures specified for ship '%s'!\n", p_objp->name));
3340  }
3341  }
3342 
3343  // now load the textures (do this outside the parse loop because we may have ship class replacements too)
3344  for (SCP_vector<texture_replace>::iterator tr = p_objp->replacement_textures.begin(); tr != p_objp->replacement_textures.end(); ++tr)
3345  {
3346  // load the texture
3347  if (!stricmp(tr->new_texture, "invisible"))
3348  {
3349  // invisible is a special case
3350  tr->new_texture_id = REPLACE_WITH_INVISIBLE;
3351  }
3352  else
3353  {
3354  // try to load texture or anim as normal
3355  tr->new_texture_id = bm_load_either(tr->new_texture);
3356  }
3357 
3358  // not found?
3359  if (tr->new_texture_id < 0)
3360  {
3361  mprintf(("Could not load replacement texture %s for ship %s\n", tr->new_texture, p_objp->name));
3362  }
3363 
3364  // account for FRED
3365  if (Fred_running)
3366  {
3367  Fred_texture_replacements.push_back(*tr);
3368  Fred_texture_replacements.back().new_texture_id = -1;
3369  }
3370  }
3371 
3372  p_objp->wingnum = -1; // set the wing number to -1 -- possibly to be set later
3373  p_objp->pos_in_wing = -1; // Goober5000
3374 
3375  for (i=0;i<MAX_IFFS;i++)
3376  {
3377  for (j=0;j<MAX_IFFS;j++)
3378  {
3379  p_objp->alt_iff_color[i][j] = -1;
3380  }
3381  }
3382 
3383  // for multiplayer, assign a network signature to this parse object. Doing this here will
3384  // allow servers to use the signature with clients when creating new ships, instead of having
3385  // to pass ship names all the time
3386  if (Game_mode & GM_MULTIPLAYER)
3388 
3389  // set the wing_status position to be -1 for all objects. This will get set to an appropriate
3390  // value when the wing positions are finally determined.
3391  p_objp->wing_status_wing_index = -1;
3392  p_objp->wing_status_wing_pos = -1;
3393  p_objp->respawn_count = 0;
3394 
3395  // Goober5000 - preload stuff for certain object flags
3396  // (done after parsing object, but before creating it)
3397  if (p_objp->flags & P_KNOSSOS_WARP_IN)
3399 
3400  // this is a valid/legal ship to create
3401  return 1;
3402 }
3403 
3405 {
3406  ship_info *sip = NULL;
3407  model_subsystem *subsystems = NULL;
3408 
3409  // only for objects which show up after the start of a mission
3410  if (p_objp->created_object != NULL)
3411  return;
3412 
3413  Assert( p_objp->ship_class >= 0 );
3414 
3415  sip = &Ship_info[p_objp->ship_class];
3416 
3417  if (sip->n_subsystems > 0) {
3418  subsystems = &sip->subsystems[0];
3419  }
3420 
3421  // we need the model to process the texture set, so go ahead and load it now
3422  sip->model_num = model_load(sip->pof_file, sip->n_subsystems, subsystems);
3423 }
3424 
3425 // Goober5000 - I split this because 1) it's clearer; and 2) initially multiple docked ships would have been
3426 // insanely difficult otherwise
3427 //
3428 // Maybe create the object.
3429 // Don't create the new ship blindly. First, check the sexp for the arrival cue
3430 // to determine when this ship should arrive. If not right away, stick this ship
3431 // onto the ship arrival list to be looked at later. Also check to see if it should use the
3432 // wings arrival cue. The ship may get created later depending on whether or not the wing
3433 // is created.
3434 // Always create ships when FRED is running.
3436 {
3437  // Bail if it was already created. This should only happen when we previously
3438  // created all the objects in a docked group simultaneously.
3439  if (pobjp->created_object != NULL)
3440  {
3441  Assert(object_is_docked(pobjp));
3442  return;
3443  }
3444 
3445  // Goober5000
3446  // shunt this guy to the arrival list if he meets one of the following conditions:
3447  // 1) he's docked but not the dock leader
3448  // 2) this is FS2 (i.e. not FRED2) AND he meets one of the following conditions:
3449  // a) he's not cued to arrive yet
3450  // b) his arrival delay hasn't elapsed
3451  // c) he's reinforcement
3452  if ( (object_is_docked(pobjp) && !(pobjp->flags & P_SF_DOCK_LEADER)) || (!Fred_running && (!eval_sexp(pobjp->arrival_cue) || !timestamp_elapsed(pobjp->arrival_delay) || (pobjp->flags & P_SF_REINFORCEMENT))) )
3453  {
3454  // we can't add ships getting destroyed to the arrival list!!!
3455  Assert (pobjp->destroy_before_mission_time < 0);
3456 
3457  // add to arrival list
3458  list_append(&Ship_arrival_list, pobjp);
3459 
3460  // we need to deal with replacement textures now, so that texture page-in will work properly
3462  }
3463  // ingame joiners bail here.
3465  {
3466  return;
3467  }
3468  // the ship is present at the beginning of the mission, so we create it
3469  else
3470  {
3471  int real_objnum = parse_create_object(pobjp); // this object may later get destroyed depending on wing status!!!!
3472 
3473  // if the ship is supposed to be destroyed before the mission, then blow up the ship and mark the pieces
3474  // as last forever. Only call this stuff when you are blowing up the ship
3475  if (pobjp->destroy_before_mission_time >= 0)
3476  {
3477  object *objp = &Objects[real_objnum];
3478 
3479  // FreeSpace
3480  if (!Fred_running)
3481  {
3482  int i;
3483  shipfx_blow_up_model(objp, Ship_info[Ships[objp->instance].ship_info_index].model_num, 0, 0, &objp->pos);
3484  objp->flags |= OF_SHOULD_BE_DEAD;
3485 
3486  // once the ship is exploded, find the debris pieces belonging to this object, mark them
3487  // as not to expire, and move them forward in time N seconds
3488  for (i = 0; i < MAX_DEBRIS_PIECES; i++)
3489  {
3490  debris *db;
3491 
3492  db = &Debris[i];
3493  if (!(db->flags & DEBRIS_USED)) // not used, move onto the next one.
3494  continue;
3495  if (db->source_objnum != real_objnum) // not from this ship, move to next one
3496  continue;
3497 
3498  debris_clear_expired_flag(db); // mark as don't expire
3499  db->lifeleft = -1.0f; // be sure that lifeleft == -1.0 so that it really doesn't expire!
3500 
3501  // now move the debris along its path for N seconds
3502  objp = &Objects[db->objnum];
3503  physics_sim(&objp->pos, &objp->orient, &objp->phys_info, (float) pobjp->destroy_before_mission_time);
3504  }
3505  }
3506  // FRED
3507  else
3508  {
3509  // be sure to set the variable in the ships structure for the final death time!!!
3512  }
3513  }
3514  }
3515 }
3516 
3518 {
3519  int i;
3520 
3521  // Genghis: used later for subsystem checking
3522  ship_info* sip = &Ship_info[objp->ship_class];
3523 
3524  // set some defaults..
3525  objp->initial_velocity = 0;
3526  objp->initial_hull = 100;
3527  objp->initial_shields = 100;
3528 
3529  // now change defaults if present
3530  if (optional_string("+Initial Velocity:")) {
3531  stuff_int(&objp->initial_velocity);
3532  }
3533 
3534  if (optional_string("+Initial Hull:"))
3535  stuff_int(&objp->initial_hull);
3536  if (optional_string("+Initial Shields:"))
3537  stuff_int(&objp->initial_shields);
3538 
3539  objp->subsys_index = Subsys_index;
3540  objp->subsys_count = 0;
3541  while (optional_string("+Subsystem:")) {
3542  i = allocate_subsys_status();
3543 
3544  objp->subsys_count++;
3545  stuff_string(Subsys_status[i].name, F_NAME, NAME_LENGTH);
3546 
3547  // Genghis: check that the subsystem name makes sense for this ship type
3548  if (subsystem_stricmp(Subsys_status[i].name, NOX("pilot")))
3549  {
3550  int j;
3551  for (j=0; j < sip->n_subsystems; ++j)
3552  if (!subsystem_stricmp(sip->subsystems[j].subobj_name, Subsys_status[i].name))
3553  break;
3554  //if (j == sip->n_subsystems)
3555  //Warning(LOCATION, "Ship \"%s\", class \"%s\"\nUnknown subsystem \"%s\" found in mission!", objp->name, sip->name, Subsys_status[i].name);
3556  }
3557 
3558  if (optional_string("$Damage:"))
3559  stuff_float(&Subsys_status[i].percent);
3560 
3561  Subsys_status[i].subsys_cargo_name = 0;
3562  if (optional_string("+Cargo Name:")) {
3563  char cargo_name[NAME_LENGTH];
3564  stuff_string(cargo_name, F_NAME, NAME_LENGTH);
3565  int index = string_lookup(cargo_name, Cargo_names, Num_cargo, "cargo", 0);
3566  if (index == -1) {
3567  if (Num_cargo < MAX_CARGO) {
3568  index = Num_cargo;
3569  strcpy(Cargo_names[Num_cargo++], cargo_name);
3570  }
3571  else {
3572  WarningEx(LOCATION, "Maximum number of cargo names (%d) exceeded, defaulting to Nothing!", MAX_CARGO);
3573  index = 0;
3574  }
3575  }
3576  Subsys_status[i].subsys_cargo_name = index;
3577  }
3578 
3579  if (optional_string("+AI Class:"))
3580  Subsys_status[i].ai_class = match_and_stuff(F_NAME, Ai_class_names, Num_ai_classes, "AI class");
3581 
3582  if (optional_string("+Primary Banks:"))
3583  stuff_int_list(Subsys_status[i].primary_banks, MAX_SHIP_PRIMARY_BANKS, WEAPON_LIST_TYPE);
3584 
3585  // Goober5000
3586  if (optional_string("+Pbank Ammo:"))
3587  stuff_int_list(Subsys_status[i].primary_ammo, MAX_SHIP_PRIMARY_BANKS, RAW_INTEGER_TYPE);
3588 
3589  if (optional_string("+Secondary Banks:"))
3590  stuff_int_list(Subsys_status[i].secondary_banks, MAX_SHIP_SECONDARY_BANKS, WEAPON_LIST_TYPE);
3591 
3592  if (optional_string("+Sbank Ammo:"))
3593  stuff_int_list(Subsys_status[i].secondary_ammo, MAX_SHIP_SECONDARY_BANKS, RAW_INTEGER_TYPE);
3594 
3595  }
3596 }
3597 
3598 
3603 int get_reassigned_index(team_data *current_team, int ship_class)
3604 {
3605  // Search through the available ships to see if there is a matching ship class in the loadout
3606  for (int i=0; i < current_team->num_ship_choices; i++)
3607  {
3608  if (ship_class == current_team->ship_list[i])
3609  {
3610  if (current_team->ship_count[i] > 0) {
3611  return i;
3612  }
3613  else {
3614  return -1;
3615  }
3616  }
3617  }
3618 
3619  return -1;
3620 }
3621 
3625 void update_loadout_totals(team_data *current_team, int loadout_index)
3626 {
3627  // Fix the loadout variables to show that the class has less available if there are still ships available
3628  if (current_team->ship_count[loadout_index] > 0)
3629  {
3630  Assert (current_team->loadout_total > 0);
3631 
3632  current_team->ship_count[loadout_index]--;
3633  current_team->loadout_total--;
3634  }
3635 }
3636 
3644 {
3645  int loadout_index = -1;
3646 
3647  team_data *data_for_team = &Team_data[p_objp->team];
3648 
3649  // First lets check if the ship specified in the mission file is of an assignable class
3650  loadout_index = get_reassigned_index(data_for_team, p_objp->ship_class);
3651  if (loadout_index != -1 )
3652  {
3653  Assert (data_for_team->loadout_total > 0);
3654 
3655  update_loadout_totals(data_for_team, loadout_index);
3656 
3657  // Since the ship in the mission file matched one available in the loadout we need go no further
3658  return true;
3659  }
3660 
3661  // Now we check the alt_classes (if there are any)
3662  for (SCP_vector<alt_class>::iterator pac = p_objp->alt_classes.begin(); pac != p_objp->alt_classes.end(); ++pac) {
3663  // we don't check availability unless we are asked to
3664  if (pac->default_to_this_class == false) {
3665  loadout_index = pac->ship_class;
3666  break;
3667  }
3668  else {
3669  loadout_index = get_reassigned_index(data_for_team, pac->ship_class);
3670  if (loadout_index != -1 ) {
3671  update_loadout_totals(data_for_team, loadout_index);
3672  break;
3673  }
3674  }
3675  }
3676 
3677  // If we managed to assign a class we'd may need to actually swap to it
3678  if (loadout_index != -1 ) {
3679  if (p_objp->ship_class != data_for_team->ship_list[loadout_index])
3680  {
3681  swap_parse_object(p_objp, data_for_team->ship_list[loadout_index]);
3682  }
3683  return true;
3684  }
3685 
3686  return false;
3687 }
3688 
3694 {
3695  SCP_vector<size_t> reassignments;
3696 
3697  // Loop through all the Parse_objects looking for ships that should be affected by the loadout code.
3698  for (size_t i=0; i < Parse_objects.size(); i++)
3699  {
3700  p_object *p_objp = &Parse_objects[i];
3701  if (p_objp->flags2 & P2_SF2_SET_CLASS_DYNAMICALLY)
3702  {
3703  if (!(is_ship_assignable(p_objp)))
3704  {
3705  // store the ship so we can come back to it later.
3706  reassignments.push_back(i);
3707  }
3708  }
3709  }
3710 
3711  // Now we go though the ships we were unable to assign earlier and reassign them on a first come first
3712  // served basis.
3713  for (size_t m=0; m < reassignments.size(); m++)
3714  {
3715  p_object *p_objp = &Parse_objects[reassignments[m]];
3716  team_data *current_team = &Team_data[p_objp->team];
3717  bool loadout_assigned = false;
3719 
3720  // First thing to check is whether we actually have any ships left to assign
3721  if (current_team->loadout_total == 0)
3722  {
3723  // If there is nothing left to assign we should use the ship in the mission file
3724  loadout_assigned = true;
3725  }
3726  // We do have ships left in the team loadout that we can assign
3727  else
3728  {
3729  // Go through the loadout until we find an unassigned ship
3730  for (int j=0; j < current_team->num_ship_choices; j++)
3731  {
3732  if (current_team->ship_count[j] > 0)
3733  {
3734  update_loadout_totals(current_team, j);
3735  // We will need to assign a new class too (if a p_object the same class was available
3736  // it should have been assigned by attempt_loadout_assignation_from_defaults()
3737  Assert (p_objp->ship_class != current_team->ship_list[j]);
3738  swap_parse_object(p_objp, current_team->ship_list[j]);
3739 
3740  loadout_assigned = true;
3741  break ;
3742  }
3743  }
3744  }
3745 
3746  // We should never reach here with an unassigned loadout
3747  Assert (loadout_assigned);
3748  }
3749 }
3750 
3751 extern int Multi_ping_timestamp;
3752 void parse_objects(mission *pm, int flag)
3753 {
3754  Assert(pm != NULL);
3755 
3756  required_string("#Objects");
3757 
3758  // parse in objects
3759  Parse_objects.clear();
3760  while (required_string_either("#Wings", "$Name:"))
3761  {
3762  p_object pobj;
3763 
3764  // parse a single object
3765  int valid = parse_object(pm, flag, &pobj);
3766 
3767  // not all objects are always valid or legal
3768  if (!valid)
3769  continue;
3770 
3771  // add it
3772  Parse_objects.push_back(pobj);
3773 
3774  // send out a ping if we are multi so that psnet2 doesn't kill us off for a long load
3775  // NOTE that we can't use the timestamp*() functions here since they won't increment
3776  // during this loading process
3777  if (Game_mode & GM_MULTIPLAYER)
3778  {
3779  if ((Multi_ping_timestamp == -1) || (Multi_ping_timestamp <= timer_get_milliseconds()))
3780  {
3782  Multi_ping_timestamp = timer_get_milliseconds() + 10000; // timeout is 10 seconds between pings
3783  }
3784  }
3785  }
3786 
3787  // Goober5000 - I moved the docking stuff to post_process_ships_wings because of interdependencies
3788  // between ships and wings. Neither docking stuff nor ship stuff (for ships present at mission start)
3789  // will be valid until after post_process_ships_wings is run.
3790 
3791  // Karajorma - Now that we've parsed all the objects we can set the class of those which were flagged
3792  // to be set based on the number of ships available in the loadout.
3793  if (!Fred_running)
3794  {
3796  }
3797 }
3798 
3802 void swap_parse_object(p_object *p_obj, int new_ship_class)
3803 {
3804  ship_info *new_ship_info = &Ship_info[new_ship_class];
3805  ship_info *old_ship_info = &Ship_info[p_obj->ship_class];
3806  int subsys_ind = p_obj->subsys_index;
3807  subsys_status *ship_subsystems = &Subsys_status[subsys_ind];
3808 
3809  // Class
3810  // First things first. Change the class of the p_object
3811  p_obj->ship_class = new_ship_class;
3812 
3813  // Hitpoints
3814  // We need to take into account that the ship might have been assigned special hitpoints so we can't
3815  // simply swap old for new.
3816  Assert (p_obj->ship_max_hull_strength > 0);
3817  Assert (old_ship_info->max_hull_strength > 0);
3818 
3819  float hp_multiplier = p_obj->ship_max_hull_strength / old_ship_info->max_hull_strength;
3820  p_obj->ship_max_hull_strength = new_ship_info->max_hull_strength * hp_multiplier;
3821 
3822  // Shields
3823  // Again we have to watch out for special hitpoints but this time we can't assume that there will be a
3824  // shield. So first lets see if there is one.
3825  if ((p_obj->ship_max_shield_strength != old_ship_info->max_shield_strength) &&
3826  (p_obj->ship_max_shield_strength > 0) &&
3827  (new_ship_info->max_shield_strength > 0))
3828  {
3829  // This ship is using special hitpoints to alter the shield strength
3830  float shield_multiplier = p_obj->ship_max_shield_strength / i2fl(old_ship_info->max_shield_strength);
3831  p_obj->ship_max_shield_strength = new_ship_info->max_shield_strength * shield_multiplier;
3832  }
3833  // Not using special hitpoints or a class which has a shield strength of zero
3834  else
3835  {
3836  p_obj->ship_max_shield_strength = new_ship_info->max_shield_strength;
3837  }
3838 
3839  // Primary weapons
3840  // First find out what is the correct number for a ship of this class
3841  int num_pbanks = new_ship_info->num_primary_banks;
3842  // Now cycle through the primary banks looking for banks that were added or removed
3843  for (int i=0; i < MAX_SHIP_PRIMARY_BANKS; i++)
3844  {
3845  // If we're dealing with a primary bank that actually should exist on this ship
3846  if ( i < num_pbanks )
3847  {
3848  // We only care if a weapon hasn't been parsed in for this bank
3849  if (ship_subsystems->primary_banks[i] == -1)
3850  {
3851  // Give the ship the default weapon for this bank.
3852  ship_subsystems->primary_banks[i] = new_ship_info->primary_bank_weapons[i];
3853  }
3854  }
3855  // Any primary banks the ship doesn't have should be set to -1
3856  else
3857  {
3858  ship_subsystems->primary_banks[i] = -1;
3859  }
3860  }
3861 
3862  // Secondary weapons
3863  // Again we first have to find out how many we should have
3864  int num_sbanks = new_ship_info->num_secondary_banks;
3865  // Now cycle through the secondary banks looking for banks that were added or removed
3866  for (int j=0; j < MAX_SHIP_SECONDARY_BANKS; j++)
3867  {
3868  // If we're dealing with a primary bank that actually should exist on this ship
3869  if ( j < num_sbanks )
3870  {
3871  // We only care if a weapon hasn't been parsed in for this bank
3872  if (ship_subsystems->secondary_banks[j] == -1){
3873  // Give the ship the default weapon for this bank.
3874  ship_subsystems->secondary_banks[j] = new_ship_info->secondary_bank_weapons[j];
3875  }
3876  }
3877  // Any secondary banks the ship doesn't have should be set to -1
3878  else
3879  {
3880  ship_subsystems->secondary_banks[j] = -1;
3881  }
3882  }
3883 }
3884 
3886 {
3888 
3889  // look for original ships
3890  for (ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
3891  if (ii->net_signature == net_signature)
3892  return &(*ii);
3893 
3894  // boo
3895  return NULL;
3896 }
3897 
3898 // Goober5000 - also get it by name
3900 {
3902 
3903  // look for original ships
3904  for (ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
3905  if (!stricmp(ii->name, name))
3906  return &(*ii);
3907 
3908  // boo
3909  return NULL;
3910 }
3911 
3913 {
3914  int i;
3915 
3916  for (i = 0; i < Num_wings; i++)
3917  {
3918  if (!stricmp(name, Wings[i].name))
3919  return i;
3920  }
3921 
3922  return -1;
3923 }
3924 
3934 int parse_wing_create_ships( wing *wingp, int num_to_create, int force, int specific_instance )
3935 {
3936  int wingnum, objnum, num_create_save;
3937  int time_to_arrive;
3938  int pre_create_count;
3939  int i, j;
3940 
3941  // we need to send this in multiplayer
3942  pre_create_count = wingp->total_arrived_count;
3943 
3944  // force is used to force creation of the wing -- used for multiplayer
3945  if ( !force ) {
3946  // we only want to evaluate the arrival cue of the wing if:
3947  // 1) single player
3948  // 2) multiplayer and I am the host of the game
3949  // can't create any ships if the arrival cue is false or the timestamp has not elapsed.
3950 
3951  if ( !eval_sexp(wingp->arrival_cue) ) /* || !timestamp_elapsed(wingp->arrival_delay) ) */
3952  return 0;
3953 
3954  // once the sexpressions becomes true, then check the arrival delay on the wing. The first time, the
3955  // arrival delay will be <= 0 meaning that no timer object has been set yet. Set up the timestamp
3956  // which should always give a number >= 0;
3957  if ( wingp->arrival_delay <= 0 ) {
3958  wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
3959  Assert ( wingp->arrival_delay >= 0 );
3960  }
3961 
3962  if ( !timestamp_elapsed( wingp->arrival_delay ) )
3963  return 0;
3964 
3965  // if wing is coming from docking bay, then be sure that ship we are arriving from actually exists
3966  // (or will exist).
3967  if ( wingp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
3968  int shipnum;
3969  char *name;
3970 
3971  Assert( wingp->arrival_anchor >= 0 );
3972  name = Parse_names[wingp->arrival_anchor];
3973 
3974  // see if ship is in mission.
3975  shipnum = ship_name_lookup( name );
3976  if ( shipnum == -1 ) {
3977  int num_remaining;
3978 
3979  // see if ship is yet to arrive. If so, then return 0 so we can evaluate again later.
3981  return 0;
3982 
3983  // since this wing cannot arrive from this place, we need to mark the wing as destroyed and
3984  // set the wing variables appropriately. Good for directives.
3985 
3986  // set the gone flag
3987  wingp->flags |= WF_WING_GONE;
3988 
3989  // mark the number of waves and number of ships destroyed equal to the last wave and the number
3990  // of ships yet to arrive
3991  num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
3992  wingp->total_arrived_count += num_remaining;
3993  wingp->current_wave = wingp->num_waves;
3994 
3995  if ( mission_log_get_time(LOG_SHIP_DESTROYED, name, NULL, NULL) || mission_log_get_time(LOG_SELF_DESTRUCTED, name, NULL, NULL) ) {
3996  wingp->total_destroyed += num_remaining;
3997  } else if ( mission_log_get_time(LOG_SHIP_DEPARTED, name, NULL, NULL) ) {
3998  wingp->total_departed += num_remaining;
3999  } else {
4000  wingp->total_vanished += num_remaining;
4001  }
4002 
4003  mission_parse_mark_non_arrival(wingp); // Goober5000
4004  return 0;
4005  }
4006 
4007  // Goober5000 - check status of fighterbays - if they're destroyed, we can't launch - but we want to reeval later
4008  if (ship_fighterbays_all_destroyed(&Ships[shipnum]))
4009  return 0;
4010  }
4011 
4012  if ( num_to_create == 0 )
4013  return 0;
4014 
4015  // check the wave_delay_timestamp field. If it is not valid, make it valid (based on wave delay min
4016  // and max values). If it is valid, and not elapsed, then return. If it is valid and elasped, then
4017  // continue on.
4018  if ( !timestamp_valid(wingp->wave_delay_timestamp) ) {
4019 
4020  // if at least one of these is valid, then reset the timestamp. If they are both zero, we will create the
4021  // wave
4022  if ( (wingp->wave_delay_min > 0) || (wingp->wave_delay_max > 0) ) {
4023  Assert ( wingp->wave_delay_min <= wingp->wave_delay_max );
4024  time_to_arrive = wingp->wave_delay_min + (int)(frand() * (wingp->wave_delay_max - wingp->wave_delay_min));
4025 
4026  // MWA -- 5/18/98
4027  // HACK HACK -- in the presense of Mike Comet and Mitri, I have introduced one of the most
4028  // serious breaches of coding standards. I'm to lazy to fix this the correct way. Insert
4029  // a delay before the next wave of the wing can arrive to that clients in the game have ample
4030  // time to kill off any ships in the wing before the next wave arrives.
4031  if ( Game_mode & GM_MULTIPLAYER ){
4032  time_to_arrive += 7;
4033  }
4034  wingp->wave_delay_timestamp = timestamp(time_to_arrive * 1000);
4035  return 0;
4036  }
4037 
4038  // if we get here, both min and max values are 0; See comments above for a most serious hack
4039  time_to_arrive = 0;
4040  if ( Game_mode & GM_MULTIPLAYER )
4041  time_to_arrive += 7;
4042  time_to_arrive *= 1000;
4043  wingp->wave_delay_timestamp = timestamp(time_to_arrive);
4044  }
4045 
4046  // now check to see if the wave_delay_timestamp is elapsed or not
4047  if ( !timestamp_elapsed(wingp->wave_delay_timestamp) )
4048  return 0;
4049  }
4050 
4051  // finally we can create the wing.
4052 
4053  num_create_save = num_to_create;
4054 
4055  wingnum = WING_INDEX(wingp); // get the wing number
4056 
4057  // if there are no ships to create, then all ships must be player start ships -- do nothing in this case.
4058  if ( num_to_create == 0 ){
4059  return 0;
4060  }
4061 
4062  wingp->current_wave++; // we are creating new ships
4063  // we need to create num_to_create ships. Since the arrival cues for ships in a wing
4064  // are ignored, then *all* ships must be in the Ship_arrival_list.
4065 
4066  objnum = -1;
4067 
4068  // Goober5000 - we have to do this via the array because we have no guarantee we'll be able to iterate along the list
4069  // (since created objects plus anything they're docked to will be removed from it)
4070  for (SCP_vector<p_object>::iterator ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
4071  {
4072  int index;
4073  ai_info *aip;
4074  p_object *p_objp = &(*ii);
4075 
4076  // ensure on arrival list
4077  if (!parse_object_on_arrival_list(p_objp))
4078  continue;
4079 
4080  // compare the wingnums. When they are equal, we can create the ship. In the case of
4081  // wings that have multiple waves, this code implies that we essentially creating clones
4082  // of the ships that were created in Fred for the wing when more ships for a new wave
4083  // arrive. The threshold value of a wing can also make one of the ships in a wing be "cloned"
4084  // more often than other ships in the wing. I don't think this matters much.
4085  if (p_objp->wingnum != wingnum)
4086  continue;
4087 
4088  Assert( (p_objp->pos_in_wing >= 0) && (p_objp->pos_in_wing < MAX_SHIPS_PER_WING) );
4089 
4090  // when ingame joining, we need to create a specific ship out of the list of ships for a
4091  // wing. specific_instance is a 0 based integer which specified which ship in the wing
4092  // to create. So, only create the ship we actually need to.
4093  if ((Game_mode & GM_MULTIPLAYER) && (specific_instance > 0))
4094  {
4095  specific_instance--;
4096  continue;
4097  }
4098  // when not creating a specific ship, we should skip over any ships that weren't carried along in the red-alert
4099  else if (p_objp->flags2 & P2_RED_ALERT_DELETED)
4100  {
4101  num_to_create--;
4102  num_create_save--;
4103  ship_add_ship_type_count(p_objp->ship_class, -1);
4104  wingp->red_alert_skipped_ships++;
4105 
4106  // clear the flag so that this parse object can be used for the next wave
4107  p_objp->flags2 &= ~P2_RED_ALERT_DELETED;
4108 
4109  // skip over this parse object
4110  if (num_to_create == 0)
4111  break;
4112  else
4113  continue;
4114  }
4115 
4116  Assert (!(p_objp->flags & P_SF_CANNOT_ARRIVE)); // get allender
4117 
4118  // if we have the maximum number of ships in the wing, we must bail as well
4119  if (wingp->current_count >= MAX_SHIPS_PER_WING)
4120  {
4121  Int3(); // this is bogus -- we should always allow all ships to be created
4122  num_to_create = 0;
4123  break;
4124  }
4125 
4126  // bash the ship name to be the name of the wing + some number if there is > 1 wave in this wing
4127  wingp->total_arrived_count++;
4128  if (wingp->num_waves > 1)
4129  wing_bash_ship_name(p_objp->name, wingp->name, wingp->total_arrived_count + wingp->red_alert_skipped_ships);
4130 
4131  // also, if multiplayer, set the parse object's net signature to be wing's net signature
4132  // base + total_arrived_count (before adding 1)
4133  if (Game_mode & GM_MULTIPLAYER)
4134  {
4135  p_objp->net_signature = (ushort) (wingp->net_signature + wingp->total_arrived_count);
4136  }
4137 
4138 
4139  objnum = parse_create_object(p_objp);
4140  aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
4141 
4142  // copy any goals from the wing to the newly created ship
4143  for (index = 0; index < MAX_AI_GOALS; index++)
4144  {
4145  if (wingp->ai_goals[index].ai_mode != AI_GOAL_NONE)
4146  ai_copy_mission_wing_goal(&wingp->ai_goals[index], aip);
4147  }
4148 
4149  Ai_info[Ships[Objects[objnum].instance].ai_index].wing = wingnum;
4150 
4151  if (wingp->flags & WF_NO_DYNAMIC)
4152  aip->ai_flags |= AIF_NO_DYNAMIC;
4153 
4154  // update housekeeping variables
4155  // NOTE: for the initial wing setup we use actual position to get around
4156  // object order isses, but ships in all following waves just get
4157  // tacked onto the end of the list
4158  if (wingp->current_wave == 1) {
4159  wingp->ship_index[p_objp->pos_in_wing] = Objects[objnum].instance;
4160  } else {
4161  wingp->ship_index[wingp->current_count] = Objects[objnum].instance;
4162  }
4163 
4164  // set up wingman status index
4165  hud_wingman_status_set_index(wingp, &Ships[Objects[objnum].instance], p_objp);
4166 
4167  p_objp->wing_status_wing_index = Ships[Objects[objnum].instance].wing_status_wing_index;
4168  p_objp->wing_status_wing_pos = Ships[Objects[objnum].instance].wing_status_wing_pos;
4169 
4170  wingp->current_count++;
4171 
4172  // keep any player ship on the parse object list -- used for respawns
4173  // 5/8/98 -- MWA -- don't remove ships from the list when you are ingame joining
4174  if (!(p_objp->flags & P_OF_PLAYER_START))
4175  {
4177  {
4178  // only remove ship if one wave in wing
4179  if (wingp->num_waves == wingp->current_wave)
4180  {
4181  // remove p_objp from the list
4182  list_remove(&Ship_arrival_list, p_objp);
4183 
4184  // free up sexp nodes for reuse
4185  if (p_objp->ai_goals != -1)
4186  free_sexp2(p_objp->ai_goals);
4187  }
4188  }
4189  }
4190 
4191  // flag ship with SF_FROM_PLAYER_WING if a member of player starting wings
4192  if (MULTI_TEAM)
4193  {
4194  // different for tvt -- Goober5000
4195  for (j = 0; j < MAX_TVT_WINGS; j++)
4196  {
4197  if (!stricmp(TVT_wing_names[j], wingp->name))
4198  Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
4199  }
4200  }
4201  else
4202  {
4203  for (j = 0; j < MAX_STARTING_WINGS; j++)
4204  {
4205  if (!stricmp(Starting_wing_names[j], wingp->name))
4206  Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
4207  }
4208  }
4209 
4210  // keep track of how many ships to create. Stop when we have done all that we are supposed to do.
4211  num_to_create--;
4212  if (num_to_create == 0)
4213  break;
4214  }
4215 
4216  // we should always have enough ships in the list!!!
4217  Assert (num_to_create == 0);
4218 
4219  // wing current_count needs to match the end of the ship_index[] list, but there
4220  // is a very off chance it could have holes in it (especially if it's a red-alert
4221  // wing that arrives late), so make sure to compact the list
4222  int length = MAX_SHIPS_PER_WING;
4223  for (i = 0; i < length; i++)
4224  {
4225  if (wingp->ship_index[i] == -1)
4226  {
4227  // shift actual values downward
4228  for (j = i; j < length - 1; j++)
4229  {
4230  wingp->ship_index[j] = wingp->ship_index[j+1];
4231 
4232  // update "special" ship too
4233  if (wingp->special_ship == j+1)
4234  wingp->special_ship--;
4235  }
4236 
4237  // last value becomes -1
4238  wingp->ship_index[j] = -1;
4239  length--;
4240 
4241  // stay on the current index in case we still have a -1
4242  i--;
4243  }
4244  }
4245 
4246  // possibly play some event driven music here. Send a network packet indicating the wing was
4247  // created. Only do this stuff if actually in the mission.
4248  if ( (objnum != -1) && (Game_mode & GM_IN_MISSION) ) { // if true, we have created at least one new ship.
4249  int it, ship_num;
4250 
4251  // see if this wing is a player starting wing, and if so, call the maybe_add_form_goal
4252  // function to possibly make the wing form on the player
4253  for (it = 0; it < MAX_STARTING_WINGS; it++ ) {
4254  if ( Starting_wings[it] == wingnum ){
4255  break;
4256  }
4257  }
4258  if ( it < MAX_STARTING_WINGS ){
4259  ai_maybe_add_form_goal( wingp );
4260  }
4261 
4262  mission_log_add_entry( LOG_WING_ARRIVED, wingp->name, NULL, wingp->current_wave );
4263  ship_num = wingp->ship_index[0];
4264 
4265  if ( !(Ships[ship_num].flags & SF_NO_ARRIVAL_MUSIC) && !(wingp->flags & WF_NO_ARRIVAL_MUSIC) ) {
4266  if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
4267  Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
4268  event_music_arrival(Ships[ship_num].team);
4269  }
4270  }
4271 
4272  // possibly change the location where these ships arrive based on the wings arrival location
4273  mission_set_wing_arrival_location( wingp, num_create_save );
4274 
4275  // if in multiplayer (and I am the host) and in the mission, send a wing create command to all
4276  // other players
4277  if ( MULTIPLAYER_MASTER ){
4278  send_wing_create_packet( wingp, num_create_save, pre_create_count );
4279  }
4280 
4281 #ifndef NDEBUG
4282  // test code to check to be sure that all ships in the wing are ignoring the same types
4283  // of orders from the leader
4284  if ( Fred_running ) {
4285  Assert( wingp->ship_index[wingp->special_ship] != -1 );
4286  int orders = Ships[wingp->ship_index[0]].orders_accepted;
4287  for (it = 0; it < wingp->current_count; it++ ) {
4288  if (it == wingp->special_ship)
4289  continue;
4290 
4291  if ( orders != Ships[wingp->ship_index[it]].orders_accepted ) {
4292  Warning(LOCATION, "ships in wing %s are ignoring different player orders. Please find Mark A\nto talk to him about this.", wingp->name );
4293  break;
4294  }
4295  }
4296  }
4297 #endif
4298 
4299  }
4300 
4301  wingp->wave_delay_timestamp = timestamp(-1); // we will need to set this up properly for the next wave
4302  return num_create_save;
4303 }
4304 
4306 {
4307  int wingnum, i, wing_goals, delay, saved_arrival_delay;
4308  char name[NAME_LENGTH], ship_names[MAX_SHIPS_PER_WING][NAME_LENGTH];
4309  char wing_flag_strings[MAX_WING_FLAGS][NAME_LENGTH];
4310  wing *wingp;
4311 
4312  Assert(pm != NULL);
4313  wingp = &Wings[Num_wings];
4314 
4315  required_string("$Name:");
4316  stuff_string(wingp->name, F_NAME, NAME_LENGTH);
4317  wingnum = find_wing_name(wingp->name);
4318  if (wingnum != -1)
4319  error_display(0, NOX("Redundant wing name: %s\n"), wingp->name);
4320  wingnum = Num_wings;
4321 
4322  wingp->total_arrived_count = 0;
4323  wingp->red_alert_skipped_ships = 0;
4324  wingp->total_destroyed = 0;
4325  wingp->total_departed = 0; // Goober5000
4326  wingp->total_vanished = 0; // Goober5000
4327  wingp->flags = 0;
4328 
4329  // squad logo - Goober5000
4330  if (optional_string("+Squad Logo:"))
4331  {
4332  int flag = -1;
4333 
4335 
4336  // load it only if FRED isn't running
4337  if (!Fred_running)
4338  {
4339  // check all previous wings to see if we already loaded it (we want to save memory)
4340  for (i = 0; i < Num_wings; i++)
4341  {
4342  // do we have a previous texture?
4343  if (Wings[i].wing_insignia_texture != -1)
4344  {
4345  // if we have a match
4346  if (!stricmp(Wings[i].wing_squad_filename, wingp->wing_squad_filename))
4347  {
4348  flag = i;
4349  break;
4350  }
4351  }
4352  }
4353 
4354  // if we have loaded it already, just use the old bitmap index
4355  if (flag != -1)
4356  {
4358  }
4359  else
4360  {
4361  wing_load_squad_bitmap(wingp);
4362  }
4363  }
4364  }
4365 
4366  required_string("$Waves:");
4367  stuff_int(&wingp->num_waves);
4368  Assert ( wingp->num_waves >= 1 ); // there must be at least 1 wave
4369 
4370  wingp->current_wave = 0;
4371 
4372  required_string("$Wave Threshold:");
4373  stuff_int(&wingp->threshold);
4374 
4375  required_string("$Special Ship:");
4376  stuff_int(&wingp->special_ship);
4377 
4378  wingp->arrival_anchor = -1;
4379  wingp->arrival_distance = 0;
4380  wingp->arrival_path_mask = -1; // -1 only until resolved
4381 
4382  find_and_stuff("$Arrival Location:", &wingp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
4383 
4384  if ( optional_string("+Arrival Distance:") )
4385  {
4386  stuff_int( &wingp->arrival_distance );
4387 
4388  // Goober5000
4389  if ((wingp->arrival_distance <= 0) && ((wingp->arrival_location == ARRIVE_NEAR_SHIP) || (wingp->arrival_location == ARRIVE_IN_FRONT_OF_SHIP)))
4390  {
4391  Warning(LOCATION, "Arrival distance for wing %s cannot be %d. Setting to 1.\n", wingp->name, wingp->arrival_distance);
4392  wingp->arrival_distance = 1;
4393  }
4394  }
4395 
4396  if ( wingp->arrival_location != ARRIVE_AT_LOCATION )
4397  {
4398  required_string("$Arrival Anchor:");
4400  wingp->arrival_anchor = get_anchor(name);
4401  }
4402 
4403  if (optional_string("+Arrival Paths:"))
4404  {
4405  // temporarily use mask to point to the restriction index
4407  }
4408 
4409  if (optional_string("+Arrival delay:")) {
4410  stuff_int(&delay);
4411  if ( delay < 0 )
4412  Error(LOCATION, "Cannot have arrival delay < 0 on wing %s", wingp->name );
4413  } else
4414  delay = 0;
4415  saved_arrival_delay = delay;
4416 
4417  if ( !Fred_running ){
4418  wingp->arrival_delay = -delay;
4419  } else {
4420  wingp->arrival_delay = delay;
4421  }
4422 
4423  required_string("$Arrival Cue:");
4424  wingp->arrival_cue = get_sexp_main();
4425  if ( !Fred_running && (wingp->arrival_cue >= 0) ) {
4426  if ( eval_sexp(wingp->arrival_cue) ) // evaluate to determine if sexp is always false.
4427  wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
4428  }
4429 
4430 
4431  wingp->departure_anchor = -1;
4432  wingp->departure_path_mask = -1; // -1 only until resolved
4433 
4434  find_and_stuff("$Departure Location:", &wingp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
4435 
4436  if ( wingp->departure_location != DEPART_AT_LOCATION )
4437  {
4438  required_string("$Departure Anchor:");
4439  stuff_string( name, F_NAME, NAME_LENGTH );
4440  wingp->departure_anchor = get_anchor(name);
4441  }
4442 
4443  if (optional_string("+Departure Paths:"))
4444  {
4445  // temporarily use mask to point to the restriction index
4447  }
4448 
4449  if (optional_string("+Departure delay:")) {
4450  stuff_int(&delay);
4451  if ( delay < 0 )
4452  Error(LOCATION, "Cannot have departure delay < 0 on wing %s", wingp->name );
4453  } else
4454  delay = 0;
4455 
4456  if ( !Fred_running )
4457  wingp->departure_delay = -delay; // use negative numbers to mean that delay timer not yet set
4458  else
4459  wingp->departure_delay = delay;
4460 
4461  required_string("$Departure Cue:");
4462  wingp->departure_cue = get_sexp_main();
4463 
4464  // stores a list of all names of ships in the wing
4465  required_string("$Ships:");
4466  wingp->wave_count = stuff_string_list( ship_names, MAX_SHIPS_PER_WING );
4467  wingp->current_count = 0;
4468 
4469  // get the wings goals, if any
4470  wing_goals = -1;
4471  if ( optional_string("$AI Goals:") )
4472  wing_goals = get_sexp_main();
4473 
4474  wingp->hotkey = -1;
4475  if (optional_string("+Hotkey:")) {
4476  stuff_int(&wingp->hotkey);
4477  Assert((wingp->hotkey >= 0) && (wingp->hotkey < 10));
4478  }
4479 
4480  if (optional_string("+Flags:")) {
4481  int count;
4482 
4483  count = stuff_string_list( wing_flag_strings, MAX_WING_FLAGS );
4484  for (i = 0; i < count; i++ ) {
4485  if ( !stricmp( wing_flag_strings[i], NOX("ignore-count")) )
4486  wingp->flags |= WF_IGNORE_COUNT;
4487  else if ( !stricmp( wing_flag_strings[i], NOX("reinforcement")) )
4488  wingp->flags |= WF_REINFORCEMENT;
4489  else if ( !stricmp( wing_flag_strings[i], NOX("no-arrival-music")) )
4490  wingp->flags |= WF_NO_ARRIVAL_MUSIC;
4491  else if ( !stricmp( wing_flag_strings[i], NOX("no-arrival-message")) )
4492  wingp->flags |= WF_NO_ARRIVAL_MESSAGE;
4493  else if ( !stricmp( wing_flag_strings[i], NOX("no-arrival-warp")) )
4494  wingp->flags |= WF_NO_ARRIVAL_WARP;
4495  else if ( !stricmp( wing_flag_strings[i], NOX("no-departure-warp")) )
4496  wingp->flags |= WF_NO_DEPARTURE_WARP;
4497  else if ( !stricmp( wing_flag_strings[i], NOX("no-dynamic")) )
4498  wingp->flags |= WF_NO_DYNAMIC;
4499  else if ( !stricmp( wing_flag_strings[i], NOX("nav-carry-status")) )
4500  wingp->flags |= WF_NAV_CARRY;
4501  else
4502  Warning(LOCATION, "unknown wing flag\n%s\n\nSkipping.", wing_flag_strings[i]);
4503  }
4504  }
4505 
4506  // get the wave arrival delay bounds (if present). Used as lower and upper bounds (in seconds)
4507  // which determine when new waves of a wing should arrive.
4508  wingp->wave_delay_min = 0;
4509  wingp->wave_delay_max = 0;
4510  if ( optional_string("+Wave Delay Min:") )
4511  stuff_int( &(wingp->wave_delay_min) );
4512  if ( optional_string("+Wave Delay Max:") )
4513  stuff_int( &(wingp->wave_delay_max) );
4514 
4515  // be sure to set the wave arrival timestamp of this wing to pop right away so that the
4516  // wing could be created if it needs to be
4517  wingp->wave_delay_timestamp = timestamp(0);
4518 
4519  // initialize wing goals
4520  for (i=0; i<MAX_AI_GOALS; i++) {
4521  wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
4522  wingp->ai_goals[i].signature = -1;
4523  wingp->ai_goals[i].priority = -1;
4524  wingp->ai_goals[i].flags = 0;
4525  }
4526 
4527  // 7/13/98 -- MWA
4528  // error checking against the player ship wings (i.e. starting & tvt) to be sure that wave count doesn't exceed one for
4529  // these wings.
4530  if ( MULTI_NOT_TEAM ) {
4531  for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
4532  if ( !stricmp(Starting_wing_names[i], wingp->name) ) {
4533  if ( wingp->num_waves > 1 ) {
4534  // only end the game if we're the server - clients will eventually find out :)
4537  }
4538  }
4539  }
4540  }
4541  }
4542  else if (MULTI_TEAM) {
4543  for (i = 0; i < MAX_TVT_WINGS; i++ ) {
4544  if ( !stricmp(TVT_wing_names[i], wingp->name) ) {
4545  if ( wingp->num_waves > 1 ) {
4546  // only end the game if we're the server - clients will eventually find out :)
4549  }
4550  }
4551  }
4552  }
4553  }
4554 
4555  // Get the next starting signature for this in this wing. We want to reserve wave_count * num_waves
4556  // of signature. These can be used to construct wings for ingame joiners.
4557  if ( Game_mode & GM_MULTIPLAYER ) {
4558  int next_signature;
4559 
4561  next_signature = wingp->net_signature + (wingp->wave_count * wingp->num_waves);
4562  if ( next_signature > SHIP_SIG_MAX )
4563  Error(LOCATION, "Too many total ships in mission (%d) for network signature assignment", SHIP_SIG_MAX);
4565  }
4566 
4567  for (i=0; i<MAX_SHIPS_PER_WING; i++)
4568  wingp->ship_index[i] = -1;
4569 
4570  // set up the ai_goals for this wing -- all ships created from this wing will inherit these goals
4571  // goals for the wing are stored slightly differently than for ships. We simply store the index
4572  // into the sexpression array of each goal (max 10). When a ship in this wing is created, each
4573  // goal in the wings goal array is given to the ship.
4574  if ( wing_goals != -1 ) {
4575  int sexp;
4576 
4577  // this will assign the goals to the wings as well as to any ships in the wing that have been
4578  // already created.
4579  for ( sexp = CDR(wing_goals); sexp != -1; sexp = CDR(sexp) )
4580  ai_add_wing_goal_sexp(sexp, AIG_TYPE_EVENT_WING, wingnum); // used by Fred
4581 
4582  free_sexp2(wing_goals); // free up sexp nodes for reuse, since they aren't needed anymore.
4583  }
4584 
4585  // set the wing number for all ships in the wing
4586  for (i = 0; i < wingp->wave_count; i++ ) {
4587  char *ship_name = ship_names[i];
4588  int assigned = 0;
4589 
4590  // Goober5000 - since the ship/wing creation stuff is reordered to accommodate multiple docking,
4591  // everything is still only in the parse array at this point (in both FRED and FS2)
4592 
4593  // find the parse object and assign it the wing number
4594  for (SCP_vector<p_object>::iterator p_objp = Parse_objects.begin(); p_objp != Parse_objects.end(); ++p_objp) {
4595  if ( !strcmp(ship_name, p_objp->name) ) {
4596  // get Allender -- ship appears to be in multiple wings
4597  Assert (p_objp->wingnum == -1);
4598 
4599  // assign wingnum
4600  p_objp->wingnum = wingnum;
4601  p_objp->pos_in_wing = i;
4602  assigned++;
4603 
4604  // Goober5000 - if this is a player start object, there shouldn't be a wing arrival delay (Mantis #2678)
4605  if ((p_objp->flags & P_OF_PLAYER_START) && (saved_arrival_delay != 0)) {
4606  Warning(LOCATION, "Wing %s specifies an arrival delay of %ds, but it also contains a player. The arrival delay will be reset to 0.", wingp->name, saved_arrival_delay);
4607  if (!Fred_running && wingp->arrival_delay > 0) {
4608  // timestamp has been set, so set it again
4609  wingp->arrival_delay = timestamp(0);
4610  } else {
4611  // no timestamp, or timestamp invalid
4612  wingp->arrival_delay = 0;
4613  }
4614  // prevent message from reappearing
4615  saved_arrival_delay = 0;
4616  }
4617  }
4618  }
4619 
4620  // error checking
4621  if (assigned == 0) {
4622  Error(LOCATION, "Cannot load mission -- for wing %s, ship %s is not present in #Objects section.\n", wingp->name, ship_name);
4623  } else if (assigned > 1) {
4624  Error(LOCATION, "Cannot load mission -- for wing %s, ship %s is specified multiple times in wing.\n", wingp->name, ship_name);
4625  }
4626  }
4627 
4628  // Goober5000 - wing creation stuff moved to post_process_ships_wings
4629 }
4630 
4632 {
4633  required_string("#Wings");
4634  while (required_string_either("#Events", "$Name:"))
4635  {
4637  parse_wing(pm);
4638  Num_wings++;
4639  }
4640 }
4641 
4642 // Goober5000
4643 void resolve_path_masks(int anchor, int *path_mask)
4644 {
4645  path_restriction_t *prp;
4646 
4647  // if we have no restrictions, do a quick out
4648  if (*path_mask < 0)
4649  {
4650  *path_mask = 0;
4651  return;
4652  }
4653 
4654  // get path restriction info
4655  prp = &Path_restrictions[*path_mask];
4656 
4657  // uninitialized; compute the mask from scratch
4658  if (prp->cached_mask & (1 << MAX_SHIP_BAY_PATHS))
4659  {
4660  int j, bay_path, modelnum;
4661  p_object *parent_pobjp;
4662 
4663  // get anchor ship
4664  Assert(!(anchor & SPECIAL_ARRIVAL_ANCHOR_FLAG));
4665  parent_pobjp = mission_parse_get_parse_object(Parse_names[anchor]);
4666 
4667  // Load the anchor ship model with subsystems and all; it'll need to be done for this mission anyway
4668  ship_info *sip = &Ship_info[parent_pobjp->ship_class];
4669  modelnum = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);
4670 
4671  // resolve names to indexes
4672  *path_mask = 0;
4673  for (j = 0; j < prp->num_paths; j++)
4674  {
4675  bay_path = model_find_bay_path(modelnum, prp->path_names[j]);
4676  if (bay_path < 0)
4677  continue;
4678 
4679  *path_mask |= (1 << bay_path);
4680  }
4681 
4682  // cache the result
4683  prp->cached_mask = *path_mask;
4684  }
4685  // already computed; so reuse it
4686  else
4687  {
4688  *path_mask = prp->cached_mask;
4689  }
4690 }
4691 
4698 {
4699  int i;
4700  wing *wingp;
4701 
4702  // take care of parse objects (ships)
4703  for (SCP_vector<p_object>::iterator pobjp = Parse_objects.begin(); pobjp != Parse_objects.end(); ++pobjp)
4704  {
4705  resolve_path_masks(pobjp->arrival_anchor, &pobjp->arrival_path_mask);
4706  resolve_path_masks(pobjp->departure_anchor, &pobjp->departure_path_mask);
4707  }
4708 
4709  // take care of wings
4710  for (i = 0; i < Num_wings; i++)
4711  {
4712  wingp = &Wings[i];
4713 
4716  }
4717 }
4718 
4719 // Goober5000
4721 {
4722  int i;
4723 
4724  // Goober5000 - first, resolve the path masks. Needs to be done first because
4725  // mission_parse_maybe_create_parse_object relies on it.
4727 
4728  // Goober5000 - now that we've parsed all the objects, resolve the initially docked references.
4729  // This must be done before anything that relies on the dock references but can't be done until
4730  // both ships and wings have been parsed.
4732 
4733  // Goober5000 - now create all objects that we can. This must be done before any ship stuff
4734  // but can't be done until the dock references are resolved. This was originally done
4735  // in parse_object().
4736  for (SCP_vector<p_object>::iterator ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
4737  {
4739  }
4740 
4741 
4742  // ----------------- at this point the ships have been created -----------------
4743  // Now set up the wings. This must be done after both dock stuff and ship stuff.
4744 
4745  // error checking for custom wings
4746  if (strcmp(Starting_wing_names[0], TVT_wing_names[0]))
4747  {
4748  Error(LOCATION, "The first starting wing and the first team-versus-team wing must have the same wing name.\n");
4749  }
4750 
4751  // Goober5000 - for FRED, the ships are initialized after the wings, so we must now tell the wings
4752  // where their ships are
4753  if (Fred_running)
4754  {
4755  // even though the ships are already created, only the parse objects know the wing info
4756  for (SCP_vector<p_object>::iterator p_objp = Parse_objects.begin(); p_objp != Parse_objects.end(); ++p_objp)
4757  {
4758  // link the ship into the wing's array of ship indices (previously done in parse_wing
4759  // in a rather less backwards way)
4760  if (p_objp->wingnum >= 0)
4761  {
4762  int shipnum = ship_name_lookup(p_objp->name);
4763 
4764  Assert(shipnum >= 0 && shipnum < MAX_SHIPS);
4765  Assert(p_objp->pos_in_wing >= 0 && p_objp->pos_in_wing < MAX_SHIPS_PER_WING);
4766 
4767  Wings[p_objp->wingnum].ship_index[p_objp->pos_in_wing] = shipnum;
4768  }
4769  }
4770  }
4771  // Goober5000 - for FS2, the wings are initialized first, so all we have to do is create their ships
4772  else
4773  {
4774  for (i = 0; i < Num_wings; i++)
4775  {
4776  wing *wingp = &Wings[i];
4777 
4778  // create the wing if is isn't a reinforcement.
4779  if (!(wingp->flags & WF_REINFORCEMENT))
4780  parse_wing_create_ships(wingp, wingp->wave_count);
4781  }
4782  }
4783 }
4784 
4785 // mission events are sexpressions which cause things to happen based on the outcome
4786 // of other events in a mission. Essentially scripting the different things that can happen
4787 // in a mission
4788 
4790 {
4791  char buf[NAME_LENGTH];
4793 
4795  event->chain_delay = -1;
4796 
4797  required_string( "$Formula:" );
4798  event->formula = get_sexp_main();
4799 
4800  if (optional_string("+Name:")){
4801  stuff_string(event->name, F_NAME, NAME_LENGTH);
4802  } else {
4803  event->name[0] = 0;
4804  }
4805 
4806  if ( optional_string("+Repeat Count:")){
4807  stuff_int( &(event->repeat_count) );
4808  } else {
4809  event->repeat_count = 1;
4810  }
4811 
4812  if ( optional_string("+Trigger Count:")){
4813  stuff_int( &(event->trigger_count) );
4814  // if we have a trigger count but no repeat count, we want the event to loop until it has triggered enough times
4815  if (event->repeat_count == 1) {
4816  event->repeat_count = -1;
4817  }
4818  event->flags |= MEF_USING_TRIGGER_COUNT;
4819  }
4820  else {
4821  event->trigger_count = 1;
4822  }
4823 
4824  event->interval = -1;
4825  if ( optional_string("+Interval:")){
4826  stuff_int( &(event->interval) );
4827  }
4828 
4829  event->score = 0;
4830  if ( optional_string("+Score:") ){
4831  stuff_int(&event->score);
4832  }
4833 
4834  if ( optional_string("+Chained:") ){
4835  stuff_int(&event->chain_delay);
4836  }
4837 
4838  if ( optional_string("+Objective:") ) {
4840  event->objective_text = vm_strdup(buf);
4841  } else {
4842  event->objective_text = NULL;
4843  }
4844 
4845  if ( optional_string("+Objective key:") ) {
4847  event->objective_key_text = vm_strdup(buf);
4848  } else {
4849  event->objective_key_text = NULL;
4850  }
4851 
4852  event->team = -1;
4853  if( optional_string("+Team:") ) {
4854  stuff_int(&event->team);
4855 
4856  // sanity check
4857  if (event->team < -1 || event->team >= MAX_TVT_TEAMS) {
4858  if (Fred_running && !Warned_about_team_out_of_range) {
4859  Warning(LOCATION, "+Team: value was out of range in the mission file! This was probably caused by a bug in an older version of FRED. Using -1 for now.");
4860  Warned_about_team_out_of_range = true;
4861  }
4862  event->team = -1;
4863  }
4864  }
4865 
4866  if( optional_string("+Event Log Flags:") ) {
4868 
4869  stuff_string_list(buffer);
4870  for (int i = 0; i < (int)buffer.size(); i++) {
4871  int add_flag = 1;
4872 
4873  for (int j = 0; j < MAX_MISSION_EVENT_LOG_FLAGS; j++) {
4874  if (!stricmp(buffer[i].c_str(), Mission_event_log_flags[j])) {
4875  // bitshift add_flag so that it equals the index of the flag in Mission_event_log_flags[]
4876  add_flag = add_flag << j;
4877  event->mission_log_flags |= add_flag;
4878  }
4879  }
4880  }
4881  }
4882 
4883  event->timestamp = timestamp(-1);
4884 
4885  // sanity check on the repeat count variable
4886  // _argv[-1] - negative repeat count is now legal; means repeat indefinitely.
4887  if ( event->repeat_count == 0 ){
4888  Error (LOCATION, "Repeat count for mission event %s is 0.\nMust be >= 1 or negative!", event->name );
4889  }
4890 }
4891 
4893 {
4894  required_string("#Events");
4895 
4896  while (required_string_either( "#Goals", "$Formula:")) {
4898  parse_event(pm);
4900  }
4901 }
4902 
4904 {
4905  int dummy;
4906 
4907  mission_goal *goalp;
4908 
4909  goalp = &Mission_goals[Num_goals++];
4910 
4912  Assert(pm != NULL);
4913 
4914  find_and_stuff("$Type:", &goalp->type, F_NAME, Goal_type_names, Num_goal_type_names, "goal type");
4915 
4916  required_string("+Name:");
4917  stuff_string(goalp->name, F_NAME, NAME_LENGTH);
4918 
4919  // backwards compatibility for old Fred missions - all new missions should use $MessageNew
4920  if(optional_string("$Message:")){
4922  } else {
4923  required_string("$MessageNew:");
4925  }
4926 
4927  if (optional_string("$Rating:")){
4928  stuff_int(&dummy); // not used
4929  }
4930 
4931  required_string("$Formula:");
4932  goalp->formula = get_sexp_main();
4933 
4934  goalp->flags = 0;
4935  if ( optional_string("+Invalid:") )
4936  goalp->type |= INVALID_GOAL;
4937  if ( optional_string("+Invalid") )
4938  goalp->type |= INVALID_GOAL;
4939  if ( optional_string("+No music") )
4940  goalp->flags |= MGF_NO_MUSIC;
4941 
4942  goalp->score = 0;
4943  if ( optional_string("+Score:") ){
4944  stuff_int(&goalp->score);
4945  }
4946 
4947  goalp->team = 0;
4948  if ( optional_string("+Team:") ){
4949  stuff_int( &goalp->team );
4950 
4951  // sanity check
4952  if (goalp->team < -1 || goalp->team >= Num_iffs) {
4953  if (Fred_running && !Warned_about_team_out_of_range) {
4954  Warning(LOCATION, "+Team: value was out of range in the mission file! This was probably caused by a bug in an older version of FRED. Using -1 for now.");
4955  Warned_about_team_out_of_range = true;
4956  }
4957  goalp->team = -1;
4958  }
4959  }
4960 }
4961 
4963 {
4964  required_string("#Goals");
4965 
4966  while (required_string_either("#Waypoints", "$Type:")){
4967  parse_goal(pm);
4968  }
4969 }
4970 
4972 {
4973  Assert(pm != NULL);
4974 
4975  char name_buf[NAME_LENGTH];
4976  required_string("$Name:");
4977  stuff_string(name_buf, F_NAME, NAME_LENGTH);
4978 
4979  SCP_vector<vec3d> vec_list;
4980  required_string("$List:");
4981  stuff_vec3d_list(vec_list);
4982 
4983  waypoint_add_list(name_buf, vec_list);
4984 }
4985 
4987 {
4988  vec3d pos;
4989 
4990  required_string("#Waypoints");
4991 
4992  char file_name[MAX_FILENAME_LEN] = { 0 };
4993  char jump_name[NAME_LENGTH] = { 0 };
4994 
4995  while (optional_string("$Jump Node:")) {
4996  stuff_vec3d(&pos);
4997  CJumpNode jnp(&pos);
4998 
4999  if (optional_string("$Jump Node Name:") || optional_string("+Jump Node Name:")) {
5000  stuff_string(jump_name, F_NAME, NAME_LENGTH);
5001  jnp.SetName(jump_name);
5002  }
5003 
5004  if(optional_string("+Model File:")){
5005  stuff_string(file_name, F_NAME, MAX_FILENAME_LEN);
5006  jnp.SetModel(file_name);
5007  }
5008 
5009  if(optional_string("+Alphacolor:")) {
5010  ubyte r,g,b,a;
5011  stuff_ubyte(&r);
5012  stuff_ubyte(&g);
5013  stuff_ubyte(&b);
5014  stuff_ubyte(&a);
5015  jnp.SetAlphaColor(r, g, b, a);
5016  }
5017 
5018  if(optional_string("+Hidden:")) {
5019  int hide;
5020  stuff_boolean(&hide);
5021  jnp.SetVisibility(!hide);
5022  }
5023 
5024  Jump_nodes.push_back(std::move(jnp));
5025  }
5026 
5027  while (required_string_either("#Messages", "$Name:"))
5028  parse_waypoint_list(pm);
5029 }
5030 
5032 {
5033  required_string("#Messages");
5034 
5035  // command stuff by Goober5000 ---------------------------------------
5037  if (optional_string("$Command Sender:"))
5038  {
5039  char temp[NAME_LENGTH];
5041 
5042  if (*temp == '#')
5043  strcpy_s(pm->command_sender, &temp[1]);
5044  else
5045  strcpy_s(pm->command_sender, temp);
5046  }
5047 
5049  if (optional_string("$Command Persona:"))
5050  {
5051  int idx;
5052  char temp[NAME_LENGTH];
5054 
5055  idx = message_persona_name_lookup(temp);
5056  if (idx >= 0)
5057  pm->command_persona = idx;
5058  else
5059  Warning(LOCATION, "Supplied Command Persona is invalid! Defaulting to %s.", Personas[Default_command_persona].name);
5060  }
5061  // end of command stuff ----------------------------------------------
5062 
5063 
5064  mprintf(("Starting mission message count : %d\n", (int)Message_waves.size()));
5065 
5066  // the message_parse function can be found in MissionMessage.h. The format in the
5067  // mission file takes the same format as the messages in messages,tbl. Make parsing
5068  // a whole lot easier!!!
5069  while ( required_string_either("#Reinforcements", "$Name")){
5070  message_parse((flags & MPF_IMPORT_FSM) != 0); // call the message parsing system
5071  }
5072 
5073  mprintf(("Ending mission message count : %d\n", (int)Message_waves.size()));
5074 }
5075 
5077 {
5078  reinforcements *ptr;
5079  p_object *rforce_obj = NULL;
5080  int instance = -1;
5081 
5083  Assert(pm != NULL);
5085 
5086  required_string("$Name:");
5088 
5089  find_and_stuff("$Type:", &ptr->type, F_NAME, Reinforcement_type_names, Num_reinforcement_type_names, "reinforcement type");
5090 
5091  required_string("$Num times:");
5092  stuff_int(&ptr->uses);
5093  ptr->num_uses = 0;
5094 
5095  // reset the flags to 0
5096  ptr->flags = 0;
5097 
5098  if ( optional_string("+Arrival delay:") ){
5099  stuff_int( &(ptr->arrival_delay) );
5100  }
5101 
5102  if ( optional_string("+No Messages:") ){
5104  }
5105 
5106  if ( optional_string("+Yes Messages:") ){
5108  }
5109 
5110  // sanity check on the names of reinforcements
5111  rforce_obj = mission_parse_get_parse_object(ptr->name);
5112 
5113  if (rforce_obj == NULL) {
5114  if ((instance = wing_name_lookup(ptr->name, 1)) == -1) {
5115  Warning(LOCATION, "Reinforcement %s not found as ship or wing", ptr->name);
5116  return;
5117  }
5118  } else {
5119  // Individual ships in wings can't be reinforcements - FUBAR
5120  if (rforce_obj->wingnum >= 0)
5121  {
5122  Warning(LOCATION, "Reinforcement %s is part of a wing - Ignoring reinforcement declaration", ptr->name);
5123  return;
5124  }
5125  else
5126  {
5127  instance = rforce_obj->wingnum;
5128  }
5129  }
5130 
5131  // now, if the reinforcement is a wing, then set the number of waves of the wing == number of
5132  // uses of the reinforcement
5133  if (instance >= 0) {
5134  Wings[instance].num_waves = ptr->uses;
5135  }
5136 
5138 }
5139 
5141 {
5142  Num_reinforcements = 0;
5143  required_string("#Reinforcements");
5144 
5145  while (required_string_either("#Background bitmaps", "$Name:"))
5146  parse_reinforcement(pm);
5147 }
5148 
5150 {
5151  // clear here too because this function can be called from more than one place
5152  background->suns.clear();
5153  background->bitmaps.clear();
5154 
5155  // parse suns
5156  while (optional_string("$Sun:"))
5157  {
5159 
5160  // filename
5162 
5163  // angles
5164  required_string("+Angles:");
5165  stuff_float(&sle.ang.p);
5166  stuff_float(&sle.ang.b);
5167  stuff_float(&sle.ang.h);
5168 
5169  // scale
5170  required_string("+Scale:");
5171  stuff_float(&sle.scale_x);
5172  sle.scale_y = sle.scale_x;
5173  sle.div_x = 1;
5174  sle.div_y = 1;
5175 
5176  // add it
5177  background->suns.push_back(sle);
5178  }
5179 
5180  // parse starfields
5181  while (optional_string("$Starbitmap:"))
5182  {
5184 
5185  // filename
5187 
5188  // angles
5189  required_string("+Angles:");
5190  stuff_float(&sle.ang.p);
5191  stuff_float(&sle.ang.b);
5192  stuff_float(&sle.ang.h);
5193 
5194  // scale
5195  if (optional_string("+Scale:"))
5196  {
5197  stuff_float(&sle.scale_x);
5198  sle.scale_y = sle.scale_x;
5199  sle.div_x = 1;
5200  sle.div_y = 1;
5201  }
5202  else
5203  {
5204  required_string("+ScaleX:");
5205  stuff_float(&sle.scale_x);
5206 
5207  required_string("+ScaleY:");
5208  stuff_float(&sle.scale_y);
5209 
5210  required_string("+DivX:");
5211  stuff_int(&sle.div_x);
5212 
5213  required_string("+DivY:");
5214  stuff_int(&sle.div_y);
5215  }
5216 
5217  // add it
5218  background->bitmaps.push_back(sle);
5219  }
5220 }
5221 
5223 {
5224  char str[MAX_FILENAME_LEN];
5225  int z;
5226 
5227  required_string("#Background bitmaps");
5228 
5229  required_string("$Num stars:");
5230  stuff_int(&Num_stars);
5231  if (Num_stars >= MAX_STARS)
5232  Num_stars = MAX_STARS;
5233 
5234  required_string("$Ambient light level:");
5236 
5237  if (pm->ambient_light_level == 0)
5238  {
5240  }
5241 
5242  // This should call light_set_ambient() to
5243  // set the ambient light
5244 
5245  Nebula_index = -1;
5246  Mission_palette = 1;
5247 
5248  // neb2 info
5249  strcpy_s(Neb2_texture_name, "Eraseme3");
5250  Neb2_poof_flags = ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
5251  if(optional_string("+Neb2:")){
5253 
5254  required_string("+Neb2Flags:");
5256 
5257  // initialize neb effect. its gross to do this here, but Fred is dumb so I have no choice ... :(
5258  if(Fred_running && (pm->flags & MISSION_FLAG_FULLNEB)){
5260  }
5261  }
5262 
5263  if(pm->flags & MISSION_FLAG_FULLNEB){
5264  // no regular nebula stuff
5265  nebula_close();
5266  } else {
5267  if (optional_string("+Nebula:")) {
5269 
5270  // parse the proper nebula type (full or not)
5271  for (z=0; z<NUM_NEBULAS; z++){
5272  if(pm->flags & MISSION_FLAG_FULLNEB){
5273  if (!stricmp(str, Neb2_filenames[z])) {
5274  Nebula_index = z;
5275  break;
5276  }
5277  } else {
5278  if (!stricmp(str, Nebula_filenames[z])) {
5279  Nebula_index = z;
5280  break;
5281  }
5282  }
5283  }
5284 
5285  if (z == NUM_NEBULAS)
5286  WarningEx(LOCATION, "Mission %s\nUnknown nebula %s!", pm->name, str);
5287 
5288  if (optional_string("+Color:")) {
5290  for (z=0; z<NUM_NEBULA_COLORS; z++){
5291  if (!stricmp(str, Nebula_colors[z])) {
5292  Mission_palette = z;
5293  break;
5294  }
5295  }
5296  }
5297 
5298  if (z == NUM_NEBULA_COLORS)
5299  WarningEx(LOCATION, "Mission %s\nUnknown nebula color %s!", pm->name, str);
5300 
5301  if (optional_string("+Pitch:")){
5303  } else {
5304  Nebula_pitch = 0;
5305  }
5306 
5307  if (optional_string("+Bank:")){
5309  } else {
5310  Nebula_bank = 0;
5311  }
5312 
5313  if (optional_string("+Heading:")){
5315  } else {
5316  Nebula_heading = 0;
5317  }
5318  }
5319 
5320  if (Nebula_index >= 0){
5322  } else {
5323  nebula_close();
5324  }
5325  }
5326 
5327  // Goober5000
5328  Num_backgrounds = 0;
5329  while (optional_string("$Bitmap List:") || check_for_string("$Sun:") || check_for_string("$Starbitmap:"))
5330  {
5331  // don't allow overflow; just make sure the last background is the last read
5333  {
5334  Warning(LOCATION, "Too many backgrounds in mission! Max is %d.", MAX_BACKGROUNDS);
5336  }
5337 
5339  Num_backgrounds++;
5340  }
5341 
5342  // Goober5000
5344 
5345  if (optional_string("$Environment Map:")) {
5347  }
5348 
5349  // bypass spurious stuff from e.g. FS1 missions
5351 }
5352 
5354 {
5355  int i, count, subtype;
5356 
5357  Assert(pm != NULL);
5358  for (i=0; i<MAX_ASTEROID_FIELDS; i++)
5360 
5361  i = 0;
5362  count = 0;
5363 
5364  if (!optional_string("#Asteroid Fields"))
5365  return;
5366 
5367  while (required_string_either("#", "$density:")) {
5368  float speed, density;
5369  int type;
5370 
5371  Assert(i < 1);
5372  required_string("$Density:");
5373  stuff_float(&density);
5374 
5376 
5378  if (optional_string("+Field Type:")) {
5379  stuff_int( &type );
5381  }
5382 
5384  if (optional_string("+Debris Genre:")) {
5385  stuff_int( &type );
5387  }
5388 
5393  if (optional_string("+Field Debris Type:")) {
5395  }
5396  if (optional_string("+Field Debris Type:")) {
5398  }
5399  if (optional_string("+Field Debris Type:")) {
5401  }
5402  } else {
5403  // debris asteroid
5404  if (optional_string("+Field Debris Type:")) {
5405  stuff_int(&subtype);
5407  count++;
5408  }
5409  if (optional_string("+Field Debris Type:")) {
5410  stuff_int(&subtype);
5412  count++;
5413  }
5414  if (optional_string("+Field Debris Type:")) {
5415  stuff_int(&subtype);
5417  count++;
5418  }
5419  }
5420 
5421  // backward compatibility
5422  if ( (Asteroid_field.debris_genre == DG_ASTEROID) && (count == 0) ) {
5424  }
5425 
5426  required_string("$Average Speed:");
5427  stuff_float(&speed);
5428 
5430  vm_vec_scale(&Asteroid_field.vel, speed);
5431 
5432  Asteroid_field.speed = speed;
5433 
5434  required_string("$Minimum:");
5436 
5437  required_string("$Maximum:");
5439 
5440  vec3d a_rad;
5442  vm_vec_scale(&a_rad, 0.5f);
5443  float b_rad = vm_vec_mag(&a_rad);
5444 
5445  Asteroid_field.bound_rad = MAX(3000.0f, b_rad);
5446 
5447  if (optional_string("+Inner Bound:")) {
5449 
5450  required_string("$Minimum:");
5452 
5453  required_string("$Maximum:");
5455  } else {
5457  }
5458  i++;
5459  }
5460 }
5461 
5463 {
5464  int i, j, num_variables = 0;
5465 
5466  if (! optional_string("#Sexp_variables") ) {
5467  return;
5468  } else {
5469  num_variables = stuff_sexp_variable_list();
5470  }
5471 
5472  // yeesh - none of this should be done in FRED :)
5473  // It shouldn't be done for missions in the tecroom either. They should default to whatever FRED set them to
5474  if ( Fred_running || !(Game_mode & GM_CAMPAIGN_MODE) ) {
5475  return;
5476  }
5477 
5478  // Goober5000 - now set the default value, if it's a campaign-persistent variable
5479  // loop through the current mission's variables
5480  for (j = 0; j < num_variables; j++) {
5481  // check against existing variables
5482  for (i = 0; i < Campaign.num_variables; i++) {
5483  // if the active mission has a variable with the same name as a campaign
5484  // variable AND it is not a block variable, override its initial value
5485  // with the previous mission's value
5486  if ( !stricmp(Sexp_variables[j].variable_name, Campaign.variables[i].variable_name) ) {
5490  break;
5491  } else {
5492  WarningEx(LOCATION, "Variable %s has the same name as a campaign persistent variable. One of these should be renamed to avoid confusion", Sexp_variables[j].text);
5493  }
5494  }
5495  }
5496  }
5497 
5498  // Goober5000 - next, see if any player-persistent variables are set
5499  // loop through the current mission's variables
5500  for (j = 0; j < num_variables; j++) {
5501  // check against existing variables
5502  for (i = 0; i < (int)Player->variables.size(); i++) {
5503  // if the active mission has a variable with the same name as a player
5504  // variable AND it is not a block variable, override its initial value
5505  // with the previous mission's value
5506  if ( !stricmp(Sexp_variables[j].variable_name, Player->variables[i].variable_name) ) {
5508  Sexp_variables[j].type = Player->variables[i].type;
5509  strcpy_s(Sexp_variables[j].text, Player->variables[i].text);
5510  break;
5511  } else {
5512  WarningEx(LOCATION, "Variable %s has the same name as a player persistent variable. One of these should be renamed to avoid confusion", Sexp_variables[j].text);
5513  }
5514  }
5515  }
5516  }
5517 }
5518 
5520 {
5521  int saved_warning_count = Global_warning_count;
5522  int saved_error_count = Global_error_count;
5523 
5524  int i;
5525  Warned_about_team_out_of_range = false;
5526 
5528 
5530  Player_start_shipnum = -1;
5531  *Player_start_shipname = 0; // make the string 0 length for checking later
5533 
5534  // initialize the initially_docked array.
5535  for ( i = 0; i < MAX_SHIPS; i++ ) {
5536  Initially_docked[i].docker[0] = '\0';
5537  Initially_docked[i].dockee[0] = '\0';
5538  Initially_docked[i].docker_point[0] = '\0';
5539  Initially_docked[i].dockee_point[0] = '\0';
5540  }
5542 
5543  list_init(&Ship_arrival_list); // init list for arrival ships
5544 
5545  parse_init();
5546 
5547  Subsys_index = 0;
5548  Subsys_status_size = 0;
5549 
5550  if (Subsys_status != NULL) {
5551  vm_free( Subsys_status );
5552  Subsys_status = NULL;
5553  }
5554 
5555  parse_mission_info(pm);
5556 
5558 
5559  if (flags & MPF_ONLY_MISSION_INFO)
5560  return 0;
5561 
5562  parse_plot_info(pm);
5563  parse_variables();
5564  parse_briefing_info(pm); // TODO: obsolete code, keeping so we don't obsolete existing mission files
5565  parse_cutscenes(pm);
5566  parse_fiction(pm);
5567  parse_cmd_briefs(pm);
5568  parse_briefing(pm, flags);
5570  parse_player_info(pm);
5571  parse_objects(pm, flags);
5572  parse_wings(pm);
5573  parse_events(pm);
5574  parse_goals(pm);
5576  parse_messages(pm, flags);
5578  parse_bitmaps(pm);
5580  parse_music(pm, flags);
5581 
5582  // if we couldn't load some mod data
5584  // if running on standalone server, just print to the log
5586  mprintf(("Warning! Could not load %d ship classes!", Num_unknown_ship_classes));
5587  return -2;
5588  }
5589  // don't do this in FRED; we will display a separate popup
5590  else if (!Fred_running) {
5591  // build up the prompt...
5592  char text[1024];
5593 
5594  if (Num_unknown_ship_classes > 0) {
5595  sprintf(text, "Warning!\n\nFreeSpace was unable to find %d ship class%s while loading this mission. This can happen if you try to play a %s that is incompatible with the current mod.\n\n", Num_unknown_ship_classes, (Num_unknown_ship_classes > 1) ? "es" : "", (Game_mode & GM_CAMPAIGN_MODE) ? "campaign" : "mission");
5596  }
5597  else {
5598  sprintf(text, "Warning!\n\nFreeSpace was unable to find %d weapon class%s while loading this mission. This can happen if you try to play a %s that is incompatible with the current mod.\n\n", Num_unknown_loadout_classes, (Num_unknown_loadout_classes > 1) ? "es" : "", (Game_mode & GM_CAMPAIGN_MODE) ? "campaign" : "mission");
5599  }
5600 
5601  if (Game_mode & GM_CAMPAIGN_MODE) {
5602  strcat_s(text, "(The current campaign is \"");
5603  strcat_s(text, Campaign.name);
5604  } else {
5605  strcat_s(text, "(The current mission is \"");
5606  strcat_s(text, pm->name);
5607  }
5608 
5609  strcat_s(text, "\", and the current mod is \"");
5610 
5611  if (Cmdline_mod == NULL || *Cmdline_mod == 0) {
5612  strcat_s(text, "<retail default> ");
5613  } else {
5614  for (char *mod_token = Cmdline_mod; *mod_token != '\0'; mod_token += strlen(mod_token) + 1) {
5615  strcat_s(text, mod_token);
5616  strcat_s(text, " ");
5617  }
5618  }
5619 
5620  strcpy(text + strlen(text) - 1, "\".)\n\n You can continue to load the mission, but it is quite likely that you will encounter a large number of mysterious errors. It is recommended that you either select a ");
5621  strcat(text, (Game_mode & GM_CAMPAIGN_MODE) ? "campaign" : "mission");
5622  strcat(text, " that is compatible with your current mod, or else exit FreeSpace and select a different mod.\n\n");
5623 
5624  strcat(text, "Do you want to continue to load the mission?");
5625 
5626  // now display the popup
5627  int popup_rval = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, text);
5628  if (popup_rval == 0) {
5629  return -2;
5630  }
5631  }
5632  }
5633 
5635 
5636  if ((saved_warning_count - Global_warning_count) > 10 || (saved_error_count - Global_error_count) > 0) {
5637  char text[512];
5638  sprintf(text, "Warning!\n\nThe current mission has generated %d warnings and/or errors during load. These are usually caused by corrupted ship models or syntax errors in the mission file. While FreeSpace Open will attempt to compensate for these issues, it cannot guarantee a trouble-free gameplay experience. Source Code Project staff cannot provide assistance or support for these problems, as they are caused by the mission's data files, not FreeSpace Open's source code.", (saved_warning_count - Global_warning_count) + (saved_error_count - Global_error_count));
5640  }
5641 
5642  log_printf(LOGFILE_EVENT_LOG, "Mission %s loaded.\n", pm->name);
5643 
5644  // success
5645  return 0;
5646 }
5647 
5649 {
5650  int i;
5651  int indices[MAX_SHIPS], objnum;
5652  ship_weapon *swp;
5653  ship_obj *so;
5654 
5655  // Goober5000 - must be done before all other post processing
5657 
5658  // the player_start_shipname had better exist at this point!
5660  Assert( Player_start_shipnum != -1 );
5661  Player_start_pobject = mission_parse_get_parse_object( Player_start_shipname );
5662  Assert( Player_start_pobject != NULL );
5663 
5664  // Assign objnum, shipnum, etc. to the player structure
5665  objnum = Ships[Player_start_shipnum].objnum;
5666  Player_obj = &Objects[objnum];
5667  if (!Fred_running){
5668  Player->objnum = objnum;
5669  }
5670 
5671  Player_obj->flags |= OF_PLAYER_SHIP; // make this object a player controlled ship.
5674 
5675  Player_ai->targeted_subsys = NULL;
5677 
5678  // determine if player start has initial velocity and set forward cruise percent to relect this
5679  if ( Player_obj->phys_info.vel.xyz.z > 0.0f )
5681 
5682  // set up wing indexes
5683  for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
5685  }
5686 
5687  for (i = 0; i < MAX_SQUADRON_WINGS; i++ ) {
5689  }
5690 
5691  for (i = 0; i < MAX_TVT_WINGS; i++ ) {
5693  }
5694 
5695  // when TVT, hack starting wings to be team wings
5696  if(MULTI_TEAM){
5697  Assert(MAX_TVT_WINGS <= MAX_STARTING_WINGS);
5698  for (i=0; i<MAX_STARTING_WINGS; i++)
5699  {
5700  if (i<MAX_TVT_WINGS)
5702  else
5703  Starting_wings[i] = -1;
5704  }
5705  }
5706 
5707  init_ai_system();
5708 
5710 
5711  // Goober5000 - this needs to be called only once after parsing of objects and wings is complete
5712  // (for individual invalidation, see mission_parse_mark_non_arrival)
5714 
5715  // deal with setting up arrival location for all ships. Must do this now after all ships are created
5717 
5718  // clear out information about arriving support ships
5719  Arriving_support_ship = NULL;
5721 
5722  // convert all ship name indices to ship indices now that mission has been loaded
5723  if (Fred_running) {
5724  for (i=0; i<Num_parse_names; i++) {
5725  indices[i] = ship_name_lookup(Parse_names[i], 1);
5726  if (indices[i] < 0)
5727  Warning(LOCATION, "Ship name \"%s\" referenced, but this ship doesn't exist", Parse_names[i]);
5728  }
5729 
5730  for (i=0; i<MAX_SHIPS; i++) {
5731  if ((Ships[i].objnum >= 0) && (Ships[i].arrival_anchor >= 0) && (Ships[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHOR_FLAG))
5732  Ships[i].arrival_anchor = indices[Ships[i].arrival_anchor];
5733 
5734  if ( (Ships[i].objnum >= 0) && (Ships[i].departure_anchor >= 0) )
5735  Ships[i].departure_anchor = indices[Ships[i].departure_anchor];
5736  }
5737 
5738  for (i=0; i<MAX_WINGS; i++) {
5739  if (Wings[i].wave_count && (Wings[i].arrival_anchor >= 0) && (Wings[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHOR_FLAG))
5740  Wings[i].arrival_anchor = indices[Wings[i].arrival_anchor];
5741 
5742  if (Wings[i].wave_count && (Wings[i].departure_anchor >= 0) )
5743  Wings[i].departure_anchor = indices[Wings[i].departure_anchor];
5744  }
5745 
5746  }
5747 
5748  // before doing anything else, we must validate all of the sexpressions that were loaded into the mission.
5749  // Loop through the Sexp_nodes array and send the top level functions to the check_sexp_syntax parser
5750 
5751  for (i = 0; i < Num_sexp_nodes; i++) {
5752  if (is_sexp_top_level(i) && (!Fred_running || (i != Sexp_clipboard))) {
5753  int result, bad_node, op;
5754 
5755  op = get_operator_index(CTEXT(i));
5756  Assert(op != -1); // need to make sure it is an operator before we treat it like one..
5757  result = check_sexp_syntax( i, query_operator_return_type(op), 1, &bad_node);
5758 
5759  // entering this if statement will result in program termination!!!!!
5760  // print out an error based on the return value from check_sexp_syntax()
5761  if ( result ) {
5762  SCP_string sexp_str;
5763  SCP_string error_msg;
5764 
5766  truncate_message_lines(sexp_str, 30);
5767  sprintf(error_msg, "%s.\n\nIn sexpression: %s\n(Error appears to be: %s)", sexp_error_message(result), sexp_str.c_str(), Sexp_nodes[bad_node].text);
5768 
5769  if (!Fred_running) {
5770  nprintf(("Error", "%s", error_msg.c_str()));
5771  Error(LOCATION, "%s", error_msg.c_str());
5772  } else {
5773  nprintf(("Warning", "%s", error_msg.c_str()));
5774  Warning(LOCATION, "%s", error_msg.c_str());
5775  }
5776  }
5777  }
5778  }
5779 
5780  // multiplayer missions are handled just before mission start
5781  if (!(Game_mode & GM_MULTIPLAYER) ){
5783  }
5784 
5785  // first we need to clear out the counts for this mission
5787 
5788  // we must also count all of the ships of particular types. We count all of the ships that do not have
5789  // their SF_IGNORE_COUNT flag set. We don't count ships in wings when the equivalent wing flag is set.
5790  // in counting ships in wings, we increment the count by the wing's wave count to account for everyone.
5791  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5792  int num, shipnum;
5793 
5794  shipnum = Objects[so->objnum].instance;
5795  // pass over non-ship objects and player ship objects
5796  if ( Ships[shipnum].objnum == -1 || (Objects[Ships[shipnum].objnum].flags & OF_PLAYER_SHIP) )
5797  continue;
5798  if ( Ships[shipnum].flags & SF_IGNORE_COUNT )
5799  continue;
5800  if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_IGNORE_COUNT) )
5801  continue;
5802 
5803  num = 1;
5804 
5805  ship_add_ship_type_count( Ships[shipnum].ship_info_index, num );
5806  }
5807 
5808  // now go through the list of ships yet to arrive
5809  for (p_object *p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
5810  {
5811  int num;
5812 
5813  // go through similar motions as above
5814  if ( p_objp->flags & P_SF_IGNORE_COUNT )
5815  continue;
5816  if ( (p_objp->wingnum != -1) && (Wings[p_objp->wingnum].flags & WF_IGNORE_COUNT) )
5817  continue;
5818 
5819  if ( p_objp->wingnum == -1 )
5820  num = 1;
5821  else
5822  num = Wings[p_objp->wingnum].num_waves - 1; // subtract one since we already counted the first wave
5823 
5824  ship_add_ship_type_count( p_objp->ship_class, num );
5825  }
5826 
5827  // set player weapons that are selected by default
5828  // AL 09/17/97: I added this code to select the first primary/secondary weapons,
5829  // since I noticed the player ship sometimes doesn't get default weapons selected
5830 
5831  // DB: modified 4/23/98 to take multiplayer into account. Under certain circumstances, multiplayer netplayer ships
5832  // had their current_primary_bank and current_secondary_bank set to -1 (from ship_set()) and left there since
5833  // Player_ship is not the only one we need to need about.
5834  for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
5835  ship *shipp = &Ships[Objects[so->objnum].instance];
5836 
5837  // don't process non player wing ships
5838  if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
5839  continue;
5840 
5841  swp = &shipp->weapons;
5842 
5843  if ( swp->num_primary_banks > 0 ) {
5844  swp->current_primary_bank = 0; // currently selected primary bank
5845  }
5846 
5847  if ( swp->num_secondary_banks > 0 ) {
5848  swp->current_secondary_bank = 0; // currently selected secondary bank
5849  }
5850  }
5851 
5852  ets_init_ship(Player_obj); // init ETS data for the player
5853 
5854  // put the timestamp stuff here for now
5855  Mission_arrival_timestamp = timestamp( ARRIVAL_TIMESTAMP );
5856  Mission_departure_timestamp = timestamp( DEPARTURE_TIMESTAMP );
5857  Mission_end_time = -1;
5858 
5859  Allow_arrival_music_timestamp=timestamp(0);
5860  Allow_arrival_message_timestamp=timestamp(0);
5861  Arrival_message_delay_timestamp = timestamp(-1);
5862 
5863  int idx;
5864  for(idx=0; idx<2; idx++){
5865  Allow_arrival_music_timestamp_m[idx]=timestamp(0);
5866  Allow_arrival_message_timestamp_m[idx]=timestamp(0);
5867  Arrival_message_delay_timestamp_m[idx] = timestamp(-1);
5868  }
5869 
5870  if(Game_mode & GM_MULTIPLAYER){
5872  }
5873 
5874  // maybe reset hotkey defaults when loading new mission
5877  }
5879 }
5880 
5881 int get_mission_info(const char *filename, mission *mission_p, bool basic)
5882 {
5883  char real_fname[MAX_FILENAME_LEN];
5884 
5885  strncpy(real_fname, filename, MAX_FILENAME_LEN-1);
5886  real_fname[sizeof(real_fname)-1] = '\0';
5887 
5888  char *p = strrchr(real_fname, '.');
5889  if (p) *p = 0; // remove any extension
5890  strcat_s(real_fname, FS_MISSION_FILE_EXT); // append mission extension
5891 
5892  int filelength;
5893 
5894  // if mission_p is NULL, make it point to The_mission
5895  if ( mission_p == NULL )
5896  mission_p = &The_mission;
5897 
5898  CFILE *ftemp = cfopen(real_fname, "rt");
5899  if (!ftemp) {
5900  return -1;
5901  }
5902 
5903  // 7/9/98 -- MWA -- check for 0 length file.
5904  filelength = cfilelength(ftemp);
5905  cfclose(ftemp);
5906  if (filelength == 0) {
5907  return -1;
5908  }
5909 
5910  try
5911  {
5912  read_file_text(real_fname, CF_TYPE_MISSIONS);
5913  mission_p->Reset();
5914  parse_init(basic);
5915  parse_mission_info(mission_p, basic);
5916  }
5917  catch (const parse::ParseException& e)
5918  {
5919  mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", real_fname, e.what()));
5920  return -1;
5921  }
5922 
5923  return 0;
5924 }
5925 
5929 void parse_init(bool basic)
5930 {
5931  reset_parse();
5932 
5933  for (int i = 0; i < MAX_CARGO; i++)
5934  Cargo_names[i] = Cargo_names_buf[i]; // make a pointer array for compatibility
5935 
5937 
5938  // if we are just wanting basic info then we shouldn't need sexps
5939  // (prevents memory fragmentation with the now dynamic Sexp_nodes[])
5940  if ( !basic )
5941  init_sexp();
5942 }
5943 
5944 // mai parse routine for parsing a mission. The default parameter flags tells us which information
5945 // to get when parsing the mission. 0 means get everything (default). Other flags just gets us basic
5946 // info such as game type, number of players etc.
5947 int parse_main(const char *mission_name, int flags)
5948 {
5949  int rval, i;
5950 
5951  // reset parse error stuff
5955 
5956  // fill in Ship_class_names array with the names from the ship_info struct;
5957  Num_parse_names = 0;
5959  Assert(Ship_info.size() <= MAX_SHIP_CLASSES);
5960 
5961  i = 0;
5962  for (auto it = Ship_info.begin(); it != Ship_info.end(); i++, ++it)
5963  Ship_class_names[i] = it->name;
5964 
5965  do {
5966  // don't do this for imports
5967  if (!(flags & MPF_IMPORT_FSM)) {
5968  CFILE *ftemp = cfopen(mission_name, "rt", CFILE_NORMAL, CF_TYPE_MISSIONS);
5969 
5970  // fail situation.
5971  if (!ftemp) {
5972  if (!Fred_running)
5973  Error( LOCATION, "Couldn't open mission '%s'\n", mission_name );
5974 
5975  Current_file_length = -1;
5977 
5978  rval = -1;
5979  break;
5980  }
5981 
5983  cfclose(ftemp);
5984  }
5985 
5986  try
5987  {
5988  // import?
5989  if (flags & MPF_IMPORT_FSM) {
5990  read_file_text(mission_name, CF_TYPE_ANY);
5991  convertFSMtoFS2();
5992  }
5993  else {
5994  read_file_text(mission_name, CF_TYPE_MISSIONS);
5995  }
5996 
5997  The_mission.Reset();
5998  rval = parse_mission(&The_mission, flags);
6000  }
6001  catch (const parse::ParseException& e)
6002  {
6003  mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", mission_name, e.what()));
6004  rval = 1;
6005  break;
6006  }
6007  } while (0);
6008 
6009  if (!Fred_running)
6010  strcpy_s(Mission_filename, mission_name);
6011 
6012  return rval;
6013 }
6014 
6015 // Note, this is currently only called from game_shutdown()
6017 {
6018  // free subsystems
6019  if (Subsys_status != NULL)
6020  {
6021  vm_free(Subsys_status);
6022  Subsys_status = NULL;
6023  }
6024 
6025  // the destructor for each p_object will clear its dock list
6026  Parse_objects.clear();
6027 }
6028 
6035 void mission_set_wing_arrival_location( wing *wingp, int num_to_set )
6036 {
6037  int index;
6038 
6039  // get the starting index into the ship_index array of the first ship whose location we need set.
6040 
6041  index = wingp->current_count - num_to_set;
6042  if ( (wingp->arrival_location == ARRIVE_FROM_DOCK_BAY) || (wingp->arrival_location == ARRIVE_AT_LOCATION) ) {
6043  while ( index < wingp->current_count ) {
6044  object *objp;
6045 
6046  objp = &Objects[Ships[wingp->ship_index[index]].objnum];
6048 
6049  index++;
6050  }
6051  } else {
6052  object *leader_objp;
6053  vec3d pos;
6054  matrix orient;
6055  int wing_index;
6056 
6057  // wing is not arriving from a docking bay -- possibly move them based on arriving near
6058  // or in front of some other ship.
6059  index = wingp->current_count - num_to_set;
6060  leader_objp = &Objects[Ships[wingp->ship_index[index]].objnum];
6061  if (mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(leader_objp), wingp->arrival_path_mask, &pos, &orient) != -1) {
6062  // modify the remaining ships created
6063  index++;
6064  wing_index = 1;
6065  while ( index < wingp->current_count ) {
6066  object *objp;
6067 
6068  objp = &Objects[Ships[wingp->ship_index[index]].objnum];
6069 
6070  // change the position of the next ships in the wing. Use the cool function in AiCode.cpp which
6071  // Mike K wrote to give new positions to the wing members.
6072  get_absolute_wing_pos( &objp->pos, leader_objp, wing_index++, 0);
6073  memcpy( &objp->orient, &orient, sizeof(matrix) );
6074 
6075  index++;
6076  }
6077  }
6078  }
6079 
6080  // create warp effect if in mission and not arriving from docking bay
6081  if ( (Game_mode & GM_IN_MISSION) && (wingp->arrival_location != ARRIVE_FROM_DOCK_BAY) ) {
6082  for ( index = wingp->current_count - num_to_set; index < wingp->current_count; index ++ ) {
6083  shipfx_warpin_start( &Objects[Ships[wingp->ship_index[index]].objnum] );
6084  }
6085  }
6086 }
6087 
6094 {
6095  int i;
6096  object *objp;
6097 
6098  if ( Fred_running )
6099  return;
6100 
6102  for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
6103  ship *shipp;
6104 
6105  if ( objp->type != OBJ_SHIP )
6106  continue;
6107 
6108  shipp = &Ships[objp->instance];
6109  // if the ship is in a wing -- ignore the info and let the wing info handle it
6110  if ( shipp->wingnum != -1 )
6111  continue;
6112 
6113  // call function to set arrival location for this ship.
6115  }
6116 
6117  // do the wings
6118  for ( i = 0; i < Num_wings; i++ ) {
6119 
6120  // if wing has no ships, then don't process it.
6121  if ( Wings[i].current_count == 0 )
6122  continue;
6123 
6124  mission_set_wing_arrival_location( &Wings[i], Wings[i].current_count );
6125  }
6126 }
6127 
6128 // Goober5000
6129 bool sexp_is_locked_false(int node)
6130 {
6131  // dunno why these are different, but they are
6132  if (Fred_running)
6133  return (node == Locked_sexp_false);
6134  else
6135  return (Sexp_nodes[node].value == SEXP_KNOWN_FALSE);
6136 }
6137 
6138 void set_cue_to_false(int *cue)
6139 {
6140  free_sexp2(*cue);
6141  *cue = Locked_sexp_false;
6142 }
6143 
6144 // function to set the arrival cue of a ship to false
6145 void reset_arrival_to_false(p_object *pobjp, bool reset_wing)
6146 {
6147  // falsify the ship cue
6148  mprintf(("Setting arrival cue of ship %s to false for initial docking purposes.\n", pobjp->name));
6149  set_cue_to_false(&pobjp->arrival_cue);
6150 
6151  // falsify the wing cue and all ships in that wing
6152  if (reset_wing && pobjp->wingnum >= 0)
6153  {
6154  wing *wingp = &Wings[pobjp->wingnum];
6155  mprintf(("Setting arrival cue of wing %s to false for initial docking purposes.\n", wingp->name));
6156  set_cue_to_false(&wingp->arrival_cue);
6157 
6158  for (SCP_vector<p_object>::iterator ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
6159  {
6160  if ((&(*ii) != pobjp) && (ii->wingnum == pobjp->wingnum))
6161  reset_arrival_to_false(&(*ii), false);
6162  }
6163  }
6164 }
6165 
6171 {
6172  int cue_to_check;
6173 
6174  // if this guy is part of a wing, he uses his wing's arrival cue
6175  if (pobjp->wingnum >= 0)
6176  {
6177  cue_to_check = Wings[pobjp->wingnum].arrival_cue;
6178  }
6179  // check the object's arrival cue
6180  else
6181  {
6182  cue_to_check = pobjp->arrival_cue;
6183  }
6184 
6185  // is he a leader (using the definition above)?
6186  if (!sexp_is_locked_false(cue_to_check))
6187  {
6188  p_object *existing_leader;
6189 
6190  // increment number of leaders found
6192 
6193  // see if we already found a leader
6194  existing_leader = infop->maintained_variables.objp_value;
6195  if (existing_leader != NULL)
6196  {
6197  // keep existing leader if he has a higher priority than us
6198  if (ship_class_compare(pobjp->ship_class, existing_leader->ship_class) >= 0)
6199  {
6200  // set my arrival cue to false
6201  reset_arrival_to_false(pobjp, true);
6202  return;
6203  }
6204 
6205  // otherwise, unmark the existing leader and set his arrival cue to false
6206  existing_leader->flags &= ~P_SF_DOCK_LEADER;
6207  reset_arrival_to_false(existing_leader, true);
6208  }
6209 
6210  // mark and save me as the leader
6211  pobjp->flags |= P_SF_DOCK_LEADER;
6212  infop->maintained_variables.objp_value = pobjp;
6213  }
6214 }
6215 
6216 // Goober5000
6218 {
6219  pobjp->flags2 |= P2_ALREADY_HANDLED;
6220 }
6221 
6222 // Goober5000
6224 {
6225  pobjp->flags2 &= ~P2_ALREADY_HANDLED;
6226 }
6227 
6228 // Goober5000
6230 {
6231  // clear flag for all ships
6232  for (SCP_vector<p_object>::iterator ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
6233  {
6234  p_object *pobjp = &(*ii);
6236 
6237  // since we're going through all objects, this object may not be docked
6238  if (!object_is_docked(pobjp))
6239  continue;
6240 
6241  // has this object (by extension, this group of docked objects) been cleared already?
6242  if (!(pobjp->flags2 & P2_ALREADY_HANDLED))
6243  continue;
6244 
6245  // clear the handled flag for this group
6247  }
6248 }
6249 
6250 // Goober5000
6251 // This function iterates through the Initially_docked array and builds the dock trees
6252 // for each parse object. This can only be done after all objects and wings have been parsed.
6254 {
6255  int i;
6256 
6257  // build trees
6258  for (i = 0; i < Total_initially_docked; i++)
6259  {
6260  char *docker_point, *dockee_point;
6261  p_object *docker, *dockee;
6262 
6263  // resolve the docker and dockee
6265  if (docker == NULL)
6266  {
6267  Warning(LOCATION, "Could not resolve initially docked object '%s'!", Initially_docked[i].docker);
6268  continue;
6269  }
6271  if (dockee == NULL)
6272  {
6273  Warning(LOCATION, "Could not resolve docking target '%s' of initially docked object '%s'!", Initially_docked[i].dockee, Initially_docked[i].docker);
6274  continue;
6275  }
6276 
6277  // skip docking if they're already docked
6278  // (in FSO, we list all initially docked pairs for all ships,
6279  // so we end up with twice as many docking entries as we need)
6280  if (dock_check_find_direct_docked_object(docker, dockee))
6281  continue;
6282 
6283  // resolve the dockpoints
6284  docker_point = Initially_docked[i].docker_point;
6285  dockee_point = Initially_docked[i].dockee_point;
6286 
6287  // docker point in use?
6288  if (dock_find_object_at_dockpoint(docker, docker_point) != NULL)
6289  {
6290  Warning(LOCATION, "Trying to initially dock '%s' and '%s', but the former's dockpoint is already in use!", Initially_docked[i].docker, Initially_docked[i].dockee);
6291  continue;
6292  }
6293 
6294  // dockee point in use?
6295  if (dock_find_object_at_dockpoint(dockee, dockee_point) != NULL)
6296  {
6297  Warning(LOCATION, "Trying to initially dock '%s' and '%s', but the latter's dockpoint is already in use!", Initially_docked[i].docker, Initially_docked[i].dockee);
6298  continue;
6299  }
6300 
6301  dock_dock_objects(docker, docker_point, dockee, dockee_point);
6302  }
6303 
6304  // now resolve the leader of each tree
6305  for (SCP_vector<p_object>::iterator ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
6306  {
6307  p_object *pobjp = &(*ii);
6309 
6310  // since we're going through all objects, this object may not be docked
6311  if (!object_is_docked(pobjp))
6312  continue;
6313 
6314  // has this object (by extension, this group of docked objects) been handled already?
6315  if (pobjp->flags2 & P2_ALREADY_HANDLED)
6316  continue;
6317 
6318  // find the dock leader(s)
6320 
6321  // display an error if necessary
6322  if (dfi.maintained_variables.int_value == 0)
6323  {
6324  Warning(LOCATION, "No dock leaders found in the docking group containing %s. The group will not appear in-mission!\n", pobjp->name);
6325  }
6326  else if (dfi.maintained_variables.int_value > 1)
6327  {
6328  Warning(LOCATION, "There are multiple dock leaders in the docking group containing the leader %s! Setting %s as the sole leader...\n", dfi.maintained_variables.objp_value->name, dfi.maintained_variables.objp_value->name);
6329  }
6330 
6331  // clear dfi stuff
6333  dfi.maintained_variables.objp_value = NULL;
6334 
6335  // set the handled flag for this group
6337  }
6338 
6339  // now clear the handled flags
6341 }
6342 
6346 int mission_parse_is_multi(const char *filename, char *mission_name)
6347 {
6348  int game_type;
6349  int filelength;
6350  CFILE *ftemp;
6351 
6352  // new way of getting information. Open the file, and just get the name and the game_type flags.
6353  // return the flags if a multiplayer mission
6354 
6355  ftemp = cfopen(filename, "rt");
6356  if (!ftemp)
6357  return 0;
6358 
6359  // 7/9/98 -- MWA -- check for 0 length file.
6360  filelength = cfilelength(ftemp);
6361  cfclose(ftemp);
6362  if ( filelength == 0 )
6363  return 0;
6364 
6365  game_type = 0;
6366  do {
6367  try
6368  {
6369  read_file_text(filename, CF_TYPE_MISSIONS);
6370  reset_parse();
6371 
6372  if (skip_to_string("$Name:") != 1) {
6373  nprintf(("Network", "Unable to process %s because we couldn't find $Name:", filename));
6374  break;
6375  }
6376  stuff_string(mission_name, F_NAME, NAME_LENGTH);
6377 
6378  if (skip_to_string("+Game Type Flags:") != 1) {
6379  nprintf(("Network", "Unable to process %s because we couldn't find +Game Type Flags:\n", filename));
6380  break;
6381  }
6382  stuff_int(&game_type);
6383  }
6384  catch (const parse::ParseException& e)
6385  {
6386  mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
6387  break;
6388  }
6389  } while (0);
6390 
6391  return (game_type & MISSION_TYPE_MULTI) ? game_type : 0;
6392 }
6393 
6402 {
6403  if ( get_mission_info(filename, &The_mission) )
6404  return -1;
6405 
6406  Assert( The_mission.game_type & MISSION_TYPE_MULTI ); // assume multiplayer only for now?
6407 
6408  // return the number of parse_players. later, we might want to include (optionally?) the number
6409  // of other ships in the main players wing (usually wing 'alpha') for inclusion of number of
6410  // players allowed.
6411 
6412  return The_mission.num_players;
6413 }
6414 
6424 {
6425  p_object *p_objp;
6426 
6427  if (name == NULL)
6428  return NULL;
6429 
6430  for (p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
6431  {
6432  if (!stricmp(p_objp->name, name))
6433  {
6434  return p_objp; // still on the arrival list
6435  }
6436  }
6437 
6438  return NULL;
6439 }
6440 
6450 {
6451  p_object *p_objp;
6452 
6453  for (p_objp = GET_FIRST(&Ship_arrival_list); p_objp !=END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
6454  {
6455  if (p_objp->net_signature == net_signature)
6456  {
6457  return p_objp; // still on the arrival list
6458  }
6459  }
6460 
6461  return NULL;
6462 }
6463 
6468 int mission_set_arrival_location(int anchor, int location, int dist, int objnum, int path_mask, vec3d *new_pos, matrix *new_orient)
6469 {
6470  int shipnum, anchor_objnum;
6471  vec3d anchor_pos, rand_vec, new_fvec;
6472  matrix orient;
6473 
6474  if ( location == ARRIVE_AT_LOCATION )
6475  return -1;
6476 
6477  Assert(anchor >= 0);
6478 
6479  // this ship might possibly arrive at another location. The location is based on the
6480  // proximity of some ship (and some other special tokens)
6481  if (anchor & SPECIAL_ARRIVAL_ANCHOR_FLAG)
6482  {
6483  bool get_players = (anchor & SPECIAL_ARRIVAL_ANCHOR_PLAYER_FLAG) > 0;
6484 
6485  // filter out iff
6486  int iff_index = anchor;
6487  iff_index &= ~SPECIAL_ARRIVAL_ANCHOR_FLAG;
6488  iff_index &= ~SPECIAL_ARRIVAL_ANCHOR_PLAYER_FLAG;
6489 
6490  // get ship
6491  shipnum = ship_get_random_team_ship(iff_get_mask(iff_index), get_players ? SHIP_GET_ONLY_PLAYERS : SHIP_GET_ANY_SHIP);
6492  }
6493  // if we didn't find the arrival anchor in the list of special nodes, then do a
6494  // ship name lookup on the anchor
6495  else
6496  {
6497  shipnum = ship_name_lookup(Parse_names[anchor]);
6498  }
6499 
6500  // if we didn't get an object from one of the above functions, then make the object
6501  // arrive at its placed location
6502  if (shipnum < 0)
6503  {
6504  Assert ( location != ARRIVE_FROM_DOCK_BAY ); // bogus data somewhere!!! get mwa
6505  nprintf (("allender", "couldn't find ship for arrival anchor -- using location ship created at"));
6506  return -1;
6507  }
6508 
6509  // take the shipnum and get the position. once we have positions, we can determine where
6510  // to make this ship appear
6511  Assert ( shipnum != -1 );
6512  anchor_objnum = Ships[shipnum].objnum;
6513  anchor_pos = Objects[anchor_objnum].pos;
6514 
6515  // if arriving from docking bay, then set ai mode and call function as per AL's instructions.
6516  if ( location == ARRIVE_FROM_DOCK_BAY ) {
6517  vec3d pos, fvec;
6518 
6519  // if we get an error, just let the ship arrive(?)
6520  if ( ai_acquire_emerge_path(&Objects[objnum], anchor_objnum, path_mask, &pos, &fvec) == -1 ) {
6521  Int3(); // get MWA or AL -- not sure what to do here when we cannot acquire a path
6522  return -1;
6523  }
6524  Objects[objnum].pos = pos;
6525  vm_vector_2_matrix(&Objects[objnum].orient, &fvec, NULL, NULL);
6526  } else {
6527 
6528  // AL: ensure dist > 0 (otherwise get errors in vecmat)
6529  // TODO: maybe set distance to 2x ship radius of ship appearing in front of?
6530  if ( dist <= 0 )
6531  {
6532  // Goober5000 - default to 100
6533  Warning(LOCATION, "Distance of %d is invalid in mission_set_arrival_location. Defaulting to 100.\n", dist);
6534  dist = 100;
6535  }
6536 
6537  // get a vector which is the ships arrival position based on the type of arrival
6538  // this ship should have. Arriving near a ship we use a random normalized vector
6539  // scaled by the distance given by the designer. Arriving in front of a ship means
6540  // entering the battle in the view cone.
6541  if ( location == ARRIVE_NEAR_SHIP ) {
6542  // get a random vector -- use static randvec if in multiplayer
6543  if ( Game_mode & GM_NORMAL )
6544  vm_vec_rand_vec_quick(&rand_vec);
6545  else
6546  static_randvec( Objects[objnum].net_signature, &rand_vec );
6547  } else if ( location == ARRIVE_IN_FRONT_OF_SHIP ) {
6548  vec3d t1, t2, t3;
6549  int r1, r2;
6550  float x;
6551 
6552  // cool function by MK to give a reasonable random vector "in front" of a ship
6553  // rvec and uvec are the right and up vectors.
6554  // If these are not available, this would be an expensive method.
6555  x = cosf(fl_radians(45.0f));
6556  if ( Game_mode & GM_NORMAL ) {
6557  r1 = rand() < RAND_MAX_2 ? -1 : 1;
6558  r2 = rand() < RAND_MAX_2 ? -1 : 1;
6559  } else {
6560  // in multiplayer, use the static rand functions so that all clients can get the
6561  // same information.
6562  r1 = static_rand(Objects[objnum].net_signature) < RAND_MAX_2 ? -1 : 1;
6563  r2 = static_rand(Objects[objnum].net_signature+1) < RAND_MAX_2 ? -1 : 1;
6564  }
6565 
6566  vm_vec_copy_scale(&t1, &(Objects[anchor_objnum].orient.vec.fvec), x);
6567  vm_vec_copy_scale(&t2, &(Objects[anchor_objnum].orient.vec.rvec), (1.0f - x) * r1);
6568  vm_vec_copy_scale(&t3, &(Objects[anchor_objnum].orient.vec.uvec), (1.0f - x) * r2);
6569 
6570  vm_vec_add(&rand_vec, &t1, &t2);
6571  vm_vec_add2(&rand_vec, &t3);
6572  vm_vec_normalize(&rand_vec);
6573  }
6574 
6575  // add in the radius of the two ships involved. This will make the ship arrive further than
6576  // specified, but will appear more accurate since we are pushing the edge of the model to the
6577  // specified distance. large objects appears to be a lot closer without the following line because
6578  // the object centers were at the correct distance, but the model itself was much closer to the
6579  // target ship.
6580  dist += (int)Objects[objnum].radius + (int)Objects[anchor_objnum].radius;
6581  vm_vec_scale_add(&Objects[objnum].pos, &anchor_pos, &rand_vec, (float)dist);
6582 
6583  // I think that we will always want to orient the ship that is arriving to face towards
6584  // the ship it is arriving near/in front of. The effect will be cool!
6585  //
6586  // calculate the new fvec of the ship arriving and use only that to get the matrix. isn't a big
6587  // deal not getting bank.
6588  vm_vec_sub(&new_fvec, &anchor_pos, &Objects[objnum].pos );
6589  vm_vector_2_matrix( &orient, &new_fvec, NULL, NULL );
6590  Objects[objnum].orient = orient;
6591  }
6592 
6593  // set the new_pos parameter since it might be used outside the function (i.e. when dealing with wings).
6594  if ( new_pos )
6595  memcpy(new_pos, &Objects[objnum].pos, sizeof(vec3d) );
6596 
6597  if ( new_orient )
6598  memcpy( new_orient, &Objects[objnum].orient, sizeof(matrix) );
6599 
6600  return anchor_objnum;
6601 }
6602 
6607 {
6608  int i;
6609  reinforcements *rp;
6610 
6611  for (i = 0; i < Num_reinforcements; i++) {
6612  rp = &Reinforcements[i];
6613  if ( !stricmp(rp->name, name) ) {
6614  if ( !(rp->flags & RF_IS_AVAILABLE) ) {
6615  rp->flags |= RF_IS_AVAILABLE;
6616 
6617  // tell all of the clients.
6618  if ( MULTIPLAYER_MASTER ) {
6620  }
6621  }
6622  return;
6623  }
6624  }
6625 
6626  Assert ( i < Num_reinforcements );
6627 }
6628 
6636 {
6637  int should_arrive;
6638 
6639  // find out in the arrival cue became true
6640  should_arrive = eval_sexp(objp->arrival_cue);
6641 
6642  // we must first check to see if this ship is a reinforcement or not. If so, then don't
6643  // process
6644  if ( objp->flags & P_SF_REINFORCEMENT ) {
6645 
6646  // if this ship did arrive, mark the reinforcement as available, and tell clients if in multiplayer
6647  // mode
6648  if ( should_arrive ) {
6650  }
6651  return -1;
6652  }
6653 
6654  if ( should_arrive ) { // has the arrival criteria been met?
6655  int object_num;
6656 
6657  // check to see if the delay field <= 0. if so, then create a timestamp and then maybe
6658  // create the object
6659  if ( objp->arrival_delay <= 0 ) {
6660  objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
6661 
6662  // make sure we have a valid timestamp
6663  Assert( objp->arrival_delay > 0 );
6664  }
6665 
6666  // if the timestamp hasn't elapsed, move onto the next ship.
6667  if ( !timestamp_elapsed(objp->arrival_delay) )
6668  return -1;
6669 
6670  // check to see if this ship is to arrive via a docking bay. If so, and the ship to arrive from
6671  // doesn't exist, don't create.
6672  if ( objp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
6673  int shipnum;
6674  char *name;
6675 
6676  Assert( objp->arrival_anchor >= 0 );
6677  name = Parse_names[objp->arrival_anchor];
6678 
6679  // see if ship is in mission.
6680  shipnum = ship_name_lookup( name );
6681  if ( shipnum == -1 ) {
6682  // see if ship is yet to arrive. If so, then return -1 so we can evaluate again later.
6684  return -1;
6685 
6686  mission_parse_mark_non_arrival(objp); // Goober5000
6687  WarningEx(LOCATION, "Warning: Ship %s cannot arrive from docking bay of destroyed or departed %s.\n", objp->name, name);
6688  return -1;
6689  }
6690 
6691  // Goober5000: aha - also don't create if fighterbay is destroyed
6692  if (ship_fighterbays_all_destroyed(&Ships[shipnum])) {
6693  WarningEx(LOCATION, "Warning: Ship %s cannot arrive from destroyed docking bay of %s.\n", objp->name, name);
6694  return -1;
6695  }
6696  }
6697 
6698  if ( objp->flags & P_SF_CANNOT_ARRIVE ) {
6699  WarningEx(LOCATION, "Warning: Ship %s cannot arrive. Ship not created.\n", objp->name);
6700  return -1;
6701  }
6702 
6703  // create the ship
6704  object_num = parse_create_object(objp);
6705 
6706  // since this ship is not in a wing, create a SHIP_ARRIVE entry
6707  //mission_log_add_entry( LOG_SHIP_ARRIVE, objp->name, NULL );
6708  Assert(object_num >= 0 && object_num < MAX_OBJECTS);
6709 
6710  // Play the music track for an arrival
6711  if ( !(Ships[Objects[object_num].instance].flags & SF_NO_ARRIVAL_MUSIC) )
6712  if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
6713  Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
6714  event_music_arrival(Ships[Objects[object_num].instance].team);
6715  }
6716  return object_num;
6717  }
6718 
6719  return -1;
6720 }
6721 
6722 // Goober5000
6724 {
6725  // try to create ship
6726  int objnum = mission_did_ship_arrive(p_objp);
6727  if (objnum < 0)
6728  return;
6729 
6730  // remove from arrival list
6731  if (p_objp == Arriving_support_ship)
6733  else
6734  list_remove(&Ship_arrival_list, p_objp);
6735 }
6736 
6737 // Goober5000
6739 {
6740  // mark the flag
6741  p_objp->flags |= P_SF_CANNOT_ARRIVE;
6742 }
6743 
6744 // Goober5000
6746 {
6747  int wingnum = WING_INDEX(wingp);
6748 
6749  // look through all ships yet to arrive...
6750  for (p_object *p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
6751  {
6752  // ...and mark the ones in this wing
6753  if (p_objp->wingnum == wingnum)
6754  p_objp->flags |= P_SF_CANNOT_ARRIVE;
6755  }
6756 }
6757 
6762 {
6763  for (p_object *p_objp = GET_FIRST(&Ship_arrival_list); p_objp != END_OF_LIST(&Ship_arrival_list); p_objp = GET_NEXT(p_objp))
6764  {
6765  if (p_objp->wingnum != -1)
6766  {
6767  if (!object_is_docked(p_objp) && (Sexp_nodes[Wings[p_objp->wingnum].arrival_cue].value == SEXP_KNOWN_FALSE))
6768  p_objp->flags |= P_SF_CANNOT_ARRIVE;
6769  }
6770  else
6771  {
6772  if (Sexp_nodes[p_objp->arrival_cue].value == SEXP_KNOWN_FALSE)
6773  p_objp->flags |= P_SF_CANNOT_ARRIVE;
6774  }
6775  }
6776 }
6777 
6785 {
6786  int i;
6787 
6788  // when the support ship arrives, the shipname it is supposed to repair is in the 'misc'
6789  // field of the parse object. If the ship still exists, call ai function which actually
6790  // issues the goal for the repair
6791  for ( i = 0; i < Num_arriving_repair_targets; i++ ) {
6792  int shipnum;
6793 
6794  shipnum = ship_name_lookup( Arriving_repair_targets[i] );
6795 
6796  if ( shipnum != -1 ) {
6797  object *requester_objp, *support_objp;
6798 
6799  support_objp = &Objects[objnum];
6800  requester_objp = &Objects[Ships[shipnum].objnum];
6801  ai_add_rearm_goal( requester_objp, support_objp );
6802  }
6803  }
6804 
6806 
6807  Arriving_support_ship = NULL;
6808  Num_arriving_repair_targets = 0;
6809 }
6810 
6811 // Goober5000
6813 {
6814  return (pobjp->next != NULL) && (pobjp->prev != NULL);
6815 }
6816 
6821 {
6822  int i;
6823  int rship = -1;
6824  wing *wingp;
6825 
6826  // before checking arrivals, check to see if we should play a message concerning arrivals
6827  // of other wings. We use the timestamps to delay the arrival message slightly for
6828  // better effect
6829  if (timestamp_valid(Arrival_message_delay_timestamp) && timestamp_elapsed(Arrival_message_delay_timestamp) && !MULTI_TEAM)
6830  {
6831  int use_terran_cmd;
6832 
6833  // use terran command 25% of time
6834  use_terran_cmd = ((frand() - 0.75) > 0.0f)?1:0;
6835 
6837  if ((rship < 0) || use_terran_cmd)
6839  else if (rship >= 0)
6841 
6842  Arrival_message_delay_timestamp = timestamp(-1); // make the stamp invalid
6843  }
6844 
6845  // check the arrival list
6846  // Goober5000 - we can't run through the list the usual way because we might
6847  // remove a bunch of objects and completely screw up the list linkage
6848  for (SCP_vector<p_object>::iterator ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
6849  {
6850  p_object *pobjp = &(*ii);
6851 
6852  // make sure we're on the arrival list
6853  if (!parse_object_on_arrival_list(pobjp))
6854  continue;
6855 
6856  // if this object has a wing, don't create it -- let code for wings determine if it should be created
6857  if (pobjp->wingnum >= 0)
6858  continue;
6859 
6860  // make it arrive
6862  }
6863 
6864  // check the support ship arrival list
6865  if (Arriving_support_ship)
6866  {
6867  // make it arrive (support ships are not put on the arrival list)
6868  mission_maybe_make_ship_arrive(Arriving_support_ship);
6869  }
6870 
6871  // we must also check to see if there are waves of a wing that must
6872  // reappear if all the ships of the current wing have been destroyed or
6873  // have departed. If this is the case, then create the next wave.
6874  for (i = 0; i < Num_wings; i++)
6875  {
6876  wingp = &Wings[i];
6877 
6878  // should we process this wing anymore
6879  if (wingp->flags & WF_WING_GONE)
6880  continue;
6881 
6882  // if we have a reinforcement wing, then don't try to create new ships automatically.
6883  if (wingp->flags & WF_REINFORCEMENT)
6884  {
6885  // check to see in the wings arrival cue is true, and if so, then mark the reinforcement
6886  // as available
6887  if (eval_sexp(wingp->arrival_cue))
6889 
6890  // reinforcement wings skip the rest of the loop
6891  continue;
6892  }
6893 
6894  // don't do evaluations for departing wings
6895  if (wingp->flags & WF_WING_DEPARTING)
6896  continue;
6897 
6898  // must check to see if we are at the last wave. Code above to determine when a wing is gone only
6899  // gets run when a ship is destroyed (not every N seconds like it used to). Do a quick check here.
6900  if (wingp->current_wave == wingp->num_waves)
6901  continue;
6902 
6903  // If the current wave of this wing is 0, then we haven't created the ships in the wing yet.
6904  // If the threshold of the wing has been reached, then we need to create more ships.
6905  if ((wingp->current_wave == 0) || (wingp->current_count <= wingp->threshold))
6906  {
6907  // Call parse_wing_create_ships to try and create it. That function will eval the arrival
6908  // cue of the wing and create the ships if necessary.
6909  int created = parse_wing_create_ships(wingp, wingp->wave_count);
6910 
6911  // if we didn't create any ships, nothing more to do for this wing
6912  if (created <= 0)
6913  continue;
6914 
6915  // If this wing was a reinforcement wing, then we need to reset the reinforcement flag for the wing
6916  // so the user can call in another set if need be.
6917  if (wingp->flags & WF_RESET_REINFORCEMENT)
6918  {
6919  wingp->flags &= ~WF_RESET_REINFORCEMENT;
6920  wingp->flags |= WF_REINFORCEMENT;
6921  }
6922 
6923  // probably send a message to the player when this wing arrives.
6924  // if no message, nothing more to do for this wing
6925  if (wingp->flags & WF_NO_ARRIVAL_MESSAGE)
6926  continue;
6927 
6928  // multiplayer team vs. team
6929  if(MULTI_TEAM)
6930  {
6931  // send a hostile wing arrived message
6932  rship = wingp->ship_index[wingp->special_ship];
6933 
6934  int multi_team_filter = Ships[rship].team;
6935 
6936  // there are two timestamps at work here. One to control how often the player receives
6937  // messages about incoming hostile waves, and the other to control how long after
6938  // the wing arrives does the player actually get the message.
6939  if (timestamp_elapsed(Allow_arrival_message_timestamp_m[multi_team_filter]))
6940  {
6941  if (!timestamp_valid(Arrival_message_delay_timestamp_m[multi_team_filter]))
6942  {
6943  Arrival_message_delay_timestamp_m[multi_team_filter] = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX);
6944  }
6945  Allow_arrival_message_timestamp_m[multi_team_filter] = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
6946 
6947  // send to the proper team
6949  }
6950  }
6951  // does the player attack this ship?
6952  else if (iff_x_attacks_y(Player_ship->team, Ships[wingp->ship_index[0]].team))
6953  {
6954  // there are two timestamps at work here. One to control how often the player receives
6955  // messages about incoming hostile waves, and the other to control how long after
6956  // the wing arrives does the player actually get the message.
6957  if (timestamp_elapsed(Allow_arrival_message_timestamp))
6958  {
6959  if (!timestamp_valid(Arrival_message_delay_timestamp))
6960  {
6961  Arrival_message_delay_timestamp = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX);
6962  }
6963  Allow_arrival_message_timestamp = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
6964  }
6965  }
6966  // everything else
6967  else
6968  {
6970  if (rship >= 0)
6971  {
6972  int j;
6973  char message_name[NAME_LENGTH + 10];
6974  sprintf(message_name, "%s Arrived", wingp->name);
6975 
6976  // see if this wing has an arrival message associated with it
6977  for (j = 0; j < MAX_BUILTIN_MESSAGE_TYPES; j++)
6978  {
6979  if (!stricmp(message_name, Builtin_messages[j].name))
6980  {
6982  break;
6983  }
6984  }
6985  }
6986  }
6987  }
6988  }
6989 
6990  Mission_arrival_timestamp = timestamp(ARRIVAL_TIMESTAMP);
6991 }
6992 
6997 {
6998  // must *have* a subspace drive
6999  if (shipp->flags2 & SF2_NO_SUBSPACE_DRIVE)
7000  return 0;
7001 
7002  // navigation must work
7003  if (!ship_navigation_ok_to_warp(shipp))
7004  return 0;
7005 
7006  return 1;
7007 }
7008 
7012 int mission_do_departure(object *objp, bool goal_is_to_warp)
7013 {
7014  Assert(objp->type == OBJ_SHIP);
7015  int location, anchor, path_mask;
7016  ship *shipp = &Ships[objp->instance];
7017  ai_info *aip = &Ai_info[shipp->ai_index];
7018 
7019  mprintf(("Entered mission_do_departure() for %s\n", shipp->ship_name));
7020 
7021  // abort rearm, because if we entered this function we're either going to depart via hyperspace, depart via bay,
7022  // or revert to our default behavior
7023  ai_abort_rearm_request(objp);
7024 
7025  // if our current goal is to warp, then we won't consider departing to a bay, because the goal explicitly says to warp out
7026  // (this sort of goal can be assigned in FRED, either in the ship's initial orders or as the ai-warp-out goal)
7027  if (goal_is_to_warp)
7028  {
7029  // aha, but not if we were ORDERED to depart, because the comms menu ALSO uses the goal code, and yet the comms menu means any departure method!
7030  if ((shipp->flags & SF_DEPARTURE_ORDERED) || ((shipp->wingnum >= 0) && (Wings[shipp->wingnum].flags & WF_DEPARTURE_ORDERED)))
7031  {
7032  mprintf(("Looks like we were ordered to depart; initiating the standard departure logic\n"));
7033  }
7034  // since our goal is to warp, then if we can warp, jump directly to the warping part
7035  else if (ship_can_use_warp_drive(shipp))
7036  {
7037  mprintf(("Our current goal is to warp! Trying to warp...\n"));
7038  goto try_to_warp;
7039  }
7040  // otherwise, since we can't warp, we'll do the standard bay departure check, etc.
7041  }
7042 
7043  // if this ship belongs to a wing, then use the wing departure information
7044  if (shipp->wingnum >= 0)
7045  {
7046  wing *wingp = &Wings[shipp->wingnum];
7047 
7048  // copy the wing's departure information to the ship
7049  // (needed because the bay departure code will check the ship's information again later on)
7050  shipp->departure_location = wingp->departure_location;
7051  shipp->departure_anchor = wingp->departure_anchor;
7052  shipp->departure_path_mask = wingp->departure_path_mask;
7053  }
7054 
7055  location = shipp->departure_location;
7056  anchor = shipp->departure_anchor;
7057  path_mask = shipp->departure_path_mask;
7058 
7059  // if departing to a docking bay, try to find the anchor ship to depart to. If not found, then
7060  // just make it warp out like anything else.
7061  if (location == DEPART_AT_DOCK_BAY)
7062  {
7063  int anchor_shipnum;
7064  char *name;
7065 
7066  Assert(anchor >= 0);
7067  name = Parse_names[anchor];
7068 
7069  // see if ship is yet to arrive. If so, then warp.
7071  {
7072  mprintf(("Anchor ship %s hasn't arrived yet! Trying to warp...\n", name));
7073  goto try_to_warp;
7074  }
7075 
7076  // see if ship is in mission. If not, then we can assume it was destroyed or departed since
7077  // it is not on the arrival list (as shown by above if statement).
7078  anchor_shipnum = ship_name_lookup(name);
7079  if (anchor_shipnum < 0)
7080  {
7081  mprintf(("Anchor ship %s not found! Trying to warp...\n", name));
7082  goto try_to_warp;
7083  }
7084 
7085  // see if we can actually depart to the ship
7086  if (!ship_useful_for_departure(anchor_shipnum, shipp->departure_path_mask))
7087  {
7088  mprintf(("Anchor ship %s not suitable for departure (dying, departing, bays destroyed, etc.). Trying to warp...\n", name));
7089  goto try_to_warp;
7090  }
7091 
7092  // find a path
7093  if (ai_acquire_depart_path(objp, Ships[anchor_shipnum].objnum, path_mask) >= 0)
7094  {
7095  MONITOR_INC(NumShipDepartures,1);
7096 
7097  mprintf(("Acquired departure path\n"));
7098  return 1;
7099  }
7100  }
7101 
7102 try_to_warp:
7103 
7104  // make sure we can actually warp
7105  if (ship_can_use_warp_drive(shipp))
7106  {
7107  mprintf(("Setting mode to warpout\n"));
7108 
7109  ai_set_mode_warp_out(objp, aip);
7110  MONITOR_INC(NumShipDepartures,1);
7111 
7112  return 1;
7113  }
7114  // find something else to do
7115  else
7116  {
7117  // NOTE: this point should no longer be reached in the standard goal code, since the goal or comm order must be achievable
7118  // for this function to be called. This point should only be reached if the ship has no subspace drive, AND either has no
7119  // mothership assigned (or departs to hyperspace) or the mothership was destroyed, AND falls into one of the following cases:
7120  // 1) The ship's departure cue evaluates to true in the mission
7121  // 2) A support ship has had its hull fall to 25% when it has no repair targets
7122  // 3) A fighter or bomber with an IFF that doesn't allow support ships has its warp_out_timestamp elapse (but this seems to not be a possibility anymore)
7123  // 4) An instructor in a training mission has been fired upon
7124  mprintf(("Can't warp! Doing something else instead.\n"));
7125 
7126  shipp->flags &= ~SF_DEPARTING;
7127  ai_do_default_behavior(objp);
7128 
7129  return 0;
7130  }
7131 }
7132 
7138 {
7139  int i, j;
7140  object *objp;
7141  wing *wingp;
7142 
7143  // scan through the active ships an evaluate their departure cues. For those
7144  // ships whose time has come, set their departing flag.
7145 
7146  for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
7147  if (objp->type == OBJ_SHIP) {
7148  ship *shipp;
7149 
7150  Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
7151 
7152  shipp = &Ships[objp->instance];
7153 
7154  // don't process a ship that is already departing or dying or disabled
7155  // AL 12-30-97: Added SF_CANNOT_WARP to check
7156  // Goober5000 - fixed so that it WILL eval when SF_CANNOT_WARP if departing to dockbay
7157  if ( (shipp->flags & (SF_DEPARTING | SF_DYING)) || ((shipp->flags & SF_CANNOT_WARP) && (shipp->departure_location != DEPART_AT_DOCK_BAY)) || ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) ) {
7158  continue;
7159  }
7160 
7161  // don't process ships that are part of a wing -- handled in seperate case
7162  if ( shipp->wingnum != -1 )
7163  continue;
7164 
7165  // when the departure cue becomes true, set off the departure delay timer. We store the
7166  // timer as -seconds in FreeSpace which indicates that the timer has not been set. If the timer
7167  // is not set, then turn it into a valid timer and keep evaluating the timer until it is elapsed
7168  if ( eval_sexp(shipp->departure_cue) ) {
7169  if ( shipp->departure_delay <= 0 )
7170  shipp->departure_delay = timestamp(-shipp->departure_delay * 1000 );
7171  if ( timestamp_elapsed(shipp->departure_delay) )
7172  mission_do_departure( objp );
7173  }
7174  }
7175  }
7176 
7177  // now scan through the list of wings and check their departure cues. For wings with
7178  // that cue being true, we must update internal variables to indicate that the wing is
7179  // departed and that no further waves of this wing will appear
7180 
7181  for ( i = 0; i < Num_wings; i++ ) {
7182  wingp = &Wings[i];
7183 
7184  // should we process this wing anymore
7185  if ( wingp->flags & WF_WING_DEPARTING )
7186  continue;
7187 
7188  // evaluate the sexpression. If true, mark all the ships in this wing as departing and increment
7189  // the num departed in the wing structure. Then add number of remaining waves * ships/wave to
7190  // departed count to get total count of ships in the wing which departed. (We are counting ships
7191  // that have not yet arrived as departed if they never arrive -- this may be bad, but for some reason
7192  // seems like the right thing to do).
7193 
7194  if ( eval_sexp(wingp->departure_cue) ) {
7195  // if we haven't set up the departure timer yet (would be <= 0) setup the timer to pop N seconds
7196  // later
7197  if ( wingp->departure_delay <= 0 )
7198  wingp->departure_delay = timestamp( -wingp->departure_delay * 1000 );
7199  if ( !timestamp_elapsed(wingp->departure_delay) )
7200  continue;
7201 
7202  wingp->flags |= WF_WING_DEPARTING;
7203  for ( j = 0; j < wingp->current_count; j++ ) {
7204  ship *shipp;
7205 
7206  shipp = &Ships[wingp->ship_index[j]];
7207  if ( (shipp->flags & SF_DEPARTING) || (shipp->flags & SF_DYING) )
7208  continue;
7209 
7210  Assert ( shipp->objnum != -1 );
7211  objp = &Objects[shipp->objnum];
7212 
7213  mission_do_departure( objp );
7214  // don't add to wingp->total_departed here -- this is taken care of in ship code.
7215  }
7216  }
7217  }
7218  Mission_departure_timestamp = timestamp(DEPARTURE_TIMESTAMP);
7219 }
7220 
7225 {
7228 }
7229 
7231 {
7232  int i;
7233  // set primary weapon ammunition here, but does it actually matter? - Goober5000
7234 
7235  Assert(Subsys_index >= 0);
7236 
7237  // we allocate in blocks of MIN_SUBSYS_STATUS_SIZE so if we need more then make more
7238  if ( (Subsys_status == NULL) || (Subsys_index >= (Subsys_status_size - 1)) ) {
7240 
7242  Subsys_status = (subsys_status*)vm_realloc(Subsys_status, sizeof(subsys_status) * Subsys_status_size );
7243  }
7244 
7245  Verify( Subsys_status != NULL );
7246 
7247  // the memset is redundant to the below assignments
7248  //memset( &Subsys_status[Subsys_index], 0, sizeof(subsys_status) );
7249 
7250  Subsys_status[Subsys_index].name[0] = '\0';
7251 
7252  Subsys_status[Subsys_index].percent = 0.0f;
7253 
7255  Subsys_status[Subsys_index].primary_ammo[0] = 100; // *
7256 
7257  for (i=1; i<MAX_SHIP_PRIMARY_BANKS; i++)
7258  {
7259  Subsys_status[Subsys_index].primary_banks[i] = -1; // none
7260  Subsys_status[Subsys_index].primary_ammo[i] = 100; // *
7261  }
7262 
7264  Subsys_status[Subsys_index].secondary_ammo[0] = 100;
7265 
7266  for (i=1; i<MAX_SHIP_SECONDARY_BANKS; i++)
7267  {
7268  Subsys_status[Subsys_index].secondary_banks[i] = -1;
7269  Subsys_status[Subsys_index].secondary_ammo[i] = 100;
7270  }
7271 
7273 
7274  Subsys_status[Subsys_index].subsys_cargo_name = 0; // "Nothing"
7275 
7276  return Subsys_index++;
7277 }
7278 
7279 // Goober5000
7281 {
7282  int i, new_index;
7283 
7284  // this is not good; we have to allocate another slot, but then bump all the
7285  // slots upward so that this particular parse object's subsystems are contiguous
7286  new_index = allocate_subsys_status();
7287 
7288  // only bump the subsystems if this isn't the very last subsystem
7289  if (new_index != pobjp->subsys_index + pobjp->subsys_count)
7290  {
7291  // copy the new blank entry for future reference
7292  subsys_status temp_entry;
7293  memcpy(&temp_entry, &Subsys_status[new_index], sizeof(subsys_status));
7294 
7295  // shift elements upward
7296  for (i = Subsys_index - 1; i > (pobjp->subsys_index + pobjp->subsys_count); i--)
7297  {
7298  memcpy(&Subsys_status[i], &Subsys_status[i-1], sizeof(subsys_status));
7299  }
7300 
7301  // correct the index so that the new subsystem belongs to the proper p_object
7302  new_index = pobjp->subsys_index + pobjp->subsys_count;
7303 
7304  // put the blank entry in the p_object
7305  memcpy(&Subsys_status[new_index], &temp_entry, sizeof(subsys_status));
7306  }
7307 
7308  // make the p_object aware of its new subsystem
7309  pobjp->subsys_count++;
7310 
7311  // we also have to adjust all the indexes in existing parse objects
7312  // (each p_object's subsys_index points to subsystem 0 in its list)
7313  for (SCP_vector<p_object>::iterator ii = Parse_objects.begin(); ii != Parse_objects.end(); ++ii)
7314  {
7315  // bump up base index to accommodate inserted subsystem
7316  if (ii->subsys_index >= new_index)
7317  ii->subsys_index++;
7318  }
7319 
7320  return new_index;
7321 }
7322 
7323 // Goober5000
7325 {
7326  int i;
7327  subsys_status *sssp;
7328 
7329  for (i = 0; i < pobjp->subsys_count; i++)
7330  {
7331  sssp = &Subsys_status[pobjp->subsys_index + i];
7332 
7333  if (!subsystem_stricmp(sssp->name, subsys_name))
7334  return sssp;
7335  }
7336 
7337  return NULL;
7338 }
7339 
7340 // find (or add) the name in the list and return an index to it.
7341 int get_parse_name_index(const char *name)
7342 {
7343  int i;
7344 
7345  for (i=0; i<Num_parse_names; i++)
7346  if (!stricmp(name, Parse_names[i]))
7347  return i;
7348 
7349  Assert(i < MAX_SHIPS + MAX_WINGS);
7350  Assert(strlen(name) < NAME_LENGTH);
7351  strcpy_s(Parse_names[i], name);
7352  return Num_parse_names++;
7353 }
7354 
7355 // Goober5000
7357 {
7358  int i, j;
7359 
7360  // parse it
7362  temp.cached_mask = (1 << MAX_SHIP_BAY_PATHS); // uninitialized value (too high)
7364 
7365  // no restriction?
7366  if (temp.num_paths == 0)
7367  return -1;
7368 
7369  // first, see if it's duplicated anywhere
7370  for (i = 0; i < Num_path_restrictions; i++)
7371  {
7372  // must have same number of allowed paths
7373  if (temp.num_paths != Path_restrictions[i].num_paths)
7374  continue;
7375 
7376  // see if path names match
7377  for (j = 0; j < temp.num_paths; j++)
7378  {
7379  // no match, so skip this
7380  if (stricmp(temp.path_names[j], Path_restrictions[i].path_names[j]))
7381  goto continue_outer_loop;
7382  }
7383 
7384  // match!
7385  return i;
7386 
7387 continue_outer_loop:
7388  ;
7389  }
7390 
7391  // no match, so add a new restriction
7392 
7393  // check limit
7394  if (Num_path_restrictions >= MAX_PATH_RESTRICTIONS)
7395  {
7396  Warning(LOCATION, "Maximum number of path restrictions reached");
7397  return -1;
7398  }
7399 
7400  // add this restriction at the new index
7401  int index = Num_path_restrictions++;
7402  Path_restrictions[index] = temp;
7403 
7404  return index;
7405 }
7406 
7411 {
7412  char tmp[NAME_LENGTH + 15];
7413  char *iff_name;
7414  int iff_index;
7415 
7416  if (strnicmp(name, "<any ", 5))
7417  return -1;
7418 
7419  strcpy_s(tmp, name+5);
7420  iff_name = strtok(tmp, " >");
7421 
7422  // hack substitute "hostile" for "enemy"
7423  if (!stricmp(iff_name, "enemy"))
7424  iff_name = "hostile";
7425 
7426  iff_index = iff_lookup(iff_name);
7427  if (iff_index < 0)
7428  return -1;
7429 
7430  // restrict to players?
7431  if (stristr(name+5, "player") != NULL)
7433  else
7434  return (iff_index | SPECIAL_ARRIVAL_ANCHOR_FLAG);
7435 }
7436 
7437 int get_anchor(char *name)
7438 {
7439  int special_anchor = get_special_anchor(name);
7440 
7441  if (special_anchor >= 0)
7442  return special_anchor;
7443 
7444  return get_parse_name_index(name);
7445 }
7446 
7451 {
7452  object *objp;
7453 
7454  for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
7455  if ( (objp->type == OBJ_SHIP) && (objp->flags & OF_PLAYER_SHIP) ) {
7456  game_busy( NOX("** fixing up player/ai stuff **") ); // animate the loading screen, doesn't nothing if the screen is not active
7458  init_ai_object( OBJ_INDEX(objp) );
7459  }
7460  }
7461 }
7462 
7463 // code to warp in a new support ship. It works by finding the average position of all ships
7464 // in the mission, creating a vector from that position to the player, and scaling out behind the
7465 // player some distance. Should be sufficient.
7466 
7467 #define WARP_IN_MIN_DISTANCE 1000.0f
7468 #define WARP_IN_TIME_MIN 3000 // warps in min 3 seconds later
7469 #define WARP_IN_TIME_MAX 6000 // warps in max 6 seconds later
7470 
7474 void mission_add_to_arriving_support( object *requester_objp )
7475 {
7476  int i;
7477  ship *shipp;
7478 
7479  Assert ( Arriving_support_ship );
7480 
7482  mprintf(("Reached MAX_AI_GOALS trying to add repair request!\n"));
7483  return;
7484  }
7485 
7486  shipp = &Ships[requester_objp->instance];
7487  // check for duplicates before adding
7488  for (i = 0; i < Num_arriving_repair_targets; i++ ) {
7489  if ( !stricmp(Arriving_repair_targets[i], shipp->ship_name) ){
7490  break;
7491  }
7492  }
7493  if ( i != Num_arriving_repair_targets ){ // found the ship before reaching the end -- ignore it!
7494  return;
7495  }
7496 
7497  strcpy_s( Arriving_repair_targets[Num_arriving_repair_targets], Ships[requester_objp->instance].ship_name );
7498  Num_arriving_repair_targets++;
7499 
7500  if ( MULTIPLAYER_MASTER ){
7501  multi_maybe_send_repair_info( requester_objp, NULL, REPAIR_INFO_WARP_ADD );
7502  }
7503 }
7504 
7505 extern int pp_collide_any(vec3d *curpos, vec3d *goalpos, float radius, object *ignore_objp1, object *ignore_objp2, int big_only_flag);
7506 
7511 int get_warp_in_pos(vec3d *pos, object *objp, float x, float y, float z)
7512 {
7513  float rand_val;
7514 
7515  if ( Game_mode & GM_NORMAL )
7516  rand_val = frand();
7517  else
7518  rand_val = static_randf(objp->net_signature);
7519 
7520  rand_val = 1.0f + (rand_val - 0.5f)*0.2f;
7521 
7522  *pos = objp->pos;
7523 
7524  vm_vec_scale_add2( pos, &objp->orient.vec.rvec, x*rand_val*800.0f);
7525  vm_vec_scale_add2( pos, &objp->orient.vec.uvec, y*rand_val*800.0f);
7526  vm_vec_scale_add2( pos, &objp->orient.vec.fvec, z*rand_val*800.0f);
7527 
7528  return pp_collide_any(&objp->pos, pos, objp->radius, objp, NULL, 1);
7529 }
7530 
7534 void mission_bring_in_support_ship( object *requester_objp )
7535 {
7536  vec3d center, warp_in_pos;
7537  p_object *pobj;
7538  ship *requester_shipp;
7539  int i, j, requester_species;
7540 
7541  Assert ( requester_objp->type == OBJ_SHIP );
7542  requester_shipp = &Ships[requester_objp->instance]; // MK, 10/23/97, used to be ->type, bogus, no?
7543 
7544  // if the support ship is already arriving, add the requester to the list
7545  if ( Arriving_support_ship ) {
7546  mission_add_to_arriving_support( requester_objp );
7547  return;
7548  }
7549 
7550  // create a parse object, and put it onto the ship arrival list. This whole thing kind of stinks.
7551  // I want to put it into a parse object since it needs to arrive just a little later than
7552  // this function is called. I have to make some assumptions in the code about values for the parse
7553  // object since I'm no longer working with a mission file. These exceptions will be noted with
7554  // comments
7555 
7556  Arriving_support_ship = &Support_ship_pobj;
7557  pobj = Arriving_support_ship;
7558 
7559  // get average position of all ships
7560  obj_get_average_ship_pos( &center );
7561  vm_vec_sub( &warp_in_pos, &center, &(requester_objp->pos) );
7562 
7563  // Choose position to warp in ship.
7564  // Temporary, but changed by MK because it used to be exactly behind the player.
7565  // This could cause an Assert if the player immediately targeted it (before moving).
7566  // Tend to put in front of the player to aid him in flying towards the ship.
7567 
7568  if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.1f, 1.0f))
7569  if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.2f, -1.0f))
7570  if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.2f, -1.0f))
7571  if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.1f, 1.0f))
7572  get_warp_in_pos(&warp_in_pos, requester_objp, 0.1f, 1.0f, 0.2f);
7573 
7574  // position for ship if it warps in
7575  pobj->pos = warp_in_pos;
7576 
7577  // tally the ship
7578  The_mission.support_ships.tally++;
7579 
7580  // create a name for the ship. use "Support #". look for collisions until one isn't found anymore
7581  i = 1;
7582  do {
7583  sprintf(pobj->name, NOX("Support %d"), i);
7584  if ( (ship_name_lookup(pobj->name) == -1) && (ship_find_exited_ship_by_name(pobj->name) == -1) )
7585  break;
7586  i++;
7587  } while(1);
7588 
7589  vm_set_identity( &(pobj->orient) );
7590 
7591  // *sigh*. Gotta get the ship class. For now, this will amount to finding a ship in the ship_info
7592  // array with the same team as the requester of type SIF_SUPPORT. Might need to be changed, but who knows
7593 
7594  // Goober5000 - who knew of the SCP release? ;) only determine ship class if not set by SEXP
7595  pobj->ship_class = The_mission.support_ships.ship_class;
7596  if (pobj->ship_class < 0)
7597  {
7598  requester_species = Ship_info[requester_shipp->ship_info_index].species;
7599 
7600  // 5/6/98 -- MWA Don't need to do anything for multiplayer. I think that we always want to use
7601  // the species of the caller ship.
7602 
7603  i = -1;
7604  // get index of correct species support ship
7605  for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
7606  if ( (it->species == requester_species) && (it->flags & SIF_SUPPORT) ) {
7607  i = std::distance(Ship_info.cbegin(), it);
7608  break;
7609  }
7610  }
7611 
7612  if ( i != -1 )
7613  pobj->ship_class = i;
7614  else
7615  Int3(); // BOGUS!!!! gotta figure something out here
7616  }
7617 
7618  // set support ship hitpoints
7619  pobj->ship_max_hull_strength = Ship_info[i].max_hull_strength;
7620  pobj->ship_max_shield_strength = Ship_info[i].max_shield_strength;
7621  pobj->max_shield_recharge = Ship_info[i].max_shield_recharge;
7622 
7623  pobj->team = requester_shipp->team;
7624 
7625  for (i=0;i<MAX_IFFS;i++)
7626  {
7627  for (j=0;j<MAX_IFFS;j++)
7628  {
7629  pobj->alt_iff_color[i][j] = -1;
7630  }
7631  }
7632 
7633  pobj->behavior = AIM_NONE; // ASSUMPTION: the mission file has the string "None" which maps to AIM_NONE
7634 
7635  // set the ai_goals to -1. We will put the requester object shipname in repair target array and then take
7636  // care of setting up the goal when creating the ship!!!!
7637  pobj->ai_goals = -1;
7639  mission_add_to_arriving_support( requester_objp );
7640 
7641  // need to set ship's cargo to nothing. scan the cargo_names array looking for the string nothing.
7642  // add it if not found
7643  for (i = 0; i < Num_cargo; i++ )
7644  if ( !stricmp(Cargo_names[i], NOX("nothing")) )
7645  break;
7646 
7647  if ( i == Num_cargo ) {
7648  strcpy(Cargo_names[i], NOX("Nothing"));
7649  Num_cargo++;
7650  }
7651  pobj->cargo1 = char(i);
7652 
7653  pobj->status_count = 0;
7654 
7655  // Goober5000 - take some stuff from mission flags
7656  pobj->arrival_location = The_mission.support_ships.arrival_location;
7657  pobj->arrival_anchor = The_mission.support_ships.arrival_anchor;
7659  pobj->departure_anchor = The_mission.support_ships.departure_anchor;
7660 
7661  pobj->arrival_path_mask = 0;
7662  pobj->departure_path_mask = 0;
7663 
7664  pobj->arrival_distance = 0;
7665  pobj->arrival_cue = Locked_sexp_true;
7667 
7668  pobj->subsys_count = 0; // number of elements used in subsys_status array
7669  pobj->initial_velocity = 100; // start at 100% velocity
7670  pobj->initial_hull = 100; // start at 100% hull
7671  pobj->initial_shields = 100; // and 100% shields
7672 
7674  pobj->departure_delay = 0;
7675 
7676  pobj->wingnum = -1;
7677 
7678  pobj->flags = 0;
7679  pobj->flags2 = 0;
7680 
7681  if ( Player_obj->flags & OF_NO_SHIELDS )
7682  pobj->flags |= P_OF_NO_SHIELDS; // support ships have no shields when player has not shields
7683 
7684  pobj->ai_class = Ship_info[pobj->ship_class].ai_class;
7685  pobj->hotkey = -1;
7686  pobj->score = 0;
7687  pobj->assist_score_pct = 0;
7688 
7689  pobj->dock_list = NULL;
7690  pobj->created_object = NULL;
7691  pobj->group = -1;
7692  pobj->persona_index = -1;
7694  pobj->wing_status_wing_index = -1;
7695  pobj->wing_status_wing_pos = -1;
7696  pobj->respawn_count = 0;
7697  pobj->alt_type_index = -1;
7698  pobj->callsign_index = -1;
7699  pobj->replacement_textures.clear();
7700 }
7701 
7706 {
7707  if ( Arriving_support_ship )
7708  return 1;
7709  else
7710  return 0;
7711 }
7712 
7717 {
7718  char *name;
7719  int i;
7720 
7721  if ( !Arriving_support_ship )
7722  return 0;
7723 
7724  Assert ( objp->type == OBJ_SHIP );
7725  name = Ships[objp->instance].ship_name;
7726  for (i = 0; i < Num_arriving_repair_targets; i++ ) {
7727  if ( !strcmp( name, Arriving_repair_targets[i]) )
7728  return 1;
7729  }
7730 
7731  return 0;
7732 }
7733 
7738 {
7739  char *name;
7740  int i, index;
7741 
7742  if ( !Arriving_support_ship )
7743  return 0;
7744 
7745  // itereate through the target list looking for this ship name. If not found, we
7746  // can simply return.
7747  Assert ( objp->type == OBJ_SHIP );
7748  name = Ships[objp->instance].ship_name;
7749  for (index = 0; index < Num_arriving_repair_targets; index++ ) {
7750  if ( !strcmp( name, Arriving_repair_targets[index]) )
7751  break;
7752  }
7753  if ( index == Num_arriving_repair_targets )
7754  return 0;
7755 
7756  // ship is found -- compress the array
7757  for ( i = index; i < Num_arriving_repair_targets - 1; i++ )
7759 
7760  Num_arriving_repair_targets--;
7761 
7762  if ( MULTIPLAYER_MASTER )
7764 
7765  return 1;
7766 }
7767 
7772 {
7773  int idx;
7774 
7775  // sanity
7776  if(name == NULL)
7777  return -1;
7778 
7779  // lookup
7780  for(idx=0; idx<Mission_alt_type_count; idx++)
7781  {
7782  if(!strcmp(Mission_alt_types[idx], name))
7783  return idx;
7784  }
7785 
7786  // could not find
7787  return -1;
7788 }
7789 
7790 static int mission_parse_lookup_alt_index_warn = 1;
7792 {
7793  // sanity
7794  if(out == NULL)
7795  return;
7796 
7797  if((index < 0) || (index >= Mission_alt_type_count))
7798  {
7799  if (mission_parse_lookup_alt_index_warn)
7800  {
7801  Warning(LOCATION, "Ship with invalid alt_name. Get a programmer");
7802  mission_parse_lookup_alt_index_warn = 0;
7803  }
7804  return;
7805  }
7806 
7807  // stuff it
7808  strcpy(out, Mission_alt_types[index]);
7809 }
7810 
7811 int mission_parse_add_alt(const char *name)
7812 {
7813  // sanity
7814  if(name == NULL)
7815  return -1;
7816 
7817  // maybe add
7819  {
7820  // stuff the name
7822 
7823  // done
7824  return Mission_alt_type_count - 1;
7825  }
7826 
7827  return -1;
7828 }
7829 
7831 {
7832  // sanity
7833  if(name == NULL)
7834  return;
7835 
7836  // maybe remove
7837  for (int i = 0; i < Mission_alt_type_count; ++i)
7838  {
7839  if (!strcmp(Mission_alt_types[i], name))
7840  {
7841  // remove this name by overwriting it with the last name
7842  if (i < Mission_alt_type_count - 1)
7843  strcpy_s(Mission_alt_types[i], Mission_alt_types[Mission_alt_type_count - 1]);
7844 
7845  Mission_alt_type_count--;
7846  break;
7847  }
7848  }
7849 }
7850 
7852 {
7854 }
7855 
7860 {
7861  int idx;
7862 
7863  // sanity
7864  if(name == NULL)
7865  return -1;
7866 
7867  // lookup
7868  for(idx=0; idx<Mission_callsign_count; idx++)
7869  {
7870  if(!strcmp(Mission_callsigns[idx], name))
7871  return idx;
7872  }
7873 
7874  // could not find
7875  return -1;
7876 }
7877 
7878 static int mission_parse_lookup_callsign_index_warn = 1;
7880 {
7881  // sanity
7882  if(out == NULL)
7883  return;
7884 
7885  if((index < 0) || (index >= Mission_callsign_count))
7886  {
7887  if (mission_parse_lookup_callsign_index_warn)
7888  {
7889  Warning(LOCATION, "Ship with invalid callsign. Get a programmer");
7890  mission_parse_lookup_callsign_index_warn = 0;
7891  }
7892  return;
7893  }
7894 
7895  // stuff it
7896  strcpy(out, Mission_callsigns[index]);
7897 }
7898 
7900 {
7901  // sanity
7902  if(name == NULL)
7903  return -1;
7904 
7905  // maybe add
7907  {
7908  // stuff the name
7910 
7911  // done
7912  return Mission_callsign_count - 1;
7913  }
7914 
7915  return -1;
7916 }
7917 
7919 {
7920  // sanity
7921  if(name == NULL)
7922  return;
7923 
7924  // maybe remove
7925  for (int i = 0; i < Mission_callsign_count; ++i)
7926  {
7927  if (!strcmp(Mission_callsigns[i], name))
7928  {
7929  // remove this callsign by overwriting it with the last callsign
7930  if (i < Mission_callsign_count - 1)
7931  strcpy_s(Mission_callsigns[i], Mission_callsigns[Mission_callsign_count - 1]);
7932 
7933  Mission_callsign_count--;
7934  break;
7935  }
7936  }
7937 }
7938 
7940 {
7942 }
7943 
7945 {
7946  return (The_mission.game_type & MISSION_TYPE_TRAINING);
7947 }
7948 
7952 void conv_fix_punctuation_section(char *str, char *section_start, char *section_end, char *text_start, char *text_end)
7953 {
7954  char *s1, *s2, *t1, *t2;
7955 
7956  s1 = strstr(str, section_start);
7957  s2 = strstr(s1, section_end);
7958 
7959  t1 = s1;
7960 
7961  while (1)
7962  {
7963  t1 = strstr(t1+1, text_start);
7964  if (!t1 || t1 > s2) return;
7965 
7966  t2 = strstr(t1, text_end);
7967  if (!t2 || t2 > s2) return;
7968 
7969  replace_all(t1, "\"", "$quote", MISSION_TEXT_SIZE - (str - Mission_text), (t2 - t1));
7970  }
7971 }
7972 
7973 // Goober5000
7975 {
7976  // command briefings
7977  conv_fix_punctuation_section(Mission_text, "#Command Briefing", "#Briefing", "$Stage Text:", "$end_multi_text");
7978 
7979  // briefings
7980  conv_fix_punctuation_section(Mission_text, "#Briefing", "#Debriefing_info", "$multi_text", "$end_multi_text");
7981 
7982  // debriefings
7983  conv_fix_punctuation_section(Mission_text, "#Debriefing_info", "#Players", "$Multi text", "$end_multi_text");
7984 
7985  // messages
7986  conv_fix_punctuation_section(Mission_text, "#Messages", "#Reinforcements", "$Message:", "\n");
7987 }
7988 
7989 // Goober5000
7991 {
7992  // fix punctuation
7994 }
7995 
7997 {
7998  Fred_texture_replacements.clear();
7999 }
#define SF2_TOGGLE_SUBSYSTEM_SCANNING
Definition: ship.h:490
#define SF2_WEAPONS_LOCKED
Definition: ship.h:507
#define MAX_CALLSIGNS
Definition: missionparse.h:256
SCP_string sexp
Definition: sexp.cpp:25556
field_type_t field_type
Definition: asteroid.h:136
int filelength(int fd)
#define P2_SF2_SCRAMBLE_MESSAGES
Definition: missionparse.h:510
int Neb2_poof_flags
Definition: neb.cpp:64
GLuint64EXT * result
Definition: Glext.h:10775
char * Mission_text
Definition: parselo.cpp:46
#define OF_INVULNERABLE
Definition: object.h:107
void reset_arrival_to_false(p_object *pobjp, bool reset_wing)
void advance_to_eoln(char *more_terminators)
Definition: parselo.cpp:335
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
matrix skybox_orientation
Definition: missionparse.h:148
int alt_type_index
Definition: missionparse.h:422
char Parse_names[MAX_SHIPS+MAX_WINGS][NAME_LENGTH]
#define MULTI_NOT_TEAM
Definition: multi.h:660
#define P_SF_WARP_BROKEN
Definition: missionparse.h:479
char Starting_wing_names[MAX_STARTING_WINGS][NAME_LENGTH]
Definition: ship.cpp:139
void dock_free_dock_list(object *objp)
Definition: objectdock.cpp:725
#define AIDO_DOCK_NOW
Definition: ai.h:82
char misc[NAME_LENGTH]
Definition: missionparse.h:382
#define SHIP_GET_UNSILENCED
Definition: ship.h:1789
int flags
Definition: ship.h:150
void parse_music(mission *pm, int flags)
#define WEAPON_LIST_TYPE
Definition: parselo.h:51
#define ARRIVAL_TIMESTAMP
int timestamp(int delta_ms)
Definition: timer.cpp:226
char Neb2_texture_name[MAX_FILENAME_LEN]
Definition: neb.cpp:75
void parse_object_set_handled_flag_helper(p_object *pobjp, p_dock_function_info *infop)
int mission_is_support_ship_arriving()
wing Wings[MAX_WINGS]
Definition: ship.cpp:128
#define FS_MISSION_FILE_EXT
Definition: missionparse.h:25
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
#define ICON_CRUISER
int ship_info_lookup(const char *token)
Definition: ship.cpp:12772
#define CFILE_NORMAL
Definition: cfile.h:89
void wing_bash_ship_name(char *ship_name, const char *wing_name, int index)
Definition: ship.cpp:12686
int secondary_ammo[MAX_SHIP_SECONDARY_BANKS]
Definition: missionparse.h:318
void obj_set_flags(object *obj, uint new_flags)
Definition: object.cpp:1000
int i
Definition: multi_pxo.cpp:466
float get_max_shield_quad(object *objp)
Definition: object.cpp:260
char wing_status_wing_pos
Definition: ship.h:553
#define vm_free(ptr)
Definition: pstypes.h:548
int Nebula_heading
Definition: nebula.cpp:40
int wave_delay_min
Definition: ship.h:1552
uint num_respawns
Definition: missionparse.h:141
int n_textures
Definition: model.h:761
int mission_parse_add_callsign(const char *name)
float p
Definition: pstypes.h:111
int model_find_bay_path(int modelnum, char *bay_path_name)
Definition: modelread.cpp:5142
#define SF2_CLOAKED
Definition: ship.h:504
void mission_parse_close()
int stuff_string_list(SCP_vector< SCP_string > &slp)
Definition: parselo.cpp:2689
SCP_vector< starfield_list_entry > suns
Definition: starfield.h:40
model_subsystem * system_info
Definition: ship.h:314
#define Verify(x)
Definition: pstypes.h:272
vec3d Parse_viewer_pos
char weaponry_pool_variable[MAX_WEAPON_TYPES][TOKEN_LENGTH]
Definition: missionparse.h:542
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:103
char name[NAME_LENGTH]
Definition: missionparse.h:346
void post_process_mission()
int persona_index
Definition: missionparse.h:398
int Total_goal_target_names
Definition: ai.cpp:21
int escort_priority
Definition: missionparse.h:389
#define BI_HIGHLIGHT
#define MAX_SHIP_PRIMARY_BANKS
Definition: globals.h:62
void parse_custom_bitmap(const char *expected_string_640, const char *expected_string_1024, char *string_field_640, char *string_field_1024)
char weapon_select_background[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN]
int Locked_sexp_false
Definition: sexp.cpp:828
bool weapon_required[MAX_WEAPON_TYPES]
Definition: missionparse.h:544
EModelAnimationPosition turret_animation_position
Definition: ship.h:351
int respawn_priority
Definition: missionparse.h:420
ai_info * Player_ai
Definition: ai.cpp:24
#define P2_SF2_AFFECTED_BY_GRAVITY
Definition: missionparse.h:491
int ai_abort_rearm_request(object *requester_objp)
Definition: aicode.cpp:15338
int team
Definition: ship.h:606
int Cmdline_old_collision_sys
Definition: cmdline.cpp:489
#define WF_IGNORE_COUNT
Definition: ship.h:1503
control_info ci
Definition: player.h:126
#define DEPART_AT_LOCATION
Definition: missionparse.h:245
char Mission_callsigns[MAX_CALLSIGNS][NAME_LENGTH]
int Num_mission_events
int num_uses
Definition: ship.h:86
#define P2_SF2_NO_BUILTIN_MESSAGES
Definition: missionparse.h:494
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:1299
#define ICON_LARGESHIP_WING
void player_set_squad_bitmap(player *p, char *fname, bool ismulti)
#define SUBSYS_STATUS_NO_CHANGE
Definition: missionparse.h:310
void mission_parse_support_arrived(int objnum)
char name[NAME_LENGTH]
Definition: weapon.h:322
int ai_class
Definition: ship.h:148
int Mission_arrival_timestamp
void multi_respawn_build_points()
char text[TOKEN_LENGTH]
Definition: sexp.h:1044
void mission_log_add_entry(int type, char *pname, char *sname, int info_index)
Definition: missionlog.cpp:184
#define ICON_SUPERCAP
int num_primary_banks
Definition: ship.h:99
int check_for_string(const char *pstr)
Definition: parselo.cpp:517
#define SF_CANNOT_WARP
Definition: ship.h:476
int arrival_anchor
Definition: ship.h:1541
int objnum
Definition: ship.h:537
#define MPF_ONLY_MISSION_INFO
Definition: missionparse.h:50
#define P_OF_BEAM_PROTECTED
Definition: missionparse.h:464
int score
Definition: ship.h:542
int warpin_type
Definition: ship.h:1213
int pos_in_wing
Definition: missionparse.h:385
int Game_mode
Definition: systemvars.cpp:24
#define AIG_TYPE_EVENT_WING
Definition: ai.h:98
int wave_delay_max
Definition: ship.h:1553
int arrival_distance
Definition: ship.h:1540
#define LOGFILE_EVENT_LOG
Definition: generic_log.h:19
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
vec3d mins
Definition: model.h:746
#define OLD_GAME_TYPE_SINGLE_MULTI
Definition: missionparse.h:57
int game_type
Definition: missionparse.h:138
int Player_start_shipnum
#define OF_LASER_PROTECTED
Definition: object.h:120
#define MISSION_FLAG_FULLNEB
Definition: missionparse.h:70
char briefing_music_name[NAME_LENGTH]
Definition: missionparse.h:163
int alt_type_index
Definition: ship.h:556
int mission_parse_lookup_callsign(const char *name)
int arrival_location
Definition: ship.h:1539
#define ARRIVE_NEAR_SHIP
Definition: missionparse.h:238
float frand_range(float min, float max)
Return a floating point number in the range min..max.
Definition: floating.cpp:50
int div_y
Definition: starfield.h:33
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
#define P_OF_INVULNERABLE
Definition: missionparse.h:458
weapon_info Weapon_info[MAX_WEAPON_TYPES]
Definition: weapons.cpp:79
void parse_bitmaps(mission *pm)
void nebula_init(const char *filename, int pitch, int bank, int heading)
Definition: nebula.cpp:133
ship_weapon weapons
Definition: ship.h:658
int support_available_for_species
Definition: missionparse.h:112
SCP_string recommendation_text
int get_anchor(char *name)
void dock_dock_docked_objects(p_object *objp)
void send_reinforcement_avail(int rnum)
Definition: multimsgs.cpp:7458
net_player * Net_player
Definition: multi.cpp:94
char ship_name[NAME_LENGTH]
Definition: missionparse.h:324
int Total_initially_docked
void brief_reset()
#define MISSION_FLAG_SCRAMBLE
Definition: missionparse.h:85
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
void nebula_close()
Definition: nebula.cpp:42
int ai_class
Definition: missionparse.h:390
#define SF2_NO_DISABLED_SELF_DESTRUCT
Definition: ship.h:511
background_t Backgrounds[MAX_BACKGROUNDS]
Definition: starfield.cpp:125
#define P_SF_NO_ARRIVAL_MUSIC
Definition: missionparse.h:454
submodel_instance_info submodel_info_1
Definition: ship.h:368
int ambient_light_level
Definition: missionparse.h:152
void waypoint_add_list(const char *name, SCP_vector< vec3d > &vec_list)
Definition: waypoint.cpp:374
void mission_parse_remove_alt(const char *name)
#define SEXP_ERROR_CHECK_MODE
Definition: parselo.h:64
int escort_priority
Definition: ship.h:541
char name[NAME_LENGTH]
Definition: missionparse.h:131
void send_ship_create_packet(object *objp, int is_support)
Definition: multimsgs.cpp:2648
char name[NAME_LENGTH]
GLsizei const GLfloat * value
Definition: Glext.h:5646
bool is_ship_assignable(p_object *p_objp)
#define SF2_NO_SUBSPACE_DRIVE
Definition: ship.h:487
#define SF_IGNORE_COUNT
Definition: ship.h:436
void mission_parse_lookup_callsign_index(int index, char *out)
char ** Ai_class_names
Definition: aicode.cpp:268
vec3d desired_vel
Definition: physics.h:70
#define AIM_SAFETY
Definition: ai.h:179
GLuint index
Definition: Glext.h:5608
void parse_common_object_data(p_object *objp)
char ui_name[NAME_LENGTH]
Definition: fictionviewer.h:23
int Num_status_names
char wing_status_wing_index
Definition: ship.h:552
#define P_SF_ESCORT
Definition: missionparse.h:452
void waypoint_parse_init()
Definition: waypoint.cpp:101
physics_info phys_info
Definition: object.h:157
int Fred_running
Definition: fred.cpp:44
#define P2_SF2_NAV_CARRY_STATUS
Definition: missionparse.h:490
int mission_do_departure(object *objp, bool goal_is_to_warp)
#define MAX_WINGS
Definition: globals.h:50
void mission_set_wing_arrival_location(wing *wingp, int num_to_set)
LOCAL struct @256 Initially_docked[MAX_SHIPS]
SCP_vector< p_object > Parse_objects
#define MAX_SHIPS
Definition: globals.h:37
void message_parse(bool importing_from_fsm)
#define P_SF_LOCKED
Definition: missionparse.h:457
void parse_waypoints_and_jumpnodes(mission *pm)
int flags
Definition: ship.h:88
#define MULTI_SIG_SHIP
Definition: multiutil.h:32
void swap_parse_object(p_object *p_obj, int new_ship_class)
int parse_mission(mission *pm, int flags)
#define WT_HYPERSPACE
Definition: ship.h:1111
SCP_vector< texture_replace > replacement_textures
Definition: missionparse.h:431
int replace_all(char *str, char *oldstr, char *newstr, uint max_len, int range)
Definition: parselo.cpp:3941
#define LOG_SHIP_ARRIVED
Definition: missionlog.h:22
#define WF_WING_GONE
Definition: ship.h:1501
#define MIN_SUBSYS_STATUS_SIZE
void mission_maybe_make_ship_arrive(p_object *p_objp)
int departure_anchor
Definition: ship.h:618
int model_num
Definition: ship.h:1189
float ship_max_shield_strength
Definition: ship.h:596
#define DEFAULT_NMODEL_FLAGS
Definition: starfield.h:20
brief_stage stages[MAX_BRIEF_STAGES]
void process_loadout_objects()
char * Neb2_filenames[NUM_NEBULAS]
#define SF2_FORCE_SHIELDS_ON
Definition: ship.h:502
int arrival_location
Definition: ship.h:610
int special_exp_damage
Definition: missionparse.h:402
int ship_iff_color[MAX_IFFS][MAX_IFFS]
Definition: ship.h:793
int special_exp_inner
Definition: missionparse.h:404
void fiction_viewer_load(int stage)
float max_hits
Definition: ship.h:320
#define SF_DOCK_LEADER
Definition: ship.h:455
char Player_start_shipname[NAME_LENGTH]
p_object * next
Definition: missionparse.h:347
#define ICON_SUPPORT_SHIP
void mission_parse_lookup_alt_index(int index, char *out)
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
char background[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN]
Definition: fictionviewer.h:24
int special_exp_blast
Definition: ship.h:586
int submode
Definition: ai.h:394
void parse_messages(mission *pm, int flags)
#define P2_OF_TARGETABLE_AS_BOMB
Definition: missionparse.h:493
#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
#define P2_SF2_NO_ETS
Definition: missionparse.h:506
int detail[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:738
void multi_ping_send_all()
Definition: multi_ping.cpp:114
int departure_location
Definition: ship.h:617
Definition: pstypes.h:88
int callsign_index
Definition: missionparse.h:423
#define mprintf(args)
Definition: pstypes.h:238
int departure_anchor
Definition: ship.h:1547
int ai_index
Definition: ship.h:538
ship_weapon weapons
Definition: ship.h:362
ushort net_signature
Definition: object.h:163
fix Mission_end_time
SCP_vector< fiction_viewer_stage > Fiction_viewer_stages
int special_exp_inner
Definition: ship.h:587
#define P2_SF2_SECONDARIES_LOCKED
Definition: missionparse.h:496
int is_training_mission()
int total_vanished
Definition: ship.h:1535
#define MESSAGE_ARRIVE_ENEMY
#define ARRIVAL_MESSAGE_MIN_SEPARATION
void parse_event(mission *pm)
int departure_path_mask
Definition: missionparse.h:378
int secondary_banks[MAX_SHIP_SECONDARY_BANKS]
Definition: missionparse.h:317
int subsystem_stricmp(const char *str1, const char *str2)
Definition: parselo.cpp:3648
int ai_class
Definition: ai.h:369
void parse_briefing(mission *pm, int flags)
void hud_wingman_status_set_index(wing *wingp, ship *shipp, p_object *pobjp)
char story_filename[MAX_FILENAME_LEN]
Definition: fictionviewer.h:19
void player_set_squad(player *p, char *squad_name)
char * CTEXT(int n)
Definition: sexp.cpp:28821
#define P_SF2_STEALTH
Definition: missionparse.h:471
#define MAX_PATH_RESTRICTIONS
Definition: missionparse.h:261
void multi_maybe_send_repair_info(object *dest_objp, object *source_objp, int code)
Definition: multiutil.cpp:1551
char wing_squad_filename[MAX_FILENAME_LEN]
Definition: ship.h:1518
int Num_parse_names
#define WF_RESET_REINFORCEMENT
Definition: ship.h:1505
#define WARP_IN_TIME_MIN
void event_music_arrival(int team)
Definition: eventmusic.cpp:955
void parse_reinforcements(mission *pm)
int loadout_total
Definition: missionparse.h:532
void mission_parse_set_arrival_locations()
struct vec3d::@225::@227 xyz
#define P_AIF_NO_DYNAMIC
Definition: missionparse.h:462
int Loading_screen_bm_index
CButton * team
void static_randvec(int num, vec3d *vp)
[To be described]
Definition: staticrand.cpp:111
int mission_parse_add_alt(const char *name)
void parse_plot_info(mission *pm)
#define ARRIVAL_MUSIC_MIN_SEPARATION
int skybox_flags
Definition: missionparse.h:150
int Nebula_index
#define SF2_DONT_COLLIDE_INVIS
Definition: ship.h:486
GLclampf f
Definition: Glext.h:7097
#define LOG_SHIP_DEPARTED
Definition: missionlog.h:24
object * dock_find_object_at_dockpoint(object *objp, int dockpoint)
Definition: objectdock.cpp:106
void parse_waypoint_list(mission *pm)
#define MAX_OBJECTS
Definition: globals.h:83
int find_wing_name(char *name)
#define ICON_TRANSPORT
void fix_old_special_hits(p_object *p_objp, int variable_index)
void fiction_viewer_reset()
int target[MAX_OBJECT_STATUS]
Definition: missionparse.h:361
#define WF_NO_ARRIVAL_MUSIC
Definition: ship.h:1506
#define MISSION_TYPE_MULTI
Definition: missionparse.h:62
#define OF_NO_SHIELDS
Definition: object.h:110
#define SF2_FRIENDLY_STEALTH_INVIS
Definition: ship.h:484
int special_exp_outer
Definition: ship.h:588
int is_sexp_top_level(int node)
Definition: sexp.cpp:1515
#define SF2_AFFECTED_BY_GRAVITY
Definition: ship.h:489
int Num_cargo
void mission_parse_eval_stuff()
#define MAX_PARSE_OBJECT_FLAGS
Definition: missionparse.h:445
Definition: cfile.h:28
bool dock_check_find_direct_docked_object(object *objp, object *other_objp)
Definition: objectdock.cpp:91
int max_respawn_delay
Definition: missionparse.h:142
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
subsys_status * parse_get_subsys_status(p_object *pobjp, char *subsys_name)
#define WF_NO_DYNAMIC
Definition: ship.h:1511
#define P2_SF2_NO_SUBSPACE_DRIVE
Definition: missionparse.h:489
char background[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN]
#define Assertion(expr, msg,...)
Definition: clang.h:41
void parse_one_background(background_t *background)
int message_persona_name_lookup(char *name)
int Num_unknown_loadout_classes
float assist_score_pct
Definition: missionparse.h:393
int dock_find_dockpoint_used_by_object(object *objp, object *other_objp)
Definition: objectdock.cpp:116
SCP_string team_color_setting
Definition: missionparse.h:356
#define SF2_NAVPOINT_CARRY
Definition: ship.h:488
object obj_used_list
Definition: object.cpp:53
#define P_OF_NO_SHIELDS
Definition: missionparse.h:451
#define OF_SPECIAL_WARPIN
Definition: object.h:116
#define SF2_SET_CLASS_DYNAMICALLY
Definition: ship.h:500
int primary_ammo[MAX_SHIP_PRIMARY_BANKS]
Definition: missionparse.h:316
char ani_filename[MAX_FILENAME_LEN]
char voice_filename[MAX_FILENAME_LEN]
Definition: fictionviewer.h:21
model_subsystem * subsystems
Definition: ship.h:1271
#define SCORE_FICTION_VIEWER
Definition: eventmusic.h:55
int ship_class
Definition: missionparse.h:351
fix t2
Definition: animplay.cpp:37
Definition: ship.h:1516
void init_ai_object(int objnum)
Definition: aicode.cpp:14300
int current_primary_bank
Definition: ship.h:106
int kamikaze_damage
Definition: missionparse.h:399
int ds_eax_get_preset_id(const char *name)
Definition: ds.cpp:2376
ship_subsys * targeted_subsys
Definition: ai.h:472
const int RAND_MAX_2
Definition: pstypes.h:308
int Knossos_warp_ani_used
Definition: fireballs.cpp:33
ushort Last_file_checksum
int status_count
Definition: missionparse.h:358
#define P2_RED_ALERT_DELETED
Definition: missionparse.h:517
int ship_find_exited_ship_by_name(char *name)
Definition: ship.cpp:5338
int n_quadrants
Definition: object.h:158
sexp_variable Sexp_variables[MAX_SEXP_VARIABLES]
Definition: sexp.cpp:846
bool default_to_this_class
Definition: missionparse.h:335
int wing_insignia_texture
Definition: ship.h:1566
int parse_create_object_sub(p_object *objp)
bool ship_fighterbays_all_destroyed(ship *shipp)
Definition: ship.cpp:17494
#define DAMAGE
Definition: sexp.h:893
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
#define SIF2_INTRINSIC_NO_SHIELDS
Definition: ship.h:927
void parse_debriefing_new(mission *pm)
#define OF_COLLIDES
Definition: object.h:104
#define P2_SF2_NO_DISABLED_SELF_DESTRUCT
Definition: missionparse.h:512
void parse_goal(mission *pm)
#define F_MULTITEXTOLD
Definition: parselo.h:38
#define P2_SF2_WEAPONS_LOCKED
Definition: missionparse.h:509
Definition: ai.h:329
#define AIM_NONE
Definition: ai.h:175
#define MAX_STAGE_ICONS
uint flags
Definition: ship.h:644
#define SCORE_BRIEFING
Definition: eventmusic.h:51
#define MAX_SHIP_BAY_PATHS
Definition: model.h:538
int turret_next_fire_stamp
Definition: ship.h:336
int primary_bank_weapons[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:1294
#define MAX_MISSION_EVENT_LOG_FLAGS
Definition: missiongoals.h:87
void ai_clear_ship_goals(ai_info *aip)
Definition: aigoals.cpp:251
path_restriction_t Path_restrictions[MAX_PATH_RESTRICTIONS]
#define MAX_SHIPS_PER_WING
Definition: globals.h:52
char dockee_point[NAME_LENGTH]
hull_check orient
Definition: lua.cpp:5049
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
void obj_merge_created_list(void)
Definition: object.cpp:651
void parse_events(mission *pm)
#define P_SF2_FRIENDLY_STEALTH_INVIS
Definition: missionparse.h:472
object * objp
Definition: lua.cpp:3105
void stuff_matrix(matrix *mp)
Definition: parselo.cpp:3174
int ship_navigation_ok_to_warp(ship *sp)
Definition: ship.cpp:14809
int primary_bank_capacity[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:123
cmd_brief Cmd_briefs[MAX_TVT_TEAMS]
ubyte ships_allowed[MAX_SHIP_CLASSES]
int type
Definition: ship.h:84
#define AIG_TYPE_EVENT_SHIP
Definition: ai.h:97
#define P2_SF2_NO_DEATH_SCREAM
Definition: missionparse.h:497
vec3d inner_min_bound
Definition: asteroid.h:131
int current_secondary_bank
Definition: ship.h:107
GLfloat GLfloat GLfloat v2
Definition: Glext.h:5640
int Current_file_length
#define Int3()
Definition: pstypes.h:292
#define CMD_BRIEF_STAGES_MAX
int get_index_sexp_variable_name(const char *text)
Definition: sexp.cpp:29324
int arrival_anchor
Definition: missionparse.h:371
SOUNDTRACK_INFO Soundtracks[MAX_SOUNDTRACKS]
Definition: eventmusic.cpp:57
ushort net_signature
Definition: missionparse.h:413
void convert_sexp_to_string(SCP_string &dest, int cur_node, int mode)
Definition: sexp.cpp:3904
briefing Briefings[MAX_TVT_TEAMS]
int stuff_sexp_variable_list()
Definition: sexp.cpp:3590
vec3d min_bound
Definition: asteroid.h:127
#define AIF_KAMIKAZE
Definition: ai.h:55
void mission_parse_mark_non_arrival(p_object *p_objp)
int special_exp_shockwave_speed
Definition: missionparse.h:407
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
#define MAX_SQUADRON_WINGS
Definition: globals.h:55
#define MAX_DEBRIS_PIECES
Definition: debris.h:57
#define AI_GOAL_NONE
Definition: ai.h:194
int get_sexp_main()
Definition: sexp.cpp:25494
ship * shipp
Definition: lua.cpp:9162
int special_warpin_objnum
Definition: ship.h:740
int arrival_delay
Definition: ship.h:1544
vec3d pos
Definition: object.h:152
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
ship_subsys_info subsys_info[SUBSYSTEM_MAX]
Definition: ship.h:632
#define MAX_REINFORCEMENT_MESSAGES
Definition: ship.h:78
int match_and_stuff(int f_type, char *strlist[], int max, char *description)
Definition: parselo.cpp:3243
#define MAX_TVT_WINGS
Definition: globals.h:59
vec3d max_bound
Definition: asteroid.h:128
int get_max_sparks(object *ship_objp)
Definition: shiphit.cpp:1054
mission_goal Mission_goals[MAX_GOALS]
SCP_vector< message_extra > Message_waves
int ai_flags
Definition: ai.h:330
#define CONTRAIL_THRESHOLD_DEFAULT
Definition: missionparse.h:226
float volume
Definition: sound.h:93
script_state Script_system("FS2_Open Scripting")
#define TM_NUM_TYPES
Definition: model.h:663
int Game_restoring
Definition: systemvars.cpp:26
#define OLD_GAME_TYPE_SINGLE_ONLY
Definition: missionparse.h:55
#define LOG_WING_ARRIVED
Definition: missionlog.h:23
int allocate_subsys_status()
int hotkey
Definition: ship.h:1520
#define SPECIAL_ARRIVAL_ANCHOR_FLAG
Definition: missionparse.h:37
#define ICON_JUMP_NODE
int div_x
Definition: starfield.h:33
SCP_list< CJumpNode > Jump_nodes
Definition: jumpnode.cpp:16
GLenum type
Definition: Gl.h:1492
void stuff_float(float *f)
Definition: parselo.cpp:2328
void fix_old_special_explosions(p_object *p_objp, int variable_index)
#define MISSION_TYPE_MULTI_COOP
Definition: missionparse.h:64
#define BI_USE_WING_ICON
#define SHIP_GUARDIAN_THRESHOLD_DEFAULT
Definition: ship.h:47
int arrival_delay
Definition: missionparse.h:374
#define EMF_VALID
Definition: eventmusic.h:89
void parse_init(bool basic=false)
#define BI_MIRROR_ICON
#define SHIP_GET_ONLY_PLAYERS
Definition: ship.h:1788
void event_music_set_score(int score_index, char *name)
#define SHIP_SIG_MAX
Definition: multi.h:736
int hotkey
Definition: ship.h:540
iff_info Iff_info[MAX_IFFS]
Definition: iff_defs.cpp:20
int Num_backgrounds
Definition: starfield.cpp:123
int ship_count[MAX_SHIP_CLASSES]
Definition: missionparse.h:535
#define WT_IN_PLACE_ANIM
Definition: ship.h:1109
#define MSS_FLAG_TURRET_LOCKED
Definition: model.h:134
#define MAX_WING_FLAGS
Definition: ship.h:1500
#define SF2_SCRAMBLE_MESSAGES
Definition: ship.h:509
char * Reinforcement_type_names[]
reinforcements Reinforcements[MAX_REINFORCEMENTS]
Definition: ship.cpp:165
void game_busy(const char *filename=NULL)
Definition: systemvars.cpp:173
#define P_SF_HIDDEN_FROM_SENSORS
Definition: missionparse.h:459
fix Entry_delay_time
const int MAX_STARS
Definition: starfield.cpp:47
int Num_ai_behaviors
int Num_unknown_weapon_classes
int num_initial_asteroids
Definition: asteroid.h:135
float Neb2_awacs
Definition: neb.cpp:156
void parse_player_info(mission *pm)
int ship_can_use_warp_drive(ship *shipp)
#define CDR(n)
Definition: sexp.h:821
int arrival_path_mask
Definition: missionparse.h:372
int objnum
Definition: ship.h:1483
#define OF_TARGETABLE_AS_BOMB
Definition: object.h:118
int Squadron_wings[MAX_SQUADRON_WINGS]
Definition: ship.cpp:135
ship_subsys subsys_list
Definition: ship.h:630
void mission_parse_mark_reinforcement_available(char *name)
int query_operator_return_type(int op)
Definition: sexp.cpp:25589
int mission_did_ship_arrive(p_object *objp)
int arrival_path_mask
Definition: ship.h:1542
#define F_NOTES
Definition: parselo.h:36
sound_env sound_environment
Definition: missionparse.h:155
#define SCORE_DEBRIEF_FAIL
Definition: eventmusic.h:54
int object_is_docked(object *objp)
Definition: object.cpp:2019
char name[NAME_LENGTH]
Definition: missionparse.h:313
#define P_SF_DOCK_LEADER
Definition: missionparse.h:477
#define INVALID_GOAL
Definition: missiongoals.h:33
int mission_remove_scheduled_repair(object *objp)
int Sexp_clipboard
Definition: sexp.cpp:831
float scale_x
Definition: starfield.h:32
brief_icon * icons
int Num_music_files
Definition: eventmusic.cpp:250
int orders_accepted
Definition: ship.h:624
int Locked_sexp_true
Definition: sexp.cpp:828
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
int mission_parse_lookup_alt(const char *name)
int instance
Definition: object.h:150
#define SHOCK_SPEED
Definition: sexp.h:896
char * Parse_object_flags[MAX_PARSE_OBJECT_FLAGS]
#define SCORE_DEBRIEF_AVERAGE
Definition: eventmusic.h:53
#define AIPF_FIX_AI_CLASS_BUG
Definition: ai_profiles.h:51
#define DEPART_AT_DOCK_BAY
Definition: missionparse.h:246
int destroy_before_mission_time
Definition: missionparse.h:414
int Num_stars
Definition: starfield.cpp:58
angles ang
Definition: starfield.h:34
matrix * vm_vector_2_matrix(matrix *m, const vec3d *fvec, const vec3d *uvec, const vec3d *rvec)
Definition: vecmat.cpp:850
GLintptr offset
Definition: Glext.h:5497
int Num_path_restrictions
char ship_select_background[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN]
#define MISSION_TYPE_SINGLE
Definition: missionparse.h:61
Definition: debris.h:23
p_object * mission_parse_get_arrival_ship(const char *name)
Returns the parse object on the ship arrival list associated with the given name. ...
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
char pof_file[MAX_FILENAME_LEN]
Definition: ship.h:1183
char squad_filename[MAX_FILENAME_LEN]
Definition: missionparse.h:144
#define MAX_BUILTIN_MESSAGE_TYPES
char voice[MAX_FILENAME_LEN]
#define OF_IMMOBILE
Definition: object.h:122
int mission_set_arrival_location(int anchor, int location, int distance, int objnum, int path_mask, vec3d *new_pos, matrix *new_orient)
void mission_parse_fixup_players()
void mission_parse_reset_alt()
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
char * Cargo_names[MAX_CARGO]
char * Departure_location_names[MAX_DEPARTURE_NAMES]
#define MAX_OBJECT_STATUS
Definition: missionparse.h:338
#define MAX_DEPARTURE_NAMES
Definition: missionparse.h:244
int group
Definition: ship.h:674
int Num_sexp_nodes
Definition: sexp.cpp:843
void SetModel(char *model_name, bool show_polys=false)
Definition: jumpnode.cpp:190
int flags
Definition: ship.h:322
debris_genre_t
Definition: asteroid.h:115
void parse_reinforcement(mission *pm)
float max_shield_recharge
Definition: missionparse.h:428
#define OLD_GAME_TYPE_MULTI_ONLY
Definition: missionparse.h:56
fix game_get_overall_frametime()
Definition: fredstubs.cpp:230
SCP_vector< alt_class > s_alt_classes
Definition: ship.h:791
struct matrix::@228::@230 vec
#define WF_NO_DEPARTURE_WARP
Definition: ship.h:1510
#define NETINFO_FLAG_AM_MASTER
Definition: multi.h:599
char created[DATE_TIME_LENGTH]
Definition: missionparse.h:134
void resolve_parse_flags(object *objp, int parse_flags, int parse_flags2)
int mission_log_get_time(int type, char *pname, char *sname, fix *time)
Definition: missionlog.cpp:498
#define MAX_AI_BEHAVIORS
Definition: ai.h:189
char name[NAME_LENGTH]
Definition: ship.h:83
char dockee[NAME_LENGTH]
int subtype
Definition: lua.cpp:9763
float ship_max_hull_strength
Definition: ship.h:597
GLboolean GLboolean g
Definition: Glext.h:5781
#define cfopen(...)
Definition: cfile.h:134
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
#define P_SF_RED_ALERT_STORE_STATUS
Definition: missionparse.h:463
uint flags
Definition: model.h:169
#define F_DATE
Definition: parselo.h:35
#define P_OF_FLAK_PROTECTED
Definition: missionparse.h:465
#define nprintf(args)
Definition: pstypes.h:239
int mission_parse_is_multi(const char *filename, char *mission_name)
#define MAX_BACKGROUNDS
Definition: starfield.h:43
#define GM_MULTIPLAYER
Definition: systemvars.h:18
#define P_SF_WARP_NEVER
Definition: missionparse.h:480
float cargo_size
Definition: weapon.h:388
#define ARRIVAL_MESSAGE_DELAY_MIN
float version
Definition: missionparse.h:133
int primary_bank_ammo[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:121
ubyte weapons_allowed[MAX_WEAPON_TYPES]
#define MAX_GOALS
Definition: missiongoals.h:23
#define SW_FLAG_TURRET_LOCK
Definition: ship.h:95
int * ship_replacement_textures
Definition: ship.h:751
char name[NAME_LENGTH]
Definition: ship.h:1517
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
#define MAX_SHIP_CLASSES
Definition: globals.h:48
void mission_hotkey_reset_saved()
char Mission_alt_types[MAX_ALT_TYPE_NAMES][NAME_LENGTH]
int secondary_bank_capacity[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:136
void parse_fiction(mission *pm)
void parse_create_docked_object_helper(p_object *pobjp, p_dock_function_info *infop)
#define SF2_NO_DEATH_SCREAM
Definition: ship.h:495
int ship_subsys_disrupted(ship_subsys *ss)
Definition: ship.cpp:9033
char * Nebula_filenames[NUM_NEBULAS]
ai_profile_t * ai_profile
Definition: missionparse.h:168
#define MISSION_FLAG_RED_ALERT
Definition: missionparse.h:84
#define SEXP_VARIABLE_BLOCK
Definition: sexp.h:878
int departure_anchor
Definition: missionparse.h:377
char * filename
int wingnum
Definition: ship.h:623
#define strnicmp(s1, s2, n)
Definition: config.h:272
void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type)
Definition: aicode.cpp:3098
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
#define DEFAULT_COMMAND
#define MAX_STARTING_WINGS
Definition: globals.h:54
int num_secondary_banks
Definition: ship.h:100
ai_goal goals[MAX_AI_GOALS]
Definition: ai.h:412
#define BLAST
Definition: sexp.h:894
int mode
Definition: ai.h:336
mission_event Mission_events[MAX_MISSION_EVENTS]
texture_map maps[MAX_MODEL_TEXTURES]
Definition: model.h:762
Persona * Personas
#define SF2_HIDE_SHIP_NAME
Definition: ship.h:498
void parse_variables()
int departure_cue
Definition: ship.h:1549
#define P_OF_LASER_PROTECTED
Definition: missionparse.h:466
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
int Mission_callsign_count
char * stristr(char *str, const char *substr)
Definition: parselo.cpp:3729
#define MAX_WEAPON_TYPES
Definition: globals.h:73
int num_weapon_choices
Definition: missionparse.h:539
int FindTexture(int bm_handle)
float hull_strength
Definition: object.h:160
ai_profile_t Ai_profiles[MAX_AI_PROFILES]
Definition: ai_profiles.cpp:22
int persona_index
Definition: ship.h:696
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
#define MISSION_FLAG_BEAM_FREE_ALL_BY_DEFAULT
Definition: missionparse.h:75
#define P_SF_SCANNABLE
Definition: missionparse.h:460
char * Mission_event_log_flags[MAX_MISSION_EVENT_LOG_FLAGS]
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
GLint location
Definition: Glext.h:5627
char * Goal_type_names[MAX_GOAL_TYPE_NAMES]
void vm_set_identity(matrix *m)
Definition: vecmat.cpp:150
int ai_mode
Definition: ai.h:136
float ship_max_hull_strength
Definition: missionparse.h:425
#define MISSION_CHECKSUM_SIZE
void event_music_reset_choices()
#define MAX_CARGO
Definition: missionparse.h:222
void debris_clear_expired_flag(debris *db)
Definition: debris.cpp:208
#define WF_NO_ARRIVAL_WARP
Definition: ship.h:1509
int weaponry_pool[MAX_WEAPON_TYPES]
Definition: missionparse.h:540
#define MAX_AI_GOALS
Definition: ai.h:91
void ship_assign_sound(ship *sp)
Definition: ship.cpp:14191
GLdouble GLdouble z
Definition: Glext.h:5451
int flags
Definition: debris.h:25
float lifeleft
Definition: debris.h:32
#define P_OF_MISSILE_PROTECTED
Definition: missionparse.h:467
void parse_player_info2(mission *pm)
#define P2_SF2_LOCK_ALL_TURRETS_INITIALLY
Definition: missionparse.h:502
#define SF_HIDDEN_FROM_SENSORS
Definition: ship.h:464
int n_subsystems
Definition: ship.h:1270
void mission_parse_mark_non_arrivals()
#define OF_PROTECTED
Definition: object.h:108
#define RF_IS_AVAILABLE
Definition: ship.h:80
#define SUBSYSTEM_TURRET
Definition: model.h:54
SCP_vector< alt_class > alt_classes
Definition: missionparse.h:433
char squad_name[NAME_LENGTH]
Definition: missionparse.h:145
int free_sexp2(int num)
Definition: sexp.cpp:1321
int total_departed
Definition: ship.h:1534
int iff_lookup(char *iff_name)
Definition: iff_defs.cpp:540
int special_exp_deathroll_time
Definition: ship.h:591
#define GR_640
Definition: 2d.h:652
int primary_banks[MAX_SHIP_PRIMARY_BANKS]
Definition: missionparse.h:315
#define vm_strdup(ptr)
Definition: pstypes.h:549
void ai_do_default_behavior(object *obj)
Definition: aicode.cpp:14564
#define NETINFO_FLAG_INGAME_JOIN
Definition: multi.h:604
int alt_iff_color[MAX_IFFS][MAX_IFFS]
Definition: missionparse.h:435
int priority
Definition: ai.h:141
int subsys_index
Definition: missionparse.h:363
float current_max_speed
Definition: ship.h:641
int Nebula_bank
Definition: nebula.cpp:39
#define NUM_NEBULAS
Definition: missionparse.h:30
char cargo1
Definition: ship.h:549
#define ICON_CRUISER_WING
void SetVisibility(bool enabled)
Definition: jumpnode.cpp:241
int required_string(const char *pstr)
Definition: parselo.cpp:468
#define MAX_GOAL_TYPE_NAMES
Definition: missionparse.h:248
int Num_arriving_repair_targets
int uses
Definition: ship.h:85
char notes[NOTES_LENGTH]
Definition: missionparse.h:136
int arrival_location
Definition: missionparse.h:369
#define P_SF_CANNOT_ARRIVE
Definition: missionparse.h:478
int add_path_restriction()
mission The_mission
int arrival_cue
Definition: missionparse.h:373
GLuint buffer
Definition: Glext.h:5492
float max_shield_strength
Definition: ship.h:1310
int Num_wings
Definition: ship.cpp:120
#define P2_SF2_SHIP_LOCKED
Definition: missionparse.h:508
int secondary_bank_weapons[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:104
int Num_teams
int Num_ai_classes
Definition: aicode.cpp:195
int status[MAX_OBJECT_STATUS]
Definition: missionparse.h:360
#define DEFAULT_AMBIENT_LIGHT_LEVEL
Definition: missionparse.h:33
void ai_post_process_mission()
Definition: aigoals.cpp:159
#define REPAIR_INFO_WARP_ADD
Definition: multi.h:308
void mission_parse_handle_late_arrivals(p_object *p_objp)
int optional_string(const char *pstr)
Definition: parselo.cpp:539
char skybox_model[MAX_FILENAME_LEN]
Definition: missionparse.h:147
#define P_OF_PROTECTED
Definition: missionparse.h:449
int current_count
Definition: ship.h:1530
int parse_lookup_alt_name(char *name)
float aggregate_current_hits
Definition: ship.h:419
char * Status_target_names[MAX_STATUS_NAMES]
char * Ai_behavior_names[MAX_AI_BEHAVIORS]
#define MULTI_DOGFIGHT
Definition: multi.h:656
int special_exp_outer
Definition: missionparse.h:405
int special_exp_blast
Definition: missionparse.h:403
#define MISSION_DESC_LENGTH
Definition: globals.h:28
void mission_parse_set_up_initial_docks()
int subsys_cargo_name
Definition: ship.h:373
#define MISSION_LOADOUT_SHIP_LIST
Definition: parselo.h:58
#define MONITOR(function_name)
Definition: pstypes.h:454
#define ICON_KNOSSOS_DEVICE
int callsign_index
Definition: ship.h:557
float current_hits
Definition: ship.h:319
int flags2
Definition: ship.h:1228
char * Status_desc_names[MAX_STATUS_NAMES]
void parse_objects(mission *pm, int flag)
int secondary_bank_ammo_capacity[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:1300
char path_names[MAX_SHIP_BAY_PATHS][MAX_NAME_LEN]
Definition: missionparse.h:265
int source_objnum
Definition: debris.h:26
Definition: ship.h:534
void find_and_stuff(char *id, int *addr, int f_type, char *strlist[], int max, char *description)
Definition: parselo.cpp:3207
int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, int ferror=1, int duplicate=0)
Definition: modelread.cpp:2573
int ship_get_random_ship_in_wing(int wingnum, int flags, float max_dist, int get_first)
Definition: ship.cpp:14623
char Mission_filename[80]
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
#define WF_NO_ARRIVAL_MESSAGE
Definition: ship.h:1508
#define AISS_1
Definition: ai.h:86
int ai_acquire_depart_path(object *pl_objp, int parent_objnum, int path_mask)
Definition: aicode.cpp:12883
float max_subsys_strength
Definition: model.h:180
void conv_fix_punctuation()
int get_operator_index(const char *token)
Definition: sexp.cpp:1561
char Cargo_names_buf[MAX_CARGO][NAME_LENGTH]
int initial_shields
Definition: missionparse.h:367
int total_destroyed
Definition: ship.h:1533
int stuff_loadout_list(int *ilp, int max_ints, int lookup_type)
Definition: parselo.cpp:2881
bool use_shockwave
Definition: missionparse.h:406
#define ARRIVE_IN_FRONT_OF_SHIP
Definition: missionparse.h:239
void wing_load_squad_bitmap(wing *w)
Definition: ship.cpp:17406
int default_ship
Definition: missionparse.h:530
char wing_status_wing_index
Definition: missionparse.h:416
cmd_brief_stage stage[CMD_BRIEF_STAGES_MAX]
#define MESSAGE_PRIORITY_LOW
int idx
Definition: multiui.cpp:761
#define ARRIVAL_MESSAGE_DELAY_MAX
void parse_asteroid_fields(mission *pm)
#define P2_SF2_AFTERBURNER_LOCKED
Definition: missionparse.h:503
#define ARRIVE_AT_LOCATION
Definition: missionparse.h:237
uint respawn_count
Definition: missionparse.h:419
int secondary_bank_ammo[MAX_SHIP_SECONDARY_BANKS]
Definition: ship.h:134
int ship_class_compare(int ship_class_1, int ship_class_2)
Definition: ship.cpp:17715
sexp_node * Sexp_nodes
Definition: sexp.cpp:844
debris Debris[MAX_DEBRIS_PIECES]
Definition: debris.cpp:41
void ship_set_new_ai_class(int ship_num, int new_ai_class)
Definition: ship.cpp:17362
int arrival_distance
Definition: missionparse.h:370
int targeted_subsys_parent
Definition: ai.h:474
int primary_bank_ammo_capacity[MAX_SHIP_PRIMARY_BANKS]
Definition: ship.h:1296
#define SF_NO_DEPARTURE_WARP
Definition: ship.h:441
int check_sexp_syntax(int node, int return_type, int recursive, int *bad_node, int mode)
Definition: sexp.cpp:1658
float assist_score_pct
Definition: ship.h:543
void ship_recalc_subsys_strength(ship *shipp)
Definition: ship.cpp:6020
int variable_index
Definition: missionparse.h:334
builtin_message Builtin_messages[]
void dock_dock_objects(object *objp1, int dockpoint1, object *objp2, int dockpoint2)
Definition: objectdock.cpp:602
void conv_fix_punctuation_section(char *str, char *section_start, char *section_end, char *text_start, char *text_end)
#define MGF_NO_MUSIC
Definition: missiongoals.h:52
char loading_screen[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN]
Definition: missionparse.h:146
int mission_parse_get_multi_mission_info(const char *filename)
char voice[MAX_FILENAME_LEN]
int wave_count
Definition: ship.h:1527
int Num_arrival_names
int iff_x_attacks_y(int team_x, int team_y)
Definition: iff_defs.cpp:605
bool ship_useful_for_departure(int shipnum, int path_mask)
Definition: ship.cpp:17448
int type
Definition: sexp.h:1043
#define MAX_PARSE_OBJECT_FLAGS_2
Definition: missionparse.h:486
#define REPLACE_WITH_INVISIBLE
Definition: model.h:693
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
for(int idx=0;idx< i;idx++)
Definition: multi_pxo.cpp:472
void shipfx_warpin_start(object *objp)
Definition: shipfx.cpp:565
#define P_SF_CARGO_KNOWN
Definition: missionparse.h:447
#define SF_WARPED_SUPPORT
Definition: ship.h:466
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)
#define WF_NAV_CARRY
Definition: ship.h:1513
ushort Current_file_checksum
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
#define SPECIAL_ARRIVAL_ANCHOR_PLAYER_FLAG
Definition: missionparse.h:38
int get_mission_info(const char *filename, mission *mission_p, bool basic)
void stuff_vec3d(vec3d *vp)
Definition: parselo.cpp:3082
void event_music_set_soundtrack(char *name)
void ship_hit_sparks_no_rotate(object *ship_objp, vec3d *hitpos)
Definition: shiphit.cpp:1030
void parse_cutscenes(mission *pm)
#define DATE_TIME_LENGTH
Definition: globals.h:19
int orders_accepted
Definition: missionparse.h:394
int ship_create(matrix *orient, vec3d *pos, int ship_type, char *ship_name)
Definition: ship.cpp:9690
void truncate_message_lines(SCP_string &text, int num_allowed_lines)
Definition: parselo.cpp:4154
#define P_SF_GUARDIAN
Definition: missionparse.h:468
int get_parse_name_index(const char *name)
void debrief_reset()
SCP_vector< mission_cutscene > cutscenes
Definition: missionparse.h:170
int objnum
Definition: player.h:124
void ai_set_mode_warp_out(object *objp, ai_info *aip)
Definition: aicode.cpp:13301
#define WF_DEPARTURE_ORDERED
Definition: ship.h:1512
#define SF_NO_ARRIVAL_WARP
Definition: ship.h:440
#define OBJ_INDEX(objp)
Definition: object.h:235
void post_process_path_stuff()
void mission_parse_maybe_create_parse_object(p_object *pobjp)
#define MULTI_TEAM
Definition: multi.h:655
ship * Player_ship
Definition: ship.cpp:124
void obj_get_average_ship_pos(vec3d *pos)
Definition: object.cpp:1796
int num_waves
Definition: ship.h:1522
#define GM_IN_MISSION
Definition: systemvars.h:23
SCP_string team_name
Definition: ship.h:812
int mission_is_repair_scheduled(object *objp)
#define LOG_SHIP_DESTROYED
Definition: missionlog.h:20
sexp_variable * variables
char modified[DATE_TIME_LENGTH]
Definition: missionparse.h:135
void stuff_boolean(int *i, bool a_to_eol)
Definition: parselo.cpp:2519
int red_alert_skipped_ships
Definition: ship.h:1529
matrix orient
Definition: object.h:153
void convertFSMtoFS2()
int ship_guardian_threshold
Definition: ship.h:601
int Global_error_count
Definition: windebug.cpp:47
int wi_flags2
Definition: weapon.h:385
bool use_shockwave
Definition: ship.h:589
#define F_MESSAGE
Definition: parselo.h:42
#define P2_SF2_NAV_NEEDSLINK
Definition: missionparse.h:499
bool use_special_explosion
Definition: missionparse.h:401
#define NOX(s)
Definition: pstypes.h:473
#define MEF_USING_TRIGGER_COUNT
Definition: missiongoals.h:85
#define MAX_GOAL_TEXT
Definition: missiongoals.h:50
int iff_get_mask(int team)
Definition: iff_defs.cpp:615
char font_filename[MAX_FILENAME_LEN]
Definition: fictionviewer.h:20
int TVT_wings[MAX_TVT_WINGS]
Definition: ship.cpp:136
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
sexp_variable Block_variables[MAX_SEXP_VARIABLES]
Definition: sexp.cpp:847
#define OLD_GAME_TYPE_TRAINING
Definition: missionparse.h:58
#define OBJ_SHIP
Definition: object.h:32
#define P_SF_REINFORCEMENT
Definition: missionparse.h:450
GLfloat GLfloat v1
Definition: Glext.h:5639
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
#define GM_STANDALONE_SERVER
Definition: systemvars.h:27
void ai_add_ship_goal_sexp(int sexp, int type, ai_info *aip)
Definition: aigoals.cpp:1201
int Num_reinforcement_type_names
float decay
Definition: sound.h:95
#define MULTI_END_NOTIFY_NONE
Definition: multi_endgame.h:32
#define P_OF_PLAYER_START
Definition: missionparse.h:453
float max_speed
Definition: ship.h:1230
GLbitfield flags
Definition: Glext.h:6722
float forward_cruise_percent
Definition: physics.h:106
void vm_vec_rand_vec_quick(vec3d *rvec)
Definition: vecmat.cpp:1379
menu_music Spooled_music[MAX_SPOOLED_MUSIC]
Definition: eventmusic.cpp:249
int objnum
Definition: debris.h:31
#define OLD_MAX_GAME_TYPES
Definition: missionparse.h:54
#define vm_malloc(size)
Definition: pstypes.h:547
int sound_env_get(sound_env *se, int preset)
Definition: sound.cpp:1372
#define SIF_HUGE_SHIP
Definition: ship.h:945
int wing_name_lookup(const char *name, int ignore_count)
Definition: ship.cpp:12706
#define SF2_NO_BUILTIN_MESSAGES
Definition: ship.h:491
int turret_animation_done_time
Definition: ship.h:352
#define HOTKEY_MISSION_FILE_ADDED
Definition: hudtarget.h:44
int Starting_wings[MAX_STARTING_WINGS]
Definition: ship.cpp:132
void reset_parse(char *text)
Definition: parselo.cpp:3305
#define OF_MISSILE_PROTECTED
Definition: object.h:121
char weaponry_amount_variable[MAX_WEAPON_TYPES][TOKEN_LENGTH]
Definition: missionparse.h:543
int is_sexp_true(int cur_node, int referenced_node)
Definition: sexp.cpp:22665
int num_secondary_banks
Definition: ship.h:1298
GLuint const GLchar * name
Definition: Glext.h:5608
#define MAX_LABEL_LEN
void stars_load_first_valid_background()
Definition: starfield.cpp:2636
#define SHIELD_STRENGTH
Definition: sexp.h:899
int RunCondition(int condition, char format='\0', void *data=NULL, class object *objp=NULL, int more_data=0)
Definition: scripting.cpp:924
#define PROMPT_NONE
Definition: multi_endgame.h:26
int weaponry_count[MAX_WEAPON_TYPES]
Definition: missionparse.h:541
char filename[MAX_FILENAME_LEN]
Definition: missionparse.h:126
int departure_path_mask
Definition: ship.h:1548
#define P2_SF2_SET_CLASS_DYNAMICALLY
Definition: missionparse.h:501
#define INNER_RAD
Definition: sexp.h:891
char background[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN]
int get_special_anchor(char *name)
#define P_SF_VAPORIZE
Definition: missionparse.h:470
int Player_use_ai
GLuint GLfloat * val
Definition: Glext.h:6741
int final_death_time
Definition: ship.h:569
void SetHookObjects(int num,...)
Definition: scripting.cpp:556
char background[GR_NUM_RESOLUTIONS][MAX_FILENAME_LEN]
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
#define SF_RED_ALERT_STORE_STATUS
Definition: ship.h:469
#define SUBSYSTEM_ENGINE
Definition: model.h:53
vec3d vel
Definition: physics.h:77
#define vm_realloc(ptr, size)
Definition: pstypes.h:551
char * Icon_names[MIN_BRIEF_ICONS]
fix t1
Definition: animplay.cpp:37
char command_sender[NAME_LENGTH]
Definition: missionparse.h:159
p_object * Arriving_support_ship
#define TOKEN_LENGTH
Definition: globals.h:41
#define MISSION_TYPE_TRAINING
Definition: missionparse.h:63
ushort net_signature
Definition: ship.h:1560
#define SF_SCANNABLE
Definition: ship.h:465
#define SIF_SUPPORT
Definition: ship.h:878
object * created_object
Definition: missionparse.h:396
int Num_unknown_ship_classes
#define SF2_PRIMARIES_LOCKED
Definition: ship.h:492
#define SF_VAPORIZE
Definition: ship.h:470
int multi_quit_game(int prompt, int notify_code, int err_code, int wsa_error)
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
int model_find_dock_name_index(int modelnum, char *name)
Definition: modelread.cpp:5055
void stuff_int(int *i)
Definition: parselo.cpp:2372
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
void log_printf(int logfile_type, char *format,...)
Definition: generic_log.cpp:83
int stuff_int_list(int *ilp, int max_ints, int lookup_type)
Definition: parselo.cpp:2782
void parse_wings(mission *pm)
debrief_stage stages[MAX_DEBRIEF_STAGES]
#define SF_DEPARTING
Definition: ship.h:475
int get_string_or_variable(char *str)
Definition: parselo.cpp:1084
int string_lookup(const CString &str1, char *strlist[], int max)
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
int special_shield
Definition: ship.h:594
void physics_sim(vec3d *position, matrix *orient, physics_info *pi, float sim_time)
Definition: physics.cpp:364
int initial_hull
Definition: missionparse.h:366
int total_arrived_count
Definition: ship.h:1528
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
int arrival_delay
Definition: ship.h:87
GLuint GLuint num
Definition: Glext.h:9089
#define WING_INDEX(wingp)
Definition: ship.h:1601
void display_parse_diagnostics()
Definition: parselo.cpp:3320
#define WIF_PLAYER_ALLOWED
Definition: weapon.h:68
#define MAX_REPLACEMENT_TEXTURES
Definition: model.h:690
#define SF_REINFORCEMENT
Definition: ship.h:437
void send_wing_create_packet(wing *wingp, int num_to_create, int pre_create_count)
Definition: multimsgs.cpp:2707
#define SF_KILL_BEFORE_MISSION
Definition: ship.h:446
#define P_KNOSSOS_WARP_IN
Definition: missionparse.h:469
float bound_rad
Definition: asteroid.h:129
#define P2_SF2_PRIMARIES_LOCKED
Definition: missionparse.h:495
fix base_texture_anim_frametime
Definition: ship.h:691
#define MISSION_FLAG_PLAYER_START_AI
Definition: missionparse.h:87
int initial_velocity
Definition: missionparse.h:365
void post_process_ships_wings()
int Mission_all_attack
Definition: aicode.cpp:200
int arrival_cue
Definition: ship.h:1543
char ship_count_variables[MAX_SHIP_CLASSES][TOKEN_LENGTH]
Definition: missionparse.h:536
void SetName(const char *new_name)
Definition: jumpnode.cpp:224
campaign Campaign
#define MAX_ALT_TYPE_NAMES
Definition: missionparse.h:251
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
char old_texture[MAX_FILENAME_LEN]
Definition: missionparse.h:325
#define strcat_s(...)
Definition: safe_strings.h:68
#define P_AIF_KAMIKAZE
Definition: missionparse.h:461
#define SF_WARP_BROKEN
Definition: ship.h:460
#define SF2_NO_ETS
Definition: ship.h:503
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]
Definition: asteroid.h:138
#define NAME_LENGTH
Definition: globals.h:15
float frand()
Return random value in range 0.0..1.0- (1.0- means the closest number less than 1.0)
Definition: floating.cpp:35
GLuint GLuint GLsizei GLenum const GLvoid * indices
Definition: Gl.h:1502
void parse_cmd_briefs(mission *pm)
#define P2_OF_IMMOBILE
Definition: missionparse.h:505
void neb2_post_level_init()
Definition: neb.cpp:332
void Reset()
Definition: missionparse.h:172
#define HULL_STRENGTH
Definition: sexp.h:900
void ai_maybe_add_form_goal(wing *wingp)
Definition: aigoals.cpp:134
#define SSF_NO_AGGREGATE
Definition: ship.h:294
char Mission_parse_storm_name[NAME_LENGTH]
#define P2_SF2_HIDE_SHIP_NAME
Definition: missionparse.h:500
#define FILESPEC_LENGTH
Definition: globals.h:22
void submodel_get_two_random_points_better(int model_num, int submodel_num, vec3d *v1, vec3d *v2)
void mission_bring_in_support_ship(object *requester_objp)
int Default_ai_profile
Definition: ai_profiles.cpp:21
#define fl2i(fl)
Definition: floating.h:33
#define P2_SF2_TOGGLE_SUBSYSTEM_SCANNING
Definition: missionparse.h:492
#define SF2_LOCK_ALL_TURRETS_INITIALLY
Definition: ship.h:501
#define SHIP_GET_ANY_SHIP
Definition: ship.h:1786
int insert_subsys_status(p_object *pobjp)
int behavior
Definition: ai.h:335
int eval_sexp(int cur_node, int referenced_node)
Definition: sexp.cpp:22894
player * Player
char event_music_name[NAME_LENGTH]
Definition: missionparse.h:162
p_object * mission_parse_get_parse_object(ushort net_signature)
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)
int special_ship
Definition: ship.h:1537
char name[NAME_LENGTH]
Definition: eventmusic.h:82
void parse_object_clear_handled_flag_helper(p_object *pobjp, p_dock_function_info *infop)
void mission_eval_arrivals()
void parse_goals(mission *pm)
int departure_location
Definition: ship.h:1546
#define SF2_SHIP_LOCKED
Definition: ship.h:506
void ai_add_rearm_goal(object *requester_objp, object *support_objp)
Definition: aicode.cpp:15421
char * Parse_object_flags_2[MAX_PARSE_OBJECT_FLAGS_2]
void shipfx_blow_up_model(object *obj, int model, int submodel, int ndebris, vec3d *exp_center)
Definition: shipfx.cpp:374
int current_wave
Definition: ship.h:1522
#define SEXP_VARIABLE_CAMPAIGN_PERSISTENT
Definition: sexp.h:886
unsigned short ushort
Definition: pstypes.h:63
float damping
Definition: sound.h:94
void mission_hotkey_mf_add(int set, int objnum, int how_to_add)
int special_exp_deathroll_time
Definition: missionparse.h:408
void parse_bring_in_docked_wing(p_object *p_objp, int wingnum, int shipnum)
char subobj_name[MAX_NAME_LEN]
Definition: model.h:172
void find_and_stuff_or_add(char *id, int *addr, int f_type, char *strlist[], int *total, int max, char *description)
Definition: parselo.cpp:3251
int wave_delay_timestamp
Definition: ship.h:1554
int event_music_get_soundtrack_index(char *name)
struct p_dock_function_info::@259 parameter_variables
#define SF_DEPARTURE_ORDERED
Definition: ship.h:471
void parse_mission_info(mission *pm, bool basic=false)
float scale_y
Definition: starfield.h:32
void parse_object_clear_all_handled_flags()
#define P2_OF_NO_COLLIDE
Definition: missionparse.h:511
int parse_main(const char *mission_name, int flags)
ship_obj Ship_obj_list
Definition: ship.cpp:162
void dock_evaluate_all_docked_objects(object *objp, dock_function_info *infop, void(*function)(object *, dock_function_info *))
Definition: objectdock.cpp:285
void RemHookVars(unsigned int num,...)
Definition: scripting.cpp:754
#define MAX_BRIEF_STAGES
int departure_delay
Definition: missionparse.h:380
#define CF_TYPE_MISSIONS
Definition: cfile.h:74
int departure_delay
Definition: ship.h:1550
int ship_info_index
Definition: ship.h:539
void parse_briefing_info(mission *pm)
char substitute_briefing_music_name[NAME_LENGTH]
Definition: missionparse.h:165
char ship_list_variables[MAX_SHIP_CLASSES][TOKEN_LENGTH]
Definition: missionparse.h:534
GLfloat GLfloat p
Definition: Glext.h:8373
int Num_goal_type_names
int pp_collide_any(vec3d *curpos, vec3d *goalpos, float radius, object *ignore_objp1, object *ignore_objp2, int big_only_flag)
Definition: aicode.cpp:2842
#define MULTIPLAYER_MASTER
Definition: multi.h:130
#define MAX_REINFORCEMENTS
Definition: ship.h:58
int stuff_vec3d_list(vec3d *vlp, int max_vecs)
Definition: parselo.cpp:3114
#define F_NAME
Definition: parselo.h:34
void ai_add_wing_goal_sexp(int sexp, int type, int wingnum)
Definition: aigoals.cpp:1210
struct _cl_event * event
Definition: Glext.h:7296
char * Ship_class_names[MAX_SHIP_CLASSES]
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
#define OF_FLAK_PROTECTED
Definition: object.h:119
float ship_max_shield_strength
Definition: missionparse.h:426
int special_shield
Definition: missionparse.h:411
void init_ai_system(void)
Definition: aicode.cpp:14458
#define SIF_KNOSSOS_DEVICE
Definition: ship.h:912
struct p_dock_function_info::@259 maintained_variables
#define SF_NO_ARRIVAL_MUSIC
Definition: ship.h:439
#define P_SF_IGNORE_COUNT
Definition: missionparse.h:448
#define WF_REINFORCEMENT
Definition: ship.h:1504
#define SF2_AFTERBURNER_LOCKED
Definition: ship.h:499
#define AIF_NO_DYNAMIC
Definition: ai.h:56
int departure_delay
Definition: ship.h:621
int get_reassigned_index(team_data *current_team, int ship_class)
char TVT_wing_names[MAX_TVT_WINGS][NAME_LENGTH]
Definition: ship.cpp:141
char * sexp_error_message(int num)
Definition: sexp.cpp:28570
void position_ship_for_knossos_warpin(p_object *p_objp)
void cmd_brief_reset()
int ai_profile_lookup(char *name)
char * Old_game_types[OLD_MAX_GAME_TYPES]
int static_rand(int num)
Return a pseudo random 32 bit value given a reasonably small number.
Definition: staticrand.cpp:38
#define timestamp_elapsed(stamp)
Definition: timer.h:102
#define MAX_ASTEROID_FIELDS
Definition: starfield.h:23
int has_inner_bound
Definition: asteroid.h:130
#define ICON_TRANSPORT_WING
SCP_vector< float > shield_quadrant
Definition: object.h:159
SCP_vector< species_info > Species_info
void set_cue_to_false(int *cue)
char wave_filename[MAX_FILENAME_LEN]
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
#define MISSION_VERSION
Definition: missionparse.h:44
#define P2_SF2_PRIMITIVE_SENSORS
Definition: missionparse.h:488
char mission_desc[MISSION_DESC_LENGTH]
Definition: missionparse.h:137
int ship_get_default_orders_accepted(ship_info *sip)
Definition: ship.cpp:5480
char docker[NAME_LENGTH]
hull_check pos
Definition: lua.cpp:5050
void error_display(int error_level, char *format,...)
Definition: parselo.cpp:308
int Num_soundtracks
Definition: eventmusic.cpp:58
p_object * prev
Definition: missionparse.h:347
void ignore_white_space()
Definition: parselo.cpp:77
const GLfloat * m
Definition: Glext.h:10319
#define SF2_ALWAYS_DEATH_SCREAM
Definition: ship.h:496
int Multi_ping_timestamp
Definition: fredstubs.cpp:30
#define MAX_MISSION_EVENTS
Definition: missiongoals.h:71
char name[NAME_LENGTH]
Definition: missiongoals.h:55
int Iff_traitor
Definition: iff_defs.cpp:22
#define MULTI_END_ERROR_WAVE_COUNT
Definition: multi_endgame.h:53
void parse_dock_one_docked_object(p_object *pobjp, p_object *parent_pobjp)
SCP_vector< sexp_variable > variables
Definition: player.h:206
#define MAX_TVT_TEAMS
Definition: globals.h:57
int turret_best_weapon
Definition: ship.h:333
void red_alert_invalidate_timestamp()
Definition: redalert.cpp:443
char message[MAX_GOAL_TEXT]
Definition: missiongoals.h:58
int Num_parse_goals
debriefing Debriefings[MAX_TVT_TEAMS]
GLenum GLuint GLenum GLsizei length
Definition: Glext.h:5156
void SetAlphaColor(int r, int g, int b, int alpha)
Definition: jumpnode.cpp:173
void ship_add_ship_type_count(int ship_info_index, int num)
Definition: ship.cpp:14449
int departure_path_mask
Definition: ship.h:619
char cargo1
Definition: missionparse.h:355
matrix orient
Definition: missionparse.h:350
int threshold
Definition: ship.h:1523
#define i2fl(i)
Definition: floating.h:32
int wing
Definition: ai.h:333
#define P2_SF2_CLOAKED
Definition: missionparse.h:507
char name[NAME_LENGTH]
Definition: missiongoals.h:102
#define MAX_STATUS_NAMES
Definition: missionparse.h:232
vec3d inner_max_bound
Definition: asteroid.h:132
debris_genre_t debris_genre
Definition: asteroid.h:137
char yes_messages[MAX_REINFORCEMENT_MESSAGES][NAME_LENGTH]
Definition: ship.h:90
GLint GLsizei count
Definition: Gl.h:1491
#define timestamp_rand(a, b)
Definition: timer.h:92
int arrival_anchor
Definition: ship.h:612
matrix Parse_viewer_orient
bool sexp_is_locked_false(int node)
p_object Ship_arrival_list
team_data Team_data[MAX_TVT_TEAMS]
cmd_brief * Cur_cmd_brief
#define SCORE_DEBRIEF_SUCCESS
Definition: eventmusic.h:52
object * Player_obj
Definition: object.cpp:56
int Default_command_persona
void mission_eval_departures()
#define SF_ESCORT
Definition: ship.h:438
int num_players
Definition: missionparse.h:140
#define MPF_IMPORT_FSM
Definition: missionparse.h:51
int value
Definition: sexp.h:1033
#define SF_CARGO_REVEALED
Definition: ship.h:456
int Num_reinforcements
Definition: ship.cpp:121
#define MAX_ARRIVAL_NAMES
Definition: missionparse.h:236
uint flags2
Definition: ship.h:645
#define P_SF_NO_ARRIVAL_WARP
Definition: missionparse.h:455
#define F_FILESPEC
Definition: parselo.h:37
char variable_name[TOKEN_LENGTH]
Definition: sexp.h:1045
vec3d prev_ramp_vel
Definition: physics.h:69
#define MAX_IFFS
Definition: globals.h:34
#define SF_DYING
Definition: ship.h:447
int event_music_get_spooled_music_index(const char *name)
int temp
Definition: lua.cpp:4996
int kamikaze_damage
Definition: ai.h:523
int special_hitpoints
Definition: ship.h:593
#define OUTER_RAD
Definition: sexp.h:892
void stuff_ubyte(ubyte *i)
Definition: parselo.cpp:2646
int bm_load_either(const char *filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads either animation (bm_load_animation) or still image (bm_load)
Definition: bmpman.cpp:1683
SCP_vector< starfield_list_entry > bitmaps
Definition: starfield.h:39
int ship_index[MAX_SHIPS_PER_WING]
Definition: ship.h:1531
#define WARP_IN_TIME_MAX
#define P_SF_NO_DEPARTURE_WARP
Definition: missionparse.h:456
#define P2_OF_FORCE_SHIELDS_ON
Definition: missionparse.h:504
#define WIF2_BALLISTIC
Definition: weapon.h:84
polymodel * pm
Definition: lua.cpp:1598
#define MISSION_LOADOUT_WEAPON_LIST
Definition: parselo.h:59
int command_persona
Definition: missionparse.h:158
#define P_SF_USE_UNIQUE_ORDERS
Definition: missionparse.h:476
void multi_set_network_signature(ushort signature, int what_kind)
Definition: multiutil.cpp:198
int ship_class
Definition: missionparse.h:333
void mission_parse_reset_callsign()
int optional_string_one_of(int arg_count,...)
Definition: parselo.cpp:567
int special_exp_damage
Definition: ship.h:585
int departure_cue
Definition: ship.h:620
#define MAX(a, b)
Definition: pstypes.h:299
int Num_iffs
Definition: iff_defs.cpp:19
SCP_map< SCP_string, team_color > Team_Colors
Definition: alphacolors.cpp:15
float fvi_ray_plane(vec3d *new_pnt, const vec3d *plane_pnt, const vec3d *plane_norm, const vec3d *ray_origin, const vec3d *ray_direction, float rad)
Definition: fvi.cpp:118
#define DEBRIS_USED
Definition: debris.h:54
int arrival_path_mask
Definition: ship.h:613
Definition: starfield.h:30
#define SF2_PRIMITIVE_SENSORS
Definition: ship.h:483
int respawn_priority
Definition: ship.h:544
asteroid_field Asteroid_field
Definition: asteroid.cpp:64
ushort multi_assign_network_signature(int what_kind)
Definition: multiutil.cpp:105
int contrail_threshold
Definition: missionparse.h:151
SCP_vector< texture_replace > Fred_texture_replacements
subsys_status * Subsys_status
int ai_goals
Definition: missionparse.h:354
#define MAX_ICON_TEXT_LEN
int ship_name_lookup(const char *name, int inc_players)
Definition: ship.cpp:12900
int arrival_cue
Definition: ship.h:614
float max_hull_strength
Definition: ship.h:1309
char envmap_name[MAX_FILENAME_LEN]
Definition: missionparse.h:149
void waypoint_create_game_objects()
Definition: waypoint.cpp:146
char Arriving_repair_targets[MAX_AI_GOALS][NAME_LENGTH]
#define NUM_NEBULA_COLORS
Definition: missionparse.h:31
char filename[MAX_FILENAME_LEN]
Definition: starfield.h:31
#define GM_NORMAL
Definition: systemvars.h:19
void mission_add_to_arriving_support(object *requester_objp)
int parse_wing_create_ships(wing *wingp, int num_to_create, int force, int specific_instance)
Tries to create a wing of ships.
#define NOTES_LENGTH
Definition: globals.h:20
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
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
#define SEXP_KNOWN_FALSE
Definition: sexp.h:921
char * Cmdline_mod
Definition: cmdline.cpp:397
#define ARRIVE_FROM_DOCK_BAY
Definition: missionparse.h:240
#define SF2_NAVPOINT_NEEDSLINK
Definition: ship.h:497
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
int Num_goals
char no_messages[MAX_REINFORCEMENT_MESSAGES][NAME_LENGTH]
Definition: ship.h:89
int Mission_departure_timestamp
float h
Definition: pstypes.h:111
void _cdecl void void _cdecl void _cdecl void _cdecl void _cdecl int Global_warning_count
Definition: windebug.cpp:46
char type
Definition: object.h:146
int get_warp_in_pos(vec3d *pos, object *objp, float x, float y, float z)
int departure_cue
Definition: missionparse.h:379
support_ship_info support_ships
Definition: missionparse.h:143
#define CF_TYPE_ANY
Definition: cfile.h:42
int subsys_count
Definition: missionparse.h:364
void ai_copy_mission_wing_goal(ai_goal *aigp, ai_info *aip)
Definition: aigoals.cpp:1340
float Neb2_fog_near_mult
Definition: neb.cpp:159
void init_sexp()
Definition: sexp.cpp:1090
#define SF_FROM_PLAYER_WING
Definition: ship.h:457
void parse_cmd_brief(mission *pm)
#define wp(p)
Definition: modelsinc.h:69
int parse_create_object(p_object *pobjp)
#define LOCAL
Definition: pstypes.h:37
char label[MAX_LABEL_LEN]
#define SF2_SECONDARIES_LOCKED
Definition: ship.h:493
#define P2_SF2_ALWAYS_DEATH_SCREAM
Definition: missionparse.h:498
float max_shield_recharge
Definition: ship.h:599
char * Nebula_colors[NUM_NEBULA_COLORS]
int parse_object(mission *pm, int flag, p_object *p_objp)
int timer_get_milliseconds()
Definition: timer.cpp:150
char text[TOKEN_LENGTH]
Definition: sexp.h:1027
#define F_MULTITEXT
Definition: parselo.h:43
int Mission_palette
#define GM_CAMPAIGN_MODE
Definition: systemvars.h:29
char author[NAME_LENGTH]
Definition: missionparse.h:132
int num_ship_choices
Definition: missionparse.h:531
#define stricmp(s1, s2)
Definition: config.h:271
int status_type[MAX_OBJECT_STATUS]
Definition: missionparse.h:359
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
char * Mp
Definition: parselo.cpp:48
#define DEPARTURE_TIMESTAMP
int departure_location
Definition: missionparse.h:376
void hud_add_remove_ship_escort(int objnum, int supress_feedback)
Definition: hudescort.cpp:917
int Subsys_index
#define timestamp_valid(stamp)
Definition: timer.h:104
#define P_SF2_DONT_COLLIDE_INVIS
Definition: missionparse.h:473
int Mission_alt_type_count
float max_subsys_repair_val
Definition: missionparse.h:107
void get_absolute_wing_pos(vec3d *result_pos, object *leader_objp, int wing_index, int formation_object_flag)
Definition: aicode.cpp:11409
ushort netmisc_calc_checksum(void *vptr, int len)
Definition: multiutil.cpp:252
#define PROPAGATE
Definition: sexp.h:895
int flags
Definition: ai.h:139
int Subsys_status_size
int skip_to_string(char *pstr, char *end)
Definition: parselo.cpp:375
float static_randf(int num)
Return a random float in 0.0f .. 1.0f- (ie, it will never return 1.0f).
Definition: staticrand.cpp:61
#define GR_1024
Definition: 2d.h:653
int cfilelength(CFILE *cfile)
Definition: cfile.cpp:1393
char ship_name[NAME_LENGTH]
Definition: ship.h:604
p_dock_instance * dock_list
Definition: missionparse.h:395
int id
Definition: sound.h:92
int special_exp_shockwave_speed
Definition: ship.h:590
int arrival_distance
Definition: ship.h:611
char * Status_type_names[MAX_STATUS_NAMES]
#define SF_WARP_NEVER
Definition: ship.h:461
char docker_point[NAME_LENGTH]
field_type_t
Definition: asteroid.h:121
p_object Support_ship_pobj
int signature
Definition: ai.h:135
int skip_to_start_of_string(char *pstr, char *end)
Definition: parselo.cpp:404
void nebl_set_storm(char *name)
void clear_texture_replacements()
int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int path_mask, vec3d *pos, vec3d *fvec)
Definition: aicode.cpp:12632
#define LOG_SELF_DESTRUCTED
Definition: missionlog.h:39
#define CHA_ONSHIPARRIVE
Definition: scripting.h:73
#define MIN_BRIEF_ICONS
#define fl2f(fl)
Definition: floating.h:38
#define MISSION_TEXT_SIZE
Definition: parselo.h:20
#define SW_FLAG_BEAM_FREE
Definition: ship.h:94
void parse_wing(mission *pm)
float b
Definition: pstypes.h:111
GLint y
Definition: Gl.h:1505
float Neb2_fog_far_mult
Definition: neb.cpp:160
#define BLOCK_EXP_SIZE
Definition: sexp.h:890
#define ICON_LARGESHIP
#define P2_ALREADY_HANDLED
Definition: missionparse.h:518
int arrival_delay
Definition: ship.h:615
#define BLOCK_HIT_SIZE
Definition: sexp.h:898
char new_texture[MAX_FILENAME_LEN]
Definition: missionparse.h:326
#define MAX_DEBRIEF_STAGES
int num_primary_banks
Definition: ship.h:1293
int flags
Definition: ship.h:1556
#define RAW_INTEGER_TYPE
Definition: parselo.h:52
brief_line * lines
#define MESSAGE_TIME_SOON
void update_loadout_totals(team_data *current_team, int loadout_index)
ai_goal ai_goals[MAX_AI_GOALS]
Definition: ship.h:1558
#define REPAIR_INFO_WARP_REMOVE
Definition: multi.h:309
char wing_status_wing_pos
Definition: missionparse.h:417
p_object * Player_start_pobject
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
#define fl_radians(fl)
Definition: floating.h:42
#define OF_BEAM_PROTECTED
Definition: object.h:115
char substitute_event_music_name[NAME_LENGTH]
Definition: missionparse.h:164
int ship_list[MAX_SHIP_CLASSES]
Definition: missionparse.h:533
#define strcpy_s(...)
Definition: safe_strings.h:67
#define SEXP_VARIABLE_PLAYER_PERSISTENT
Definition: sexp.h:883
int Nebula_pitch
Definition: nebula.cpp:38
vec3d pos
Definition: missionparse.h:349
int Player_starts
int special_hitpoints
Definition: missionparse.h:410
#define MISSION_TYPE_MULTI_TEAMS
Definition: missionparse.h:65
#define SMF_VALID
Definition: eventmusic.h:72
void parse_object_mark_dock_leader_helper(p_object *pobjp, p_dock_function_info *infop)
int Cur_brief_id
void resolve_path_masks(int anchor, int *path_mask)
char * Arrival_location_names[MAX_ARRIVAL_NAMES]
int parse_object_on_arrival_list(p_object *pobjp)
void mission_parse_remove_callsign(const char *name)
int behavior
Definition: missionparse.h:353