]> icculus.org git repositories - taylor/freespace2.git/blob - src/mission/missionparse.cpp
merge in updated platform code
[taylor/freespace2.git] / src / mission / missionparse.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Mission/MissionParse.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * main upper level code for pasring stuff
16  *
17  * $Log$
18  * Revision 1.7  2005/10/01 22:04:58  taylor
19  * fix FS1 (de)briefing voices, the directory names are different in FS1
20  * hard code the table values so that the fs1.vp file isn't needed
21  * hard code a mission fix for sm2-08a since a have no idea how to fix it otherwise
22  * generally cleanup some FS1 code
23  * fix volume sliders in the options screen that never went all the way up
24  *
25  * Revision 1.6  2003/08/14 02:39:11  theoddone33
26  * Removed braces from initializers so GCC 3 will stop complaining.
27  *
28  * Revision 1.5  2003/05/25 02:30:43  taylor
29  * Freespace 1 support
30  *
31  * Revision 1.4  2002/06/17 06:33:09  relnev
32  * ryan's struct patch for gcc 2.95
33  *
34  * Revision 1.3  2002/06/09 04:41:22  relnev
35  * added copyright header
36  *
37  * Revision 1.2  2002/05/07 03:16:46  theoddone33
38  * The Great Newline Fix
39  *
40  * Revision 1.1.1.1  2002/05/03 03:28:09  root
41  * Initial import.
42  *
43  * 
44  * 63    9/12/99 8:09p Dave
45  * Fixed problem where skip-training button would cause mission messages
46  * not to get paged out for the current mission.
47  * 
48  * 62    9/09/99 3:53a Andsager
49  * Only reposition HUGE ships to center of knossos device on warp in
50  * 
51  * 61    8/27/99 9:07p Dave
52  * LOD explosions. Improved beam weapon accuracy.
53  * 
54  * 60    8/26/99 8:51p Dave
55  * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
56  * 
57  * 59    8/25/99 10:06a Jefff
58  * vasudan pilots get a vasudan support ship. 
59  * 
60  * 58    8/24/99 5:27p Andsager
61  * Make subsystems with zero strength before mission blown off.  Protect
62  * red alert pilot against dying between orders and jump.
63  * 
64  * 57    8/18/99 10:07p Johnson
65  * Fix Fred bug in positioning of Knossos device (when trying to warp in
66  * through self)
67  * 
68  * 56    8/18/99 3:57p Andsager
69  * Add warning for invalid alt_name.
70  * 
71  * 55    8/18/99 3:48p Andsager
72  * Make support ship take default name and not 0th alt_name.
73  * 
74  * 54    8/16/99 3:53p Andsager
75  * Add special warp in interface in Fred and saving / reading.
76  * 
77  * 53    8/16/99 2:01p Andsager
78  * Knossos warp-in warp-out.
79  * 
80  * 52    8/03/99 5:35p Andsager
81  * Dont draw target dot for instructor in training mission
82  * 
83  * 51    7/30/99 7:01p Dave
84  * Dogfight escort gauge. Fixed up laser rendering in Glide.
85  * 
86  * 50    7/28/99 1:36p Andsager
87  * Modify cargo1 to include flag CARGO_NO_DEPLETE.  Add sexp
88  * cargo-no-deplete (only for BIG / HUGE).  Modify ship struct to pack
89  * better.
90  * 
91  * 49    7/26/99 5:50p Dave
92  * Revised ingame join. Better? We'll see....
93  * 
94  * 48    7/19/99 3:01p Dave
95  * Fixed icons. Added single transport icon.
96  * 
97  * 47    7/15/99 9:20a Andsager
98  * FS2_DEMO initial checkin
99  * 
100  * 46    7/13/99 5:03p Alanl
101  * make sure object sounds get assigned to ships
102  * 
103  * 45    7/11/99 2:14p Dave
104  * Added Fred names for the new icon types.
105  * 
106  * 44    7/02/99 4:\31p Dave
107  * Much more sophisticated lightning support.
108  * 
109  * 43    7/01/99 4:23p Dave
110  * Full support for multiple linked ambient engine sounds. Added "big
111  * damage" flag.
112  * 
113  * 42    6/28/99 4:51p Andsager
114  * Add ship-guardian sexp (does not allow ship to be killed)
115  * 
116  * 41    6/21/99 1:34p Alanl
117  * event music tweaks
118  * 
119  * 40    6/16/99 10:20a Dave
120  * Added send-message-list sexpression.
121  * 
122  * 39    6/14/99 2:06p Andsager
123  * Default load brown asteroids
124  * 
125  * 38    6/10/99 11:06a Andsager
126  * Mission designed selection of asteroid types.
127  * 
128  * 37    6/03/99 6:37p Dave
129  * More TNT fun. Made perspective bitmaps more flexible.
130  * 
131  * 36    5/20/99 7:00p Dave
132  * Added alternate type names for ships. Changed swarm missile table
133  * entries.
134  * 
135  * 35    4/26/99 8:49p Dave
136  * Made all pof based nebula stuff full customizable through fred.
137  * 
138  * 34    4/26/99 12:49p Andsager
139  * Add protect object from beam support to Fred
140  * 
141  * 33    4/16/99 2:34p Andsager
142  * Second pass on debris fields
143  * 
144  * 32    4/15/99 5:00p Andsager
145  * Frist pass on Debris field
146  * 
147  * 31    4/07/99 6:22p Dave
148  * Fred and Freespace support for multiple background bitmaps and suns.
149  * Fixed link errors on all subprojects. Moved encrypt_init() to
150  * cfile_init() and lcl_init(), since its safe to call twice.
151  * 
152  * 30    3/31/99 9:52a Andsager
153  * generalization for debris field
154  * 
155  * 29    3/30/99 5:40p Dave
156  * Fixed reinforcements for TvT in multiplayer.
157  * 
158  * 28    3/29/99 6:17p Dave
159  * More work on demo system. Got just about everything in except for
160  * blowing ships up, secondary weapons and player death/warpout.
161  * 
162  * 27    3/24/99 6:23p Dave
163  * Make sure we only apply squadron changes to the player in single-player
164  * campaign mode.
165  * 
166  * 26    3/24/99 4:05p Dave
167  * Put in support for assigning the player to a specific squadron with a
168  * specific logo. Preliminary work for doing pos/orient checksumming in
169  * multiplayer to reduce bandwidth.
170  * 
171  * 25    3/01/99 7:39p Dave
172  * Added prioritizing ship respawns. Also fixed respawns in TvT so teams
173  * don't mix respawn points.
174  * 
175  * 24    2/26/99 6:01p Andsager
176  * Add sexp has-been-tagged-delay and cap-subsys-cargo-known-delay
177  * 
178  * 23    2/24/99 2:25p Dave
179  * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
180  * bug for dogfight more.
181  * 
182  * 22    2/23/99 8:11p Dave
183  * Tidied up dogfight mode. Fixed TvT ship type problems for alpha wing.
184  * Small pass over todolist items.
185  * 
186  * 21    2/17/99 2:10p Dave
187  * First full run of squad war. All freespace and tracker side stuff
188  * works.
189  * 
190  * 20    2/11/99 3:08p Dave
191  * PXO refresh button. Very preliminary squad war support.
192  * 
193  * 19    2/11/99 2:15p Andsager
194  * Add ship explosion modification to FRED
195  * 
196  * 18    2/07/99 8:51p Andsager
197  * Add inner bound to asteroid field.  Inner bound tries to stay astroid
198  * free.  Wrap when within and don't throw at ships inside.
199  * 
200  * 17    2/05/99 10:38a Johnson
201  * Fixed improper object array reference. 
202  * 
203  * 16    2/04/99 1:23p Andsager
204  * Apply max spark limit to ships created in mission parse
205  * 
206  * 15    2/03/99 12:42p Andsager
207  * Add escort priority.  Modify ship_flags_dlg to include field.  Save and
208  * Load.  Add escort priority field to ship.
209  * 
210  * 14    1/27/99 9:56a Dave
211  * Temporary checkin of beam weapons for Dan to make cool sounds.
212  * 
213  * 13    1/25/99 5:03a Dave
214  * First run of stealth, AWACS and TAG missile support. New mission type
215  * :)
216  * 
217  * 12    1/19/99 3:57p Andsager
218  * Round 2 of variables
219  * 
220  * 11    1/07/99 1:52p Andsager
221  * Initial check in of Sexp_variables
222  * 
223  * 10    11/14/98 5:32p Dave
224  * Lots of nebula work. Put in ship contrails.
225  * 
226  * 9     11/12/98 12:13a Dave
227  * Tidied code up for multiplayer test. Put in network support for flak
228  * guns.
229  * 
230  * 8     11/05/98 5:55p Dave
231  * Big pass at reducing #includes
232  * 
233  * 7     11/05/98 4:18p Dave
234  * First run nebula support. Beefed up localization a bit. Removed all
235  * conditional compiles for foreign versions. Modified mission file
236  * format.
237  * 
238  * 6     10/29/98 9:23p Dave
239  * Removed minor bug concerning externalization of campaign files.
240  * 
241  * 5     10/23/98 3:51p Dave
242  * Full support for tstrings.tbl and foreign languages. All that remains
243  * is to make it active in Fred.
244  * 
245  * 4     10/20/98 10:44a Andsager
246  * Add comment for creating sparks before mission starts
247  * 
248  * 3     10/07/98 6:27p Dave
249  * Globalized mission and campaign file extensions. Removed Silent Threat
250  * special code. Moved \cache \players and \multidata into the \data
251  * directory.
252  * 
253  * 2     10/07/98 10:53a Dave
254  * Initial checkin.
255  * 
256  * 1     10/07/98 10:49a Dave
257  * 
258  * 503   9/21/98 8:46p Dave
259  * Put in special check in fred for identifying unknown ships.
260  * 
261  * 502   9/14/98 5:09p Dave
262  * Massive hack to always ignore m-clash
263  * 
264  * 501   9/14/98 3:40p Allender
265  * better error checking for invalid number of waves for player wings in a
266  * multiplayer game.  Better popup message in FreeSpace side.
267  * 
268  * 500   9/11/98 2:05p Allender
269  * make reinforcements work correctly in multiplayer games.  There still
270  * may be a team vs team issue that I haven't thought of yet :-(
271  * 
272  * 499   8/07/98 9:48a Allender
273  * changed how SF_FROM_PLAYER_WING is assigned for team vs. team games
274  * 
275  * 498   7/16/98 2:22p Allender
276  * don't do wave check in single player
277  * 
278  * 497   7/13/98 5:19p Dave
279  * 
280  * 496   7/13/98 3:15p Allender
281  * don't allow multiple waves for any player wings
282  * 
283  * 495   7/10/98 12:11a Allender
284  * fixed problem where missions files of 0 length would cause game to
285  * crash
286  * 
287  * 494   5/21/98 3:31p Allender
288  * fix bug where Ship_obj_list was getting overwritten by the exited ships
289  * list
290  * 
291  * 493   5/20/98 1:04p Hoffoss
292  * Made credits screen use new artwork and removed rating field usage from
293  * Fred (a goal struct member).
294  * 
295  * 492   5/18/98 4:41p Comet
296  * allender: fix problem where ships in wings were not deleted on clients
297  * when a new wing create packet came in.  A serious hack of all hacks 
298  * 
299  * 491   5/18/98 3:37p Jasen
300  * move Int3() about too many ships in wing to before where ship actually
301  * gets created
302  * 
303  * 490   5/18/98 1:58a Mike
304  * Make Phoenix not be fired at fighters (but yes bombers).
305  * Improve positioning of ships in guard mode.
306  * Make turrets on player ship not fire near end of support ship docking.
307  * 
308  * 489   5/15/98 9:52a Allender
309  * added code to give Warning when orders accepted don't match the default
310  * orders
311  * 
312  * 488   5/13/98 4:41p Mike
313  * Make big ships try a tiny bit to avoid collision with each other when
314  * attacking another big ship.  Make ships a little less likely to collide
315  * into player when in formation, drop off if player flying wacky.
316  * 
317  * 487   5/13/98 3:07p Mitri
318  * fixed problem with checking current count of the mission against max
319  * ships per wing
320  * 
321  * 486   5/11/98 4:33p Allender
322  * fixed ingame join problems -- started to work on new object updating
323  * code (currently ifdef'ed out)
324  * 
325  * 485   5/08/98 5:05p Dave
326  * Go to the join game screen when quitting multiplayer. Fixed mission
327  * text chat bugs. Put mission type symbols on the create game list.
328  * Started updating standalone gui controls.
329  *
330  * $NoKeywords: $
331  */
332
333 #include        <stdio.h>
334 #include <stdlib.h>
335 #include <string.h>
336 #include <assert.h>
337 #include <stdarg.h>
338 #include <setjmp.h>
339
340 #include "freespace.h"
341 #include "parselo.h"
342 #include "missionparse.h"
343 #include "missiongoals.h"
344 #include "missionlog.h"
345 #include "missionmessage.h"
346 #include "sexp.h"
347 #include "linklist.h"
348 #include "timer.h"
349 #include "ship.h"
350 #include "ai.h"
351 #include "aigoals.h"
352 #include "player.h"
353 #include "starfield.h"
354 #include "bmpman.h"
355 #include "lighting.h"
356 #include "eventmusic.h"
357 #include "missionbriefcommon.h"
358 #include "multi.h"
359 #include "multiutil.h"
360 #include "multimsgs.h"
361 #include "shipfx.h"
362 #include "debris.h"
363 #include "cfile.h"
364 #include "fireballs.h"
365 #include "gamesnd.h"
366 #include "gamesequence.h"
367 #include "medals.h"
368 #include "nebula.h"
369 #include "palman.h"
370 #include "hudets.h"
371 #include "missionhotkey.h"
372 #include "hudescort.h"
373 #include "asteroid.h"
374 #include "shiphit.h"
375 #include "staticrand.h"
376 #include "missioncmdbrief.h"
377 #include "redalert.h"
378 #include "multi_respawn.h"
379 #include "hudwingmanstatus.h"
380 #include "jumpnode.h"
381 #include "multi_endgame.h"
382 #include "localize.h"
383 #include "neb.h"
384 #include "demo.h"
385 #include "neblightning.h"
386 #include "fvi.h"
387
388 static struct {
389         p_object *docker;
390         char dockee[NAME_LENGTH];
391         char docker_point[NAME_LENGTH];
392         char dockee_point[NAME_LENGTH];
393 } Initially_docked[MAX_SHIPS];
394
395 int Total_initially_docked;
396
397 mission The_mission;
398 char Mission_filename[80];
399
400 int Mission_palette;  // index into Nebula_palette_filenames[] of palette file to use for mission
401 int Nebula_index;  // index into Nebula_filenames[] of nebula to use in mission.
402 int Num_iff = MAX_IFF;
403 int Num_ai_behaviors = MAX_AI_BEHAVIORS;
404 int Num_cargo = 0;
405 int Num_status_names = MAX_STATUS_NAMES;
406 int Num_arrival_names = MAX_ARRIVAL_NAMES;
407 int Num_goal_type_names = MAX_GOAL_TYPE_NAMES;
408 int Num_team_names = MAX_TEAM_NAMES;
409 int Num_parse_goals;
410 int Player_starts = 1;
411 int Num_teams;
412 fix Entry_delay_time;
413
414 ushort Current_file_checksum = 0;
415 ushort Last_file_checksum = 0;
416 int    Current_file_length   = 0;
417
418 // alternate ship type names
419 char Mission_alt_types[MAX_ALT_TYPE_NAMES][NAME_LENGTH];
420 int Mission_alt_type_count = 0;
421
422 #define SHIP_WARP_TIME 5.0f             // how many seconds it takes for ship to warp in
423
424 // the ship arrival list will contain a list of ships that are yet to arrive.  This
425 // list could also include ships that are part of wings!
426
427 p_object        ship_arrivals[MAX_SHIP_ARRIVALS], ship_arrival_list;            // for linked list of ships to arrive later
428 int             num_ship_arrivals;
429
430 #define MAX_SHIP_ORIGINAL                       100
431 p_object ship_original[MAX_SHIP_ORIGINAL];
432 int             num_ship_original;
433
434 // list for arriving support ship
435 p_object        Support_ship_pobj;
436 p_object *Arriving_support_ship;
437 char Arriving_repair_targets[MAX_AI_GOALS][NAME_LENGTH];
438 int Num_arriving_repair_targets;
439
440 subsys_status Subsys_status[MAX_SUBSYS_STATUS];
441 int             Subsys_index;
442
443 char Mission_parse_storm_name[NAME_LENGTH] = "none";
444
445 team_data Team_data[MAX_TEAMS];
446
447 // variables for player start in single player
448 char            Player_start_shipname[NAME_LENGTH];
449 int             Player_start_shipnum;
450 p_object Player_start_pobject;
451
452 // name of all ships to use while parsing a mission (since a ship might be referenced by
453 // something before that ship has even been loaded yet)
454 char Parse_names[MAX_SHIPS + MAX_WINGS][NAME_LENGTH];
455 int Num_parse_names;
456
457 //XSTR:OFF
458
459 const char *Nebula_filenames[NUM_NEBULAS] = {
460         "Nebula01",
461         "Nebula02",
462         "Nebula03"      
463 };
464
465 const char *Neb2_filenames[NUM_NEBULAS] = {
466         "Nebfull01",
467         "Nebfull02",
468         "Nebfull03"
469 };
470
471 // Note: Nebula_colors[] and Nebula_palette_filenames are linked via index numbers
472 const char *Nebula_colors[NUM_NEBULA_COLORS] = {
473         "Red",
474         "Blue",
475         "Gold",
476         "Purple",
477         "Maroon",
478         "Green",
479         "Grey blue",
480         "Violet",
481         "Grey Green",
482 };
483
484 const char *Iff_names[MAX_IFF] = { "IFF 1", "IFF 2", "IFF 3" };
485
486 const char *Ai_behavior_names[MAX_AI_BEHAVIORS] = {
487         "Chase",
488         "Evade",
489         "Get behind",
490         "Stay Near",
491         "Still",
492         "Guard",
493         "Avoid",
494         "Waypoints",
495         "Dock",
496         "None",
497         "Big Ship",
498         "Path",
499         "Be Rearmed",
500         "Safety",
501         "Evade Weapon",
502         "Strafe",
503         "Play Dead",
504         "Bay Emerge",
505         "Bay Depart",
506         "Sentry Gun",
507         "Warp Out"
508 };
509
510 char *Cargo_names[MAX_CARGO];
511 char Cargo_names_buf[MAX_CARGO][NAME_LENGTH];
512
513 char *Ship_class_names[MAX_SHIP_TYPES];         // to be filled in from Ship_info array
514
515 const char *Icon_names[MAX_BRIEF_ICONS] = {
516         "Fighter", "Fighter Wing", "Cargo", "Cargo Wing", "Largeship",
517         "Largeship Wing", "Capital", "Planet", "Asteroid Field", "Waypoint",
518         "Support Ship", "Freighter(no cargo)", "Freighter(has cargo)",
519         "Freighter Wing(no cargo)", "Freighter Wing(has cargo)", "Installation",
520         "Bomber", "Bomber Wing", "Cruiser", "Cruiser Wing", "Unknown", "Unknown Wing",
521         "Player Fighter", "Player Fighter Wing", "Player Bomber", "Player Bomber Wing", 
522 #ifdef MAKE_FS1
523         "Jump Node"
524 #else
525         "Knossos Device", "Transport Wing", "Corvette", "Gas Miner", "Awacs", "Supercap", "Sentry Gun", "Jump Node", "Transport"
526 #endif
527 };
528
529 //      Translate team mask values like TEAM_FRIENDLY to indices in Team_names array.
530 //      -1 means an illegal value.
531 int     Team_names_index_xlate[MAX_TEAM_NAMES_INDEX+1] = {-1, 0, 1, -1, 2, -1, -1, -1, 3};
532
533 const char *Team_names[MAX_TEAM_NAMES] = {
534         "Hostile", "Friendly", "Neutral", "Unknown",
535 };
536
537 const char *Status_desc_names[MAX_STATUS_NAMES] = {
538         "Shields Critical", "Engines Damaged", "Fully Operational",
539 };
540
541 const char *Status_type_names[MAX_STATUS_NAMES] = {
542         "Damaged", "Disabled", "Corroded",
543 };
544
545 const char *Status_target_names[MAX_STATUS_NAMES] = {
546         "Weapons", "Engines", "Cable TV",
547 };
548
549 // definitions for arrival locations for ships/wings
550 const char *Arrival_location_names[MAX_ARRIVAL_NAMES] = {
551         "Hyperspace", "Near Ship", "In front of ship", "Docking Bay",
552 };
553
554 const char *Special_arrival_anchor_names[MAX_SPECIAL_ARRIVAL_ANCHORS] =
555 {
556         "<any friendly>",
557         "<any enemy>",
558         "<any neutral>",
559         "<any friendly player>",
560         "<any hostile player>",
561         "<any neutral player>",
562 };
563
564 const char *Departure_location_names[MAX_ARRIVAL_NAMES] = {
565         "Hyperspace", "Docking Bay",
566 };
567
568 const char *Goal_type_names[MAX_GOAL_TYPE_NAMES] = {
569         "Primary", "Secondary", "Bonus",
570 };
571
572 const char *Species_names[MAX_SPECIES_NAMES] = {
573         "Terran", "Vasudan", "Shivan",
574 };
575
576 const char *Reinforcement_type_names[] = {
577         "Attack/Protect",
578         "Repair/Rearm",
579 };
580
581 const char *Old_game_types[OLD_MAX_GAME_TYPES] = {
582         "Single Player Only",   
583         "Multiplayer Only",
584         "Single/Multi Player",
585         "Training mission"
586 };
587
588 const char *Parse_object_flags[MAX_PARSE_OBJECT_FLAGS] = {
589         "cargo-known",
590         "ignore-count",
591         "protect-ship",
592         "reinforcement",
593         "no-shields",
594         "escort",
595         "player-start",
596         "no-arrival-music",
597         "no-arrival-warp",
598         "no-departure-warp",
599         "locked",
600         "invulnerable",
601         "hidden-from-sensors",
602         "scannable",
603         "kamikaze",
604         "no-dynamic",
605         "red-alert-carry",
606         "beam-protect-ship",
607         "guardian",
608         "special-warp"
609 };
610
611 const char *Starting_wing_names[MAX_STARTING_WINGS+1] = {
612         "Alpha",
613         "Beta",
614         "Gamma",
615         "Zeta"
616 };
617
618 //XSTR:ON
619
620 int Num_reinforcement_type_names = sizeof(Reinforcement_type_names) / sizeof(char *);
621
622 vector Parse_viewer_pos;
623 matrix Parse_viewer_orient;
624
625 // definitions for timestamps for eval'ing arrival/departure cues
626 int Mission_arrival_timestamp;
627 int Mission_departure_timestamp;
628 fix Mission_end_time;
629
630 #define ARRIVAL_TIMESTAMP               2000            // every 2 seconds
631 #define DEPARTURE_TIMESTAMP     2200            // every 2.2 seconds -- just to be a little different
632
633 // calculates a "unique" file signature as a ushort (checksum) and an int (file length)
634 // the amount of The_mission we're going to checksum
635 // WARNING : do NOT call this function on the server - it will overwrite goals, etc
636 #define MISSION_CHECKSUM_SIZE (NAME_LENGTH + NAME_LENGTH + 4 + DATE_TIME_LENGTH + DATE_TIME_LENGTH)
637
638 // timers used to limit arrival messages and music
639 #define ARRIVAL_MUSIC_MIN_SEPARATION    60000
640 #define ARRIVAL_MESSAGE_MIN_SEPARATION 30000
641
642 #define ARRIVAL_MESSAGE_DELAY_MIN               2000
643 #define ARRIVAL_MESSAGE_DELAY_MAX               3000
644
645 static int Allow_arrival_music_timestamp;
646 static int Allow_arrival_message_timestamp;
647 static int Arrival_message_delay_timestamp;
648
649 // multi TvT
650 static int Allow_arrival_music_timestamp_m[2];
651 static int Allow_arrival_message_timestamp_m[2];
652 static int Arrival_message_delay_timestamp_m[2];
653
654 // local prototypes
655 void parse_player_info2(mission *pm);
656 void post_process_mission();
657 int allocate_subsys_status();
658 void parse_common_object_data(p_object  *objp);
659 void parse_asteroid_fields(mission *pm);
660 int mission_set_arrival_location(int anchor, int location, int distance, int objnum, vector *new_pos, matrix *new_orient);
661 int get_parse_name_index(const char *name);
662 int get_anchor(char *name);
663 void mission_parse_do_initial_docks();
664 void mission_parse_set_arrival_locations();
665 void mission_set_wing_arrival_location( wing *wingp, int num_to_set );
666 int parse_lookup_alt_name(char *name);
667
668 void parse_mission_info(mission *pm)
669 {
670         int i;
671         char game_string[NAME_LENGTH];
672
673         required_string("#Mission Info");
674         
675         required_string("$Version:");
676         stuff_float(&pm->version);
677         if (pm->version != MISSION_VERSION)
678                 mprintf(("Older mission, should update it (%.2f<-->%.2f)", pm->version, MISSION_VERSION));
679
680         required_string("$Name:");
681         stuff_string(pm->name, F_NAME, NULL);
682
683         required_string("$Author:");
684         stuff_string(pm->author, F_NAME, NULL);
685
686         required_string("$Created:");
687         stuff_string(pm->created, F_DATE, NULL);
688
689         required_string("$Modified:");
690         stuff_string(pm->modified, F_DATE, NULL);
691
692         required_string("$Notes:");
693         stuff_string(pm->notes, F_NOTES, NULL);
694
695         if (optional_string("$Mission Desc:"))
696                 stuff_string(pm->mission_desc, F_MULTITEXT, NULL, MISSION_DESC_LENGTH);
697         else
698                 SDL_strlcpy(pm->mission_desc, NOX("No description\n"), sizeof(pm->mission_desc));
699
700         pm->game_type = MISSION_TYPE_SINGLE;                            // default to single player only
701         if ( optional_string("+Game Type:")) {
702                 // HACK HACK HACK -- stuff_string was changed to *not* ignore carriage returns.  Since the
703                 // old style missions may have carriage returns, deal with it here.
704                 ignore_white_space();
705                 stuff_string(game_string, F_NAME, NULL);
706                 for ( i = 0; i < OLD_MAX_GAME_TYPES; i++ ) {
707                         if ( !SDL_strcasecmp(game_string, Old_game_types[i]) ) {
708
709                                 // this block of code is now old mission compatibility code.  We specify game
710                                 // type in a different manner than before.
711                                 if ( i == OLD_GAME_TYPE_SINGLE_ONLY )
712                                         pm->game_type = MISSION_TYPE_SINGLE;
713                                 else if ( i == OLD_GAME_TYPE_MULTI_ONLY )
714                                         pm->game_type = MISSION_TYPE_MULTI;
715                                 else if ( i == OLD_GAME_TYPE_SINGLE_MULTI )
716                                         pm->game_type = (MISSION_TYPE_SINGLE | MISSION_TYPE_MULTI );
717                                 else if ( i == OLD_GAME_TYPE_TRAINING )
718                                         pm->game_type = MISSION_TYPE_TRAINING;
719                                 else
720                                         Int3();
721
722                                 if ( pm->game_type & MISSION_TYPE_MULTI )
723                                         pm->game_type |= MISSION_TYPE_MULTI_COOP;
724
725                                 break;
726                         }
727                 }
728         }
729
730         if ( optional_string("+Game Type Flags:") ) {
731                 stuff_int(&pm->game_type);
732         }
733
734         pm->flags = 0;
735         if (optional_string("+Flags:")){
736                 stuff_int(&pm->flags);
737         }
738
739         // nebula mission stuff
740         Neb2_awacs = -1.0f;
741         if(optional_string("+NebAwacs:")){
742                 if(pm->flags & MISSION_FLAG_FULLNEB){
743                         stuff_float(&Neb2_awacs);
744                 } else {
745                         float temp;
746                         stuff_float(&temp);
747                 }
748         }
749         if(optional_string("+Storm:")){
750                 stuff_string(Mission_parse_storm_name, F_NAME, NULL);
751                 nebl_set_storm(Mission_parse_storm_name);
752         }
753
754         // get the number of players if in a multiplayer mission
755         pm->num_players = 1;
756         if ( pm->game_type & MISSION_TYPE_MULTI ) {
757                 if ( optional_string("+Num Players:") ) {
758                         stuff_int( &(pm->num_players) );
759                 }
760         }
761
762         // get the number of respawns
763         pm->num_respawns = 0;
764         if ( pm->game_type & MISSION_TYPE_MULTI ) {
765                 if ( optional_string("+Num Respawns:") ){
766                         stuff_int( (int*)&(pm->num_respawns) );
767                 }
768         }
769
770         pm->red_alert = 0;
771         if ( optional_string("+Red Alert:")) {
772                 stuff_int(&pm->red_alert);
773         } 
774         red_alert_set_status(pm->red_alert);
775
776         pm->scramble = 0;
777         if ( optional_string("+Scramble:")) {
778                 stuff_int(&pm->scramble);
779         }
780
781         pm->disallow_support = 0;
782         if ( optional_string("+Disallow Support:")) {
783                 stuff_int(&pm->disallow_support);
784         }
785
786         if (optional_string("+All Teams Attack")){
787                 Mission_all_attack = 1;
788         } else {
789                 Mission_all_attack = 0;
790         }
791
792         //      Maybe delay the player's entry.
793         if (optional_string("+Player Entry Delay:")) {
794                 float   temp;
795                 
796                 stuff_float(&temp);
797                 SDL_assert(temp >= 0.0f);
798                 Entry_delay_time = fl2f(temp);
799         }
800
801         if (optional_string("+Viewer pos:")){
802                 stuff_vector(&Parse_viewer_pos);
803         }
804
805         if (optional_string("+Viewer orient:")){
806                 stuff_matrix(&Parse_viewer_orient);
807         }
808
809         // possible squadron reassignment
810         SDL_strlcpy(The_mission.squad_name, "", sizeof(The_mission.squad_name));
811         SDL_strlcpy(The_mission.squad_filename, "", sizeof(The_mission.squad_filename));
812         if(optional_string("+SquadReassignName:")){
813                 stuff_string(The_mission.squad_name, F_NAME, NULL);
814                 if(optional_string("+SquadReassignLogo:")){
815                         stuff_string(The_mission.squad_filename, F_NAME, NULL);
816                 }
817         }       
818         // always clear out squad reassignments if not single player
819         if(Game_mode & GM_MULTIPLAYER){
820                 SDL_strlcpy(The_mission.squad_name, "", sizeof(The_mission.squad_name));
821                 SDL_strlcpy(The_mission.squad_filename, "", sizeof(The_mission.squad_filename));
822                 mprintf(("Ignoring squadron reassignment"));
823         }
824         // reassign the player
825         else {          
826                 if(!Fred_running && (Player != NULL) && (strlen(The_mission.squad_name) > 0) && (Game_mode & GM_CAMPAIGN_MODE)){
827                         mprintf(("Reassigning player to squadron %s\n", The_mission.squad_name));
828                         player_set_squad(Player, The_mission.squad_name);
829                         player_set_squad_bitmap(Player, The_mission.squad_filename);
830                 }
831         }
832
833         // set up the Num_teams variable accoriding to the game_type variable'
834         Num_teams = 1;                          // assume 1
835
836         // multiplayer team v. team games have two teams.  If we have three teams, we need to use
837         // a new mission mode!
838         if ( (pm->game_type & MISSION_TYPE_MULTI) && (pm->game_type & MISSION_TYPE_MULTI_TEAMS) ){
839                 Num_teams = 2;
840         }
841 }
842
843 void parse_player_info(mission *pm)
844 {
845         char alt[NAME_LENGTH + 2] = "";
846         SDL_assert(pm != NULL);
847
848 // alternate type names begin here      
849         mission_parse_reset_alt();
850         if(optional_string("#Alternate Types:")){               
851                 // read them all in
852                 while(!optional_string("#end")){
853                         required_string("$Alt:");
854                         stuff_string(alt, F_NAME, NULL, NAME_LENGTH);
855
856                         // maybe store it
857                         mission_parse_add_alt(alt);                     
858                 }
859         }
860         
861         Player_starts = 0;
862         required_string("#Players");
863
864         while (required_string_either("#Objects", "$")){
865                 parse_player_info2(pm);
866         }
867 }
868
869 void parse_player_info2(mission *pm)
870 {
871         char str[NAME_LENGTH];
872         int nt, i, total, list[MAX_SHIP_TYPES * 2], list2[MAX_WEAPON_TYPES * 2];
873         team_data *ptr;
874         char starting_wings[MAX_PLAYER_WINGS][NAME_LENGTH];
875
876         // read in a ship/weapon pool for each team.
877         for ( nt = 0; nt < Num_teams; nt++ ) {
878                 int num_ship_choices;
879
880                 ptr = &Team_data[nt];
881                 // get the shipname for single player missions
882                 // MWA -- make this required later!!!!
883                 if ( optional_string("$Starting Shipname:") )
884                         stuff_string( Player_start_shipname, F_NAME, NULL );
885
886                 required_string("$Ship Choices:");
887                 total = stuff_int_list(list, MAX_SHIP_TYPES * 2, SHIP_INFO_TYPE);
888
889                 SDL_assert(!(total & 0x01));  // make sure we have an even count
890
891                 num_ship_choices = 0;
892                 total /= 2;                                                     // there are only 1/2 the ships really on the list.
893                 for (i=0; i<total; i++) {
894                         // in a campaign, see if the player is allowed the ships or not.  Remove them from the
895                         // pool if they are not allowed
896                         if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
897                                 if ( !Campaign.ships_allowed[list[i*2]] )
898                                         continue;
899                         }
900
901                         ptr->ship_list[num_ship_choices] = list[i * 2];
902                         ptr->ship_count[num_ship_choices] = list[i * 2 + 1];
903                         num_ship_choices++;
904                 }
905                 ptr->number_choices = num_ship_choices;
906
907                 // --- obsolete data, parsing remains for compatibility reasons ---
908                 if (optional_string("+Starting Wings:"))
909                         stuff_string_list(starting_wings, MAX_PLAYER_WINGS);
910
911                 ptr->default_ship = -1;
912                 if (optional_string("+Default_ship:")) {
913                         stuff_string(str, F_NAME, NULL);
914                         ptr->default_ship = ship_info_lookup(str);
915                         // see if the player's default ship is an allowable ship (campaign only). If not, then what
916                         // do we do?  choose the first allowable one?
917                         if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
918                                 if ( !(Campaign.ships_allowed[ptr->default_ship]) ) {
919                                         for (i = 0; i < MAX_SHIP_TYPES; i++ ) {
920                                                 if ( Campaign.ships_allowed[ptr->default_ship] ) {
921                                                         ptr->default_ship = i;
922                                                         break;
923                                                 }
924                                         }
925                                         SDL_assert( i < MAX_SHIP_TYPES );
926                                 }
927                         }
928                 }
929
930                 if (ptr->default_ship == -1)  // invalid or not specified, make first in list
931                         ptr->default_ship = ptr->ship_list[0];
932
933                 for (i=0; i<MAX_WEAPON_TYPES; i++)
934                         ptr->weaponry_pool[i] = 0;
935
936                 if (optional_string("+Weaponry Pool:")) {
937                         total = stuff_int_list(list2, MAX_WEAPON_TYPES * 2, WEAPON_POOL_TYPE);
938
939                         SDL_assert(!(total & 0x01));  // make sure we have an even count
940                         total /= 2;
941                         for (i=0; i<total; i++) {
942                                 // in a campaign, see if the player is allowed the weapons or not.  Remove them from the
943                                 // pool if they are not allowed
944                                 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
945                                         if ( !Campaign.weapons_allowed[list2[i*2]] )
946                                                 continue;
947                                 }
948
949                                 if ((list2[i * 2] >= 0) && (list2[i * 2] < MAX_WEAPON_TYPES))
950                                         ptr->weaponry_pool[list2[i * 2]] = list2[i * 2 + 1];
951                         }
952                 }
953         }
954
955         if ( nt != Num_teams )
956                 Error(LOCATION, "Not enough ship/weapon pools for mission.  There are %d teams and only %d pools.", Num_teams, nt);
957 }
958
959 void parse_plot_info(mission *pm)
960 {
961         required_string("#Plot Info");
962
963         required_string("$Tour:");
964         stuff_string(pm->tour_name, F_NAME, NULL);
965
966         required_string("$Pre-Briefing Cutscene:");
967         stuff_string(pm->pre_briefing_cutscene, F_FILESPEC, NULL);
968
969         required_string("$Pre-Mission Cutscene:");
970         stuff_string(pm->pre_mission_cutscene, F_FILESPEC, NULL);
971
972         required_string("$Next Mission Success:");
973         stuff_string(pm->next_mission_success, F_NAME, NULL);
974
975         required_string("$Next Mission Partial:");
976         stuff_string(pm->next_mission_partial, F_NAME, NULL);
977
978         required_string("$Next Mission Failure:");
979         stuff_string(pm->next_mission_failure, F_NAME, NULL);
980 }
981
982 void parse_briefing_info(mission *pm)
983 {
984         char junk[4096];
985
986         if ( !optional_string("#Briefing Info") )
987                 return;
988
989         required_string("$Briefing Voice 1:");
990         stuff_string(junk, F_FILESPEC, NULL);
991
992         required_string("$Briefing Text 1:");
993         stuff_string(junk, F_MULTITEXTOLD, NULL);
994
995         required_string("$Briefing Voice 2:");
996         stuff_string(junk, F_FILESPEC, NULL);
997
998         required_string("$Briefing Text 2:");
999         stuff_string(junk, F_MULTITEXTOLD, NULL);
1000
1001         required_string("$Briefing Voice 3:");
1002         stuff_string(junk, F_FILESPEC, NULL);
1003
1004         required_string("$Briefing Text 3:");
1005         stuff_string(junk, F_MULTITEXTOLD, NULL);
1006
1007         required_string("$Debriefing Voice 1:");
1008         stuff_string(junk, F_FILESPEC, NULL);
1009
1010         required_string("$Debriefing Text 1:");
1011         stuff_string(junk, F_MULTITEXTOLD, NULL);
1012
1013         required_string("$Debriefing Voice 2:");
1014         stuff_string(junk, F_FILESPEC, NULL);
1015
1016         required_string("$Debriefing Text 2:");
1017         stuff_string(junk, F_MULTITEXTOLD, NULL);
1018
1019         required_string("$Debriefing Voice 3:");
1020         stuff_string(junk, F_FILESPEC, NULL);
1021
1022         required_string("$Debriefing Text 3:");
1023         stuff_string(junk, F_MULTITEXTOLD, NULL);
1024 }
1025
1026 // parse the event music and briefing music for the mission
1027 void parse_music(mission *pm)
1028 {
1029         char    name[NAME_LENGTH];
1030
1031         event_music_reset_choices();
1032
1033         if ( !optional_string("#Music") ) {
1034                 return;
1035         }
1036
1037         required_string("$Event Music:");
1038         stuff_string(name, F_NAME, NULL);
1039         event_music_set_soundtrack(name);
1040
1041         required_string("$Briefing Music:");
1042         stuff_string(name, F_NAME, NULL);
1043         event_music_set_score(SCORE_BRIEFING, name);
1044
1045         if ( optional_string("$Debriefing Success Music:") ) {
1046                 stuff_string(name, F_NAME, NULL);
1047                 event_music_set_score(SCORE_DEBRIEF_SUCCESS, name);
1048         }
1049
1050         if ( optional_string("$Debriefing Fail Music:") ) {
1051                 stuff_string(name, F_NAME, NULL);
1052                 event_music_set_score(SCORE_DEBRIEF_FAIL, name);
1053         }
1054 }
1055
1056 void parse_cmd_brief(mission *pm)
1057 {
1058         int stage;
1059
1060         SDL_assert(!Cur_cmd_brief->num_stages);
1061         stage = 0;
1062
1063         required_string("#Command Briefing");
1064         while (optional_string("$Stage Text:")) {
1065                 SDL_assert(stage < CMD_BRIEF_STAGES_MAX);
1066                 Cur_cmd_brief->stage[stage].text = stuff_and_malloc_string(F_MULTITEXT, NULL, CMD_BRIEF_TEXT_MAX);
1067                 SDL_assert(Cur_cmd_brief->stage[stage].text);
1068
1069                 required_string("$Ani Filename:");
1070                 stuff_string(Cur_cmd_brief->stage[stage].ani_filename, F_FILESPEC, NULL);
1071                 if (optional_string("+Wave Filename:"))
1072                         stuff_string(Cur_cmd_brief->stage[stage].wave_filename, F_FILESPEC, NULL);
1073                 else
1074                         Cur_cmd_brief->stage[stage].wave_filename[0] = 0;
1075
1076                 stage++;
1077         }
1078
1079         Cur_cmd_brief->num_stages = stage;
1080 }
1081
1082 void parse_cmd_briefs(mission *pm)
1083 {
1084         int i;
1085
1086         cmd_brief_reset();
1087         // a hack follows because old missions don't have a command briefing
1088         if (required_string_either("#Command Briefing", "#Briefing"))
1089                 return;
1090
1091         for (i=0; i<Num_teams; i++) {
1092                 Cur_cmd_brief = &Cmd_briefs[i];
1093                 parse_cmd_brief(pm);
1094         }
1095 }
1096
1097 // -------------------------------------------------------------------------------------------------
1098 // parse_briefing()
1099 //
1100 // Parse the data required for the mission briefing
1101 //
1102 // NOTE: This updates the global Briefing struct with all the data necessary to drive the briefing
1103 //
1104 void parse_briefing(mission *pm)
1105 {
1106         int nt, i, j, stage_num = 0, icon_num = 0, team_index;
1107         brief_stage *bs;
1108         brief_icon *bi;
1109         briefing *bp;
1110
1111         char not_used_text[MAX_ICON_TEXT_LEN];
1112         
1113         brief_reset();
1114
1115         // MWA -- 2/3/98.  we can now have multiple briefing and debreifings in a mission
1116         for ( nt = 0; nt < Num_teams; nt++ ) {
1117                 if ( !optional_string("#Briefing") )
1118                         break;
1119
1120                 bp = &Briefings[nt];
1121
1122                 required_string("$start_briefing");
1123                 required_string("$num_stages:");
1124                 stuff_int(&bp->num_stages);
1125                 SDL_assert(bp->num_stages <= MAX_BRIEF_STAGES);
1126
1127                 stage_num = 0;
1128                 while (required_string_either("$end_briefing", "$start_stage")) {
1129                         required_string("$start_stage");
1130                         SDL_assert(stage_num < MAX_BRIEF_STAGES);
1131                         bs = &bp->stages[stage_num++];
1132                         required_string("$multi_text");
1133                         if ( Fred_running )     {
1134                                 stuff_string(bs->new_text, F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1135                         } else {
1136                                 bs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1137                         }
1138                         required_string("$voice:");
1139                         stuff_string(bs->voice, F_FILESPEC, NULL);
1140                         required_string("$camera_pos:");
1141                         stuff_vector(&bs->camera_pos);
1142                         required_string("$camera_orient:");
1143                         stuff_matrix(&bs->camera_orient);
1144                         required_string("$camera_time:");
1145                         stuff_int(&bs->camera_time);
1146
1147                         if ( optional_string("$num_lines:") ) {
1148                                 stuff_int(&bs->num_lines);
1149
1150                                 if ( Fred_running )     {
1151                                         SDL_assert(bs->lines!=NULL);
1152                                 } else {
1153                                         if ( bs->num_lines > 0 )        {
1154                                                 bs->lines = (brief_line *)malloc(sizeof(brief_line)*bs->num_lines);
1155                                                 SDL_assert(bs->lines!=NULL);
1156                                         }
1157                                 }
1158
1159                                 for (i=0; i<bs->num_lines; i++) {
1160                                         required_string("$line_start:");
1161                                         stuff_int(&bs->lines[i].start_icon);
1162                                         required_string("$line_end:");
1163                                         stuff_int(&bs->lines[i].end_icon);
1164                                 }
1165                         }
1166                         else {
1167                                 bs->num_lines = 0;
1168                         }
1169
1170                         required_string("$num_icons:");
1171                         stuff_int(&bs->num_icons);
1172
1173                         if ( Fred_running )     {
1174                                 SDL_assert(bs->lines!=NULL);
1175                         } else {
1176                                 if ( bs->num_icons > 0 )        {
1177                                         bs->icons = (brief_icon *)malloc(sizeof(brief_icon)*bs->num_icons);
1178                                         SDL_assert(bs->icons!=NULL);
1179                                 }
1180                         }
1181
1182                         if ( optional_string("$flags:") )
1183                                 stuff_int(&bs->flags);
1184                         else
1185                                 bs->flags = 0;
1186
1187                         if ( optional_string("$formula:") )
1188                                 bs->formula = get_sexp_main();
1189                         else
1190                                 bs->formula = Locked_sexp_true;
1191
1192                         SDL_assert(bs->num_icons <= MAX_STAGE_ICONS );
1193
1194                         while (required_string_either("$end_stage", "$start_icon")) {
1195                                 required_string("$start_icon");
1196                                 SDL_assert(icon_num < MAX_STAGE_ICONS);
1197                                 bi = &bs->icons[icon_num++];
1198
1199                                 required_string("$type:");
1200                                 stuff_int(&bi->type);
1201
1202                                 find_and_stuff("$team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1203                                 SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1204                                 bi->team = 1 << team_index;
1205
1206                                 find_and_stuff("$class:", &bi->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1207
1208                                 required_string("$pos:");
1209                                 stuff_vector(&bi->pos);
1210
1211                                 bi->label[0] = 0;
1212                                 if (optional_string("$label:"))
1213                                         stuff_string(bi->label, F_MESSAGE, NULL);
1214
1215                                 if (optional_string("+id:")) {
1216                                         stuff_int(&bi->id);
1217                                         if (bi->id >= Cur_brief_id)
1218                                                 Cur_brief_id = bi->id + 1;
1219
1220                                 } else {
1221                                         bi->id = -1;
1222                                         for (i=0; i<stage_num-1; i++)
1223                                                 for (j=0; j < bp->stages[i].num_icons; j++)
1224                                                 {
1225                                                         if (!SDL_strcasecmp(bp->stages[i].icons[j].label, bi->label))
1226                                                                 bi->id = bp->stages[i].icons[j].id;
1227                                                 }
1228
1229                                         if (bi->id < 0)
1230                                                 bi->id = Cur_brief_id++;
1231                                 }
1232
1233                                 required_string("$hlight:");
1234                                 int val;
1235                                 stuff_int(&val);
1236                                 if ( val>0 ) {
1237                                         bi->flags = BI_HIGHLIGHT;
1238                                 } else {
1239                                         bi->flags=0;
1240                                 }
1241
1242                                 required_string("$multi_text");
1243 //                              stuff_string(bi->text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1244                                 stuff_string(not_used_text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1245                                 required_string("$end_icon");
1246                         } // end while
1247                         SDL_assert(bs->num_icons == icon_num);
1248                         icon_num = 0;
1249                         required_string("$end_stage");
1250                 }       // end while
1251
1252                 SDL_assert(bp->num_stages == stage_num);
1253                 required_string("$end_briefing");
1254         }
1255
1256         if ( nt != Num_teams )
1257                 Error(LOCATION, "Not enough briefings in mission file.  There are %d teams and only %d briefings.", Num_teams, nt );
1258 }
1259
1260 // -------------------------------------------------------------------------------------------------
1261 // parse_debriefing_old()
1262 //
1263 // Parse the data required for the mission debriefings
1264 void parse_debriefing_old(mission *pm)
1265 {
1266         int     junk;
1267         char    waste[MAX_DEBRIEF_LEN];
1268         
1269         if ( !optional_string("#Debriefing") )
1270                 return;
1271
1272         required_string("$num_debriefings:");
1273         stuff_int(&junk);
1274
1275         while (required_string_either("#Players", "$start_debriefing")) {
1276                 required_string("$start_debriefing");
1277                 required_string("$formula:");
1278                 junk = get_sexp_main();
1279                 required_string("$num_stages:");
1280                 stuff_int(&junk);
1281                 while (required_string_either("$end_debriefing", "$start_stage")) {
1282                         required_string("$start_stage");
1283                         required_string("$multi_text");
1284                         stuff_string(waste, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1285                         required_string("$voice:");
1286                         stuff_string(waste, F_FILESPEC, NULL);
1287                         required_string("$end_stage");
1288                 } // end while
1289                 required_string("$end_debriefing");
1290         }       // end while
1291 }
1292
1293 // -------------------------------------------------------------------------------------------------
1294 // parse_debriefing_new()
1295 //
1296 // Parse the data required for the mission debriefings
1297 void parse_debriefing_new(mission *pm)
1298 {
1299         int                             stage_num, nt;
1300         debriefing              *db;
1301         debrief_stage   *dbs;
1302         
1303         debrief_reset();
1304
1305         // next code should be old -- hopefully not called anymore
1306         //if (!optional_string("#Debriefing_info")) {
1307         //      parse_debriefing_old(pm);
1308         //      return;
1309         //}
1310
1311         // 2/3/98 -- MWA.  We can now have multiple briefings and debriefings on a team
1312         for ( nt = 0; nt < Num_teams; nt++ ) {
1313
1314                 if ( !optional_string("#Debriefing_info") )
1315                         break;
1316
1317                 stage_num = 0;
1318
1319                 db = &Debriefings[nt];
1320
1321                 required_string("$Num stages:");
1322                 stuff_int(&db->num_stages);
1323                 SDL_assert(db->num_stages <= MAX_DEBRIEF_STAGES);
1324
1325                 while (required_string_either("#", "$Formula")) {
1326                         SDL_assert(stage_num < MAX_DEBRIEF_STAGES);
1327                         dbs = &db->stages[stage_num++];
1328                         required_string("$Formula:");
1329                         dbs->formula = get_sexp_main();
1330                         required_string("$multi text");
1331                         if ( Fred_running )     {
1332                                 stuff_string(dbs->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1333                         } else {
1334                                 dbs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1335                         }
1336                         required_string("$Voice:");
1337                         stuff_string(dbs->voice, F_FILESPEC, NULL);
1338                         required_string("$Recommendation text:");
1339                         if ( Fred_running )     {
1340                                 stuff_string( dbs->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1341                         } else {
1342                                 dbs->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1343                         }
1344                 } // end while
1345
1346                 SDL_assert(db->num_stages == stage_num);
1347         }
1348
1349         if ( nt != Num_teams )
1350                 Error(LOCATION, "Not enough debriefings for mission.  There are %d teams and only %d debriefings;\n", Num_teams, nt );
1351 }
1352
1353 void position_ship_for_knossos_warpin(p_object *objp, int shipnum, int objnum)
1354 {
1355         // Assume no valid knossos device
1356         Ships[shipnum].special_warp_objnum = -1;
1357
1358         // find knossos device
1359         int found = FALSE;
1360         ship_obj *so;
1361         int knossos_num = -1;
1362         for (so=GET_FIRST(&Ship_obj_list); so!=END_OF_LIST(&Ship_obj_list); so=GET_NEXT(so)) {
1363                 knossos_num = Objects[so->objnum].instance;
1364                 if (Ship_info[Ships[knossos_num].ship_info_index].flags & SIF_KNOSSOS_DEVICE) {
1365                         // be close to the right device [allow multiple knossos's
1366                         if (vm_vec_dist_quick(&Objects[knossos_num].pos, &objp->pos) < 2.0f*(Objects[knossos_num].radius + Objects[objnum].radius) ) {
1367                                 found = TRUE;
1368                                 break;
1369                         }
1370                 }
1371         }
1372
1373         if (found) {
1374                 // set ship special_warp_objnum
1375                 Ships[shipnum].special_warp_objnum = knossos_num;
1376
1377                 // position self for warp on plane of device
1378                 vector new_point;
1379                 float dist = fvi_ray_plane(&new_point, &Objects[knossos_num].pos, &Objects[knossos_num].orient.v.fvec, &objp->pos, &objp->orient.v.fvec, 0.0f);
1380                 polymodel *pm = model_get(Ship_info[Ships[shipnum].ship_info_index].modelnum);
1381                 float desired_dist = -pm->mins.xyz.z;
1382                 vm_vec_scale_add2(&Objects[objnum].pos, &Objects[objnum].orient.v.fvec, (dist - desired_dist));
1383                 // if ship is BIG or HUGE, make it go through the center of the knossos
1384                 if (Ship_info[Ships[shipnum].ship_info_index].flags & SIF_HUGE_SHIP) {
1385                         vector offset;
1386                         vm_vec_sub(&offset, &Objects[knossos_num].pos, &new_point);
1387                         vm_vec_add2(&Objects[objnum].pos, &offset);
1388                 }
1389         }
1390 }
1391
1392 //      Given a stuffed p_object struct, create an object and fill in the necessary fields.
1393 //      Return object number.
1394 int parse_create_object(p_object *objp)
1395 {
1396         int     i, j, k, objnum, shipnum;
1397         ai_info *aip;
1398         ship_subsys *ptr;
1399         ship_info *sip;
1400         subsys_status *sssp;
1401         ship_weapon *wp;
1402
1403         // base level creation
1404         objnum = ship_create(&objp->orient, &objp->pos, objp->ship_class);
1405         SDL_assert(objnum != -1);
1406         shipnum = Objects[objnum].instance;
1407
1408         // if arriving through knossos, adjust objpj->pos to plane of knossos and set flag
1409         // special warp is single player only
1410         if ((objp->flags & P_KNOSSOS_WARP_IN) && !(Game_mode & GM_MULTIPLAYER)) {
1411                 if (!Fred_running) {
1412                         position_ship_for_knossos_warpin(objp, shipnum, objnum);
1413                 }
1414         }
1415
1416         Ships[shipnum].group = objp->group;
1417         Ships[shipnum].team = objp->team;
1418         SDL_strlcpy(Ships[shipnum].ship_name, objp->name, sizeof(Ships[0].ship_name));
1419         Ships[shipnum].escort_priority = objp->escort_priority;
1420         Ships[shipnum].special_exp_index = objp->special_exp_index;
1421         Ships[shipnum].respawn_priority = objp->respawn_priority;
1422         // if this is a multiplayer dogfight game, and its from a player wing, make it team traitor
1423         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (objp->wingnum >= 0)){
1424                 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
1425                         if ( !SDL_strcasecmp(Starting_wing_names[i], Wings[objp->wingnum].name) ) {
1426                                 Ships[shipnum].team = TEAM_TRAITOR;
1427                         } 
1428                 }
1429         }
1430
1431         sip = &Ship_info[Ships[shipnum].ship_info_index];
1432
1433         if ( !Fred_running ) {
1434                 ship_assign_sound(&Ships[shipnum]);
1435         }
1436
1437         aip = &(Ai_info[Ships[shipnum].ai_index]);
1438         aip->behavior = objp->behavior;
1439         aip->mode = aip->behavior;
1440
1441         // alternate type name
1442         Ships[shipnum].alt_type_index = objp->alt_type_index;
1443
1444         aip->ai_class = objp->ai_class;
1445         Ships[shipnum].weapons.ai_class = objp->ai_class;  // Fred uses this instead of above.
1446
1447         // must reset the number of ai goals when the object is created
1448         for (i = 0; i < MAX_AI_GOALS; i++ ){
1449                 aip->goals[i].ai_mode = AI_GOAL_NONE;
1450         }
1451
1452         Ships[shipnum].cargo1 = objp->cargo1;
1453
1454         Ships[shipnum].arrival_location = objp->arrival_location;
1455         Ships[shipnum].arrival_distance = objp->arrival_distance;
1456         Ships[shipnum].arrival_anchor = objp->arrival_anchor;
1457         Ships[shipnum].arrival_cue = objp->arrival_cue;
1458         Ships[shipnum].arrival_delay = objp->arrival_delay;
1459         Ships[shipnum].departure_location = objp->departure_location;
1460         Ships[shipnum].departure_anchor = objp->departure_anchor;
1461         Ships[shipnum].departure_cue = objp->departure_cue;
1462         Ships[shipnum].departure_delay = objp->departure_delay;
1463         Ships[shipnum].determination = objp->determination;
1464         Ships[shipnum].wingnum = objp->wingnum;
1465         Ships[shipnum].hotkey = objp->hotkey;
1466         Ships[shipnum].score = objp->score;
1467         Ships[shipnum].persona_index = objp->persona_index;
1468
1469         // set the orders that this ship will accept.  It will have already been set to default from the
1470         // ship create code, so only set them if the parse object flags say they are unique
1471         if ( objp->flags & P_SF_USE_UNIQUE_ORDERS ) {
1472                 Ships[shipnum].orders_accepted = objp->orders_accepted;
1473
1474         // MWA  5/15/98 -- Added the following debug code because some orders that ships
1475         // will accept were apparently written out incorrectly with Fred.  This Int3() should
1476         // trap these instances.
1477 #ifndef NDEBUG
1478                 if ( Fred_running ) {
1479                         int default_orders, remaining_orders;
1480                         
1481                         default_orders = ship_get_default_orders_accepted( &Ship_info[Ships[shipnum].ship_info_index] );
1482                         remaining_orders = objp->orders_accepted & ~default_orders;
1483                         if ( remaining_orders ) {
1484                                 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", Ships[shipnum].ship_name);
1485                         }
1486                 }
1487 #endif
1488         }
1489         
1490         // check the parse object's flags for possible flags to set on this newly created ship
1491         if ( objp->flags & P_OF_PROTECTED ) {
1492                 Objects[objnum].flags |= OF_PROTECTED;
1493         }
1494
1495         if ( objp->flags & P_OF_BEAM_PROTECTED ) {
1496                 Objects[objnum].flags |= OF_BEAM_PROTECTED;
1497         }
1498
1499         if (objp->flags & P_OF_CARGO_KNOWN) {
1500                 Ships[shipnum].flags |= SF_CARGO_REVEALED;
1501         }
1502
1503         if ( objp->flags & P_SF_IGNORE_COUNT )
1504                 Ships[shipnum].flags |= SF_IGNORE_COUNT;
1505
1506         if ( objp->flags & P_SF_REINFORCEMENT )
1507                 Ships[shipnum].flags |= SF_REINFORCEMENT;
1508
1509         if (objp->flags & P_OF_NO_SHIELDS || sip->shields == 0 )
1510                 Objects[objnum].flags |= OF_NO_SHIELDS;
1511
1512         if (objp->flags & P_SF_ESCORT)
1513                 Ships[shipnum].flags |= SF_ESCORT;
1514
1515         if (objp->flags & P_KNOSSOS_WARP_IN) {
1516                 Objects[objnum].flags |= OF_SPECIAL_WARP;
1517         }
1518
1519         // don't set the flag if the mission is ongoing in a multiplayer situation. This will be set by the players in the
1520         // game only before the game or during respawning.
1521         // MWA -- changed the next line to remove the !(Game_mode & GM_MULTIPLAYER).  We shouldn't be setting
1522         // this flag in single player mode -- it gets set in post process mission.
1523         //if ((objp->flags & P_OF_PLAYER_START) && (((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION)) || !(Game_mode & GM_MULTIPLAYER)))
1524         if ( (objp->flags & P_OF_PLAYER_START) && (Fred_running || ((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION))) ) 
1525                 Objects[objnum].flags |= OF_PLAYER_SHIP;
1526
1527         if (objp->flags & P_SF_NO_ARRIVAL_MUSIC)
1528                 Ships[shipnum].flags |= SF_NO_ARRIVAL_MUSIC;
1529
1530         if ( objp->flags & P_SF_NO_ARRIVAL_WARP )
1531                 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1532
1533         if ( objp->flags & P_SF_NO_DEPARTURE_WARP )
1534                 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1535
1536         if ( objp->flags & P_SF_INITIALLY_DOCKED )
1537                 Ships[shipnum].flags |= SF_INITIALLY_DOCKED;
1538
1539         if ( objp->flags & P_SF_LOCKED )
1540                 Ships[shipnum].flags |= SF_LOCKED;
1541
1542         if ( objp->flags & P_SF_WARP_BROKEN )
1543                 Ships[shipnum].flags |= SF_WARP_BROKEN;
1544
1545         if ( objp->flags & P_SF_WARP_NEVER )
1546                 Ships[shipnum].flags |= SF_WARP_NEVER;
1547
1548         if ( objp->flags & P_SF_HIDDEN_FROM_SENSORS )
1549                 Ships[shipnum].flags |= SF_HIDDEN_FROM_SENSORS;
1550
1551         // if ship is in a wing, and the wing's no_warp_effect flag is set, then set the equivalent
1552         // flag for the ship
1553         if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_ARRIVAL_WARP) )
1554                 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1555
1556         if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_DEPARTURE_WARP) )
1557                 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1558
1559         // mwa -- 1/30/98.  Do both flags.  Fred uses the ship flag, and FreeSpace will use the object
1560         // flag. I'm to lazy at this point to deal with consolidating them.
1561         if ( objp->flags & P_SF_INVULNERABLE ) {
1562                 Ships[shipnum].flags |= SF_INVULNERABLE;
1563                 Objects[objnum].flags |= OF_INVULNERABLE;
1564         }
1565
1566         if ( objp->flags & P_SF_GUARDIAN ) {
1567                 Objects[objnum].flags |= OF_GUARDIAN;
1568         }
1569
1570         if ( objp->flags & P_SF_SCANNABLE )
1571                 Ships[shipnum].flags |= SF_SCANNABLE;
1572
1573         if ( objp->flags & P_SF_RED_ALERT_STORE_STATUS ){
1574                 SDL_assert(!(Game_mode & GM_MULTIPLAYER));
1575                 Ships[shipnum].flags |= SF_RED_ALERT_STORE_STATUS;
1576         }
1577
1578         // a couple of ai_info flags.  Also, do a reasonable default for the kamikaze damage regardless of
1579         // whether this flag is set or not
1580         if ( objp->flags & P_AIF_KAMIKAZE ) {
1581                 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_KAMIKAZE;
1582                 Ai_info[Ships[shipnum].ai_index].kamikaze_damage = objp->kamikaze_damage;
1583         }
1584
1585         if ( objp->flags & P_AIF_NO_DYNAMIC )
1586                 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_NO_DYNAMIC;
1587
1588         // if the wing index and wing pos are set for this parse object, set them for the ship.  This
1589         // is useful in multiplayer when ships respawn
1590         Ships[shipnum].wing_status_wing_index = objp->wing_status_wing_index;
1591         Ships[shipnum].wing_status_wing_pos = objp->wing_status_wing_pos;
1592
1593         // set up the ai_goals for this object -- all ships created here are AI controlled.
1594         if ( objp->ai_goals != -1 ) {
1595                 int sexp;
1596
1597                 for ( sexp = CDR(objp->ai_goals); sexp != -1; sexp = CDR(sexp) )
1598                         // make a call to the routine in MissionGoals.cpp to set up the ai goals for this object.
1599                         ai_add_ship_goal_sexp( sexp, AIG_TYPE_EVENT_SHIP, aip );
1600
1601                 if ( objp->wingnum == -1 )                      // free the sexpression nodes only for non-wing ships.  wing code will handle it's own case
1602                         free_sexp2(objp->ai_goals);     // free up sexp nodes for reused, since they aren't needed anymore.
1603         }
1604
1605         SDL_assert(Ships[shipnum].modelnum != -1);
1606
1607         // initialize subsystem statii here.  The subsystems are given a percentage damaged.  So a percent value
1608         // of 20% means that the subsystem is 20% damaged (*not* 20% of max hits).  This is opposite the way
1609         // that the initial velocity/hull strength/shields work
1610         i = objp->subsys_count;
1611         while (i--) {
1612                 sssp = &Subsys_status[objp->subsys_index + i];
1613                 if (!SDL_strcasecmp(sssp->name, NOX("Pilot"))) {
1614                         wp = &Ships[shipnum].weapons;
1615                         if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1616                                 for (j=k=0; j<MAX_PRIMARY_BANKS; j++) {
1617                                         if ( (sssp->primary_banks[j] >= 0) || Fred_running ){
1618                                                 wp->primary_bank_weapons[k] = sssp->primary_banks[j];                                           
1619
1620                                                 // next
1621                                                 k++;
1622                                         }
1623                                 }
1624
1625                                 if (Fred_running){
1626                                         wp->num_primary_banks = sip->num_primary_banks;
1627                                 } else {
1628                                         wp->num_primary_banks = k;
1629                                 }
1630                         }
1631
1632                         if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1633                                 for (j=k=0; j<MAX_SECONDARY_BANKS; j++) {
1634                                         if ( (sssp->secondary_banks[j] >= 0) || Fred_running ){
1635                                                 wp->secondary_bank_weapons[k++] = sssp->secondary_banks[j];
1636                                         }
1637                                 }
1638
1639                                 if (Fred_running){
1640                                         wp->num_secondary_banks = sip->num_secondary_banks;
1641                                 } else {
1642                                         wp->num_secondary_banks = k;
1643                                 }
1644                         }
1645
1646                         for (j=0; j < wp->num_secondary_banks; j++)
1647                                 if (Fred_running){
1648                                         wp->secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1649                                 } else {
1650                                         int capacity = fl2i(sssp->secondary_ammo[j]/100.0f * sip->secondary_bank_ammo_capacity[j] + 0.5f );
1651                                         wp->secondary_bank_ammo[j] = fl2i(capacity / Weapon_info[wp->secondary_bank_weapons[j]].cargo_size + 0.5f);
1652                                 }
1653                         continue;
1654                 }
1655
1656                 ptr = GET_FIRST(&Ships[shipnum].subsys_list);
1657                 while (ptr != END_OF_LIST(&Ships[shipnum].subsys_list)) {
1658                         if (!SDL_strcasecmp(ptr->system_info->subobj_name, sssp->name)) {
1659                                 if (Fred_running)
1660                                         ptr->current_hits = sssp->percent;
1661                                 else {
1662                                         float new_hits;
1663                                         new_hits = ptr->system_info->max_hits * (100.0f - sssp->percent) / 100.f;
1664                                         Ships[shipnum].subsys_info[ptr->system_info->type].current_hits -= (ptr->system_info->max_hits - new_hits);
1665                                         if ( (100.0f - sssp->percent) < 0.5) {
1666                                                 ptr->current_hits = 0.0f;
1667                                                 ptr->submodel_info_1.blown_off = 1;
1668                                         } else {
1669                                                 ptr->current_hits = new_hits;
1670                                         }
1671                                 }
1672
1673                                 if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1674                                         for (j=0; j<MAX_PRIMARY_BANKS; j++)
1675                                                 ptr->weapons.primary_bank_weapons[j] = sssp->primary_banks[j];
1676
1677                                 if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1678                                         for (j=0; j<MAX_SECONDARY_BANKS; j++)
1679                                                 ptr->weapons.secondary_bank_weapons[j] = sssp->secondary_banks[j];
1680
1681                                 for (j=0; j<MAX_SECONDARY_BANKS; j++) {
1682                                         // AL 3-5-98:  This is correct for FRED, but not for FreeSpace... but is this even used?
1683                                         //                                      As far as I know, turrets cannot run out of ammo
1684                                         ptr->weapons.secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1685                                 }
1686
1687                                 ptr->subsys_cargo_name = sssp->subsys_cargo_name;
1688
1689                                 if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
1690                                         ptr->weapons.ai_class = sssp->ai_class;
1691
1692                                 ai_turret_select_default_weapon(ptr);
1693                         }
1694
1695                         ptr = GET_NEXT(ptr);
1696                 }
1697         }
1698
1699         // initial hull strength, shields, and velocity are all expressed as a percentage of the max value/
1700         // so a initial_hull value of 90% means 90% of max.  This way is opposite of how subsystems are dealt
1701         // with
1702         if (Fred_running) {
1703                 Objects[objnum].phys_info.speed = (float) objp->initial_velocity;
1704                 // Ships[shipnum].hull_hit_points_taken = (float) objp->initial_hull;
1705                 Objects[objnum].hull_strength = (float) objp->initial_hull;
1706                 Objects[objnum].shields[0] = (float) objp->initial_shields;
1707
1708         } else {
1709                 int max_allowed_sparks, num_sparks, i;
1710                 polymodel *pm;
1711
1712                 // Ships[shipnum].hull_hit_points_taken = (float)objp->initial_hull * sip->max_hull_hit_points / 100.0f;
1713                 Objects[objnum].hull_strength = objp->initial_hull * sip->initial_hull_strength / 100.0f;
1714                 for (i = 0; i<MAX_SHIELD_SECTIONS; i++)
1715                         Objects[objnum].shields[i] = (float)(objp->initial_shields * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
1716
1717                 // initial velocities now do not apply to ships which warp in after mission starts
1718                 if ( !(Game_mode & GM_IN_MISSION) ) {
1719                         Objects[objnum].phys_info.speed = (float)objp->initial_velocity * sip->max_speed / 100.0f;
1720                         Objects[objnum].phys_info.vel.xyz.z = Objects[objnum].phys_info.speed;
1721                         Objects[objnum].phys_info.prev_ramp_vel = Objects[objnum].phys_info.vel;
1722                         Objects[objnum].phys_info.desired_vel = Objects[objnum].phys_info.vel;
1723                 }
1724
1725                 // recalculate damage of subsystems
1726                 ship_recalc_subsys_strength( &Ships[shipnum] );
1727
1728                 // create sparks on a ship whose hull is damaged.  We will create two sparks for every 20%
1729                 // of hull damage done.  100 means no sparks.  between 80 and 100 do two sparks.  60 and 80 is
1730                 // four, etc.
1731                 pm = model_get( sip->modelnum );
1732                 max_allowed_sparks = get_max_sparks(&Objects[objnum]);
1733                 num_sparks = (int)((100.0f - objp->initial_hull) / 5.0f);
1734                 if (num_sparks > max_allowed_sparks) {
1735                         num_sparks = max_allowed_sparks;
1736                 }
1737
1738                 for (i = 0; i < num_sparks; i++ ) {
1739                         vector v1, v2;
1740
1741                         // DA 10/20/98 - sparks must be chosen on the hull and not any submodel
1742                         submodel_get_two_random_points(sip->modelnum, pm->detail[0], &v1, &v2);
1743                         ship_hit_sparks_no_rotate(&Objects[objnum], &v1);
1744 //                      ship_hit_sparks_no_rotate(&Objects[objnum], &v2);
1745                 }
1746         }
1747
1748         // in mission, we add a log entry -- set ship positions for ships not in wings, and then do
1749         // warpin effect
1750         if ( (Game_mode & GM_IN_MISSION) && (!Fred_running) ) {
1751                 mission_log_add_entry( LOG_SHIP_ARRIVE, Ships[shipnum].ship_name, NULL );
1752
1753                 // if this ship isn't in a wing, determine it's arrival location
1754                 if ( !Game_restoring )  {
1755                         if ( Ships[shipnum].wingnum == -1 ) {
1756                                 int location;
1757                                 // multiplayer clients set the arrival location of ships to be at location since their
1758                                 // position has already been determined.  Don't actually set the variable since we
1759                                 // don't want the warp effect to show if coming from a dock bay.
1760                                 location = objp->arrival_location;
1761                                 if ( MULTIPLAYER_CLIENT )
1762                                         location = ARRIVE_AT_LOCATION;
1763                                 mission_set_arrival_location(objp->arrival_anchor, location, objp->arrival_distance, objnum, NULL, NULL);
1764                                 if ( objp->arrival_location != ARRIVE_FROM_DOCK_BAY )
1765                                         shipfx_warpin_start( &Objects[objnum] );
1766                         }
1767                 }
1768                 
1769                 // possibly add this ship to a hotkey set
1770                 if ( (Ships[shipnum].wingnum == -1) && (Ships[shipnum].hotkey != -1 ) )
1771                         mission_hotkey_mf_add( Ships[shipnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1772                 else if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].hotkey != -1 ) )
1773                         mission_hotkey_mf_add( Wings[Ships[shipnum].wingnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1774
1775                 // possibly add this ship to the hud escort list
1776                 if ( Ships[shipnum].flags & SF_ESCORT ){
1777                         hud_add_remove_ship_escort( objnum, 1 );
1778                 }
1779         }
1780
1781         // for multiplayer games, make a call to the network code to assign the object signature
1782         // of the newly created object.  The network host of the netgame will always assign a signature
1783         // to a newly created object.  The network signature will get to the clients of the game in
1784         // different manners depending on whether or not an individual ship or a wing was created.
1785         if ( Game_mode & GM_MULTIPLAYER ) {
1786                 Objects[objnum].net_signature = objp->net_signature;
1787
1788                 if ( (Game_mode & GM_IN_MISSION) && MULTIPLAYER_MASTER && (objp->wingnum == -1) ){
1789                         send_ship_create_packet( &Objects[objnum], (objp==Arriving_support_ship)?1:0 );
1790                 }
1791         }
1792
1793         // if recording a demo, post the event
1794         if(Game_mode & GM_DEMO_RECORD){
1795                 demo_POST_obj_create(objp->name, Objects[objnum].signature);
1796         }
1797
1798         return objnum;
1799 }
1800
1801 //      Mp points at the text of an object, which begins with the "$Name:" field.
1802 //      Snags all object information and calls parse_create_object to create a ship.
1803 //      Why create a ship?  Why not an object?  Stay tuned...
1804 //
1805 // flag is parameter that is used to tell what kind information we are retrieving from the mission.
1806 // if we are just getting player starts, then don't create the objects
1807 int parse_object(mission *pm, int flag, p_object *objp)
1808 {
1809         // p_object     temp_object;
1810         // p_object     *objp;
1811         int     i, j, count, shipnum, delay, destroy_before_mission_time;
1812         char    name[NAME_LENGTH], flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
1813
1814         SDL_assert(pm != NULL);
1815
1816         // objp = &temp_object;
1817
1818         required_string("$Name:");
1819         stuff_string(objp->name, F_NAME, NULL);
1820         shipnum = ship_name_lookup(objp->name);
1821         if (shipnum != -1)
1822                 error_display(0, NOX("Redundant ship name: %s\n"), objp->name);
1823
1824
1825         find_and_stuff("$Class:", &objp->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1826         if (objp->ship_class < 0) {
1827                 Warning(LOCATION, "Ship \"%s\" has an invalid ship type (ships.tbl probably changed).  Making it type 0", objp->name);
1828
1829                 // if fred is running, maybe notify the user that the mission contains MD content
1830                 if(Fred_running){
1831                         Fred_found_unknown_ship_during_parsing = 1;
1832                 }
1833
1834                 objp->ship_class = 0;
1835         }
1836
1837         // if this is a multiplayer dogfight mission, skip support ships
1838         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (Ship_info[objp->ship_class].flags & SIF_SUPPORT)){
1839                 return 0;
1840         }               
1841
1842         // optional alternate name type
1843         objp->alt_type_index = -1;
1844         if(optional_string("$Alt:")){
1845                 // alternate name
1846                 stuff_string(name, F_NAME, NULL, NAME_LENGTH);
1847
1848                 // try and find the alternate name
1849                 objp->alt_type_index = (char)mission_parse_lookup_alt(name);
1850                 SDL_assert(objp->alt_type_index >= 0);
1851                 if(objp->alt_type_index < 0){
1852                         mprintf(("Error looking up alternate ship type name!\n"));
1853                 } else {
1854                         mprintf(("Using alternate ship type name : %s\n", name));
1855                 }
1856         }
1857
1858         int     team_index;
1859         find_and_stuff("$Team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1860         SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1861         objp->team = 1 << team_index;
1862
1863         required_string("$Location:");
1864         stuff_vector(&objp->pos);
1865
1866         required_string("$Orientation:");
1867         stuff_matrix(&objp->orient);
1868
1869         find_and_stuff("$IFF:",                 &objp->iff, F_NAME, Iff_names, Num_iff, "IFF");
1870         find_and_stuff("$AI Behavior:", &objp->behavior, F_NAME, Ai_behavior_names, Num_ai_behaviors, "AI behavior");
1871         objp->ai_goals = -1;
1872
1873         if ( optional_string("+AI Class:")) {
1874                 objp->ai_class = match_and_stuff(F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class");
1875                 SDL_assert(objp->ai_class > -1 );
1876         } else {
1877                 objp->ai_class = Ship_info[objp->ship_class].ai_class;
1878         }
1879
1880         if ( optional_string("$AI Goals:") ){
1881                 objp->ai_goals = get_sexp_main();
1882         }
1883
1884         if ( !required_string_either("$AI Goals:", "$Cargo 1:") ) {
1885                 required_string("$AI Goals:");
1886                 objp->ai_goals = get_sexp_main();
1887         }
1888
1889         objp->cargo1 = -1;
1890         int temp;
1891         find_and_stuff_or_add("$Cargo 1:", &temp, F_NAME, Cargo_names, NAME_LENGTH, &Num_cargo, MAX_CARGO, "cargo");
1892         objp->cargo1 = char(temp);
1893         if ( optional_string("$Cargo 2:") ) {
1894                 char buf[NAME_LENGTH];
1895                 stuff_string(buf, F_NAME, NULL);
1896         }
1897
1898         parse_common_object_data(objp);  // get initial conditions and subsys status
1899         count = 0;
1900         while (required_string_either("$Arrival Location:", "$Status Description:"))    {
1901                 SDL_assert(count < MAX_OBJECT_STATUS);
1902
1903                 find_and_stuff("$Status Description:", &objp->status_type[count], F_NAME, Status_desc_names, Num_status_names, "Status Description");
1904                 find_and_stuff("$Status:", &objp->status[count], F_NAME, Status_type_names, Num_status_names, "Status Type");
1905                 find_and_stuff("$Target:", &objp->target[count], F_NAME, Status_target_names, Num_status_names, "Target");
1906                 count++;
1907         }
1908         objp->status_count = count;
1909
1910         objp->arrival_anchor = -1;
1911         objp->arrival_distance = 0;
1912         find_and_stuff("$Arrival Location:", &objp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
1913         if ( optional_string("+Arrival Distance:") ) {
1914                 stuff_int( &objp->arrival_distance );
1915                 if ( objp->arrival_location != ARRIVE_AT_LOCATION ) {
1916                         required_string("$Arrival Anchor:");
1917                         stuff_string(name, F_NAME, NULL);
1918                         objp->arrival_anchor = get_anchor(name);
1919                 }
1920         }
1921
1922         if (optional_string("+Arrival Delay:")) {
1923                 stuff_int(&delay);
1924                 if ( delay < 0 )
1925                         Error(LOCATION, "Cannot have arrival delay < 0 (ship %s)", objp->name);
1926         } else
1927                 delay = 0;
1928
1929         if ( !Fred_running ){
1930                 objp->arrival_delay = -delay;                   // use negative numbers to mean we haven't set up a timer yet
1931         } else {
1932                 objp->arrival_delay = delay;
1933         }
1934
1935         required_string("$Arrival Cue:");
1936         objp->arrival_cue = get_sexp_main();
1937         if ( !Fred_running && (objp->arrival_cue >= 0) ) {
1938                 // eval the arrival cue.  if the cue is true, set up the timestamp for the arrival delay
1939                 SDL_assert ( objp->arrival_delay <= 0 );
1940
1941                 // don't eval arrival_cues when just looking for player information.
1942                 if ( eval_sexp(objp->arrival_cue) ){                    // evaluate to determine if sexp is always false.
1943                         objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
1944                 }
1945         }
1946
1947         find_and_stuff("$Departure Location:", &objp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
1948         objp->departure_anchor = -1;
1949         if ( objp->departure_location == DEPART_AT_DOCK_BAY ) {
1950                 required_string("$Departure Anchor:");
1951                 stuff_string(name, F_NAME, NULL);
1952                 objp->departure_anchor = get_anchor(name);
1953         }
1954
1955         if (optional_string("+Departure Delay:")) {
1956                 stuff_int(&delay);
1957                 if ( delay < 0 ){
1958                         Error(LOCATION, "Cannot have departure delay < 0 (ship %s)", objp->name);
1959                 }
1960         } else {
1961                 delay = 0;
1962         }
1963
1964         if ( !Fred_running ){
1965                 objp->departure_delay = -delay;
1966         } else {
1967                 objp->departure_delay = delay;
1968         }
1969
1970         required_string("$Departure Cue:");
1971         objp->departure_cue = get_sexp_main();
1972
1973         if (optional_string("$Misc Properties:"))
1974                 stuff_string(objp->misc, F_NAME, NULL);
1975
1976         required_string("$Determination:");
1977         stuff_int(&objp->determination);
1978
1979         objp->flags = 0;
1980         if (optional_string("+Flags:")) {
1981                 count = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
1982                 for (i=0; i<count; i++) {
1983                         for (j=0; j<MAX_PARSE_OBJECT_FLAGS; j++) {
1984                                 if (!SDL_strcasecmp(flag_strings[i], Parse_object_flags[j])) {
1985                                         objp->flags |= (1 << j);
1986                                         break;
1987                                 }
1988                         }
1989
1990                         if (j == MAX_PARSE_OBJECT_FLAGS)
1991                                 Warning(LOCATION, "Unknown flag in mission file: %s\n", flag_strings[i]);
1992                 }
1993         }
1994
1995         // always store respawn priority, just for ease of implementation
1996         objp->respawn_priority = 0;
1997         if(optional_string("+Respawn Priority:" )){
1998                 stuff_int(&objp->respawn_priority);     
1999         }
2000
2001         objp->escort_priority = 0;
2002         if ( optional_string("+Escort Priority:" ) ) {
2003                 SDL_assert(objp->flags & P_SF_ESCORT);
2004                 stuff_int(&objp->escort_priority);
2005         }       
2006
2007         if ( objp->flags & P_OF_PLAYER_START ) {
2008                 objp->flags |= P_OF_CARGO_KNOWN;                                // make cargo known for players
2009                 Player_starts++;
2010         }
2011
2012         objp->special_exp_index = -1;
2013         if ( optional_string("+Special Exp index:" ) ) {
2014                 stuff_int(&objp->special_exp_index);
2015         }
2016
2017         // if the kamikaze flag is set, we should have the next flag
2018         if ( optional_string("+Kamikaze Damage:") ) {
2019                 int damage;
2020
2021                 stuff_int(&damage);
2022                 objp->kamikaze_damage = i2fl(damage);
2023         }
2024
2025         objp->hotkey = -1;
2026         if (optional_string("+Hotkey:")) {
2027                 stuff_int(&objp->hotkey);
2028                 SDL_assert((objp->hotkey >= 0) && (objp->hotkey < 10));
2029         }
2030
2031         objp->docked_with[0] = 0;
2032         if (optional_string("+Docked With:")) {
2033                 stuff_string(objp->docked_with, F_NAME, NULL);
2034                 required_string("$Docker Point:");
2035                 stuff_string(objp->docker_point, F_NAME, NULL);
2036                 required_string("$Dockee Point:");
2037                 stuff_string(objp->dockee_point, F_NAME, NULL);
2038
2039                 objp->flags |= P_SF_INITIALLY_DOCKED;
2040
2041                 // put this information into the Initially_docked array.  We will need to use this
2042                 // informatin later since not all ships will initially get created.
2043                 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee, objp->docked_with, NAME_LENGTH);
2044                 SDL_strlcpy(Initially_docked[Total_initially_docked].docker_point, objp->docker_point, NAME_LENGTH);
2045                 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee_point, objp->dockee_point, NAME_LENGTH);
2046                 Initially_docked[Total_initially_docked].docker = objp;
2047                 Total_initially_docked++;
2048         }
2049
2050         // check the optional parameter for destroying the ship before the mission starts.  If this parameter is
2051         // here, then we need to destroy the ship N seconds before the mission starts (for debris purposes).
2052         // store the time value here.  We want to create this object for sure.  Set the arrival cue and arrival
2053         // delay to bogus values
2054         destroy_before_mission_time = -1;
2055         if ( optional_string("+Destroy At:") ) {
2056
2057                 stuff_int(&destroy_before_mission_time);
2058                 SDL_assert ( destroy_before_mission_time >= 0 );
2059                 objp->arrival_cue = Locked_sexp_true;
2060                 objp->arrival_delay = timestamp(0);
2061         }
2062
2063         // check for the optional "orders accepted" string which contains the orders from the default
2064         // set that this ship will actually listen to
2065         if ( optional_string("+Orders Accepted:") ) {
2066                 stuff_int( &objp->orders_accepted );
2067                 if ( objp->orders_accepted != -1 ){
2068                         objp->flags |= P_SF_USE_UNIQUE_ORDERS;
2069                 }
2070         }
2071
2072         if (optional_string("+Group:")){
2073                 stuff_int(&objp->group);
2074         } else {
2075                 objp->group = 0;
2076         }
2077
2078         if (optional_string("+Score:")){
2079                 stuff_int(&objp->score);
2080         } else {
2081                 objp->score = 0;
2082         }
2083
2084         // parse the persona index if present
2085         if ( optional_string("+Persona Index:")){
2086                 stuff_int(&objp->persona_index);
2087         } else {
2088                 objp->persona_index = -1;
2089         }
2090
2091         objp->wingnum = -1;                                     // set the wing number to -1 -- possibly to be set later
2092
2093         // for multiplayer, assign a network signature to this parse object.  Doing this here will
2094         // allow servers to use the signature with clients when creating new ships, instead of having
2095         // to pass ship names all the time
2096         if ( Game_mode & GM_MULTIPLAYER ){
2097                 objp->net_signature = multi_assign_network_signature( MULTI_SIG_SHIP );
2098         }
2099
2100         // set the wing_status position to be -1 for all objects.  This will get set to an appropriate
2101         // value when the wing positions are finally determined.
2102         objp->wing_status_wing_index = -1;
2103         objp->wing_status_wing_pos = -1;
2104         objp->respawn_count = 0;
2105
2106         // if this if the starting player ship, then copy if to Starting_player_pobject (used for ingame join)
2107         if ( !SDL_strcasecmp( objp->name, Player_start_shipname) ) {
2108                 Player_start_pobject = *objp;
2109                 Player_start_pobject.flags |= P_SF_PLAYER_START_VALID;
2110         }
2111         
2112
2113 // Now create the object.
2114 // Don't create the new ship blindly.  First, check the sexp for the arrival cue
2115 // to determine when this ship should arrive.  If not right away, stick this ship
2116 // onto the ship arrival list to be looked at later.  Also check to see if it should use the
2117 // wings arrival cue.  The ship may get created later depending on whether or not the wing
2118 // is created.
2119 // always create ships when FRED is running
2120
2121         // don't create the object if it is intially docked for either FreeSpcae or Fred.  Fred will
2122         // create the object later in post_process_mission
2123         if ( (objp->flags & P_SF_INITIALLY_DOCKED) || (!Fred_running && (!eval_sexp(objp->arrival_cue) || !timestamp_elapsed(objp->arrival_delay) || (objp->flags & P_SF_REINFORCEMENT))) ) {
2124                 SDL_assert ( destroy_before_mission_time == -1 );               // we can't add ships getting destroyed to the arrival list!!!
2125                 SDL_assert ( num_ship_arrivals < MAX_SHIP_ARRIVALS );
2126                 memcpy( &ship_arrivals[num_ship_arrivals], objp, sizeof(p_object) );
2127                 list_append(&ship_arrival_list, &ship_arrivals[num_ship_arrivals]);
2128                 num_ship_arrivals++;
2129         }
2130         // ingame joiners bail here.
2131         else if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_INGAME_JOIN)){
2132                 return 1;
2133         }
2134         else {
2135                 int     real_objnum;
2136
2137                 real_objnum = parse_create_object(objp);                                // this object may later get destroyed depending on wing status!!!!
2138
2139                 Subsys_index = objp->subsys_index;  // free elements that are no longer needed.
2140
2141                 // if the ship is supposed to be destroyed before the mission, then blow up the ship, mark the pieces
2142                 // as last forever.  Only call this stuff when you are blowing up the ship
2143                 if ( destroy_before_mission_time >= 0 ) {
2144                         object *objp;
2145
2146                         objp = &Objects[real_objnum];
2147                         if ( !Fred_running ) {
2148                                 int i;
2149                                 shipfx_blow_up_model( objp, Ships[objp->instance].modelnum, 0, 0, &objp->pos );
2150                                 objp->flags |= OF_SHOULD_BE_DEAD;
2151
2152                                 // once the ship is exploded, find the debris pieces belonging to this object, mark them
2153                                 // as not to expire, and move them forward in time N seconds
2154                                 for (i = 0; i < MAX_DEBRIS_PIECES; i++ ) {
2155                                         debris *db;
2156
2157                                         db = &Debris[i];
2158                                         if ( !db->flags & DEBRIS_USED )                         // not used, move onto the next one.
2159                                                 continue;
2160                                         if ( db->source_objnum != real_objnum ) // not from this ship, move to next one
2161                                                 continue;
2162
2163                                         debris_clear_expired_flag(db);                          // mark as don't expire
2164                                         db->lifeleft = -1.0f;                                                   // be sure that lifeleft == -1.0 so that it really doesn't expire!
2165
2166                                         // now move the debris along it's path for N seconds
2167                                         objp = &Objects[db->objnum];
2168                                         physics_sim( &objp->pos, &objp->orient, &objp->phys_info, (float)destroy_before_mission_time );
2169                                 }
2170                         } else  {
2171                                 // be sure to set the variable in the ships structure for the final death time!!!
2172                                 Ships[objp->instance].final_death_time = destroy_before_mission_time;
2173                                 Ships[objp->instance].flags |= SF_KILL_BEFORE_MISSION;
2174                         }
2175                 }
2176         }
2177
2178         return 1;
2179 }
2180
2181 void parse_common_object_data(p_object  *objp)
2182 {
2183         int i;
2184
2185         // set some defaults..
2186         objp->initial_velocity = 0;
2187         objp->initial_hull = 100;
2188         objp->initial_shields = 100;
2189
2190         // now change defaults if present
2191         if (optional_string("+Initial Velocity:")) {
2192                 stuff_int(&objp->initial_velocity);
2193         }
2194
2195         if (optional_string("+Initial Hull:"))
2196                 stuff_int(&objp->initial_hull);
2197         if (optional_string("+Initial Shields:"))
2198                 stuff_int(&objp->initial_shields);
2199
2200         objp->subsys_index = Subsys_index;
2201         objp->subsys_count = 0;
2202         while (optional_string("+Subsystem:")) {
2203                 i = allocate_subsys_status();
2204
2205                 objp->subsys_count++;
2206                 stuff_string(Subsys_status[i].name, F_NAME, NULL);
2207                 
2208                 if (optional_string("$Damage:"))
2209                         stuff_float(&Subsys_status[i].percent);
2210
2211                 Subsys_status[i].subsys_cargo_name = -1;
2212                 if (optional_string("+Cargo Name:")) {
2213                         char cargo_name[256];
2214                         stuff_string(cargo_name, F_NAME, NULL);
2215                         int index = string_lookup(cargo_name, (const char **)Cargo_names, Num_cargo, "cargo", 0);
2216                         if (index == -1 && (Num_cargo < MAX_CARGO)) {
2217                                 index = Num_cargo;
2218                                 SDL_strlcpy(Cargo_names[Num_cargo++], cargo_name, NAME_LENGTH);
2219                         }
2220                         Subsys_status[i].subsys_cargo_name = index;
2221                 }
2222
2223                 if (optional_string("+AI Class:"))
2224                         Subsys_status[i].ai_class = match_and_stuff(F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class");
2225
2226                 if (optional_string("+Primary Banks:"))
2227                         stuff_int_list(Subsys_status[i].primary_banks, MAX_PRIMARY_BANKS, WEAPON_LIST_TYPE);
2228
2229                 if (optional_string("+Secondary Banks:"))
2230                         stuff_int_list(Subsys_status[i].secondary_banks, MAX_SECONDARY_BANKS, WEAPON_LIST_TYPE);
2231
2232                 if (optional_string("+Sbank Ammo:"))
2233                         stuff_int_list(Subsys_status[i].secondary_ammo, MAX_SECONDARY_BANKS, RAW_INTEGER_TYPE);
2234
2235         }
2236 }
2237
2238 void parse_objects(mission *pm, int flag)
2239 {       
2240         p_object temp;
2241
2242         SDL_assert(pm != NULL); 
2243
2244         required_string("#Objects");    
2245
2246         // parse in objects
2247         num_ship_original = 0;
2248         while (required_string_either("#Wings", "$Name:")){
2249                 // not all objects are always valid or legal
2250                 if(parse_object(pm, flag, &temp)){
2251                         // add to the default list
2252                         if(num_ship_original < MAX_SHIP_ORIGINAL){
2253                                 memcpy(&ship_original[num_ship_original++], &temp, sizeof(p_object));
2254                         }
2255                 }
2256         }
2257 }
2258
2259 p_object *mission_parse_get_original_ship( ushort net_signature )
2260 {
2261         int idx;
2262
2263         // look for original ships
2264         for(idx=0; idx<num_ship_original; idx++){
2265                 if(ship_original[idx].net_signature == net_signature){
2266                         return &ship_original[idx];
2267                 }
2268         }
2269
2270         // boo
2271         return NULL;
2272 }
2273
2274 int find_wing_name(char *name)
2275 {
2276         int     i;
2277
2278         for (i=0; i<num_wings; i++){
2279                 if (!strcmp(name, Wings[i].name)){
2280                         return i;
2281                 }
2282         }
2283
2284         return -1;
2285 }
2286
2287 // function to create ships in the wing that need to be created.  We psas the wing pointer, it's index
2288 // into the Wings array
2289 int parse_wing_create_ships( wing *wingp, int num_to_create, int force, int specific_instance )
2290 {
2291         p_object *objp;
2292         int wingnum, objnum, num_create_save;
2293         int time_to_arrive;
2294         int pre_create_count;
2295
2296         // we need to send this in multiplayer
2297         pre_create_count = wingp->total_arrived_count;
2298
2299         // force is used to force creation of the wing -- used for multiplayer
2300         if ( !force ) {
2301                 // we only want to evaluate the arrival cue of the wing if:
2302                 // 1) single player
2303                 // 2) multiplayer and I am the host of the game
2304                 // can't create any ships if the arrival cue is false or the timestamp has not elapsed.
2305
2306                 if ( !eval_sexp(wingp->arrival_cue) ) /* || !timestamp_elapsed(wingp->arrival_delay) ) */
2307                         return 0;
2308
2309                 // once the sexpressions becomes true, then check the arrival delay on the wing.  The first time, the
2310                 // arrival delay will be <= 0 meaning that no timer object has been set yet.  Set up the timestamp
2311                 // which should always give a number >= 0;
2312                 if ( wingp->arrival_delay <= 0 ) {
2313                         wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
2314                         SDL_assert ( wingp->arrival_delay >= 0 );
2315                 }
2316
2317                 if ( !timestamp_elapsed( wingp->arrival_delay ) )
2318                         return 0;
2319
2320                 // if wing is coming from docking bay, then be sure that ship we are arriving from actually exists
2321                 // (or will exist).
2322                 if ( wingp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
2323                         int shipnum;
2324                         char *name;
2325
2326                         SDL_assert( wingp->arrival_anchor >= 0 );
2327                         name = Parse_names[wingp->arrival_anchor];
2328
2329                         // see if ship is yet to arrive.  If so, then return -1 so we can evaluate again later.
2330                         if ( mission_parse_get_arrival_ship( name ) )
2331                                 return 0;
2332
2333                         // see if ship is in mission.  If not, then we can assume it was destroyed or departed since
2334                         // it is not on the arrival list (as shown by above if statement).
2335                         shipnum = ship_name_lookup( name );
2336                         if ( shipnum == -1 ) {
2337                                 int num_remaining;
2338                                 // since this wing cannot arrive from this place, we need to mark the wing as destroyed and
2339                                 // set the wing variables appropriatly.  Good for directives.
2340
2341                                 // set the gone flag
2342                                 wingp->flags |= WF_WING_GONE;
2343
2344                                 // if the current wave is zero, it never existed
2345                                 wingp->flags |= WF_NEVER_EXISTED;
2346
2347                                 // mark the number of waves and number of ships destroyed equal to the last wave and the number
2348                                 // of ships yet to arrive
2349                                 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
2350                                 wingp->total_arrived_count += num_remaining;
2351                                 wingp->current_wave = wingp->num_waves;
2352
2353                                 // replaced following three lines of code with mission log call because of bug with
2354                                 // the Ships_exited list.
2355                                 //index = ship_find_exited_ship_by_name( name );
2356                                 //SDL_assert( index != -1 );
2357                                 //if (Ships_exited[index].flags & SEF_DESTROYED ) {
2358                                 if ( mission_log_get_time(LOG_SHIP_DESTROYED, name, NULL, NULL) ) {
2359                                         wingp->total_destroyed += num_remaining;
2360                                 } else {
2361                                         wingp->total_departed += num_remaining;
2362                                 }
2363
2364                                 Sexp_nodes[wingp->arrival_cue].value = SEXP_KNOWN_FALSE;
2365                                 return 0;
2366                         }
2367                 }
2368
2369                 if ( num_to_create == 0 )
2370                         return 0;
2371
2372                 // check the wave_delay_timestamp field.  If it is not valid, make it valid (based on wave delay min
2373                 // and max valuds).  If it is valid, and not elapsed, then return.  If it is valid and elasped, then
2374                 // continue on.
2375                 if ( !timestamp_valid(wingp->wave_delay_timestamp) ) {
2376
2377                         // if at least one of these is valid, then reset the timestamp.  If they are both zero, we will create the
2378                         // wave
2379                         if ( (wingp->wave_delay_min > 0) || (wingp->wave_delay_max > 0) ) {
2380                                 SDL_assert ( wingp->wave_delay_min <= wingp->wave_delay_max );
2381                                 time_to_arrive = wingp->wave_delay_min + (int)(frand() * (wingp->wave_delay_max - wingp->wave_delay_min));
2382
2383                                 // MWA -- 5/18/98
2384                                 // HACK HACK -- in the presense of Mike Comet and Mitri, I have introduced one of the most
2385                                 // serious breaches of coding standards.  I'm to lazy to fix this the correct way.  Insert
2386                                 // a delay before the next wave of the wing can arrive to that clients in the game have ample
2387                                 // time to kill off any ships in the wing before the next wave arrives.
2388                                 if ( Game_mode & GM_MULTIPLAYER ){
2389                                         time_to_arrive += 7;
2390                                 }
2391                                 wingp->wave_delay_timestamp = timestamp(time_to_arrive * 1000);
2392                                 return 0;
2393                         }
2394
2395                         // if we get here, both min and max values are 0;  See comments above for a most serious hack
2396                         time_to_arrive = 0;
2397                         if ( Game_mode & GM_MULTIPLAYER )
2398                                 time_to_arrive += 7;
2399                         time_to_arrive *= 1000;
2400                         wingp->wave_delay_timestamp = timestamp(time_to_arrive);
2401                 }
2402
2403                 // now check to see if the wave_delay_timestamp is elapsed or not
2404                 if ( !timestamp_elapsed(wingp->wave_delay_timestamp) )
2405                         return 0;
2406         }
2407
2408         // finally we can create the wing.
2409
2410         num_create_save = num_to_create;
2411
2412         wingnum = wingp - Wings;                                        // get the wing number
2413
2414         // if there are no ships to create, then all ships must be player start ships -- do nothing in this case.
2415         if ( num_to_create == 0 ){
2416                 return 0;
2417         }
2418
2419         wingp->current_wave++;                                          // we are creating new ships
2420         // we need to create num_to_create ships.  Since the arrival cues for ships in a wing
2421         // are ignored, then *all* ships must be in the ship_arrival_list.  
2422
2423         objnum = -1;
2424         objp = GET_FIRST(&ship_arrival_list);
2425         while( objp != END_OF_LIST(&ship_arrival_list) )        {
2426                 p_object *temp = GET_NEXT(objp);
2427
2428                 // compare the wingnums.  When they are equal, we can create the ship.  In the case of
2429                 // wings that have multiple waves, this code implies that we essentially creating clones
2430                 // of the ships that were created in Fred for the wing when more ships for a new wave
2431                 // arrive.  The threshold value of a wing can also make one of the ships in a wing be "cloned"
2432                 // more often than other ships in the wing.  I don't think this matters much.
2433                 if ( objp->wingnum == wingnum ) {
2434                         ai_info *aip;
2435
2436                         // when ingame joining, we need to create a specific ship out of the list of ships for a
2437                         // wing.  specific_instance is a 0 based integer which specified which ship in the wing
2438                         // to create.  So, only create the ship we actually need to.
2439                         if ( (Game_mode & GM_MULTIPLAYER) && (specific_instance > 0) ) {
2440                                 specific_instance--;
2441                                 objp = temp;
2442                                 continue;
2443                         }
2444
2445                         SDL_assert ( !(objp->flags & P_SF_CANNOT_ARRIVE) );             // get allender
2446
2447                         int index;
2448
2449                         // if we have the maximum number of ships in the wing, we must bail as well
2450                         if ( wingp->current_count >= MAX_SHIPS_PER_WING ) {
2451                                 Int3();                                 // this is bogus -- we should always allow all ships to be created
2452                                 num_to_create = 0;
2453                                 break;
2454                         }
2455
2456                         // bash the ship name to be the name of the wing + sone number if there is > 1 wave in
2457                         // this wing
2458                         // also, if multplayer, set the parse object's net signature to be wing's net signature
2459                         // base + total_arrived_count (before adding 1)
2460                         if ( Game_mode & GM_MULTIPLAYER ){
2461                                 objp->net_signature = (ushort)(wingp->net_signature + wingp->total_arrived_count);
2462                         }
2463
2464                         wingp->total_arrived_count++;
2465                         if ( wingp->num_waves > 1 ){
2466                                 SDL_snprintf(objp->name, sizeof(objp->name), NOX("%s %d"), wingp->name, wingp->total_arrived_count);
2467                         }
2468
2469                         objnum = parse_create_object(objp);
2470                         aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
2471
2472                         // copy any goals from the wing to the newly created ship
2473                         for (index = 0; index < MAX_AI_GOALS; index++) {
2474                                 if ( wingp->ai_goals[index].ai_mode != AI_GOAL_NONE ){
2475                                         ai_copy_mission_wing_goal( &wingp->ai_goals[index], aip );
2476                                 }
2477                         }
2478
2479                         Ai_info[Ships[Objects[objnum].instance].ai_index].wing = wingnum;
2480
2481                         if ( wingp->flags & WF_NO_DYNAMIC ){
2482                                 aip->ai_flags |= AIF_NO_DYNAMIC;
2483                         }
2484
2485                         // update housekeeping variables
2486                         wingp->ship_index[wingp->current_count] = Objects[objnum].instance;
2487
2488                         // set up wingman status index
2489                         hud_wingman_status_set_index(wingp->ship_index[wingp->current_count]);
2490
2491                         objp->wing_status_wing_index = Ships[Objects[objnum].instance].wing_status_wing_index;
2492                         objp->wing_status_wing_pos = Ships[Objects[objnum].instance].wing_status_wing_pos;
2493
2494                         wingp->current_count++;
2495
2496                         // keep any player ship on the parse object list -- used for respawns
2497                         // 5/8/98 -- MWA -- don't remove ships from the list when you are ingame joining
2498                         if ( !(objp->flags & P_OF_PLAYER_START) ) {
2499                                 if ( (Game_mode & GM_NORMAL) || !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2500                                         if ( wingp->num_waves == wingp->current_wave ) {        // only remove ship if one wave in wing
2501                                                 list_remove( &ship_arrival_list, objp);                 // remove objp from the list
2502                                                 if ( objp->ai_goals != -1 ){
2503                                                         free_sexp2(objp->ai_goals);                                             // free up sexp nodes for reuse
2504                                                 }
2505                                         }
2506                                 }
2507                         }
2508
2509                         // flag ship with SF_FROM_PLAYER_WING if a member of player starting wings
2510                         if ( (Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM) ) {
2511                                 // but for team vs. team games, then just check the alpha and zeta wings
2512                                 if ( !(SDL_strcasecmp(Starting_wing_names[STARTING_WING_ALPHA], wingp->name)) || !(SDL_strcasecmp(Starting_wing_names[STARTING_WING_ZETA], wingp->name)) ) {
2513                                         Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
2514                                 }
2515                         } else {
2516                                 for (int i = 0; i < MAX_STARTING_WINGS; i++ ) {
2517                                         if ( !SDL_strcasecmp(Starting_wing_names[i], wingp->name) ) {
2518                                                 Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
2519                                         } 
2520                                 }
2521                         }
2522
2523                         // keep track of how many ships to create.  Stop when we have done all that we are supposed
2524                         // to do.
2525                         num_to_create--;
2526                         if ( !num_to_create ){
2527                                 break;
2528                         }
2529                 }
2530                 objp = temp;
2531         }
2532
2533         SDL_assert ( num_to_create == 0 );              // we should always have enough ships in the list!!!
2534
2535         // possibly play some event driven music here.  Send a network packet indicating the wing was
2536         // created.  Only do this stuff if actually in the mission.
2537         if ( (objnum != -1) && (Game_mode & GM_IN_MISSION) ) {          // if true, we have created at least one new ship.
2538                 int i, ship_num;
2539
2540                 // see if this wing is a player starting wing, and if so, call the maybe_add_form_goal
2541                 // function to possibly make the wing form on the player
2542                 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
2543                         if ( Starting_wings[i] == wingnum ){
2544                                 break;
2545                         }
2546                 }
2547                 if ( i < MAX_STARTING_WINGS ){
2548                         ai_maybe_add_form_goal( wingp );
2549                 }
2550
2551                 mission_log_add_entry( LOG_WING_ARRIVE, wingp->name, NULL, wingp->current_wave );
2552                 ship_num = wingp->ship_index[0];
2553
2554                 if ( !(Ships[ship_num].flags & SF_NO_ARRIVAL_MUSIC) && !(wingp->flags & WF_NO_ARRIVAL_MUSIC) ) {
2555                         if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
2556                                 Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
2557                                 event_music_arrival(Ships[ship_num].team);      
2558                         }
2559                 }
2560
2561                 // possibly change the location where these ships arrive based on the wings arrival location
2562                 mission_set_wing_arrival_location( wingp, num_create_save );
2563
2564                 // if in multiplayer (and I am the host) and in the mission, send a wing create command to all
2565                 // other players
2566                 if ( MULTIPLAYER_MASTER ){
2567                         send_wing_create_packet( wingp, num_create_save, pre_create_count );
2568                 }
2569
2570 #ifndef NDEBUG
2571                 // test code to check to be sure that all ships in the wing are ignoring the same types
2572                 // of orders from the player
2573                 if ( Fred_running ) {
2574                         SDL_assert( wingp->ship_index[0] != -1 );
2575                         int orders = Ships[wingp->ship_index[0]].orders_accepted;
2576                         for (i = 1; i < wingp->current_count; i++ ) {
2577                                 if ( orders != Ships[wingp->ship_index[i]].orders_accepted ) {
2578                                         Warning(LOCATION, "ships in wing %s are ignoring different player orders.  Please find Mark A\nto talk to him about this.", wingp->name );
2579                                         break;
2580                                 }
2581                         }
2582                 }
2583 #endif
2584
2585         }
2586
2587         wingp->wave_delay_timestamp = timestamp(-1);            // we will need to set this up properly for the next wave
2588         return num_create_save;
2589 }
2590
2591 void parse_wing(mission *pm)
2592 {
2593         int wingnum, i, wing_goals, delay;
2594         char name[NAME_LENGTH], ship_names[MAX_SHIPS_PER_WING][NAME_LENGTH];
2595         char wing_flag_strings[MAX_WING_FLAGS][NAME_LENGTH];
2596         wing *wingp;
2597
2598         SDL_assert(pm != NULL);
2599         wingp = &Wings[num_wings];
2600
2601         required_string("$Name:");
2602         stuff_string(wingp->name, F_NAME, NULL);
2603         wingnum = find_wing_name(wingp->name);
2604         if (wingnum != -1)
2605                 error_display(0, NOX("Redundant wing name: %s\n"), wingp->name);
2606         wingnum = num_wings;
2607
2608         wingp->total_arrived_count = 0;
2609         wingp->total_destroyed = 0;
2610         wingp->flags = 0;
2611
2612         required_string("$Waves:");
2613         stuff_int(&wingp->num_waves);
2614         SDL_assert ( wingp->num_waves >= 1 );           // there must be at least 1 wave
2615
2616         wingp->current_wave = 0;
2617
2618         required_string("$Wave Threshold:");
2619         stuff_int(&wingp->threshold);
2620
2621         required_string("$Special Ship:");
2622         stuff_int(&wingp->special_ship);
2623
2624         wingp->arrival_anchor = -1;
2625         find_and_stuff("$Arrival Location:", &wingp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
2626         if ( optional_string("+Arrival Distance:") ) {
2627                 stuff_int( &wingp->arrival_distance );
2628                 if ( wingp->arrival_location != ARRIVE_AT_LOCATION ) {
2629                         required_string("$Arrival Anchor:");
2630                         stuff_string(name, F_NAME, NULL);
2631                         wingp->arrival_anchor = get_anchor(name);
2632                 }
2633         }
2634
2635         if (optional_string("+Arrival delay:")) {
2636                 stuff_int(&delay);
2637                 if ( delay < 0 )
2638                         Error(LOCATION, "Cannot have arrival delay < 0 on wing %s", wingp->name );
2639         } else
2640                 delay = 0;
2641
2642         if ( !Fred_running ){
2643                 wingp->arrival_delay = -delay;
2644         } else {
2645                 wingp->arrival_delay = delay;
2646         }
2647
2648         required_string("$Arrival Cue:");
2649         wingp->arrival_cue = get_sexp_main();
2650         if ( !Fred_running && (wingp->arrival_cue >= 0) ) {
2651                 if ( eval_sexp(wingp->arrival_cue) )                    // evaluate to determine if sexp is always false.
2652                         wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
2653         }
2654
2655         
2656         find_and_stuff("$Departure Location:", &wingp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
2657         wingp->departure_anchor = -1;
2658         if ( wingp->departure_location == DEPART_AT_DOCK_BAY ) {
2659                 required_string("$Departure Anchor:");
2660                 stuff_string( name, F_NAME, NULL );
2661                 wingp->departure_anchor = get_anchor(name);
2662         }
2663
2664         if (optional_string("+Departure delay:")) {
2665                 stuff_int(&delay);
2666                 if ( delay < 0 )
2667                         Error(LOCATION, "Cannot have departure delay < 0 on wing %s", wingp->name );
2668         } else
2669                 delay = 0;
2670
2671
2672         if ( !Fred_running )
2673                 wingp->departure_delay = -delay;                // use negative numbers to mean that delay timer not yet set
2674         else
2675                 wingp->departure_delay = delay;
2676
2677         required_string("$Departure Cue:");
2678         wingp->departure_cue = get_sexp_main();
2679
2680         // stores a list of all names of ships in the wing
2681         required_string("$Ships:");
2682         wingp->wave_count = stuff_string_list( ship_names, MAX_SHIPS_PER_WING );
2683         wingp->current_count = 0;
2684
2685         // get the wings goals, if any
2686         wing_goals = -1;
2687         if ( optional_string("$AI Goals:") )
2688                 wing_goals = get_sexp_main();
2689
2690         wingp->hotkey = -1;
2691         if (optional_string("+Hotkey:")) {
2692                 stuff_int(&wingp->hotkey);
2693                 SDL_assert((wingp->hotkey >= 0) && (wingp->hotkey < 10));
2694         }
2695
2696         if (optional_string("+Flags:")) {
2697                 int count;
2698
2699                 count = stuff_string_list( wing_flag_strings, MAX_WING_FLAGS );
2700                 for (i = 0; i < count; i++ ) {
2701                         if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("ignore-count")) )
2702                                 wingp->flags |= WF_IGNORE_COUNT;
2703                         else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("reinforcement")) )
2704                                 wingp->flags |= WF_REINFORCEMENT;
2705                         else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-music")) )
2706                                 wingp->flags |= WF_NO_ARRIVAL_MUSIC;
2707                         else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-message")) )
2708                                 wingp->flags |= WF_NO_ARRIVAL_MESSAGE;
2709                         else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-warp")) )
2710                                 wingp->flags |= WF_NO_ARRIVAL_WARP;
2711                         else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-departure-warp")) )
2712                                 wingp->flags |= WF_NO_DEPARTURE_WARP;
2713                         else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-dynamic")) )
2714                                 wingp->flags |= WF_NO_DYNAMIC;
2715                         else
2716                                 Warning(LOCATION, "unknown wing flag\n%s\n\nSkipping.", wing_flag_strings[i]);
2717                 }
2718         }
2719
2720         // get the wave arrival delay bounds (if present).  Used as lower and upper bounds (in seconds)
2721         // which determine when new waves of a wing should arrive.
2722         wingp->wave_delay_min = 0;
2723         wingp->wave_delay_max = 0;
2724         if ( optional_string("+Wave Delay Min:") )
2725                 stuff_int( &(wingp->wave_delay_min) );
2726         if ( optional_string("+Wave Delay Max:") )
2727                 stuff_int( &(wingp->wave_delay_max) );
2728
2729         // be sure to set the wave arrival timestamp of this wing to pop right away so that the
2730         // wing could be created if it needs to be
2731         wingp->wave_delay_timestamp = timestamp(0);
2732
2733         // initialize wing goals
2734         for (i=0; i<MAX_AI_GOALS; i++) {
2735                 wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
2736                 wingp->ai_goals[i].priority = -1;
2737         }
2738
2739         // 7/13/98 -- MWA
2740         // error checking against the player ship wings to be sure that wave count doesn't exceed one for
2741         // these wings.
2742         if ( Game_mode & GM_MULTIPLAYER ) {
2743                 for (i = 0; i < MAX_STARTING_WINGS+1; i++ ) {
2744                         if ( !SDL_strcasecmp(Starting_wing_names[i], wingp->name) ) {
2745                                 if ( wingp->num_waves > 1 ) {
2746                                         // only end the game if we're the server - clients will eventually find out :)
2747                                         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2748                                                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_WAVE_COUNT);                                                                                                                                
2749                                         }
2750                                         // Error(LOCATION, "Player wings Alpha, Beta, Gamma, or Zeta cannot have more than 1 wave.");
2751                                 }
2752                         }
2753                 }
2754         }
2755
2756         // Get the next starting signature for this in this wing.  We want to reserve wave_count * num_waves
2757         // of signature.  These can be used to construct wings for ingame joiners.
2758         if ( Game_mode & GM_MULTIPLAYER ) {
2759                 int next_signature;
2760
2761                 wingp->net_signature = multi_assign_network_signature( MULTI_SIG_SHIP );
2762                 next_signature = wingp->net_signature + (wingp->wave_count * wingp->num_waves);
2763                 if ( next_signature > SHIP_SIG_MAX )
2764                         Error(LOCATION, "Too many total ships in mission (%d) for network signature assignment", SHIP_SIG_MAX);
2765                 multi_set_network_signature( (ushort)next_signature, MULTI_SIG_SHIP );
2766         }
2767
2768         for (i=0; i<MAX_SHIPS_PER_WING; i++)
2769                 wingp->ship_index[i] = -1;
2770
2771         // set up the ai_goals for this wing -- all ships created from this wing will inherit these goals
2772         // goals for the wing are stored slightly differently than for ships.  We simply store the index
2773         // into the sexpression array of each goal (max 10).  When a ship in this wing is created, each
2774         // goal in the wings goal array is given to the ship.
2775         if ( wing_goals != -1 ) {
2776                 int sexp;
2777
2778                 // this will assign the goals to the wings as well as to any ships in the wing that have been
2779                 // already created.
2780                 for ( sexp = CDR(wing_goals); sexp != -1; sexp = CDR(sexp) )
2781                         ai_add_wing_goal_sexp(sexp, AIG_TYPE_EVENT_WING, wingnum);  // used by Fred
2782
2783                 //if (Fred_running)
2784                         free_sexp2(wing_goals);  // free up sexp nodes for reused, since they aren't needed anymore.
2785         }
2786
2787         // set the wing number for all ships in the wing
2788         for (i = 0; i < wingp->wave_count; i++ ) {
2789                 //char *ship_name = wingp->ship_names[i];
2790                 char *ship_name;
2791                 int num, assigned = 0;
2792                 p_object *objp;
2793
2794                 ship_name = ship_names[i];
2795                 if (Fred_running) {
2796                         num = wingp->ship_index[i] = ship_name_lookup(ship_name, 1);
2797                         SDL_assert ( num != -1 );
2798
2799                         // hack code -- REMOVE
2800                         if ( Objects[Ships[num].objnum].flags & OF_PLAYER_SHIP )
2801                                 Ships[num].wingnum = wingnum;
2802
2803                 } else {
2804                         // determine if this ship is a player ship, and deal with it appropriately.
2805                         if ( !SDL_strncasecmp(ship_name, NOX("Player "), 7) ) {
2806                                 Error(LOCATION, "Old mission file -- please convert by loading/saving in Fred -- see Allender/Hoffoss for help.");
2807                         }
2808
2809                         // assign the wing number to the ship -- if the ship has arrived, doulble check that
2810                         // there is only one wave of this wing since ships with their own arrival cue cannot be
2811                         // in a wing with > 1 wave.  Otherwise, find the ship on the ship arrival list and set
2812                         // their wing number
2813                         if ( (num = ship_name_lookup(ship_name)) != -1 ) {
2814                                 Int3();                                 // this is impossible under the new system
2815
2816                         } else {
2817                                 objp = GET_FIRST(&ship_arrival_list);
2818                                 while( objp != END_OF_LIST(&ship_arrival_list) )        {
2819                                         if ( !strcmp(ship_name, objp->name) ) {
2820                                                 SDL_assert ( objp->wingnum == -1 );                                                     // get Allender -- ship appears to be in multiple wings
2821                                                 objp->wingnum = wingnum;
2822                                                 assigned++;
2823                                         }
2824                                         objp = GET_NEXT(objp);
2825                                 }
2826                         }
2827
2828                         if ( !assigned || (assigned > 1) )
2829                                 Error(LOCATION, "Cannot load mission -- wing %s -- ship %s not present in #Objects section (or specified multiple times in wing.\n", wingp->name, ship_name);
2830                 }
2831         }
2832
2833         // Fred doesn't create the wing.  otherwise, create the wing if is isn't a reinforcement.
2834         if ( !Fred_running && !(wingp->flags & WF_REINFORCEMENT) )
2835                 parse_wing_create_ships( wingp, wingp->wave_count );
2836 }
2837
2838 void parse_wings(mission *pm)
2839 {
2840         required_string("#Wings");
2841         while (required_string_either("#Events", "$Name:")) {
2842                 SDL_assert(num_wings < MAX_WINGS);
2843                 parse_wing(pm);
2844                 num_wings++;
2845         }
2846 }
2847
2848 // mission events are sexpressions which cause things to happen based on the outcome
2849 // of other events in a mission.  Essentially scripting the different things that can happen
2850 // in a mission
2851
2852 void parse_event(mission *pm)
2853 {
2854         char buf[256];
2855         mission_event *event;
2856
2857         event = &Mission_events[Num_mission_events];
2858         event->chain_delay = -1;
2859
2860         required_string( "$Formula:" );
2861         event->formula = get_sexp_main();
2862
2863         if (optional_string("+Name:")){
2864                 stuff_string(event->name, F_NAME, NULL);
2865         } else {
2866                 event->name[0] = 0;
2867         }
2868
2869         if ( optional_string("+Repeat Count:")){
2870                 stuff_int( &(event->repeat_count) );
2871         } else {
2872                 event->repeat_count = 1;
2873         }
2874
2875         event->interval = -1;
2876         if ( optional_string("+Interval:")){
2877                 stuff_int( &(event->interval) );
2878         }
2879
2880         event->score = 0;
2881         if ( optional_string("+Score:") ){
2882                 stuff_int(&event->score);
2883         }
2884
2885         if ( optional_string("+Chained:") ){
2886                 stuff_int(&event->chain_delay);
2887         }
2888
2889         if ( optional_string("+Objective:") ) {
2890                 stuff_string(buf, F_NAME, NULL);
2891                 event->objective_text = strdup(buf);
2892         } else {
2893                 event->objective_text = NULL;
2894         }
2895
2896         if ( optional_string("+Objective key:") ) {
2897                 stuff_string(buf, F_NAME, NULL);
2898                 event->objective_key_text = strdup(buf);
2899         } else {
2900                 event->objective_key_text = NULL;
2901         }
2902
2903         event->team = -1;
2904         if( optional_string("+Team:") ) {
2905                 stuff_int(&event->team);
2906         }
2907
2908         event->timestamp = timestamp(-1);
2909
2910         // sanity check on the repeat count variable
2911         if ( event->repeat_count <= 0 ){
2912                 Error (LOCATION, "Repeat count for mission event %s is <=0.\nMust be >= 1!", event->name );
2913         }
2914 }
2915
2916 void parse_events(mission *pm)
2917 {
2918         required_string("#Events");
2919
2920         while (required_string_either( "#Goals", "$Formula:")) {
2921                 SDL_assert( Num_mission_events < MAX_MISSION_EVENTS );
2922                 parse_event(pm);
2923                 Num_mission_events++;
2924         }
2925 }
2926
2927 void parse_goal(mission *pm)
2928 {
2929         int dummy;
2930
2931         mission_goal    *goalp;
2932
2933         goalp = &Mission_goals[Num_goals++];
2934
2935         SDL_assert(Num_goals < MAX_GOALS);
2936         SDL_assert(pm != NULL);
2937
2938         find_and_stuff("$Type:", &goalp->type, F_NAME, Goal_type_names, Num_goal_type_names, "goal type");
2939
2940         required_string("+Name:");
2941         stuff_string(goalp->name, F_NAME, NULL);
2942
2943         // backwards compatibility for old Fred missions - all new missions should use $MessageNew
2944         if(optional_string("$Message:")){
2945                 stuff_string(goalp->message, F_NAME, NULL, MAX_GOAL_TEXT);
2946         } else {
2947                 required_string("$MessageNew:");
2948                 stuff_string(goalp->message, F_MULTITEXT, NULL, MAX_GOAL_TEXT);
2949         }
2950
2951         if (optional_string("$Rating:")){
2952                 stuff_int(&dummy);  // not used
2953         }
2954
2955         required_string("$Formula:");
2956         goalp->formula = get_sexp_main();
2957
2958         goalp->flags = 0;
2959         if ( optional_string("+Invalid:") )
2960                 goalp->type |= INVALID_GOAL;
2961         if ( optional_string("+Invalid") )
2962                 goalp->type |= INVALID_GOAL;
2963         if ( optional_string("+No music") )
2964                 goalp->flags |= MGF_NO_MUSIC;
2965
2966         goalp->score = 0;
2967         if ( optional_string("+Score:") ){
2968                 stuff_int(&goalp->score);
2969         }
2970
2971         goalp->team = 0;
2972         if ( optional_string("+Team:") ){
2973                 stuff_int( &goalp->team );
2974         }
2975 }
2976
2977 void parse_goals(mission *pm)
2978 {
2979         required_string("#Goals");
2980
2981         while (required_string_either("#Waypoints", "$Type:")){
2982                 parse_goal(pm);
2983         }
2984 }
2985
2986 void parse_waypoint_list(mission *pm)
2987 {
2988         waypoint_list   *wpl;
2989
2990
2991         SDL_assert(Num_waypoint_lists < MAX_WAYPOINT_LISTS);
2992         SDL_assert(pm != NULL);
2993         wpl = &Waypoint_lists[Num_waypoint_lists];
2994
2995         required_string("$Name:");
2996         stuff_string(wpl->name, F_NAME, NULL);
2997
2998         required_string("$List:");
2999         wpl->count = stuff_vector_list(wpl->waypoints, MAX_WAYPOINTS_PER_LIST);
3000
3001 #ifdef MAKE_FS1
3002         // AAAAHH!  I don't like to hard code a mission fix but I have no clue what to do
3003         // to fix this properly.  In the FS1 mission "Playing Judas" you have to try and fly
3004         // into one of the docking bays on the Lucifer.  Due to some change in the code the
3005         // waypoints and the Lucifer's position don't match up so we have to change the
3006         // waypoint position to compensate.
3007         if ( !SDL_strcasecmp(pm->name, "Playing Judas") ) {
3008                 if ( !SDL_strcasecmp(wpl->name, "Docking Bay 1") ) {
3009                         wpl->waypoints[0].xyz.x = -1262.550903;
3010                         wpl->waypoints[0].xyz.y = 27.676950;
3011                         wpl->waypoints[0].xyz.z = 4461.702930;
3012                 } else if ( !SDL_strcasecmp(wpl->name, "Docking Bat 2") ) { // it really is spelled "Bat" in the mission
3013                         wpl->waypoints[0].xyz.x = -1105.347976;
3014                         wpl->waypoints[0].xyz.y = 27.676950;
3015                         wpl->waypoints[0].xyz.z = 3900.236867;
3016                 }
3017         }
3018 #endif
3019
3020         Num_waypoint_lists++;
3021 }
3022
3023 void parse_waypoints(mission *pm)
3024 {
3025         int z;
3026         vector pos;
3027
3028         required_string("#Waypoints");
3029
3030         Num_jump_nodes = 0;
3031         while (optional_string("$Jump Node:")) {
3032                 SDL_assert(Num_jump_nodes < MAX_JUMP_NODES);
3033                 stuff_vector(&pos);
3034                 z = jumpnode_create(&pos);
3035                 SDL_assert(z >= 0);
3036
3037                 if (optional_string("$Jump Node Name:")) {
3038                         stuff_string(Jump_nodes[Num_jump_nodes - 1].name, F_NAME, NULL);
3039                 }
3040
3041                 // If no name exists, then use a standard name
3042                 if ( Jump_nodes[Num_jump_nodes - 1].name[0] == 0 ) {
3043                         SDL_snprintf(Jump_nodes[Num_jump_nodes - 1].name, NAME_LENGTH, "Jump Node %d", Num_jump_nodes);
3044                 }
3045         }
3046
3047         while (required_string_either("#Messages", "$Name:"))
3048                 parse_waypoint_list(pm);
3049 }
3050
3051 void parse_messages(mission *pm)
3052 {
3053         required_string("#Messages");
3054
3055         mprintf(("Starting mission message count : %d\n", Num_message_waves));
3056
3057         // the message_parse function can be found in MissionMessage.h.  The format in the
3058         // mission file takes the same format as the messages in messages,tbl.  Make parsing
3059         // a whole lot easier!!!
3060         while ( required_string_either("#Reinforcements", "$Name")){
3061                 message_parse();                // call the message parsing system
3062         }
3063
3064         mprintf(("Ending mission message count : %d\n", Num_message_waves));
3065 }
3066
3067 void parse_reinforcement(mission *pm)
3068 {
3069         reinforcements *ptr;
3070         int instance;
3071
3072         SDL_assert(Num_reinforcements < MAX_REINFORCEMENTS);
3073         SDL_assert(pm != NULL);
3074         ptr = &Reinforcements[Num_reinforcements];
3075
3076         required_string("$Name:");
3077         stuff_string(ptr->name, F_NAME, NULL);  
3078
3079         find_and_stuff("$Type:", &ptr->type, F_NAME, Reinforcement_type_names, Num_reinforcement_type_names, "reinforcement type");
3080
3081         required_string("$Num times:");
3082         stuff_int(&ptr->uses);
3083         ptr->num_uses = 0;
3084
3085         // reset the flags to 0
3086         ptr->flags = 0;
3087
3088         if ( optional_string("+Arrival delay:") ){
3089                 stuff_int( &(ptr->arrival_delay) );
3090         }
3091
3092         if ( optional_string("+No Messages:") ){
3093                 stuff_string_list( ptr->no_messages, MAX_REINFORCEMENT_MESSAGES );
3094         }
3095
3096         if ( optional_string("+Yes Messages:") ){
3097                 stuff_string_list( ptr->yes_messages, MAX_REINFORCEMENT_MESSAGES );
3098         }       
3099
3100         // sanity check on the names of reinforcements -- must either be wings/ships/arrival list.
3101         if ( ship_name_lookup(ptr->name) == -1 ) {
3102                 if ( wing_name_lookup(ptr->name, 1) == -1 ) {
3103                         p_object *p_objp;
3104
3105                         for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3106                                 if ( !SDL_strcasecmp(ptr->name, p_objp->name) ){
3107                                         break;
3108                                 }
3109                         }
3110
3111                         if ( p_objp == END_OF_LIST(&ship_arrival_list) ) {
3112                                 Warning(LOCATION, "Reinforcement %s not found as ship or wing", ptr->name);
3113                                 return;
3114                         }
3115                 }
3116         }
3117
3118         // now, if the reinforcement is a wing, then set the number of waves of the wing == number of
3119         // uses of the reinforcement
3120         instance = wing_name_lookup(ptr->name, 1);
3121         if ( instance != -1 )
3122                 Wings[instance].num_waves = ptr->uses;
3123
3124         Num_reinforcements++;
3125 }
3126
3127 void parse_reinforcements(mission *pm)
3128 {
3129         Num_reinforcements = 0;
3130         required_string("#Reinforcements");
3131
3132         while (required_string_either("#Background bitmaps", "$Name:"))
3133                 parse_reinforcement(pm);
3134 }
3135
3136 void parse_bitmap(mission *pm)
3137 {
3138 #ifdef MAKE_FS1
3139         starfield_bitmap_instance b;
3140
3141         Num_suns = 0;
3142
3143         SDL_assert(pm != NULL);
3144
3145         while(optional_string("$Bitmap:")) {
3146                 stuff_string(b.filename, F_NAME, NULL);
3147         
3148                 required_string("$Orientation:");
3149                 stuff_matrix(&b.m);
3150
3151                 required_string("$Rotation rate:");
3152                 stuff_float(&b.rot);
3153
3154                 required_string("$Distance:");
3155                 stuff_float(&b.scale_x);                
3156                 b.scale_y = b.scale_x;
3157                 b.div_x = 1;
3158                 b.div_y = 1;
3159
3160                 required_string("$Light:");
3161                 stuff_int(&b.sun_light);
3162
3163                 if(Num_suns < MAX_STARFIELD_BITMAPS){
3164                         Suns[Num_suns] = b;
3165                         SDL_strlcpy(Suns[Num_suns].filename, b.filename, sizeof(b.filename));
3166                         Num_suns++;
3167                 }
3168         }
3169 #else
3170         /*
3171         char name[NAME_LENGTH];
3172         int z;
3173         starfield_bitmaps *ptr;
3174
3175         SDL_assert(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS);
3176         SDL_assert(pm != NULL);
3177         ptr = &Starfield_bitmaps[Num_starfield_bitmaps];
3178
3179         required_string("$Bitmap:");
3180         stuff_string(name, F_NAME, NULL);
3181         for (z=0; z<Num_starfield_bitmap_lists; z++)    {
3182                 if (!SDL_strcasecmp(name, Starfield_bitmap_list[z].name)){
3183                         break;
3184                 }
3185         }
3186
3187         if ( z >= Num_starfield_bitmap_lists )  {
3188                 Warning( LOCATION, "Bitmap specified in mission not in game!\n" );
3189                 z = 0;
3190         }
3191         
3192         ptr->bitmap_index = z;
3193         required_string("$Orientation:");
3194         stuff_matrix(&ptr->m);
3195
3196         required_string("$Rotation rate:");
3197         stuff_float(&ptr->rot);
3198
3199         required_string("$Distance:");
3200         stuff_float(&ptr->dist);
3201
3202         required_string("$Light:");
3203         stuff_int(&ptr->light);
3204         Num_starfield_bitmaps++;
3205         calculate_bitmap_points(ptr);
3206         */
3207         Int3();
3208 #endif
3209 }
3210
3211 void parse_bitmaps(mission *pm)
3212 {
3213         char str[MAX_FILENAME_LEN+1] = "";
3214         starfield_bitmap_instance b;
3215         int z;
3216
3217         Num_starfield_bitmaps = 0;
3218         required_string("#Background bitmaps");
3219
3220         required_string("$Num stars:");
3221         stuff_int(&Num_stars);
3222         if (Num_stars >= MAX_STARS)
3223                 Num_stars = MAX_STARS;
3224
3225         int Ambient_light_level;
3226         required_string("$Ambient light level:");
3227         stuff_int(&Ambient_light_level);
3228
3229         // This should call light_set_ambient() to
3230         // set the ambient light
3231
3232         Nebula_index = -1;
3233         Mission_palette = 1;
3234
3235         if(The_mission.flags & MISSION_FLAG_FULLNEB){
3236                 // no regular nebula stuff
3237                 nebula_close();
3238
3239                 // neb2 info
3240                 SDL_strlcpy(Neb2_texture_name, "Eraseme3", sizeof(Neb2_texture_name));
3241                 Neb2_poof_flags = ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
3242                 if(optional_string("+Neb2:")){
3243                         stuff_string(Neb2_texture_name, F_NAME, NULL);
3244
3245                         required_string("+Neb2Flags:");                 
3246                         stuff_int(&Neb2_poof_flags);
3247
3248                         // initialize neb effect. its gross to do this here, but Fred is dumb so I have no choice ... :(
3249                         if(Fred_running){
3250                                 neb2_level_init();
3251                         }
3252                 }
3253         } else {
3254                 if (optional_string("+Nebula:")) {
3255                         stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3256                         
3257                         // parse the proper nebula type (full or not)   
3258                         for (z=0; z<NUM_NEBULAS; z++){
3259                                 if(The_mission.flags & MISSION_FLAG_FULLNEB){
3260                                         if (!SDL_strcasecmp(str, Neb2_filenames[z])) {
3261                                                 Nebula_index = z;
3262                                                 break;
3263                                         }
3264                                 } else {
3265                                         if (!SDL_strcasecmp(str, Nebula_filenames[z])) {
3266                                                 Nebula_index = z;
3267                                                 break;
3268                                         }
3269                                 }
3270                         }
3271
3272                         if (optional_string("+Color:")) {
3273                                 stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3274                                 for (z=0; z<NUM_NEBULA_COLORS; z++){
3275                                         if (!SDL_strcasecmp(str, Nebula_colors[z])) {
3276                                                 Mission_palette = z;
3277                                                 break;
3278                                         }
3279                                 }
3280                         }
3281
3282                         if (optional_string("+Pitch:")){
3283                                 stuff_int(&Nebula_pitch);
3284                         } else {
3285                                 Nebula_pitch = 0;
3286                         }
3287
3288                         if (optional_string("+Bank:")){
3289                                 stuff_int(&Nebula_bank);
3290                         } else {
3291                                 Nebula_bank = 0;
3292                         }
3293
3294                         if (optional_string("+Heading:")){
3295                                 stuff_int(&Nebula_heading);
3296                         } else {
3297                                 Nebula_heading = 0;
3298                         }                                               
3299                 }
3300
3301                 if (Nebula_index >= 0){         
3302                         nebula_init(Nebula_filenames[Nebula_index], Nebula_pitch, Nebula_bank, Nebula_heading);
3303                 } else {
3304                         nebula_close();         
3305                 }
3306         }       
3307         
3308         // parse suns
3309         Num_suns = 0;
3310         while(optional_string("$Sun:")){
3311                 // filename
3312                 stuff_string(b.filename, F_NAME, NULL);
3313                         
3314                 // angles
3315                 required_string("+Angles:");
3316                 stuff_float(&b.ang.p);
3317                 stuff_float(&b.ang.b);
3318                 stuff_float(&b.ang.h);          
3319
3320                 // scale
3321                 required_string("+Scale:");
3322                 stuff_float(&b.scale_x);                
3323                 b.scale_y = b.scale_x;
3324                 b.div_x = 1;
3325                 b.div_y = 1;
3326                 
3327                 // if we have room, store it
3328                 if(Num_suns < MAX_STARFIELD_BITMAPS){
3329                         Suns[Num_suns] = b;
3330                         SDL_strlcpy(Suns[Num_suns].filename, b.filename, sizeof(b.filename));
3331                         Num_suns++;
3332                 }
3333         }
3334
3335         // parse background bitmaps
3336         Num_starfield_bitmaps = 0;
3337         while(optional_string("$Starbitmap:")){
3338                 // filename
3339                 stuff_string(b.filename, F_NAME, NULL);
3340                         
3341                 // angles
3342                 required_string("+Angles:");
3343                 stuff_float(&b.ang.p);
3344                 stuff_float(&b.ang.b);
3345                 stuff_float(&b.ang.h);          
3346
3347                 // scale
3348                 // scale
3349                 if(optional_string("+Scale:")){
3350                         stuff_float(&b.scale_x);
3351                         b.scale_y = b.scale_x;
3352                         b.div_x = 1;
3353                         b.div_y = 1;
3354                 } else {
3355                         required_string("+ScaleX:");
3356                         stuff_float(&b.scale_x);
3357
3358                         required_string("+ScaleY:");
3359                         stuff_float(&b.scale_y);
3360
3361                         required_string("+DivX:");
3362                         stuff_int(&b.div_x);
3363
3364                         required_string("+DivY:");
3365                         stuff_int(&b.div_y);
3366                 }               
3367                 
3368                 // if we have room, store it
3369                 if(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS){
3370                         Starfield_bitmap_instance[Num_starfield_bitmaps] = b;
3371                         SDL_strlcpy(Starfield_bitmap_instance[Num_starfield_bitmaps].filename, b.filename, sizeof(b.filename));
3372                         Num_starfield_bitmaps++;
3373                 }
3374         }
3375
3376 #ifdef MAKE_FS1
3377         parse_bitmap(pm);
3378 #endif
3379         
3380         if ( optional_string("#Asteroid Fields") ){
3381                 parse_asteroid_fields(pm);
3382         }
3383 }
3384
3385 void parse_asteroid_fields(mission *pm)
3386 {
3387 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
3388
3389         int i, count, subtype;
3390
3391         SDL_assert(pm != NULL);
3392         for (i=0; i<MAX_ASTEROID_FIELDS; i++)
3393                 Asteroid_field.num_initial_asteroids = 0;
3394
3395         i = 0;
3396         count = 0;
3397 //      required_string("#Asteroid Fields");
3398 #ifdef MAKE_FS1
3399         while (required_string_either("#", "$Density:")) {
3400 #else
3401         while (required_string_either("#", "$density:")) {
3402 #endif
3403                 float speed, density;
3404
3405                 SDL_assert(i < 1);
3406                 required_string("$Density:");
3407                 stuff_float(&density);
3408
3409                 Asteroid_field.num_initial_asteroids = (int) density;
3410
3411                 Asteroid_field.field_type = FT_ACTIVE;
3412                 if (optional_string("+Field Type:")) {
3413                         stuff_int((int*)&Asteroid_field.field_type);
3414                 }
3415
3416                 Asteroid_field.debris_genre = DG_ASTEROID;
3417                 if (optional_string("+Debris Genre:")) {
3418                         stuff_int((int*)&Asteroid_field.debris_genre);
3419                 }
3420
3421                 Asteroid_field.field_debris_type[0] = -1;
3422                 Asteroid_field.field_debris_type[1] = -1;
3423                 Asteroid_field.field_debris_type[2] = -1;
3424                 if (Asteroid_field.debris_genre == DG_SHIP) {
3425                         if (optional_string("+Field Debris Type:")) {
3426                                 stuff_int(&Asteroid_field.field_debris_type[0]);
3427                         }
3428                         if (optional_string("+Field Debris Type:")) {
3429                                 stuff_int(&Asteroid_field.field_debris_type[1]);
3430                         }
3431                         if (optional_string("+Field Debris Type:")) {
3432                                 stuff_int(&Asteroid_field.field_debris_type[2]);
3433                         }
3434                 } else {
3435                         // debris asteroid
3436                         if (optional_string("+Field Debris Type:")) {
3437                                 stuff_int(&subtype);
3438                                 Asteroid_field.field_debris_type[subtype] = 1;
3439                                 count++;
3440                         }
3441                         if (optional_string("+Field Debris Type:")) {
3442                                 stuff_int(&subtype);
3443                                 Asteroid_field.field_debris_type[subtype] = 1;
3444                                 count++;
3445                         }
3446                         if (optional_string("+Field Debris Type:")) {
3447                                 stuff_int(&subtype);
3448                                 Asteroid_field.field_debris_type[subtype] = 1;
3449                                 count++;
3450                         }
3451                 }
3452
3453                 // backward compatibility
3454                 if ( (Asteroid_field.debris_genre == DG_ASTEROID) && (count == 0) ) {
3455                         Asteroid_field.field_debris_type[0] = 0;
3456                 }
3457
3458                 required_string("$Average Speed:");
3459                 stuff_float(&speed);
3460
3461                 vm_vec_rand_vec_quick(&Asteroid_field.vel);
3462                 vm_vec_scale(&Asteroid_field.vel, speed);
3463
3464                 Asteroid_field.speed = speed;
3465
3466                 required_string("$Minimum:");
3467                 stuff_vector(&Asteroid_field.min_bound);
3468
3469                 required_string("$Maximum:");
3470                 stuff_vector(&Asteroid_field.max_bound);
3471
3472                 if (optional_string("+Inner Bound:")) {
3473                         Asteroid_field.has_inner_bound = 1;
3474
3475                         required_string("$Minimum:");
3476                         stuff_vector(&Asteroid_field.inner_min_bound);
3477
3478                         required_string("$Maximum:");
3479                         stuff_vector(&Asteroid_field.inner_max_bound);
3480                 } else {
3481                         Asteroid_field.has_inner_bound = 0;
3482                 }
3483                 i++;
3484         }
3485 #endif // DEMO
3486 }
3487
3488 void parse_variables()
3489 {
3490         if (! optional_string("#Sexp_variables") ) {
3491                 return;
3492         } else {
3493                 stuff_sexp_variable_list();
3494         }
3495 }
3496
3497
3498 void parse_mission(mission *pm, int flag)
3499 {
3500         int i;
3501
3502         Player_starts = Num_cargo = Num_waypoint_lists = Num_goals = num_wings = num_ship_arrivals = 0;
3503         Player_start_shipnum = -1;
3504         *Player_start_shipname = 0;             // make the string 0 length for checking later
3505         memset( &Player_start_pobject, 0, sizeof(Player_start_pobject) );
3506
3507         // initialize the initially_docked array.
3508         for ( i = 0; i < MAX_SHIPS; i++ ) {
3509                 Initially_docked[i].docker = NULL;
3510                 Initially_docked[i].dockee[0] = '\0';
3511                 Initially_docked[i].docker_point[0] = '\0';
3512                 Initially_docked[i].dockee_point[0] = '\0';
3513         }
3514         Total_initially_docked = 0;
3515
3516         list_init( &ship_arrival_list );                // init lists for arrival objects and wings
3517
3518         init_parse();
3519         Subsys_index = 0;
3520
3521         parse_mission_info(pm); 
3522         Current_file_checksum = netmisc_calc_checksum(pm,MISSION_CHECKSUM_SIZE);
3523         if ( flag == MISSION_PARSE_MISSION_INFO )
3524                 return;
3525         parse_plot_info(pm);
3526         parse_variables();
3527         parse_briefing_info(pm);        // TODO: obsolete code, keeping so we don't obsolete existing mission files
3528         parse_cmd_briefs(pm);
3529         parse_briefing(pm);
3530         parse_debriefing_new(pm);
3531         parse_player_info(pm);
3532         parse_objects(pm, flag);
3533         parse_wings(pm);
3534         parse_events(pm);
3535         parse_goals(pm);
3536         parse_waypoints(pm);
3537         parse_messages(pm);
3538         parse_reinforcements(pm);
3539         parse_bitmaps(pm);
3540         parse_music(pm);
3541
3542         post_process_mission();
3543 }
3544
3545 void post_process_mission()
3546 {
3547         int                     i;
3548         int                     indices[MAX_SHIPS], objnum;
3549         p_object                *p_objp;
3550         ship_weapon     *swp;
3551         ship_obj *so;
3552
3553         // the player_start_shipname had better exist at this point!
3554         Player_start_shipnum = ship_name_lookup( Player_start_shipname );
3555         SDL_assert ( Player_start_shipnum != -1 );
3556         SDL_assert ( Player_start_pobject.flags & P_SF_PLAYER_START_VALID );
3557
3558         // Assign objnum, shipnum, etc. to the player structure
3559         objnum = Ships[Player_start_shipnum].objnum;
3560         Player_obj = &Objects[objnum];
3561         if (!Fred_running){
3562                 Player->objnum = objnum;
3563         }
3564
3565         Player_obj->flags |= OF_PLAYER_SHIP;                    // make this object a player controlled ship.
3566         Player_ship = &Ships[Player_start_shipnum];
3567         Player_ai = &Ai_info[Player_ship->ai_index];
3568
3569         Player_ai->targeted_subsys = NULL;
3570         Player_ai->targeted_subsys_parent = -1;
3571
3572         // determine if player start has initial velocity and set forward cruise percent to relect this
3573         if ( Player_obj->phys_info.vel.xyz.z > 0.0f )
3574                 Player->ci.forward_cruise_percent = Player_obj->phys_info.vel.xyz.z / Player_ship->current_max_speed * 100.0f;
3575
3576         // put in hard coded starting wing names.
3577         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3578                 Starting_wings[0] = wing_name_lookup(Starting_wing_names[0],1);
3579                 Starting_wings[1] = wing_name_lookup(Starting_wing_names[MAX_STARTING_WINGS],1);
3580         } else {
3581                 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
3582                         Starting_wings[i] = wing_name_lookup(Starting_wing_names[i], 1);
3583                 }
3584         }
3585
3586         init_ai_system();
3587
3588         // call a function to deal with intially docked ships
3589         mission_parse_do_initial_docks();
3590
3591         // deal with setting up arrival location for all ships.  Must do this now after all ships are created
3592         mission_parse_set_arrival_locations();
3593
3594         // clear out information about arriving support ships
3595         Arriving_support_ship = NULL;
3596         Num_arriving_repair_targets = 0;
3597
3598         // convert all ship name indices to ship indices now that mission has been loaded
3599         if (Fred_running) {
3600                 for (i=0; i<Num_parse_names; i++) {
3601                         indices[i] = ship_name_lookup(Parse_names[i], 1);
3602                         if (indices[i] < 0)
3603                                 Warning(LOCATION, "Ship name \"%s\" referenced, but this ship doesn't exist", Parse_names[i]);
3604                 }
3605
3606                 for (i=0; i<MAX_SHIPS; i++) {
3607                         if ((Ships[i].objnum >= 0) && (Ships[i].arrival_anchor >= 0) && (Ships[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3608                                 Ships[i].arrival_anchor = indices[Ships[i].arrival_anchor];
3609
3610                         if ( (Ships[i].objnum >= 0) && (Ships[i].departure_anchor >= 0) )
3611                                 Ships[i].departure_anchor = indices[Ships[i].departure_anchor];
3612                 }
3613
3614                 for (i=0; i<MAX_WINGS; i++) {
3615                         if (Wings[i].wave_count  && (Wings[i].arrival_anchor >= 0) && (Wings[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3616                                 Wings[i].arrival_anchor = indices[Wings[i].arrival_anchor];
3617
3618                         if (Wings[i].wave_count  && (Wings[i].departure_anchor >= 0) )
3619                                 Wings[i].departure_anchor = indices[Wings[i].departure_anchor];
3620                 }
3621
3622         }
3623
3624         // before doing anything else, we must validate all of the sexpressions that were loaded into the mission.
3625         // Loop through the Sexp_nodes array and send the top level functions to the check_sexp_syntax parser
3626
3627         for (i = 0; i < MAX_SEXP_NODES; i++) {
3628                 if ( is_sexp_top_level(i) && (!Fred_running || (i != Sexp_clipboard))) {
3629                         int result, bindex, op;
3630
3631                         op = identify_operator(CTEXT(i));
3632                         SDL_assert(op != -1);  // need to make sure it is an operator before we treat it like one..
3633                         result = check_sexp_syntax( i, query_operator_return_type(op), 1, &bindex);
3634
3635                         // entering this if statement will result in program termination!!!!!
3636                         // print out an error based on the return value from check_sexp_syntax()
3637                         if ( result ) {
3638                                 char sexp_str[8192], text[8192];
3639
3640                                 convert_sexp_to_string( i, sexp_str, sizeof(sexp_str), SEXP_ERROR_CHECK_MODE);
3641                                 SDL_snprintf(text, sizeof(text), "%s.\n\nIn sexpression: %s\n(Error appears to be: %s)",
3642                                         sexp_error_message(result), sexp_str, Sexp_nodes[bindex].text);
3643
3644                                 if (!Fred_running)
3645                                         Error( LOCATION, text );
3646                                 else
3647                                         Warning( LOCATION, text );
3648                         }
3649                 }
3650         }
3651
3652         ai_post_process_mission();
3653
3654
3655         /*
3656         for (i=0; i<Total_initially_docked; i++) {
3657                 z = ship_name_lookup(Initially_docked[i].dockee);
3658                 if (z >= 0) {
3659                         SDL_assert(Initially_docked[i].docker->type == OBJ_SHIP);
3660                         p1 = model_find_dock_name_index(Ships[Initially_docked[i].docker->instance].modelnum,
3661                                 Initially_docked[i].docker_point);
3662                         SDL_assert(Objects[z].type == OBJ_SHIP);
3663                         p2 = model_find_dock_name_index(Ships[Objects[z].instance].modelnum,
3664                                 Initially_docked[i].dockee_point);
3665
3666                         if ((p1 >= 0) && (p2 >= 0)) {
3667                                 nprintf(("AI", "Initially Docked: %s with %s\n", Ships[Initially_docked[i].docker->instance].ship_name, Ships[Objects[z].instance].ship_name));
3668                                 if (ship_docking_valid(Initially_docked[i].docker->instance, Objects[z].instance))  // only dock if they are allowed to be docked.
3669                                         ai_dock_with_object(Initially_docked[i].docker, &Objects[z], 89, AIDO_DOCK_NOW, p1, p2);
3670                                         
3671                         } else
3672                                 Int3();         //      Curious.  Two ships told to dock, but one of the dock points is bogus.  
3673                                                                 // Get Allender or Hoffoss, one of whom probably wrote the above if ()
3674                 }
3675         }
3676         */
3677
3678         // we must also count all of the ships of particular types.  We count all of the ships that do not have
3679         // their SF_IGNORE_COUNT flag set.  We don't count ships in wings when the equivalent wing flag is set.
3680         // in counting ships in wings, we increment the count by the wing's wave count to account for everyone.
3681         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
3682                 int siflags, num, shipnum;
3683
3684                 shipnum = Objects[so->objnum].instance;
3685                 // pass over non-ship objects and player ship objects
3686                 if ( Ships[shipnum].objnum == -1 || (Objects[Ships[shipnum].objnum].flags & OF_PLAYER_SHIP) )
3687                         continue;
3688                 if ( Ships[shipnum].flags & SF_IGNORE_COUNT )
3689                         continue;
3690                 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_IGNORE_COUNT) )
3691                         continue;
3692
3693                 siflags = Ship_info[Ships[shipnum].ship_info_index].flags;
3694                 
3695                 // determine the number of times we need to add this ship into the count
3696 //              if ( Ships[i].wingnum == -1 )
3697                         num = 1;
3698 //              else
3699 //                      num = Wings[Ships[i].wingnum].num_waves;
3700
3701                 ship_add_ship_type_count( siflags, num );
3702         }
3703         // now go through the list of ships yet to arrive
3704         for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3705                 int siflags, num;
3706
3707                 // go through similar motions as above
3708                 if ( p_objp->flags & P_SF_IGNORE_COUNT )
3709                         continue;
3710                 if ( (p_objp->wingnum != -1) && (Wings[p_objp->wingnum].flags & WF_IGNORE_COUNT) )
3711                         continue;
3712
3713                 siflags = Ship_info[p_objp->ship_class].flags;
3714
3715                 if ( p_objp->wingnum == -1 )
3716                         num = 1;
3717                 else
3718                         num = Wings[p_objp->wingnum].num_waves - 1;                     // subtract one since we already counted the first wave
3719                 
3720                 ship_add_ship_type_count( siflags, num );
3721         }
3722
3723         // set player weapons that are selected by default
3724         // AL 09/17/97: I added this code to select the first primary/secondary weapons, 
3725         // since I noticed the player ship sometimes doesn't get default weapons selected               
3726
3727         // DB: modified 4/23/98 to take multiplayer into account. Under certain circumstances, multiplayer netplayer ships
3728         //     had their current_primary_bank and current_secondary_bank set to -1 (from ship_set()) and left there since
3729         //     Player_ship is not the only one we need to need about.
3730         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
3731                 ship *shipp = &Ships[Objects[so->objnum].instance];
3732
3733                 // don't process non player wing ships
3734                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
3735                         continue;                       
3736
3737                 swp = &shipp->weapons;
3738         
3739                 // swp = &Player_ship->weapons;
3740                 if ( swp->num_primary_banks > 0 ) {
3741                         swp->current_primary_bank = 0;                  // currently selected primary bank
3742                 }
3743
3744                 if ( swp->num_secondary_banks > 0 ) {
3745                         swp->current_secondary_bank = 0;                        // currently selected secondary bank
3746                 }
3747         }
3748
3749         ets_init_ship(Player_obj);      // init ETS data for the player
3750
3751         // put the timestamp stuff here for now
3752         Mission_arrival_timestamp = timestamp( ARRIVAL_TIMESTAMP );
3753         Mission_departure_timestamp = timestamp( DEPARTURE_TIMESTAMP );
3754         Mission_end_time = -1;
3755
3756         if(Game_mode & GM_MULTIPLAYER){ 
3757                 multi_respawn_build_points();
3758         }       
3759
3760         // maybe reset hotkey defaults when loading new mission
3761         if ( Last_file_checksum != Current_file_checksum ){
3762                 mission_hotkey_reset_saved();
3763         }
3764
3765         Allow_arrival_music_timestamp=timestamp(0);
3766         Allow_arrival_message_timestamp=timestamp(0);
3767         Arrival_message_delay_timestamp = timestamp(-1);
3768
3769         int idx;
3770         for(idx=0; idx<2; idx++){
3771                 Allow_arrival_music_timestamp_m[idx]=timestamp(0);
3772                 Allow_arrival_message_timestamp_m[idx]=timestamp(0);
3773                 Arrival_message_delay_timestamp_m[idx] = timestamp(-1);
3774         }       
3775
3776         Last_file_checksum = Current_file_checksum;
3777 }
3778
3779 int get_mission_info(char *filename, mission *mission_p)
3780 {
3781         int rval;
3782
3783         // if mission_p is NULL, make it point to The_mission
3784         if ( mission_p == NULL )
3785                 mission_p = &The_mission;
3786
3787         if ((rval = setjmp(parse_abort)) != 0) {
3788                 nprintf(("Error", "Error abort!  Code = %d", rval));
3789                 return rval;
3790         
3791         } else {
3792                 int filelength;
3793
3794                 // open localization
3795                 lcl_ext_open();
3796
3797                 CFILE *ftemp = cfopen(filename, "rt");
3798                 if (!ftemp){
3799                         // close localization
3800                         lcl_ext_close();
3801
3802                         return -1;
3803                 }
3804
3805                 // 7/9/98 -- MWA -- check for 0 length file.
3806                 filelength = cfilelength(ftemp);
3807                 cfclose(ftemp);
3808                 if ( filelength == 0 ){
3809                         // close localization
3810                         lcl_ext_close();        
3811
3812                         return -1;
3813                 }
3814
3815                 read_file_text(filename, CF_TYPE_MISSIONS);
3816                 memset( mission_p, 0, sizeof(mission) );
3817                 init_parse();
3818                 parse_mission_info(mission_p);
3819
3820                 // close localization
3821                 lcl_ext_close();
3822         }
3823
3824         return 0;
3825 }
3826
3827 // mai parse routine for parsing a mission.  The default parameter flags tells us which information
3828 // to get when parsing the mission.  0 means get everything (default).  Other flags just gets us basic
3829 // info such as game type, number of players etc.
3830 int parse_main(const char *mission_name, int flags)
3831 {
3832         int rval, i;
3833
3834         // fill in Ship_class_names array with the names from the ship_info struct;
3835         Num_parse_names = 0;
3836         Mission_all_attack = 0; //      Might get set in mission load.
3837         SDL_assert(Num_ship_types < MAX_SHIP_TYPES);
3838
3839         for (i = 0; i < Num_ship_types; i++)
3840                 Ship_class_names[i] = Ship_info[i].name;
3841
3842         if ((rval = setjmp(parse_abort)) != 0) {
3843                 nprintf(("Error", "Error abort!  Code = %i.", rval));
3844                 return rval;
3845         
3846         } else {
3847                 // open localization
3848                 lcl_ext_open();
3849
3850                 CFILE *ftemp = cfopen(mission_name, "rt", CFILE_NORMAL, CF_TYPE_MISSIONS);
3851                 // fail situation.
3852                 if (!ftemp) {
3853                         if (!Fred_running)
3854                                 Error( LOCATION, "Couldn't open mission '%s'\n", mission_name );
3855
3856                         Current_file_length = -1;
3857                         Current_file_checksum = 0;
3858
3859                         // close localization
3860                         lcl_ext_close();
3861
3862                         return -1;
3863                 }
3864
3865                 Current_file_length = cfilelength(ftemp);
3866                 cfclose(ftemp);
3867
3868                 read_file_text(mission_name, CF_TYPE_MISSIONS);
3869                 memset(&The_mission, 0, sizeof(The_mission));
3870                 parse_mission(&The_mission, flags);
3871                 display_parse_diagnostics();
3872
3873                 // close localization
3874                 lcl_ext_close();
3875         }
3876
3877         if (!Fred_running)
3878                 SDL_strlcpy(Mission_filename, mission_name, sizeof(Mission_filename));
3879
3880         return 0;
3881 }
3882
3883 // sets the arrival lcoation of the ships in wingp.  pass num_to_set since the threshold value
3884 // for wings may have us create more ships in the wing when there are still some remaining
3885 void mission_set_wing_arrival_location( wing *wingp, int num_to_set )
3886 {
3887         int index;
3888
3889         // get the starting index into the ship_index array of the first ship whose location we need set.
3890
3891         index = wingp->current_count - num_to_set;
3892         if ( (wingp->arrival_location == ARRIVE_FROM_DOCK_BAY) || (wingp->arrival_location == ARRIVE_AT_LOCATION) ) {
3893                 while ( index < wingp->current_count ) {
3894                         object *objp;
3895
3896                         objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3897                         mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3898
3899                         index++;
3900                 }
3901         } else {
3902                 object *leader_objp;
3903                 vector pos;
3904                 matrix orient;
3905                 int wing_index;
3906
3907                 // wing is not arriving from a docking bay -- possibly move them based on arriving near
3908                 // or in front of some other ship.
3909                 index = wingp->current_count - num_to_set;
3910                 leader_objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3911                 if (mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(leader_objp), &pos, &orient)) {
3912                         // modify the remaining ships created
3913                         index++;
3914                         wing_index = 1;
3915                         while ( index < wingp->current_count ) {
3916                                 object *objp;
3917
3918                                 objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3919
3920                                 // change the position of the next ships in the wing.  Use the cool function in AiCode.cpp which
3921                                 // Mike K wrote to give new positions to the wing members.
3922                                 get_absolute_wing_pos( &objp->pos, leader_objp, wing_index++, 0);
3923                                 memcpy( &objp->orient, &orient, sizeof(matrix) );
3924
3925                                 index++;
3926                         }
3927                 }
3928         }
3929
3930         // create warp effect if in mission and not arriving from docking bay
3931         if ( (Game_mode & GM_IN_MISSION) && (wingp->arrival_location != ARRIVE_FROM_DOCK_BAY) ) {
3932                 for ( index = wingp->current_count - num_to_set; index < wingp->current_count; index ++ ) {
3933                         shipfx_warpin_start( &Objects[Ships[wingp->ship_index[index]].objnum] );
3934                 }
3935         }
3936 }
3937
3938 // this function is called after a mission is parsed to set the arrival locations of all ships in the
3939 // mission to the apprioriate spot.  Mainly needed because ships might be in dock bays to start
3940 // the mission, so their AI mode must be set appropriately.
3941 void mission_parse_set_arrival_locations()
3942 {
3943         int i;
3944         object *objp;
3945
3946         if ( Fred_running )
3947                 return;
3948
3949         obj_merge_created_list();
3950         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3951                 ship *shipp;
3952
3953                 if ( objp->type != OBJ_SHIP ) 
3954                         continue;
3955
3956                 shipp = &Ships[objp->instance];
3957                 // if the ship is in a wing -- ignore the info and let the wing info handle it
3958                 if ( shipp->wingnum != -1 )
3959                         continue;
3960
3961                 // call function to set arrival location for this ship.
3962                 mission_set_arrival_location( shipp->arrival_anchor, shipp->arrival_location, shipp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3963         }
3964
3965         // do the wings
3966         for ( i = 0; i < num_wings; i++ ) {
3967
3968                 // if wing has no ships, then don't process it.
3969                 if ( Wings[i].current_count == 0 )
3970                         continue;
3971
3972                 mission_set_wing_arrival_location( &Wings[i], Wings[i].current_count );
3973         }
3974 }
3975
3976
3977 // function which iterates through the ship_arrival_list and creates any ship which
3978 // should be intially docked with a ship which currently exists in the mission
3979 void mission_parse_do_initial_docks()
3980 {
3981         p_object *pobjp, *tmp;
3982
3983         pobjp = GET_FIRST( &ship_arrival_list );
3984         while ( pobjp != END_OF_LIST(&ship_arrival_list) ) {
3985                 int shipnum;
3986
3987                 tmp = GET_NEXT(pobjp);
3988
3989                 // see if the flag for initial docked is set
3990                 if ( pobjp->flags & P_SF_INITIALLY_DOCKED ) {
3991                         // see if who this parse object is supposed to be docked with is in the mission
3992                         shipnum = ship_name_lookup( pobjp->docked_with );
3993                         if ( shipnum != -1 ) {
3994                                 int objnum, p1, p2;
3995
3996                                 // the ship exists, so create this object, then dock the two.
3997                                 objnum = parse_create_object( pobjp );
3998                                 SDL_assert ( objnum != -1 );
3999
4000                                 list_remove( &ship_arrival_list, pobjp);
4001
4002                                 // p1 is the parse object's docking point.
4003                                 // p2 is the existing objects docking point.
4004                                 p1 = model_find_dock_name_index(Ships[shipnum].modelnum, pobjp->docker_point);
4005                                 p2 = model_find_dock_name_index(Ships[Objects[objnum].instance].modelnum, pobjp->dockee_point);
4006
4007                                 if ((p1 >= 0) && (p2 >= 0)) {
4008                                         nprintf(("AI", "Initially Docked: %s with %s\n", Ships[shipnum].ship_name, Ships[Objects[objnum].instance].ship_name));
4009                                         if (ship_docking_valid(shipnum, Objects[objnum].instance))  // only dock if they are allowed to be docked.
4010                                                 ai_dock_with_object(&Objects[Ships[shipnum].objnum], &Objects[objnum], 89, AIDO_DOCK_NOW, p1, p2);
4011                                         else
4012                                                 ai_dock_with_object(&Objects[objnum], &Objects[Ships[shipnum].objnum], 89, AIDO_DOCK_NOW, p2, p1);
4013                                                 
4014                                 } else
4015                                         Int3();         //      Curious.  Two ships told to dock, but one of the dock points is bogus.  
4016                                                                         // Get Allender or Hoffoss, one of whom probably wrote the above if ()
4017                         }
4018                 }
4019
4020                 pobjp = tmp;
4021         }
4022 }
4023
4024 // function which returns true or false if the given mission support multiplayers
4025 int mission_parse_is_multi(const char *filename, char *mission_name)
4026 {
4027         int rval, game_type;
4028         int filelength;
4029         CFILE *ftemp;
4030
4031         // new way of getting information.  Open the file, and just get the name and the game_type flags.
4032         // return the flags if a multiplayer mission
4033
4034         game_type = 0;
4035
4036         ftemp = cfopen(filename, "rt");
4037         if (!ftemp)
4038                 return 0;
4039
4040         // 7/9/98 -- MWA -- check for 0 length file.
4041         filelength = cfilelength(ftemp);
4042         cfclose(ftemp);
4043         if ( filelength == 0 )
4044                 return 0;
4045
4046         // open localization
4047         lcl_ext_open();
4048
4049         if ((rval = setjmp(parse_abort)) != 0) {
4050                 Error(LOCATION, "Bogus!  Trying to get multi game type on mission %s returned as a mission from cf_get_filelist\n");
4051         } else  {
4052                 read_file_text(filename, CF_TYPE_MISSIONS);
4053                 reset_parse();
4054                 if ( skip_to_string("$Name:") != 1 ) {
4055                         nprintf(("Network", "Unable to process %s because we couldn't find $Name:", filename));
4056
4057                         // close localization
4058                         lcl_ext_close();
4059
4060                         return 0;
4061                 }
4062                 stuff_string( mission_name, F_NAME, NULL );
4063                 if ( skip_to_string("+Game Type Flags:") != 1 ) {
4064                         nprintf(("Network", "Unable to process %s because we couldn't find +Game Type Flags:\n", filename));
4065
4066                         // close localization
4067                         lcl_ext_close();
4068
4069                         return 0;
4070                 }
4071                 stuff_int(&game_type);
4072         }
4073         if ( game_type & MISSION_TYPE_MULTI ){
4074                 // close localization
4075                 lcl_ext_close();
4076
4077                 return game_type;
4078         }
4079
4080         // close localization
4081         lcl_ext_close();
4082         
4083         return 0;
4084 }
4085
4086 // function which gets called to retrieve useful information about a mission.  We will get the
4087 // name, description, and number of players for a mission.  Probably used for multiplayer only?
4088 // The calling function can use the information in The_mission to get the name/description of the mission
4089 // if needed.
4090
4091 int mission_parse_get_multi_mission_info( const char *filename )
4092 {
4093         if ( parse_main(filename, MISSION_PARSE_MISSION_INFO) ){
4094                 return -1;
4095         }
4096
4097         SDL_assert( The_mission.game_type & MISSION_TYPE_MULTI );               // assume multiplayer only for now?
4098
4099         // return the number of parse_players.  later, we might want to include (optionally?) the number
4100         // of other ships in the main players wing (usually wing 'alpha') for inclusion of number of
4101         // players allowed.
4102
4103         return The_mission.num_players;
4104 }
4105
4106 // returns true or false if this is on the yet to arrive list
4107 int mission_parse_ship_arrived( const char *shipname )
4108 {
4109         p_object *objp;
4110
4111         for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) )     {
4112                 if ( !SDL_strcasecmp( objp->name, shipname) )
4113                         return 0;                       // still on the arrival list
4114         }
4115         return 1;
4116 }
4117
4118 // return the parse object on the ship arrival list associated with the given name
4119 p_object *mission_parse_get_arrival_ship( const char *name )
4120 {
4121         p_object *objp;
4122
4123         for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) )     {
4124                 if ( !SDL_strcasecmp( objp->name, name) )
4125                         return objp;                    // still on the arrival list
4126         }
4127
4128         return NULL;
4129 }
4130
4131 // return the parse object on the ship arrival list associated with the given signature
4132 p_object *mission_parse_get_arrival_ship( ushort net_signature )
4133 {
4134         p_object *objp;
4135
4136         for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) )     {
4137                 if ( objp->net_signature == net_signature )
4138                         return objp;                    // still on the arrival list
4139         }
4140
4141         return NULL;
4142 }
4143
4144 // mission_set_arrival_location() sets the arrival location of a parse object according to the arrival location
4145 // of the object.  Returns true if object set to new position, false if not.
4146 int mission_set_arrival_location(int anchor, int location, int dist, int objnum, vector *new_pos, matrix *new_orient)
4147 {
4148         int shipnum, anchor_objnum;
4149         vector anchor_pos, rand_vec, new_fvec;
4150         matrix orient;
4151
4152         if ( location == ARRIVE_AT_LOCATION )
4153                 return 0;
4154
4155         SDL_assert(anchor >= 0);
4156
4157         // this ship might possibly arrive at another location.  The location is based on the
4158         // proximity of some ship (and some other special tokens)
4159
4160         // if we didn't find the arrival anchor in the list of special nodes, then do a
4161         // ship name lookup on the anchor
4162         if (anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET) {
4163                 shipnum = ship_name_lookup(Parse_names[anchor]);
4164                 if ( shipnum == -1 ) {
4165                         SDL_assert ( location != ARRIVE_FROM_DOCK_BAY );                // bogus data somewhere!!!  get mwa
4166                         nprintf (("allender", "couldn't find ship for arrival anchor -- using location ship created at"));
4167                         return 0;
4168                 }
4169
4170         } else {
4171                 // come up with a position based on the special token names
4172                 shipnum = -1;
4173
4174                 if (anchor == ANY_FRIENDLY) {
4175                         shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ANY_SHIP );
4176                 } else if (anchor == ANY_HOSTILE) {
4177                         shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ANY_SHIP );
4178                 } else if (anchor == ANY_FRIENDLY_PLAYER) {
4179                         shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ONLY_PLAYERS );
4180                 } else if (anchor == ANY_HOSTILE_PLAYER) {
4181                         shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ONLY_PLAYERS );
4182                 } else
4183                         Int3();         // get allender -- unknown special arrival instructions
4184
4185                 // if we didn't get an object from one of the above functions, then make the object
4186                 // arrive at it's placed location
4187                 if ( shipnum == -1 ) {
4188                         nprintf (("Allender", "Couldn't find random ship for arrival anchor -- using default location\n"));
4189                         return 0;
4190                 }
4191         }
4192
4193         // take the shipnum and get the position.  once we have positions, we can determine where
4194         // to make this ship appear
4195         SDL_assert ( shipnum != -1 );
4196         anchor_objnum = Ships[shipnum].objnum;
4197         anchor_pos = Objects[anchor_objnum].pos;
4198
4199         // if arriving from docking bay, then set ai mode and call function as per AL's instructions.
4200         if ( location == ARRIVE_FROM_DOCK_BAY ) {
4201                 vector pos, fvec;
4202
4203                 // if we get an error, just let the ship arrive(?)
4204                 if ( ai_acquire_emerge_path(&Objects[objnum], anchor_objnum, &pos, &fvec) == -1 ) {
4205                         Int3();                 // get MWA or AL -- not sure what to do here when we cannot acquire a path
4206                         return 0;
4207                 }
4208                 Objects[objnum].pos = pos;
4209                 Objects[objnum].orient.v.fvec = fvec;
4210         } else {
4211
4212                 // AL: ensure dist > 0 (otherwise get errors in vecmat)
4213                 // TODO: maybe set distance to 2x ship radius of ship appearing in front of?
4214                 if ( dist <= 0 ) {
4215                         Error(LOCATION, "Distance of %d is invalid in mission_set_arrival_location\n", dist);
4216                         return 0;
4217                 }
4218                 
4219                 // get a vector which is the ships arrival position based on the type of arrival
4220                 // this ship should have.  Arriving near a ship we use a random normalized vector
4221                 // scaled by the distance given by the designer.  Arriving in front of a ship means
4222                 // entering the battle in the view cone.
4223                 if ( location == ARRIVE_NEAR_SHIP ) {
4224                         // get a random vector -- use static randvec if in multiplayer
4225                         if ( Game_mode & GM_NORMAL )
4226                                 vm_vec_rand_vec_quick(&rand_vec);
4227                         else
4228                                 static_randvec( Objects[objnum].net_signature, &rand_vec );
4229                 } else if ( location == ARRIVE_IN_FRONT_OF_SHIP ) {
4230                         vector t1, t2, t3;
4231                         int r1, r2;
4232                         float x;
4233
4234                         // cool function by MK to give a reasonable random vector "in front" of a ship
4235                         // rvec and uvec are the right and up vectors.
4236                         // If these are not available, this would be an expensive method.
4237                         //x = cos(angle)
4238                         x = (float)cos(ANG_TO_RAD(45));
4239                         if ( Game_mode & GM_NORMAL ) {
4240                                 r1 = myrand() < MY_RAND_MAX/2 ? -1 : 1;
4241                                 r2 = myrand() < MY_RAND_MAX/2 ? -1 : 1;
4242                         } else {
4243                                 // in multiplayer, use the static rand functions so that all clients can get the
4244                                 // same information.
4245                                 r1 = static_rand(Objects[objnum].net_signature) < MY_RAND_MAX/2 ? -1 : 1;
4246                                 r2 = static_rand(Objects[objnum].net_signature+1) < MY_RAND_MAX/2 ? -1 : 1;
4247                         }
4248
4249                         vm_vec_copy_scale(&t1, &(Objects[anchor_objnum].orient.v.fvec), x);
4250                         vm_vec_copy_scale(&t2, &(Objects[anchor_objnum].orient.v.rvec), (1.0f - x) * r1);
4251                         vm_vec_copy_scale(&t3, &(Objects[anchor_objnum].orient.v.uvec), (1.0f - x) * r2);
4252
4253                         vm_vec_add(&rand_vec, &t1, &t2);
4254                         vm_vec_add2(&rand_vec, &t3);
4255                         vm_vec_normalize(&rand_vec);
4256                 }
4257
4258                 // add in the radius of the two ships involved.  This will make the ship arrive further than
4259                 // specified, but will appear more accurate since we are pushing the edge of the model to the
4260                 // specified distance.  large objects appears to be a lot closer without the following line because
4261                 // the object centers were at the correct distance, but the model itself was much closer to the
4262                 // target ship.
4263                 dist += (int)Objects[objnum].radius + (int)Objects[anchor_objnum].radius;
4264                 vm_vec_scale_add(&Objects[objnum].pos, &anchor_pos, &rand_vec, (float)dist);
4265
4266                 // I think that we will always want to orient the ship that is arriving to face towards
4267                 // the ship it is arriving near/in front of.  The effect will be cool!
4268                 //
4269                 // calculate the new fvec of the ship arriving and use only that to get the matrix.  isn't a big
4270                 // deal not getting bank.
4271                 vm_vec_sub(&new_fvec, &anchor_pos, &Objects[objnum].pos );
4272                 vm_vector_2_matrix( &orient, &new_fvec, NULL, NULL );
4273                 Objects[objnum].orient = orient;
4274         }
4275
4276         // set the new_pos parameter since it might be used outside the function (i.e. when dealing with wings).
4277         if ( new_pos )
4278                 memcpy(new_pos, &Objects[objnum].pos, sizeof(vector) );
4279
4280         if ( new_orient )
4281                 memcpy( new_orient, &Objects[objnum].orient, sizeof(matrix) );
4282
4283         return 1;
4284 }
4285
4286 // mark a reinforcement as available
4287 void mission_parse_mark_reinforcement_available(char *name)
4288 {
4289         int i;
4290         reinforcements *rp;
4291
4292         for (i = 0; i < Num_reinforcements; i++) {
4293                 rp = &Reinforcements[i];
4294                 if ( !SDL_strcasecmp(rp->name, name) ) {
4295                         if ( !(rp->flags & RF_IS_AVAILABLE) ) {
4296                                 rp->flags |= RF_IS_AVAILABLE;
4297
4298                                 // tell all of the clients.
4299                                 if ( MULTIPLAYER_MASTER ) {
4300                                         send_reinforcement_avail( i );
4301                                 }
4302                         }
4303                         return;
4304                 }
4305         }
4306
4307         SDL_assert ( i < Num_reinforcements );
4308 }
4309
4310 // mission_did_ship_arrive takes a parse object and checked the arrival cue and delay and
4311 // creates the object if necessary.  Returns -1 if not created.  objnum of created ship otherwise
4312 int mission_did_ship_arrive(p_object *objp)
4313 {
4314         int did_arrive;
4315
4316         // find out in the arrival cue became true
4317         did_arrive = eval_sexp(objp->arrival_cue);
4318
4319         // we must first check to see if this ship is a reinforcement or not.  If so, then don't
4320         // process
4321         if ( objp->flags & P_SF_REINFORCEMENT ) {
4322
4323                 // if this ship did arrive, mark the reinforcement as available, and tell clients if in multiplayer
4324                 // mode
4325                 if ( did_arrive ) {
4326                         mission_parse_mark_reinforcement_available(objp->name);
4327                 }
4328                 return -1;
4329         }
4330
4331         if ( did_arrive ) {             // has the arrival criteria been met?
4332                 int object_num;         
4333
4334                 SDL_assert ( !(objp->flags & P_SF_CANNOT_ARRIVE) );             // get allender
4335
4336                 // check to see if the delay field <= 0.  if so, then create a timestamp and then maybe
4337                 // create the object
4338                 if ( objp->arrival_delay <= 0 ) {
4339                         objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
4340                         SDL_assert( objp->arrival_delay >= 0 );
4341                 }
4342                 
4343                 // if the timestamp hasn't elapsed, move onto the next ship.
4344                 if ( !timestamp_elapsed(objp->arrival_delay) )
4345                         return -1;
4346
4347                 // check to see if this ship is to arrive via a docking bay.  If so, and the ship to arrive from
4348                 // doesn't exist, don't create.
4349                 if ( objp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
4350                         int shipnum;
4351                         char *name;
4352
4353                         SDL_assert( objp->arrival_anchor >= 0 );
4354                         name = Parse_names[objp->arrival_anchor];
4355         
4356                         // see if ship is yet to arrive.  If so, then return -1 so we can evaluate again later.
4357                         if ( mission_parse_get_arrival_ship( name ) )
4358                                 return -1;
4359
4360                         // see if ship is in mission.  If not, then we can assume it was destroyed or departed since
4361                         // it is not on the arrival list (as shown by above if statement).
4362                         shipnum = ship_name_lookup( name );
4363                         if ( shipnum == -1 ) {
4364                                 Sexp_nodes[objp->arrival_cue].value = SEXP_KNOWN_FALSE;
4365                                 return -1;
4366                         }
4367                 }
4368
4369                 object_num = parse_create_object(objp);                                                 // create the ship
4370
4371                 // since this ship is not in a wing, create a SHIP_ARRIVE entry
4372                 //mission_log_add_entry( LOG_SHIP_ARRIVE, objp->name, NULL );
4373                 SDL_assert(object_num >= 0 && object_num < MAX_OBJECTS);
4374                 
4375                 // Play the music track for an arrival
4376                 if ( !(Ships[Objects[object_num].instance].flags & SF_NO_ARRIVAL_MUSIC) )
4377                         if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
4378                                 Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
4379                                 event_music_arrival(Ships[Objects[object_num].instance].team);
4380                         }
4381                 return object_num;
4382         } else {
4383                 // check to see if the arrival cue of this ship is known false -- if so, then remove
4384                 // the parse object from the ship
4385                 if ( Sexp_nodes[objp->arrival_cue].value == SEXP_KNOWN_FALSE )
4386                         objp->flags |= P_SF_CANNOT_ARRIVE;
4387         }
4388
4389         return -1;
4390
4391 }
4392
4393 // funciton to set a flag on all parse objects on ship arrival list which cannot
4394 // arrive in the mission
4395 void mission_parse_mark_non_arrivals()
4396 {
4397         p_object *pobjp;
4398
4399         for ( pobjp = GET_FIRST(&ship_arrival_list); pobjp != END_OF_LIST(&ship_arrival_list); pobjp = GET_NEXT(pobjp) ) {
4400                 if ( pobjp->wingnum != -1 ) {
4401                         if ( Sexp_nodes[Wings[pobjp->wingnum].arrival_cue].value == SEXP_KNOWN_FALSE )
4402                                 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4403                 } else {
4404                         if ( Sexp_nodes[pobjp->arrival_cue].value == SEXP_KNOWN_FALSE )
4405                                 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4406                 }
4407         }
4408 }
4409
4410 // function to deal with support ship arrival.  objnum is the object number of the arriving support
4411 // ship.  This function can get called from either single or multiplayer.  Needed to that clients
4412 // can know when to abort rearm.
4413 void mission_parse_support_arrived( int objnum )
4414 {
4415         int i;
4416
4417         // when the support ship arrives, the shipname it is supposed to repair is in the 'misc'
4418         // field of the parse_object.  If the ship still exists, call ai function which actually
4419         // issues the goal for the repair
4420         for ( i = 0; i < Num_arriving_repair_targets; i++ ) {
4421                 int shipnum;
4422
4423                 shipnum = ship_name_lookup( Arriving_repair_targets[i] );
4424
4425                 if ( shipnum != -1 ) {
4426                         object *requester_objp, *support_objp;
4427
4428                         support_objp = &Objects[objnum];
4429                         requester_objp = &Objects[Ships[shipnum].objnum];
4430                         ai_add_rearm_goal( requester_objp, support_objp );
4431                 }
4432         }
4433
4434         //      MK: A bit of a hack.  If on player's team and player isn't allowed shields, don't give this ship shields.
4435         if ((Player_obj->flags & OF_NO_SHIELDS) && (Player_ship->team == Ships[Objects[objnum].instance].team))
4436                 Objects[objnum].flags |= OF_NO_SHIELDS;
4437
4438         Ships[Objects[objnum].instance].flags |= SF_WARPED_SUPPORT;
4439
4440         Arriving_support_ship = NULL;
4441         Num_arriving_repair_targets = 0;
4442 }
4443
4444 MONITOR(NumShipArrivals);
4445
4446 // mission_parse_arrivals will parse the lists of arriving ships and
4447 // wings -- creating new ships/wings if the arrival criteria have been
4448 // met.
4449 void mission_eval_arrivals()
4450 {
4451         p_object *objp;
4452         wing *wingp;
4453         int i, objnum;
4454
4455         // before checking arrivals, check to see if we should play a message concerning arrivals
4456         // of other wings.  We use the timestamps to delay the arrival message slightly for
4457         // better effect
4458         if ( timestamp_valid(Arrival_message_delay_timestamp) && timestamp_elapsed(Arrival_message_delay_timestamp) && !((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)) ){
4459                 int rship, use_terran;
4460
4461                 // use terran command 25% of time
4462                 use_terran = ((frand() - 0.75) > 0.0f)?1:0;
4463
4464                 rship = ship_get_random_player_wing_ship( SHIP_GET_NO_PLAYERS );
4465                 if ( (rship == -1) || use_terran ){
4466                         message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4467                 } else if ( rship != -1 ) {
4468                         message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4469                 }
4470
4471                 Arrival_message_delay_timestamp = timestamp(-1);                // make the stamp invalid
4472         }
4473
4474 //      if ( !timestamp_elapsed(Mission_arrival_timestamp) )
4475 //              return;
4476
4477         // check the ship_arrival_list
4478         objnum = -1;
4479         objp = GET_FIRST(&ship_arrival_list);
4480         while( objp !=END_OF_LIST(&ship_arrival_list) ) {
4481                 p_object *temp = GET_NEXT(objp);
4482                 if ( objp->wingnum == -1 )      {                                                               // if this object has a wing -- let code for wings determine if it should be created
4483
4484                         objnum = mission_did_ship_arrive( objp );
4485                         if ( objnum != -1 )     {
4486                                 list_remove( &ship_arrival_list, objp);
4487                                 MONITOR_INC(NumShipArrivals,1);
4488                         }
4489
4490                 }
4491                 objp = temp;
4492         }
4493
4494         // check for any initially docked ships.  Do it after all are created since the next function
4495         // messes with the ship_arrival_list
4496         mission_parse_do_initial_docks();                       // maybe create it's docked counterpart
4497
4498         mission_parse_mark_non_arrivals();                      // mark parse objects which can no longer arrive
4499
4500         // check the support ship arrival list
4501         if ( Arriving_support_ship )    {
4502                 int objnum;
4503
4504                 objnum = mission_did_ship_arrive( Arriving_support_ship );
4505
4506                 if ( objnum != -1 ) {
4507                         MONITOR_INC(NumShipArrivals,1);
4508                         mission_parse_support_arrived( objnum );
4509                 }
4510         }
4511
4512         // we must also check to see if there are waves of a wing that must
4513         // reappear if all the ships of the current wing have been destroyed or
4514         // have departed. If this is the case, then create the next wave.
4515
4516         for ( i = 0; i < num_wings; i++ ) {
4517                 wingp = &Wings[i];
4518
4519                 // should we process this wing anymore
4520                 if ( wingp->flags & WF_WING_GONE )
4521                         continue;
4522
4523                 // if we have a reinforcement wing, then don't try to create new ships automatically.
4524                 if ( wingp->flags & WF_REINFORCEMENT ) {
4525
4526                         // check to see in the wings arrival cue is true, and if so, then mark the reinforcement
4527                         // as available
4528                         if ( eval_sexp(wingp->arrival_cue) ) {
4529                                 mission_parse_mark_reinforcement_available(wingp->name);
4530                         }
4531                         continue;
4532                 }
4533                 
4534                 // don't do evaluations for departing wings
4535                 if ( wingp->flags & WF_WING_DEPARTING ){
4536                         continue;
4537                 }
4538
4539                 // must check to see if we are at the last wave.  Code above to determine when a wing is gone only
4540                 // gets run when a ship is destroyed (not every N seconds like it used to).  Do a quick check
4541                 // here.
4542                 if ( wingp->current_wave == wingp->num_waves ){
4543                         continue;
4544                 }
4545
4546                 // if the current wave of this wing is 0, then we haven't created the ships in the wing yet.
4547                 // call parse_wing_create_ships to try and create it.  That function will eval the arrival
4548                 // cue of the wing and create the ships if necessary, or if the threshold of the wing has
4549                 // been reached, then try and create more ships
4550                 if ( (wingp->current_wave == 0) || (wingp->current_count <= wingp->threshold) ) {
4551                         int created;
4552
4553                         created = parse_wing_create_ships( wingp, wingp->wave_count );
4554
4555                         // if we created ships in this wing, check to see if the wings was int the reinforcements
4556                         // array.  If so, then if we have more uses, then reset the reinforcement flag for the wing
4557                         // so the user can call in another set if need be.
4558                         if ( created > 0 ) {
4559                                 int rship;
4560
4561                                 mission_parse_do_initial_docks();               // maybe create other initially docked ships
4562                                 if ( Wings[i].flags & WF_RESET_REINFORCEMENT ) {
4563                                         Wings[i].flags &= ~WF_RESET_REINFORCEMENT;
4564                                         Wings[i].flags |= WF_REINFORCEMENT;
4565                                 }
4566
4567                                 // possibly send a message to the player when this wing arrives.
4568                                 if ( wingp->flags & WF_NO_ARRIVAL_MESSAGE ){
4569                                         continue;
4570                                 }
4571
4572                                 // multiplayer team vs. team
4573                                 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
4574                                         // send a hostile wing arrived message
4575                                         rship = Wings[i].ship_index[0];
4576
4577                                         int multi_team_filter = Ships[rship].team == TEAM_FRIENDLY ? 1 : 0;
4578
4579                                         // there are two timestamps at work here.  One to control how often the player receives
4580                                         // messages about incoming hostile waves, and the other to control how long after
4581                                         // the wing arrives does the player actually get the message.
4582                                         if ( timestamp_elapsed(Allow_arrival_message_timestamp_m[multi_team_filter]) ) {
4583                                                 if ( !timestamp_valid(Arrival_message_delay_timestamp_m[multi_team_filter]) ){
4584                                                         Arrival_message_delay_timestamp_m[multi_team_filter] = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4585                                                 }
4586                                                 Allow_arrival_message_timestamp_m[multi_team_filter] = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);                                       
4587                                                 
4588                                                 // send to the proper team
4589                                                 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, multi_team_filter );
4590                                         }
4591                                 } 
4592                                 // everything else
4593                                         else {
4594                                         // see if this is a starting player wing
4595                                         if ( i == Starting_wings[STARTING_WING_BETA] ) {                                        // this is the beta wing
4596                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4597                                                 if ( rship != -1 ){
4598                                                         message_send_builtin_to_player( MESSAGE_BETA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4599                                                 }
4600                                         } else if ( i == Starting_wings[STARTING_WING_GAMMA] ) {                        // this is the gamma wing
4601                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4602                                                 if ( rship != -1 ) {
4603                                                         message_send_builtin_to_player( MESSAGE_GAMMA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4604                                                 }
4605                                         } else if ( !SDL_strcasecmp( wingp->name, "delta") ) {
4606                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4607                                                 if ( rship != -1 ) {
4608                                                         message_send_builtin_to_player( MESSAGE_DELTA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4609                                                 }
4610                                         } else if ( !SDL_strcasecmp(wingp->name, "epsilon") ) {
4611                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4612                                                 if ( rship != -1 ) {
4613                                                         message_send_builtin_to_player( MESSAGE_EPSILON_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4614                                                 }
4615                                         } else {
4616                                                 // see if we have a hostile wing that arrived
4617                                                 rship = Wings[i].ship_index[0];
4618                                                 if ( Ships[rship].team != TEAM_FRIENDLY ) {
4619
4620                                                         // there are two timestamps at work here.  One to control how often the player receives
4621                                                         // messages about incoming hostile waves, and the other to control how long after
4622                                                         // the wing arrives does the player actually get the message.
4623                                                         if ( timestamp_elapsed(Allow_arrival_message_timestamp) ) {
4624                                                                 if ( !timestamp_valid(Arrival_message_delay_timestamp) ){
4625                                                                         Arrival_message_delay_timestamp = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4626                                                                 }
4627                                                                 Allow_arrival_message_timestamp = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
4628                                                         }
4629                                                 }
4630                                         }
4631                                 }
4632                         }
4633                 }
4634         }
4635         Mission_arrival_timestamp = timestamp(ARRIVAL_TIMESTAMP);
4636 }
4637
4638 MONITOR(NumShipDepartures);
4639
4640 // called to make object objp depart.
4641 void mission_do_departure( object *objp )
4642 {
4643         ship *shipp;
4644 //      vector v;
4645
4646         MONITOR_INC(NumShipDepartures,1);
4647
4648         SDL_assert ( objp->type == OBJ_SHIP );
4649         shipp = &Ships[objp->instance];
4650
4651         // if departing to a docking bay, try to find the anchor ship to depart to.  If not found, then
4652         // just make it warp out like anything else.
4653         if ( shipp->departure_location == DEPART_AT_DOCK_BAY ) {
4654                 int anchor_shipnum;
4655                 char *name;
4656
4657                 SDL_assert( shipp->departure_anchor >= 0 );
4658                 name = Parse_names[shipp->departure_anchor];
4659
4660                 // see if ship is yet to arrive.  If so, then return -1 so we can evaluate again later.
4661                 if ( mission_parse_get_arrival_ship( name ) )
4662                         goto do_departure_warp;
4663
4664                 // see if ship is in mission.  If not, then we can assume it was destroyed or departed since
4665                 // it is not on the arrival list (as shown by above if statement).
4666                 anchor_shipnum = ship_name_lookup( name );
4667                 if ( anchor_shipnum == -1 )
4668                         goto do_departure_warp;
4669
4670                 ai_acquire_depart_path(objp, Ships[anchor_shipnum].objnum);
4671                 return;
4672         }
4673
4674 do_departure_warp:
4675         ai_set_mode_warp_out( objp, &Ai_info[Ships[objp->instance].ai_index] );
4676
4677 }
4678
4679 // put here because mission_eval_arrivals is here.  Might move these to a better location
4680 // later -- MWA
4681 void mission_eval_departures()
4682 {
4683         int i, j;
4684         object *objp;
4685         wing *wingp;
4686
4687 //      if ( !timestamp_elapsed(Mission_departure_timestamp) )
4688 //              return;
4689
4690         // scan through the active ships an evaluate their departure cues.  For those
4691         // ships whose time has come, set their departing flag.
4692
4693         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4694                 if (objp->type == OBJ_SHIP) {
4695                         ship    *shipp;
4696
4697                         SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
4698
4699                         shipp = &Ships[objp->instance];
4700                         
4701                         // don't process a ship that is already departing or dying or disabled
4702                         // AL 12-30-97: Added SF_CANNOT_WARP to check
4703                         if ( (shipp->flags & (SF_DEPARTING | SF_DYING | SF_CANNOT_WARP )) || ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) ) {
4704                                 continue;
4705                         }
4706
4707                         // don't process ships that are part of a wing -- handled in seperate case
4708                         if ( shipp->wingnum != -1 )
4709                                 continue;
4710
4711 //                              && (!timestamp_valid(shipp->departure_delay) || timestamp_elapsed(shipp->departure_delay)) )
4712                         // when the departure cue becomes true, set off the departure delay timer.  We store the
4713                         // timer as -seconds in Freespace which indicates that the timer has not been set.  If the timer
4714                         // is not set, then turn it into a valid timer and keep evaluating the timer until it is elapsed
4715                         if ( eval_sexp(shipp->departure_cue) ) {
4716                                 if ( shipp->departure_delay <= 0 )
4717                                         shipp->departure_delay = timestamp(-shipp->departure_delay * 1000 );
4718                                 if ( timestamp_elapsed(shipp->departure_delay) )
4719                                         mission_do_departure( objp );
4720                         }
4721                 }
4722         }
4723
4724         // now scan through the list of wings and check their departure cues.  For wings with
4725         // that cue being true, we must update internal variables to indicate that the wing is
4726         // departed and that no further waves of this wing will appear
4727
4728         for ( i = 0; i < num_wings; i++ ) {
4729                 wingp = &Wings[i];
4730
4731                 // should we process this wing anymore
4732                 if ( wingp->flags & WF_WING_DEPARTING )
4733                         continue;
4734
4735                 // evaluate the sexpression.  If true, mark all the ships in this wing as departing and increment
4736                 // the num departed in the wing structure.  Then add number of remaining waves * ships/wave to
4737                 // departed count to get total count of ships in the wing which departed.  (We are counting ships
4738                 // that have not yet arrived as departed if they never arrive -- this may be bad, but for some reason
4739                 // seems like the right thing to do).
4740  //&& (!timestamp_valid(wingp->departure_delay) || timestamp_elapsed(wingp->departure_delay)) ) {
4741
4742                 if ( eval_sexp(wingp->departure_cue) ) {
4743                         // if we haven't set up the departure timer yet (would be <= 0) setup the timer to pop N seconds
4744                         // later
4745                         if ( wingp->departure_delay <= 0 )
4746                                 wingp->departure_delay = timestamp( -wingp->departure_delay * 1000 );
4747                         if ( !timestamp_elapsed(wingp->departure_delay) )
4748                                 continue;
4749
4750                         wingp->flags |= WF_WING_DEPARTING;
4751                         for ( j = 0; j < wingp->current_count; j++ ) {
4752                                 ship *shipp;
4753
4754                                 shipp = &Ships[wingp->ship_index[j]];
4755                                 if ( (shipp->flags & SF_DEPARTING) || (shipp->flags & SF_DYING) )
4756                                         continue;
4757
4758 //                              shipp->flags |= SF_DEPARTING;
4759 //                              shipp->final_depart_time = timestamp(3*1000);
4760
4761                                 SDL_assert ( shipp->objnum != -1 );
4762                                 objp = &Objects[shipp->objnum];
4763
4764                                 // copy the wing's depature information to the ship
4765                                 shipp->departure_location = wingp->departure_location;
4766                                 shipp->departure_anchor = wingp->departure_anchor;
4767
4768                                 mission_do_departure( objp );
4769                                 // don't add to wingp->total_departed here -- this is taken care of in ship code.
4770                         }
4771
4772                         // MWA 2/25/98 -- don't do the follwoing wing member updates.  It makes the accurate counts
4773                         // sort of messed up and causes problems for the event log.  The code in ship_wing_cleanup()
4774                         // now keys off of the WF_WING_DEPARTING flag instead of the counts below.
4775
4776                         /*
4777                         // now be sure that we update wing structure members if there are any remaining waves left
4778                         if ( wingp->current_wave < wingp->num_waves ) {
4779                                 int num_remaining;
4780
4781                                 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
4782                                 wingp->total_departed += num_remaining;
4783                                 wingp->total_arrived_count += num_remaining;
4784                                 wingp->current_wave = wingp->num_waves;
4785                         }
4786                         */
4787
4788                 }
4789         }
4790         Mission_departure_timestamp = timestamp(DEPARTURE_TIMESTAMP);
4791 }
4792
4793 // function called from high level game loop to do mission evaluation stuff
4794 void mission_parse_eval_stuff()
4795 {
4796         mission_eval_arrivals();
4797         mission_eval_departures();
4798 }
4799
4800 int allocate_subsys_status()
4801 {
4802         int i;
4803
4804         SDL_assert(Subsys_index < MAX_SUBSYS_STATUS);
4805         Subsys_status[Subsys_index].percent = 0.0f;
4806         Subsys_status[Subsys_index].primary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4807         for (i=1; i<MAX_PRIMARY_BANKS; i++)
4808                 Subsys_status[Subsys_index].primary_banks[i] = -1;  // none
4809
4810         Subsys_status[Subsys_index].secondary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4811         Subsys_status[Subsys_index].secondary_ammo[0] = 100;
4812         for (i=1; i<MAX_SECONDARY_BANKS; i++) {
4813                 Subsys_status[Subsys_index].secondary_banks[i] = -1;
4814                 Subsys_status[Subsys_index].secondary_ammo[i] = 100;
4815         }
4816
4817         Subsys_status[Subsys_index].ai_class = SUBSYS_STATUS_NO_CHANGE;
4818         return Subsys_index++;
4819 }
4820
4821 // find (or add) the name in the list and return an index to it.
4822 int get_parse_name_index(const char *name)
4823 {
4824         int i;
4825
4826         for (i=0; i<Num_parse_names; i++)
4827                 if (!SDL_strcasecmp(name, Parse_names[i]))
4828                         return i;
4829
4830         SDL_assert(i < MAX_SHIPS + MAX_WINGS);
4831         SDL_assert(strlen(name) < NAME_LENGTH);
4832         SDL_strlcpy(Parse_names[i], name, NAME_LENGTH);
4833         return Num_parse_names++;
4834 }
4835
4836 int get_anchor(char *name)
4837 {
4838         int i;
4839
4840         for (i=0; i<MAX_SPECIAL_ARRIVAL_ANCHORS; i++)
4841                 if (!SDL_strcasecmp(name, Special_arrival_anchor_names[i]))
4842                         return SPECIAL_ARRIVAL_ANCHORS_OFFSET + i;
4843
4844         return get_parse_name_index(name);
4845 }
4846
4847 // function to fixup the goals/ai references for player objects in the mission
4848 void mission_parse_fixup_players()
4849 {
4850         object *objp;
4851
4852         // merge created list to have all objects on used list
4853         obj_merge_created_list();
4854         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4855                 if ( (objp->type == OBJ_SHIP) && (objp->flags & OF_PLAYER_SHIP) ) {
4856                         ai_clear_ship_goals( &Ai_info[Ships[objp->instance].ai_index] );
4857                         init_ai_object( OBJ_INDEX(objp) );
4858                 }
4859         }
4860 }
4861
4862 // code to warp in a new support ship.  It works by finding the average position of all ships
4863 // in the mission, creating a vector from that position to the player, and scaling out behind the
4864 // player some distance.  Should be sufficient.
4865
4866 #define WARP_IN_MIN_DISTANCE    1000.0f
4867 #define WARP_IN_TIME_MIN                3000                            // warps in min 3 seconds later
4868 #define WARP_IN_TIME_MAX                6000                            // warps in max 6 seconds later
4869
4870 // function which adds requester_objp onto the queue of ships for the arriving support ship to service
4871 void mission_add_to_arriving_support( object *requester_objp )
4872 {
4873         int i;
4874         ship *shipp;
4875
4876         SDL_assert ( Arriving_support_ship );
4877
4878         if ( Num_arriving_repair_targets == MAX_AI_GOALS ) {
4879                 // Int3();                      // get allender -- ship isn't going to get repair, but I hope they never queue up this far!!!
4880                 mprintf(("Reached MAX_AI_GOALS trying to add repair request!\n"));
4881                 return;
4882         }
4883
4884         shipp = &Ships[requester_objp->instance];
4885         // check for duplicates before adding
4886         for (i = 0; i < Num_arriving_repair_targets; i++ ) {
4887                 if ( !SDL_strcasecmp(Arriving_repair_targets[i], shipp->ship_name) ){
4888                         break;
4889                 }
4890         }
4891         if ( i != Num_arriving_repair_targets ){                // found the ship before reaching the end -- ignore it!
4892                 return;
4893         }
4894
4895         SDL_strlcpy( Arriving_repair_targets[Num_arriving_repair_targets], Ships[requester_objp->instance].ship_name, NAME_LENGTH );
4896         Num_arriving_repair_targets++;
4897
4898         if ( MULTIPLAYER_MASTER ){
4899                 multi_maybe_send_repair_info( requester_objp, NULL, REPAIR_INFO_WARP_ADD );
4900         }       
4901 }
4902
4903 extern int pp_collide_any(vector *curpos, vector *goalpos, float radius, object *ignore_objp1, object *ignore_objp2, int big_only_flag);
4904
4905 //      Set the warp in position for a support ship relative to an object.
4906 //      Caller tries several positions, passing vector in x, y, z.
4907 int get_warp_in_pos(vector *pos, object *objp, float x, float y, float z)
4908 {
4909         float   rand_val;
4910
4911         if ( Game_mode & GM_NORMAL )
4912                 rand_val = frand();
4913         else
4914                 rand_val = static_randf(objp->net_signature);
4915
4916         rand_val = 1.0f + (rand_val - 0.5f)*0.2f;
4917
4918         *pos = objp->pos;
4919
4920         vm_vec_scale_add2( pos, &objp->orient.v.rvec, x*rand_val*800.0f);
4921         vm_vec_scale_add2( pos, &objp->orient.v.uvec, y*rand_val*800.0f);
4922         vm_vec_scale_add2( pos, &objp->orient.v.fvec, z*rand_val*800.0f);
4923
4924         return pp_collide_any(&objp->pos, pos, objp->radius, objp, NULL, 1);
4925 }
4926
4927 void mission_warp_in_support_ship( object *requester_objp )
4928 {
4929         vector center, warp_in_pos;
4930         //float mag;
4931         p_object *pobj;
4932         int i, requester_species;
4933         ship *requester_shipp;
4934
4935         SDL_assert ( requester_objp->type == OBJ_SHIP );
4936         requester_shipp = &Ships[requester_objp->instance];     //      MK, 10/23/97, used to be ->type, bogus, no?
4937
4938         // if the support ship is already arriving, add the requester to the list
4939         if ( Arriving_support_ship ) {
4940                 mission_add_to_arriving_support( requester_objp );
4941                 return;
4942         }
4943         
4944         // get average position of all ships
4945         obj_get_average_ship_pos( &center );
4946         vm_vec_sub( &warp_in_pos, &center, &(requester_objp->pos) );
4947
4948         // be sure to account for case as player being only ship left in mission
4949         /*
4950         if ( !(IS_VEC_NULL( warp_in_pos)) ) {
4951                 mag = vm_vec_mag( &warp_in_pos );
4952                 if ( mag < WARP_IN_MIN_DISTANCE )
4953                         vm_vec_scale( &warp_in_pos, WARP_IN_MIN_DISTANCE/mag);
4954                 else
4955                         vm_vec_scale( &warp
4956         } else {
4957                 // take -player_pos.fvec scaled by 1000.0f;
4958                 warp_in_pos = Player_obj->orient.fvec;
4959                 vm_vec_scale( &warp_in_pos, -1000.0f );
4960         }
4961         */
4962
4963         //      Choose position to warp in ship.
4964         //      Temporary, but changed by MK because it used to be exactly behind the player.
4965         //      This could cause an SDL_assert if the player immediately targeted it (before moving).
4966         //      Tend to put in front of the player to aid him in flying towards the ship.
4967
4968         if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.1f, 1.0f))
4969                 if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.2f, -1.0f))
4970                         if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.2f, -1.0f))
4971                                 if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.1f, 1.0f))
4972                                         get_warp_in_pos(&warp_in_pos, requester_objp, 0.1f, 1.0f, 0.2f);
4973
4974         // create a parse object, and put it onto the ship_arrival_list.  This whole thing kind of sucks.
4975         // I want to put it into a parse object since it needs to arrive just a little later than
4976         // this function is called.  I have to make some assumptions in the code about values for the parse
4977         // object since I'm no longer working with a mission file.  These exceptions will be noted with
4978         // comments
4979
4980         Arriving_support_ship = &Support_ship_pobj;
4981         pobj = Arriving_support_ship;
4982
4983         // create a name for the ship.  use "Support #".  look for collisions until one isn't found anymore
4984         i = 1;
4985         do {
4986                 SDL_snprintf(pobj->name, sizeof(pobj->name), NOX("Support %d"), i);
4987                 if ( (ship_name_lookup(pobj->name) == -1) && (ship_find_exited_ship_by_name(pobj->name) == -1) )
4988                         break;
4989                 i++;
4990         } while(1);
4991
4992         pobj->pos = warp_in_pos;
4993         vm_set_identity( &(pobj->orient) );
4994
4995         // *sigh*.  Gotta get the ship class.  For now, this will amount to finding a ship in the ship_info
4996         // array with the same team as the requester of type SIF_SUPPORT.  Might need to be changed, but who knows
4997         // vasudans use the terran support ship.
4998         requester_species = Ship_info[requester_shipp->ship_info_index].species;
4999
5000         // 5/6/98 -- MWA  Don't need to do anything for multiplayer.  I think that we always want to use
5001         // the species of the caller ship.
5002         SDL_assert( (requester_species == SPECIES_TERRAN) || (requester_species == SPECIES_VASUDAN) );
5003 //      if ( (Game_mode & GM_NORMAL) && (requester_species == SPECIES_VASUDAN) )        {       // make vasundan's use the terran support ship
5004 //              requester_species = SPECIES_TERRAN;
5005 //      }
5006
5007         // get index of correct species support ship
5008         for (i=0; i < Num_ship_types; i++) {
5009                 if ( (Ship_info[i].species == requester_species) && (Ship_info[i].flags & SIF_SUPPORT) )
5010                         break;
5011         }
5012
5013         if ( i < Num_ship_types )
5014                 pobj->ship_class = i;
5015         else
5016                 Int3();                         // BOGUS!!!!  gotta figure something out here
5017
5018         pobj->team = requester_shipp->team;
5019
5020         pobj->behavior = AIM_NONE;              // ASSUMPTION:  the mission file has the string "None" which maps to AIM_NONE
5021
5022         // set the ai_goals to -1.  We will put the requester object shipname in repair target array and then take
5023         // care of setting up the goal when creating the ship!!!!
5024         pobj->ai_goals = -1;
5025         Num_arriving_repair_targets = 0;
5026         mission_add_to_arriving_support( requester_objp );
5027
5028         // need to set ship's cargo to nothing.  scan the cargo_names array looking for the string nothing.
5029         // add it if not found
5030         for (i = 0; i < Num_cargo; i++ )
5031                 if ( !SDL_strcasecmp(Cargo_names[i], NOX("nothing")) )
5032                         break;
5033
5034         if ( i == Num_cargo ) {
5035                 SDL_strlcpy(Cargo_names[i], NOX("Nothing"), NAME_LENGTH);
5036                 Num_cargo++;
5037         }
5038         pobj->cargo1 = char(i);
5039
5040         pobj->status_count = 0;
5041
5042         pobj->arrival_location = 0;                     // ASSUMPTION: this is index to arrival_lcation string array for hyperspace!!!!
5043         pobj->arrival_distance = 0;
5044         pobj->arrival_anchor = -1;
5045         pobj->arrival_cue = Locked_sexp_true;
5046         pobj->arrival_delay = timestamp_rand(WARP_IN_TIME_MIN, WARP_IN_TIME_MAX);
5047
5048         pobj->subsys_count = 0;                         // number of elements used in subsys_status array
5049         pobj->initial_velocity = 100;           // start at 100% velocity
5050         pobj->initial_hull = 100;                       // start at 100% hull   
5051         pobj->initial_shields = 100;            // and 100% shields
5052
5053         pobj->departure_location = 0;           // ASSUMPTION: this is index to departure_lcation string array for hyperspace!!!!
5054         pobj->departure_anchor = -1;
5055         pobj->departure_cue = Locked_sexp_false;
5056         pobj->departure_delay= 0;
5057
5058         pobj->determination = 10;                       // ASSUMPTION:  mission file always had this number written out
5059         pobj->wingnum = -1;
5060         if ( Player_obj->flags & P_OF_NO_SHIELDS )
5061                 pobj->flags = P_OF_NO_SHIELDS;  // support ships have no shields when player has not shields
5062
5063         pobj->ai_class = Ship_info[pobj->ship_class].ai_class;
5064         pobj->hotkey = -1;
5065         pobj->score = 0;
5066
5067         pobj->docked_with[0] = '\0';
5068         pobj->group = -1;
5069         pobj->persona_index = -1;
5070         pobj->net_signature = multi_assign_network_signature(MULTI_SIG_SHIP);
5071         pobj->wing_status_wing_index = -1;
5072         pobj->wing_status_wing_pos = -1;
5073         pobj->respawn_count = 0;
5074         pobj->alt_type_index = -1;
5075
5076 }
5077
5078 // returns true if a support ship is currently in the process of warping in.
5079 int mission_is_support_ship_arriving()
5080 {
5081         if ( Arriving_support_ship )
5082                 return 1;
5083         else
5084                 return 0;
5085 }
5086
5087 // returns true if the given ship is scheduled to be repaired by the arriving support ship
5088 int mission_is_repair_scheduled( object *objp )
5089 {
5090         char *name;
5091         int i;
5092
5093         if ( !Arriving_support_ship )
5094                 return 0;
5095
5096         SDL_assert ( objp->type == OBJ_SHIP );
5097         name = Ships[objp->instance].ship_name;
5098         for (i = 0; i < Num_arriving_repair_targets; i++ ) {
5099                 if ( !strcmp( name, Arriving_repair_targets[i]) )
5100                         return 1;
5101         }
5102
5103         return 0;
5104 }
5105
5106 // function which removed the given ship from the list of ships that are to get repair
5107 // by arriving support ship
5108 int mission_remove_scheduled_repair( object *objp )
5109 {
5110         char *name;
5111         int i, index;
5112
5113         if ( !Arriving_support_ship )
5114                 return 0;
5115
5116         // itereate through the target list looking for this ship name.  If not found, we
5117         // can simply return.
5118         SDL_assert ( objp->type == OBJ_SHIP );
5119         name = Ships[objp->instance].ship_name;
5120         for (index = 0; index < Num_arriving_repair_targets; index++ ) {
5121                 if ( !strcmp( name, Arriving_repair_targets[index]) )
5122                         break;
5123         }
5124         if ( index == Num_arriving_repair_targets )
5125                 return 0;
5126
5127         // ship is found -- compress the array
5128         for ( i = index; i < Num_arriving_repair_targets - 1; i++ )
5129                 SDL_strlcpy( Arriving_repair_targets[i], Arriving_repair_targets[i+1], NAME_LENGTH );
5130
5131         Num_arriving_repair_targets--;
5132
5133         if ( MULTIPLAYER_MASTER )
5134                 multi_maybe_send_repair_info( objp, NULL, REPAIR_INFO_WARP_REMOVE );
5135
5136         return 1;
5137 }
5138
5139 // alternate name stuff
5140 int mission_parse_lookup_alt(char *name)
5141 {
5142         int idx;
5143
5144         // sanity
5145         if(name == NULL){
5146                 return -1;
5147         }
5148
5149         // lookup
5150         for(idx=0; idx<Mission_alt_type_count; idx++){
5151                 if(!strcmp(Mission_alt_types[idx], name)){
5152                         return idx;
5153                 }
5154         }
5155
5156         // could not find
5157         return -1;
5158 }
5159
5160 static int mission_parse_lookup_alt_index_warn = 1;
5161 void mission_parse_lookup_alt_index(int index, char *out, const int max_outlen)
5162 {
5163         // sanity
5164         if(out == NULL){
5165                 return;
5166         }
5167         if((index < 0) || (index > Mission_alt_type_count)){
5168                 if (mission_parse_lookup_alt_index_warn) {
5169                         Warning(LOCATION, "Ship with invalid alt_name.  Get a programmer");
5170                         mission_parse_lookup_alt_index_warn = 0;
5171                 }
5172                 return;
5173         }
5174
5175         // stuff it
5176         SDL_strlcpy(out, Mission_alt_types[index], max_outlen);
5177 }
5178
5179 int mission_parse_add_alt(char *name)
5180 {
5181         // sanity
5182         if(name == NULL){
5183                 return -1;
5184         }
5185
5186         // maybe add
5187         if(Mission_alt_type_count < MAX_ALT_TYPE_NAMES){
5188                 // stuff the name
5189                 SDL_strlcpy(Mission_alt_types[Mission_alt_type_count++], name, NAME_LENGTH);
5190
5191                 // done
5192                 return Mission_alt_type_count - 1;
5193         }
5194
5195         return -1;
5196 }
5197
5198 void mission_parse_reset_alt()
5199 {
5200         Mission_alt_type_count = 0;
5201 }
5202
5203 int is_training_mission()
5204 {
5205         return (The_mission.game_type & MISSION_TYPE_TRAINING);
5206 }
5207