]> icculus.org git repositories - taylor/freespace2.git/blob - src/mission/missionparse.cpp
const-char warning fixes
[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 LOCAL 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                 strcpy(pm->mission_desc, NOX("No description\n"));
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 ( !stricmp(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                 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         strcpy(The_mission.squad_name, "");
811         strcpy(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                 strcpy(The_mission.squad_name, "");
821                 strcpy(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         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], num_starting_wings;
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                 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                 num_starting_wings = 0;
908                 if (optional_string("+Starting Wings:"))
909                         num_starting_wings = 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                                         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                         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         Assert(!Cur_cmd_brief->num_stages);
1061         stage = 0;
1062
1063         required_string("#Command Briefing");
1064         while (optional_string("$Stage Text:")) {
1065                 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                 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                 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                         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                                         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                                                 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                                 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                                         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                         Assert(bs->num_icons <= MAX_STAGE_ICONS );
1193
1194                         while (required_string_either("$end_stage", "$start_icon")) {
1195                                 required_string("$start_icon");
1196                                 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                                 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 (!stricmp(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                         Assert(bs->num_icons == icon_num);
1248                         icon_num = 0;
1249                         required_string("$end_stage");
1250                 }       // end while
1251
1252                 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                 Assert(db->num_stages <= MAX_DEBRIEF_STAGES);
1324
1325                 while (required_string_either("#", "$Formula")) {
1326                         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                 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         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         strcpy(Ships[shipnum].ship_name, objp->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 ( !stricmp(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                 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         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 (!stricmp(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 (!stricmp(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         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                 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         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                 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, &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                 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                 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 (!stricmp(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                 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                 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                 strcpy(Initially_docked[Total_initially_docked].dockee, objp->docked_with);
2044                 strcpy(Initially_docked[Total_initially_docked].docker_point, objp->docker_point);
2045                 strcpy(Initially_docked[Total_initially_docked].dockee_point, objp->dockee_point);
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                 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 ( !stricmp( 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                 Assert ( destroy_before_mission_time == -1 );           // we can't add ships getting destroyed to the arrival list!!!
2125                 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                                 strcpy(Cargo_names[Num_cargo++], cargo_name);
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         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                         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                         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                                 //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                                 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                         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                                 sprintf(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 ( !(stricmp(Starting_wing_names[STARTING_WING_ALPHA], wingp->name)) || !(stricmp(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 ( !stricmp(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         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                         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         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         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                 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 ( !stricmp( wing_flag_strings[i], NOX("ignore-count")) )
2702                                 wingp->flags |= WF_IGNORE_COUNT;
2703                         else if ( !stricmp( wing_flag_strings[i], NOX("reinforcement")) )
2704                                 wingp->flags |= WF_REINFORCEMENT;
2705                         else if ( !stricmp( wing_flag_strings[i], NOX("no-arrival-music")) )
2706                                 wingp->flags |= WF_NO_ARRIVAL_MUSIC;
2707                         else if ( !stricmp( wing_flag_strings[i], NOX("no-arrival-message")) )
2708                                 wingp->flags |= WF_NO_ARRIVAL_MESSAGE;
2709                         else if ( !stricmp( wing_flag_strings[i], NOX("no-arrival-warp")) )
2710                                 wingp->flags |= WF_NO_ARRIVAL_WARP;
2711                         else if ( !stricmp( wing_flag_strings[i], NOX("no-departure-warp")) )
2712                                 wingp->flags |= WF_NO_DEPARTURE_WARP;
2713                         else if ( !stricmp( 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 ( !stricmp(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, index;
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                 index = 0;
2781                 for ( sexp = CDR(wing_goals); sexp != -1; sexp = CDR(sexp) )
2782                         ai_add_wing_goal_sexp(sexp, AIG_TYPE_EVENT_WING, wingnum);  // used by Fred
2783
2784                 //if (Fred_running)
2785                         free_sexp2(wing_goals);  // free up sexp nodes for reused, since they aren't needed anymore.
2786         }
2787
2788         // set the wing number for all ships in the wing
2789         for (i = 0; i < wingp->wave_count; i++ ) {
2790                 //char *ship_name = wingp->ship_names[i];
2791                 char *ship_name;
2792                 int num, assigned = 0;
2793                 p_object *objp;
2794
2795                 ship_name = ship_names[i];
2796                 if (Fred_running) {
2797                         num = wingp->ship_index[i] = ship_name_lookup(ship_name, 1);
2798                         Assert ( num != -1 );
2799
2800                         // hack code -- REMOVE
2801                         if ( Objects[Ships[num].objnum].flags & OF_PLAYER_SHIP )
2802                                 Ships[num].wingnum = wingnum;
2803
2804                 } else {
2805                         // determine if this ship is a player ship, and deal with it appropriately.
2806                         if ( !strnicmp(ship_name, NOX("Player "), 7) ) {
2807                                 Error(LOCATION, "Old mission file -- please convert by loading/saving in Fred -- see Allender/Hoffoss for help.");
2808                         }
2809
2810                         // assign the wing number to the ship -- if the ship has arrived, doulble check that
2811                         // there is only one wave of this wing since ships with their own arrival cue cannot be
2812                         // in a wing with > 1 wave.  Otherwise, find the ship on the ship arrival list and set
2813                         // their wing number
2814                         if ( (num = ship_name_lookup(ship_name)) != -1 ) {
2815                                 Int3();                                 // this is impossible under the new system
2816
2817                         } else {
2818                                 objp = GET_FIRST(&ship_arrival_list);
2819                                 while( objp != END_OF_LIST(&ship_arrival_list) )        {
2820                                         if ( !strcmp(ship_name, objp->name) ) {
2821                                                 Assert ( objp->wingnum == -1 );                                                 // get Allender -- ship appears to be in multiple wings
2822                                                 objp->wingnum = wingnum;
2823                                                 assigned++;
2824                                         }
2825                                         objp = GET_NEXT(objp);
2826                                 }
2827                         }
2828
2829                         if ( !assigned || (assigned > 1) )
2830                                 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);
2831                 }
2832         }
2833
2834         // Fred doesn't create the wing.  otherwise, create the wing if is isn't a reinforcement.
2835         if ( !Fred_running && !(wingp->flags & WF_REINFORCEMENT) )
2836                 parse_wing_create_ships( wingp, wingp->wave_count );
2837 }
2838
2839 void parse_wings(mission *pm)
2840 {
2841         required_string("#Wings");
2842         while (required_string_either("#Events", "$Name:")) {
2843                 Assert(num_wings < MAX_WINGS);
2844                 parse_wing(pm);
2845                 num_wings++;
2846         }
2847 }
2848
2849 // mission events are sexpressions which cause things to happen based on the outcome
2850 // of other events in a mission.  Essentially scripting the different things that can happen
2851 // in a mission
2852
2853 void parse_event(mission *pm)
2854 {
2855         char buf[256];
2856         mission_event *event;
2857
2858         event = &Mission_events[Num_mission_events];
2859         event->chain_delay = -1;
2860
2861         required_string( "$Formula:" );
2862         event->formula = get_sexp_main();
2863
2864         if (optional_string("+Name:")){
2865                 stuff_string(event->name, F_NAME, NULL);
2866         } else {
2867                 event->name[0] = 0;
2868         }
2869
2870         if ( optional_string("+Repeat Count:")){
2871                 stuff_int( &(event->repeat_count) );
2872         } else {
2873                 event->repeat_count = 1;
2874         }
2875
2876         event->interval = -1;
2877         if ( optional_string("+Interval:")){
2878                 stuff_int( &(event->interval) );
2879         }
2880
2881         event->score = 0;
2882         if ( optional_string("+Score:") ){
2883                 stuff_int(&event->score);
2884         }
2885
2886         if ( optional_string("+Chained:") ){
2887                 stuff_int(&event->chain_delay);
2888         }
2889
2890         if ( optional_string("+Objective:") ) {
2891                 stuff_string(buf, F_NAME, NULL);
2892                 event->objective_text = strdup(buf);
2893         } else {
2894                 event->objective_text = NULL;
2895         }
2896
2897         if ( optional_string("+Objective key:") ) {
2898                 stuff_string(buf, F_NAME, NULL);
2899                 event->objective_key_text = strdup(buf);
2900         } else {
2901                 event->objective_key_text = NULL;
2902         }
2903
2904         event->team = -1;
2905         if( optional_string("+Team:") ) {
2906                 stuff_int(&event->team);
2907         }
2908
2909         event->timestamp = timestamp(-1);
2910
2911         // sanity check on the repeat count variable
2912         if ( event->repeat_count <= 0 ){
2913                 Error (LOCATION, "Repeat count for mission event %s is <=0.\nMust be >= 1!", event->name );
2914         }
2915 }
2916
2917 void parse_events(mission *pm)
2918 {
2919         required_string("#Events");
2920
2921         while (required_string_either( "#Goals", "$Formula:")) {
2922                 Assert( Num_mission_events < MAX_MISSION_EVENTS );
2923                 parse_event(pm);
2924                 Num_mission_events++;
2925         }
2926 }
2927
2928 void parse_goal(mission *pm)
2929 {
2930         int dummy;
2931
2932         mission_goal    *goalp;
2933
2934         goalp = &Mission_goals[Num_goals++];
2935
2936         Assert(Num_goals < MAX_GOALS);
2937         Assert(pm != NULL);
2938
2939         find_and_stuff("$Type:", &goalp->type, F_NAME, Goal_type_names, Num_goal_type_names, "goal type");
2940
2941         required_string("+Name:");
2942         stuff_string(goalp->name, F_NAME, NULL);
2943
2944         // backwards compatibility for old Fred missions - all new missions should use $MessageNew
2945         if(optional_string("$Message:")){
2946                 stuff_string(goalp->message, F_NAME, NULL, MAX_GOAL_TEXT);
2947         } else {
2948                 required_string("$MessageNew:");
2949                 stuff_string(goalp->message, F_MULTITEXT, NULL, MAX_GOAL_TEXT);
2950         }
2951
2952         if (optional_string("$Rating:")){
2953                 stuff_int(&dummy);  // not used
2954         }
2955
2956         required_string("$Formula:");
2957         goalp->formula = get_sexp_main();
2958
2959         goalp->flags = 0;
2960         if ( optional_string("+Invalid:") )
2961                 goalp->type |= INVALID_GOAL;
2962         if ( optional_string("+Invalid") )
2963                 goalp->type |= INVALID_GOAL;
2964         if ( optional_string("+No music") )
2965                 goalp->flags |= MGF_NO_MUSIC;
2966
2967         goalp->score = 0;
2968         if ( optional_string("+Score:") ){
2969                 stuff_int(&goalp->score);
2970         }
2971
2972         goalp->team = 0;
2973         if ( optional_string("+Team:") ){
2974                 stuff_int( &goalp->team );
2975         }
2976 }
2977
2978 void parse_goals(mission *pm)
2979 {
2980         required_string("#Goals");
2981
2982         while (required_string_either("#Waypoints", "$Type:")){
2983                 parse_goal(pm);
2984         }
2985 }
2986
2987 void parse_waypoint_list(mission *pm)
2988 {
2989         waypoint_list   *wpl;
2990
2991
2992         Assert(Num_waypoint_lists < MAX_WAYPOINT_LISTS);
2993         Assert(pm != NULL);
2994         wpl = &Waypoint_lists[Num_waypoint_lists];
2995
2996         required_string("$Name:");
2997         stuff_string(wpl->name, F_NAME, NULL);
2998
2999         required_string("$List:");
3000         wpl->count = stuff_vector_list(wpl->waypoints, MAX_WAYPOINTS_PER_LIST);
3001
3002 #ifdef MAKE_FS1
3003         // AAAAHH!  I don't like to hard code a mission fix but I have no clue what to do
3004         // to fix this properly.  In the FS1 mission "Playing Judas" you have to try and fly
3005         // into one of the docking bays on the Lucifer.  Due to some change in the code the
3006         // waypoints and the Lucifer's position don't match up so we have to change the
3007         // waypoint position to compensate.
3008         if ( !stricmp(pm->name, "Playing Judas") ) {
3009                 if ( !stricmp(wpl->name, "Docking Bay 1") ) {
3010                         wpl->waypoints[0].xyz.x = -1262.550903;
3011                         wpl->waypoints[0].xyz.y = 27.676950;
3012                         wpl->waypoints[0].xyz.z = 4461.702930;
3013                 } else if ( !stricmp(wpl->name, "Docking Bat 2") ) { // it really is spelled "Bat" in the mission
3014                         wpl->waypoints[0].xyz.x = -1105.347976;
3015                         wpl->waypoints[0].xyz.y = 27.676950;
3016                         wpl->waypoints[0].xyz.z = 3900.236867;
3017                 }
3018         }
3019 #endif
3020
3021         Num_waypoint_lists++;
3022 }
3023
3024 void parse_waypoints(mission *pm)
3025 {
3026         int z;
3027         vector pos;
3028
3029         required_string("#Waypoints");
3030
3031         Num_jump_nodes = 0;
3032         while (optional_string("$Jump Node:")) {
3033                 Assert(Num_jump_nodes < MAX_JUMP_NODES);
3034                 stuff_vector(&pos);
3035                 z = jumpnode_create(&pos);
3036                 Assert(z >= 0);
3037
3038                 if (optional_string("$Jump Node Name:")) {
3039                         stuff_string(Jump_nodes[Num_jump_nodes - 1].name, F_NAME, NULL);
3040                 }
3041
3042                 // If no name exists, then use a standard name
3043                 if ( Jump_nodes[Num_jump_nodes - 1].name[0] == 0 ) {
3044                         sprintf(Jump_nodes[Num_jump_nodes - 1].name, "Jump Node %d", Num_jump_nodes);
3045                 }
3046         }
3047
3048         while (required_string_either("#Messages", "$Name:"))
3049                 parse_waypoint_list(pm);
3050 }
3051
3052 void parse_messages(mission *pm)
3053 {
3054         required_string("#Messages");
3055
3056         mprintf(("Starting mission message count : %d\n", Num_message_waves));
3057
3058         // the message_parse function can be found in MissionMessage.h.  The format in the
3059         // mission file takes the same format as the messages in messages,tbl.  Make parsing
3060         // a whole lot easier!!!
3061         while ( required_string_either("#Reinforcements", "$Name")){
3062                 message_parse();                // call the message parsing system
3063         }
3064
3065         mprintf(("Ending mission message count : %d\n", Num_message_waves));
3066 }
3067
3068 void parse_reinforcement(mission *pm)
3069 {
3070         reinforcements *ptr;
3071         int instance;
3072
3073         Assert(Num_reinforcements < MAX_REINFORCEMENTS);
3074         Assert(pm != NULL);
3075         ptr = &Reinforcements[Num_reinforcements];
3076
3077         required_string("$Name:");
3078         stuff_string(ptr->name, F_NAME, NULL);  
3079
3080         find_and_stuff("$Type:", &ptr->type, F_NAME, Reinforcement_type_names, Num_reinforcement_type_names, "reinforcement type");
3081
3082         required_string("$Num times:");
3083         stuff_int(&ptr->uses);
3084         ptr->num_uses = 0;
3085
3086         // reset the flags to 0
3087         ptr->flags = 0;
3088
3089         if ( optional_string("+Arrival delay:") ){
3090                 stuff_int( &(ptr->arrival_delay) );
3091         }
3092
3093         if ( optional_string("+No Messages:") ){
3094                 stuff_string_list( ptr->no_messages, MAX_REINFORCEMENT_MESSAGES );
3095         }
3096
3097         if ( optional_string("+Yes Messages:") ){
3098                 stuff_string_list( ptr->yes_messages, MAX_REINFORCEMENT_MESSAGES );
3099         }       
3100
3101         // sanity check on the names of reinforcements -- must either be wings/ships/arrival list.
3102         if ( ship_name_lookup(ptr->name) == -1 ) {
3103                 if ( wing_name_lookup(ptr->name, 1) == -1 ) {
3104                         p_object *p_objp;
3105
3106                         for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3107                                 if ( !stricmp(ptr->name, p_objp->name) ){
3108                                         break;
3109                                 }
3110                         }
3111
3112                         if ( p_objp == END_OF_LIST(&ship_arrival_list) ) {
3113                                 Warning(LOCATION, "Reinforcement %s not found as ship or wing", ptr->name);
3114                                 return;
3115                         }
3116                 }
3117         }
3118
3119         // now, if the reinforcement is a wing, then set the number of waves of the wing == number of
3120         // uses of the reinforcement
3121         instance = wing_name_lookup(ptr->name, 1);
3122         if ( instance != -1 )
3123                 Wings[instance].num_waves = ptr->uses;
3124
3125         Num_reinforcements++;
3126 }
3127
3128 void parse_reinforcements(mission *pm)
3129 {
3130         Num_reinforcements = 0;
3131         required_string("#Reinforcements");
3132
3133         while (required_string_either("#Background bitmaps", "$Name:"))
3134                 parse_reinforcement(pm);
3135 }
3136
3137 void parse_bitmap(mission *pm)
3138 {
3139 #ifdef MAKE_FS1
3140         starfield_bitmap_instance b;
3141
3142         Num_suns = 0;
3143
3144         Assert(pm != NULL);
3145
3146         while(optional_string("$Bitmap:")) {
3147                 stuff_string(b.filename, F_NAME, NULL);
3148         
3149                 required_string("$Orientation:");
3150                 stuff_matrix(&b.m);
3151
3152                 required_string("$Rotation rate:");
3153                 stuff_float(&b.rot);
3154
3155                 required_string("$Distance:");
3156                 stuff_float(&b.scale_x);                
3157                 b.scale_y = b.scale_x;
3158                 b.div_x = 1;
3159                 b.div_y = 1;
3160
3161                 required_string("$Light:");
3162                 stuff_int(&b.sun_light);
3163
3164                 if(Num_suns < MAX_STARFIELD_BITMAPS){
3165                         Suns[Num_suns] = b;
3166                         strcpy(Suns[Num_suns].filename, b.filename);
3167                         Num_suns++;
3168                 }
3169         }
3170 #else
3171         /*
3172         char name[NAME_LENGTH];
3173         int z;
3174         starfield_bitmaps *ptr;
3175
3176         Assert(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS);
3177         Assert(pm != NULL);
3178         ptr = &Starfield_bitmaps[Num_starfield_bitmaps];
3179
3180         required_string("$Bitmap:");
3181         stuff_string(name, F_NAME, NULL);
3182         for (z=0; z<Num_starfield_bitmap_lists; z++)    {
3183                 if (!stricmp(name, Starfield_bitmap_list[z].name)){
3184                         break;
3185                 }
3186         }
3187
3188         if ( z >= Num_starfield_bitmap_lists )  {
3189                 Warning( LOCATION, "Bitmap specified in mission not in game!\n" );
3190                 z = 0;
3191         }
3192         
3193         ptr->bitmap_index = z;
3194         required_string("$Orientation:");
3195         stuff_matrix(&ptr->m);
3196
3197         required_string("$Rotation rate:");
3198         stuff_float(&ptr->rot);
3199
3200         required_string("$Distance:");
3201         stuff_float(&ptr->dist);
3202
3203         required_string("$Light:");
3204         stuff_int(&ptr->light);
3205         Num_starfield_bitmaps++;
3206         calculate_bitmap_points(ptr);
3207         */
3208         Int3();
3209 #endif
3210 }
3211
3212 void parse_bitmaps(mission *pm)
3213 {
3214         char str[MAX_FILENAME_LEN+1] = "";
3215         starfield_bitmap_instance b;
3216         int z;
3217
3218         Num_starfield_bitmaps = 0;
3219         required_string("#Background bitmaps");
3220
3221         required_string("$Num stars:");
3222         stuff_int(&Num_stars);
3223         if (Num_stars >= MAX_STARS)
3224                 Num_stars = MAX_STARS;
3225
3226         int Ambient_light_level;
3227         required_string("$Ambient light level:");
3228         stuff_int(&Ambient_light_level);
3229
3230         // This should call light_set_ambient() to
3231         // set the ambient light
3232
3233         Nebula_index = -1;
3234         Mission_palette = 1;
3235
3236         if(The_mission.flags & MISSION_FLAG_FULLNEB){
3237                 // no regular nebula stuff
3238                 nebula_close();
3239
3240                 // neb2 info
3241                 strcpy(Neb2_texture_name, "Eraseme3");
3242                 Neb2_poof_flags = ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
3243                 if(optional_string("+Neb2:")){
3244                         stuff_string(Neb2_texture_name, F_NAME, NULL);
3245
3246                         required_string("+Neb2Flags:");                 
3247                         stuff_int(&Neb2_poof_flags);
3248
3249                         // initialize neb effect. its gross to do this here, but Fred is dumb so I have no choice ... :(
3250                         if(Fred_running){
3251                                 neb2_level_init();
3252                         }
3253                 }
3254         } else {
3255                 if (optional_string("+Nebula:")) {
3256                         stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3257                         
3258                         // parse the proper nebula type (full or not)   
3259                         for (z=0; z<NUM_NEBULAS; z++){
3260                                 if(The_mission.flags & MISSION_FLAG_FULLNEB){
3261                                         if (!stricmp(str, Neb2_filenames[z])) {
3262                                                 Nebula_index = z;
3263                                                 break;
3264                                         }
3265                                 } else {
3266                                         if (!stricmp(str, Nebula_filenames[z])) {
3267                                                 Nebula_index = z;
3268                                                 break;
3269                                         }
3270                                 }
3271                         }
3272
3273                         if (optional_string("+Color:")) {
3274                                 stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3275                                 for (z=0; z<NUM_NEBULA_COLORS; z++){
3276                                         if (!stricmp(str, Nebula_colors[z])) {
3277                                                 Mission_palette = z;
3278                                                 break;
3279                                         }
3280                                 }
3281                         }
3282
3283                         if (optional_string("+Pitch:")){
3284                                 stuff_int(&Nebula_pitch);
3285                         } else {
3286                                 Nebula_pitch = 0;
3287                         }
3288
3289                         if (optional_string("+Bank:")){
3290                                 stuff_int(&Nebula_bank);
3291                         } else {
3292                                 Nebula_bank = 0;
3293                         }
3294
3295                         if (optional_string("+Heading:")){
3296                                 stuff_int(&Nebula_heading);
3297                         } else {
3298                                 Nebula_heading = 0;
3299                         }                                               
3300                 }
3301
3302                 if (Nebula_index >= 0){         
3303                         nebula_init(Nebula_filenames[Nebula_index], Nebula_pitch, Nebula_bank, Nebula_heading);
3304                 } else {
3305                         nebula_close();         
3306                 }
3307         }       
3308         
3309         // parse suns
3310         Num_suns = 0;
3311         while(optional_string("$Sun:")){
3312                 // filename
3313                 stuff_string(b.filename, F_NAME, NULL);
3314                         
3315                 // angles
3316                 required_string("+Angles:");
3317                 stuff_float(&b.ang.p);
3318                 stuff_float(&b.ang.b);
3319                 stuff_float(&b.ang.h);          
3320
3321                 // scale
3322                 required_string("+Scale:");
3323                 stuff_float(&b.scale_x);                
3324                 b.scale_y = b.scale_x;
3325                 b.div_x = 1;
3326                 b.div_y = 1;
3327                 
3328                 // if we have room, store it
3329                 if(Num_suns < MAX_STARFIELD_BITMAPS){
3330                         Suns[Num_suns] = b;
3331                         strcpy(Suns[Num_suns].filename, b.filename);
3332                         Num_suns++;
3333                 }
3334         }
3335
3336         // parse background bitmaps
3337         Num_starfield_bitmaps = 0;
3338         while(optional_string("$Starbitmap:")){
3339                 // filename
3340                 stuff_string(b.filename, F_NAME, NULL);
3341                         
3342                 // angles
3343                 required_string("+Angles:");
3344                 stuff_float(&b.ang.p);
3345                 stuff_float(&b.ang.b);
3346                 stuff_float(&b.ang.h);          
3347
3348                 // scale
3349                 // scale
3350                 if(optional_string("+Scale:")){
3351                         stuff_float(&b.scale_x);
3352                         b.scale_y = b.scale_x;
3353                         b.div_x = 1;
3354                         b.div_y = 1;
3355                 } else {
3356                         required_string("+ScaleX:");
3357                         stuff_float(&b.scale_x);
3358
3359                         required_string("+ScaleY:");
3360                         stuff_float(&b.scale_y);
3361
3362                         required_string("+DivX:");
3363                         stuff_int(&b.div_x);
3364
3365                         required_string("+DivY:");
3366                         stuff_int(&b.div_y);
3367                 }               
3368                 
3369                 // if we have room, store it
3370                 if(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS){
3371                         Starfield_bitmap_instance[Num_starfield_bitmaps] = b;
3372                         strcpy(Starfield_bitmap_instance[Num_starfield_bitmaps].filename, b.filename);
3373                         Num_starfield_bitmaps++;
3374                 }
3375         }
3376
3377 #ifdef MAKE_FS1
3378         parse_bitmap(pm);
3379 #endif
3380         
3381         if ( optional_string("#Asteroid Fields") ){
3382                 parse_asteroid_fields(pm);
3383         }
3384 }
3385
3386 void parse_asteroid_fields(mission *pm)
3387 {
3388 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
3389
3390         int i, count, subtype;
3391
3392         Assert(pm != NULL);
3393         for (i=0; i<MAX_ASTEROID_FIELDS; i++)
3394                 Asteroid_field.num_initial_asteroids = 0;
3395
3396         i = 0;
3397         count = 0;
3398 //      required_string("#Asteroid Fields");
3399 #ifdef MAKE_FS1
3400         while (required_string_either("#", "$Density:")) {
3401 #else
3402         while (required_string_either("#", "$density:")) {
3403 #endif
3404                 float speed, density;
3405
3406                 Assert(i < 1);
3407                 required_string("$Density:");
3408                 stuff_float(&density);
3409
3410                 Asteroid_field.num_initial_asteroids = (int) density;
3411
3412                 Asteroid_field.field_type = FT_ACTIVE;
3413                 if (optional_string("+Field Type:")) {
3414                         stuff_int((int*)&Asteroid_field.field_type);
3415                 }
3416
3417                 Asteroid_field.debris_genre = DG_ASTEROID;
3418                 if (optional_string("+Debris Genre:")) {
3419                         stuff_int((int*)&Asteroid_field.debris_genre);
3420                 }
3421
3422                 Asteroid_field.field_debris_type[0] = -1;
3423                 Asteroid_field.field_debris_type[1] = -1;
3424                 Asteroid_field.field_debris_type[2] = -1;
3425                 if (Asteroid_field.debris_genre == DG_SHIP) {
3426                         if (optional_string("+Field Debris Type:")) {
3427                                 stuff_int(&Asteroid_field.field_debris_type[0]);
3428                         }
3429                         if (optional_string("+Field Debris Type:")) {
3430                                 stuff_int(&Asteroid_field.field_debris_type[1]);
3431                         }
3432                         if (optional_string("+Field Debris Type:")) {
3433                                 stuff_int(&Asteroid_field.field_debris_type[2]);
3434                         }
3435                 } else {
3436                         // debris asteroid
3437                         if (optional_string("+Field Debris Type:")) {
3438                                 stuff_int(&subtype);
3439                                 Asteroid_field.field_debris_type[subtype] = 1;
3440                                 count++;
3441                         }
3442                         if (optional_string("+Field Debris Type:")) {
3443                                 stuff_int(&subtype);
3444                                 Asteroid_field.field_debris_type[subtype] = 1;
3445                                 count++;
3446                         }
3447                         if (optional_string("+Field Debris Type:")) {
3448                                 stuff_int(&subtype);
3449                                 Asteroid_field.field_debris_type[subtype] = 1;
3450                                 count++;
3451                         }
3452                 }
3453
3454                 // backward compatibility
3455                 if ( (Asteroid_field.debris_genre == DG_ASTEROID) && (count == 0) ) {
3456                         Asteroid_field.field_debris_type[0] = 0;
3457                 }
3458
3459                 required_string("$Average Speed:");
3460                 stuff_float(&speed);
3461
3462                 vm_vec_rand_vec_quick(&Asteroid_field.vel);
3463                 vm_vec_scale(&Asteroid_field.vel, speed);
3464
3465                 Asteroid_field.speed = speed;
3466
3467                 required_string("$Minimum:");
3468                 stuff_vector(&Asteroid_field.min_bound);
3469
3470                 required_string("$Maximum:");
3471                 stuff_vector(&Asteroid_field.max_bound);
3472
3473                 if (optional_string("+Inner Bound:")) {
3474                         Asteroid_field.has_inner_bound = 1;
3475
3476                         required_string("$Minimum:");
3477                         stuff_vector(&Asteroid_field.inner_min_bound);
3478
3479                         required_string("$Maximum:");
3480                         stuff_vector(&Asteroid_field.inner_max_bound);
3481                 } else {
3482                         Asteroid_field.has_inner_bound = 0;
3483                 }
3484                 i++;
3485         }
3486 #endif // DEMO
3487 }
3488
3489 void parse_variables()
3490 {
3491         if (! optional_string("#Sexp_variables") ) {
3492                 return;
3493         } else {
3494                 int num_variables;
3495                 num_variables = stuff_sexp_variable_list();
3496         }
3497 }
3498
3499
3500 void parse_mission(mission *pm, int flag)
3501 {
3502         int i;
3503
3504         Player_starts = Num_cargo = Num_waypoint_lists = Num_goals = num_wings = num_ship_arrivals = 0;
3505         Player_start_shipnum = -1;
3506         *Player_start_shipname = 0;             // make the string 0 length for checking later
3507         memset( &Player_start_pobject, 0, sizeof(Player_start_pobject) );
3508
3509         // initialize the initially_docked array.
3510         for ( i = 0; i < MAX_SHIPS; i++ ) {
3511                 Initially_docked[i].docker = NULL;
3512                 Initially_docked[i].dockee[0] = '\0';
3513                 Initially_docked[i].docker_point[0] = '\0';
3514                 Initially_docked[i].dockee_point[0] = '\0';
3515         }
3516         Total_initially_docked = 0;
3517
3518         list_init( &ship_arrival_list );                // init lists for arrival objects and wings
3519
3520         init_parse();
3521         Subsys_index = 0;
3522
3523         parse_mission_info(pm); 
3524         Current_file_checksum = netmisc_calc_checksum(pm,MISSION_CHECKSUM_SIZE);
3525         if ( flag == MISSION_PARSE_MISSION_INFO )
3526                 return;
3527         parse_plot_info(pm);
3528         parse_variables();
3529         parse_briefing_info(pm);        // TODO: obsolete code, keeping so we don't obsolete existing mission files
3530         parse_cmd_briefs(pm);
3531         parse_briefing(pm);
3532         parse_debriefing_new(pm);
3533         parse_player_info(pm);
3534         parse_objects(pm, flag);
3535         parse_wings(pm);
3536         parse_events(pm);
3537         parse_goals(pm);
3538         parse_waypoints(pm);
3539         parse_messages(pm);
3540         parse_reinforcements(pm);
3541         parse_bitmaps(pm);
3542         parse_music(pm);
3543
3544         post_process_mission();
3545 }
3546
3547 void post_process_mission()
3548 {
3549         int                     i;
3550         int                     indices[MAX_SHIPS], objnum;
3551         p_object                *p_objp;
3552         ship_weapon     *swp;
3553         ship_obj *so;
3554
3555         // the player_start_shipname had better exist at this point!
3556         Player_start_shipnum = ship_name_lookup( Player_start_shipname );
3557         Assert ( Player_start_shipnum != -1 );
3558         Assert ( Player_start_pobject.flags & P_SF_PLAYER_START_VALID );
3559
3560         // Assign objnum, shipnum, etc. to the player structure
3561         objnum = Ships[Player_start_shipnum].objnum;
3562         Player_obj = &Objects[objnum];
3563         if (!Fred_running){
3564                 Player->objnum = objnum;
3565         }
3566
3567         Player_obj->flags |= OF_PLAYER_SHIP;                    // make this object a player controlled ship.
3568         Player_ship = &Ships[Player_start_shipnum];
3569         Player_ai = &Ai_info[Player_ship->ai_index];
3570
3571         Player_ai->targeted_subsys = NULL;
3572         Player_ai->targeted_subsys_parent = -1;
3573
3574         // determine if player start has initial velocity and set forward cruise percent to relect this
3575         if ( Player_obj->phys_info.vel.xyz.z > 0.0f )
3576                 Player->ci.forward_cruise_percent = Player_obj->phys_info.vel.xyz.z / Player_ship->current_max_speed * 100.0f;
3577
3578         // put in hard coded starting wing names.
3579         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3580                 Starting_wings[0] = wing_name_lookup(Starting_wing_names[0],1);
3581                 Starting_wings[1] = wing_name_lookup(Starting_wing_names[MAX_STARTING_WINGS],1);
3582         } else {
3583                 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
3584                         Starting_wings[i] = wing_name_lookup(Starting_wing_names[i], 1);
3585                 }
3586         }
3587
3588         init_ai_system();
3589
3590         // call a function to deal with intially docked ships
3591         mission_parse_do_initial_docks();
3592
3593         // deal with setting up arrival location for all ships.  Must do this now after all ships are created
3594         mission_parse_set_arrival_locations();
3595
3596         // clear out information about arriving support ships
3597         Arriving_support_ship = NULL;
3598         Num_arriving_repair_targets = 0;
3599
3600         // convert all ship name indices to ship indices now that mission has been loaded
3601         if (Fred_running) {
3602                 for (i=0; i<Num_parse_names; i++) {
3603                         indices[i] = ship_name_lookup(Parse_names[i], 1);
3604                         if (indices[i] < 0)
3605                                 Warning(LOCATION, "Ship name \"%s\" referenced, but this ship doesn't exist", Parse_names[i]);
3606                 }
3607
3608                 for (i=0; i<MAX_SHIPS; i++) {
3609                         if ((Ships[i].objnum >= 0) && (Ships[i].arrival_anchor >= 0) && (Ships[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3610                                 Ships[i].arrival_anchor = indices[Ships[i].arrival_anchor];
3611
3612                         if ( (Ships[i].objnum >= 0) && (Ships[i].departure_anchor >= 0) )
3613                                 Ships[i].departure_anchor = indices[Ships[i].departure_anchor];
3614                 }
3615
3616                 for (i=0; i<MAX_WINGS; i++) {
3617                         if (Wings[i].wave_count  && (Wings[i].arrival_anchor >= 0) && (Wings[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3618                                 Wings[i].arrival_anchor = indices[Wings[i].arrival_anchor];
3619
3620                         if (Wings[i].wave_count  && (Wings[i].departure_anchor >= 0) )
3621                                 Wings[i].departure_anchor = indices[Wings[i].departure_anchor];
3622                 }
3623
3624         }
3625
3626         // before doing anything else, we must validate all of the sexpressions that were loaded into the mission.
3627         // Loop through the Sexp_nodes array and send the top level functions to the check_sexp_syntax parser
3628
3629         for (i = 0; i < MAX_SEXP_NODES; i++) {
3630                 if ( is_sexp_top_level(i) && (!Fred_running || (i != Sexp_clipboard))) {
3631                         int result, bindex, op;
3632
3633                         op = identify_operator(CTEXT(i));
3634                         Assert(op != -1);  // need to make sure it is an operator before we treat it like one..
3635                         result = check_sexp_syntax( i, query_operator_return_type(op), 1, &bindex);
3636
3637                         // entering this if statement will result in program termination!!!!!
3638                         // print out an error based on the return value from check_sexp_syntax()
3639                         if ( result ) {
3640                                 char sexp_str[8192], text[8192];
3641
3642                                 convert_sexp_to_string( i, sexp_str, SEXP_ERROR_CHECK_MODE);
3643                                 sprintf(text, "%s.\n\nIn sexpression: %s\n(Error appears to be: %s)",
3644                                         sexp_error_message(result), sexp_str, Sexp_nodes[bindex].text);
3645
3646                                 if (!Fred_running)
3647                                         Error( LOCATION, text );
3648                                 else
3649                                         Warning( LOCATION, text );
3650                         }
3651                 }
3652         }
3653
3654         ai_post_process_mission();
3655
3656
3657         /*
3658         for (i=0; i<Total_initially_docked; i++) {
3659                 z = ship_name_lookup(Initially_docked[i].dockee);
3660                 if (z >= 0) {
3661                         Assert(Initially_docked[i].docker->type == OBJ_SHIP);
3662                         p1 = model_find_dock_name_index(Ships[Initially_docked[i].docker->instance].modelnum,
3663                                 Initially_docked[i].docker_point);
3664                         Assert(Objects[z].type == OBJ_SHIP);
3665                         p2 = model_find_dock_name_index(Ships[Objects[z].instance].modelnum,
3666                                 Initially_docked[i].dockee_point);
3667
3668                         if ((p1 >= 0) && (p2 >= 0)) {
3669                                 nprintf(("AI", "Initially Docked: %s with %s\n", Ships[Initially_docked[i].docker->instance].ship_name, Ships[Objects[z].instance].ship_name));
3670                                 if (ship_docking_valid(Initially_docked[i].docker->instance, Objects[z].instance))  // only dock if they are allowed to be docked.
3671                                         ai_dock_with_object(Initially_docked[i].docker, &Objects[z], 89, AIDO_DOCK_NOW, p1, p2);
3672                                         
3673                         } else
3674                                 Int3();         //      Curious.  Two ships told to dock, but one of the dock points is bogus.  
3675                                                                 // Get Allender or Hoffoss, one of whom probably wrote the above if ()
3676                 }
3677         }
3678         */
3679
3680         // we must also count all of the ships of particular types.  We count all of the ships that do not have
3681         // their SF_IGNORE_COUNT flag set.  We don't count ships in wings when the equivalent wing flag is set.
3682         // in counting ships in wings, we increment the count by the wing's wave count to account for everyone.
3683         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
3684                 int siflags, num, shipnum;
3685
3686                 shipnum = Objects[so->objnum].instance;
3687                 // pass over non-ship objects and player ship objects
3688                 if ( Ships[shipnum].objnum == -1 || (Objects[Ships[shipnum].objnum].flags & OF_PLAYER_SHIP) )
3689                         continue;
3690                 if ( Ships[shipnum].flags & SF_IGNORE_COUNT )
3691                         continue;
3692                 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_IGNORE_COUNT) )
3693                         continue;
3694
3695                 siflags = Ship_info[Ships[shipnum].ship_info_index].flags;
3696                 
3697                 // determine the number of times we need to add this ship into the count
3698 //              if ( Ships[i].wingnum == -1 )
3699                         num = 1;
3700 //              else
3701 //                      num = Wings[Ships[i].wingnum].num_waves;
3702
3703                 ship_add_ship_type_count( siflags, num );
3704         }
3705         // now go through the list of ships yet to arrive
3706         for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3707                 int siflags, num;
3708
3709                 // go through similar motions as above
3710                 if ( p_objp->flags & P_SF_IGNORE_COUNT )
3711                         continue;
3712                 if ( (p_objp->wingnum != -1) && (Wings[p_objp->wingnum].flags & WF_IGNORE_COUNT) )
3713                         continue;
3714
3715                 siflags = Ship_info[p_objp->ship_class].flags;
3716
3717                 if ( p_objp->wingnum == -1 )
3718                         num = 1;
3719                 else
3720                         num = Wings[p_objp->wingnum].num_waves - 1;                     // subtract one since we already counted the first wave
3721                 
3722                 ship_add_ship_type_count( siflags, num );
3723         }
3724
3725         // set player weapons that are selected by default
3726         // AL 09/17/97: I added this code to select the first primary/secondary weapons, 
3727         // since I noticed the player ship sometimes doesn't get default weapons selected               
3728
3729         // DB: modified 4/23/98 to take multiplayer into account. Under certain circumstances, multiplayer netplayer ships
3730         //     had their current_primary_bank and current_secondary_bank set to -1 (from ship_set()) and left there since
3731         //     Player_ship is not the only one we need to need about.
3732         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {          
3733                 ship *shipp = &Ships[Objects[so->objnum].instance];
3734
3735                 // don't process non player wing ships
3736                 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
3737                         continue;                       
3738
3739                 swp = &shipp->weapons;
3740         
3741                 // swp = &Player_ship->weapons;
3742                 if ( swp->num_primary_banks > 0 ) {
3743                         swp->current_primary_bank = 0;                  // currently selected primary bank
3744                 }
3745
3746                 if ( swp->num_secondary_banks > 0 ) {
3747                         swp->current_secondary_bank = 0;                        // currently selected secondary bank
3748                 }
3749         }
3750
3751         ets_init_ship(Player_obj);      // init ETS data for the player
3752
3753         // put the timestamp stuff here for now
3754         Mission_arrival_timestamp = timestamp( ARRIVAL_TIMESTAMP );
3755         Mission_departure_timestamp = timestamp( DEPARTURE_TIMESTAMP );
3756         Mission_end_time = -1;
3757
3758         if(Game_mode & GM_MULTIPLAYER){ 
3759                 multi_respawn_build_points();
3760         }       
3761
3762         // maybe reset hotkey defaults when loading new mission
3763         if ( Last_file_checksum != Current_file_checksum ){
3764                 mission_hotkey_reset_saved();
3765         }
3766
3767         Allow_arrival_music_timestamp=timestamp(0);
3768         Allow_arrival_message_timestamp=timestamp(0);
3769         Arrival_message_delay_timestamp = timestamp(-1);
3770
3771         int idx;
3772         for(idx=0; idx<2; idx++){
3773                 Allow_arrival_music_timestamp_m[idx]=timestamp(0);
3774                 Allow_arrival_message_timestamp_m[idx]=timestamp(0);
3775                 Arrival_message_delay_timestamp_m[idx] = timestamp(-1);
3776         }       
3777
3778         Last_file_checksum = Current_file_checksum;
3779 }
3780
3781 int get_mission_info(char *filename, mission *mission_p)
3782 {
3783         int rval;
3784
3785         // if mission_p is NULL, make it point to The_mission
3786         if ( mission_p == NULL )
3787                 mission_p = &The_mission;
3788
3789         if ((rval = setjmp(parse_abort)) != 0) {
3790                 nprintf(("Error", "Error abort!  Code = %d", rval));
3791                 return rval;
3792         
3793         } else {
3794                 int filelength;
3795
3796                 // open localization
3797                 lcl_ext_open();
3798
3799                 CFILE *ftemp = cfopen(filename, "rt");
3800                 if (!ftemp){
3801                         // close localization
3802                         lcl_ext_close();
3803
3804                         return -1;
3805                 }
3806
3807                 // 7/9/98 -- MWA -- check for 0 length file.
3808                 filelength = cfilelength(ftemp);
3809                 cfclose(ftemp);
3810                 if ( filelength == 0 ){
3811                         // close localization
3812                         lcl_ext_close();        
3813
3814                         return -1;
3815                 }
3816
3817                 read_file_text(filename, CF_TYPE_MISSIONS);
3818                 memset( mission_p, 0, sizeof(mission) );
3819                 init_parse();
3820                 parse_mission_info(mission_p);
3821
3822                 // close localization
3823                 lcl_ext_close();
3824         }
3825
3826         return 0;
3827 }
3828
3829 // mai parse routine for parsing a mission.  The default parameter flags tells us which information
3830 // to get when parsing the mission.  0 means get everything (default).  Other flags just gets us basic
3831 // info such as game type, number of players etc.
3832 int parse_main(const char *mission_name, int flags)
3833 {
3834         int rval, i;
3835
3836         // fill in Ship_class_names array with the names from the ship_info struct;
3837         Num_parse_names = 0;
3838         Mission_all_attack = 0; //      Might get set in mission load.
3839         Assert(Num_ship_types < MAX_SHIP_TYPES);
3840
3841         for (i = 0; i < Num_ship_types; i++)
3842                 Ship_class_names[i] = Ship_info[i].name;
3843
3844         if ((rval = setjmp(parse_abort)) != 0) {
3845                 nprintf(("Error", "Error abort!  Code = %i.", rval));
3846                 return rval;
3847         
3848         } else {
3849                 // open localization
3850                 lcl_ext_open();
3851
3852                 CFILE *ftemp = cfopen(mission_name, "rt", CFILE_NORMAL, CF_TYPE_MISSIONS);
3853                 // fail situation.
3854                 if (!ftemp) {
3855                         if (!Fred_running)
3856                                 Error( LOCATION, "Couldn't open mission '%s'\n", mission_name );
3857
3858                         Current_file_length = -1;
3859                         Current_file_checksum = 0;
3860
3861                         // close localization
3862                         lcl_ext_close();
3863
3864                         return -1;
3865                 }
3866
3867                 Current_file_length = cfilelength(ftemp);
3868                 cfclose(ftemp);
3869
3870                 read_file_text(mission_name, CF_TYPE_MISSIONS);
3871                 memset(&The_mission, 0, sizeof(The_mission));
3872                 parse_mission(&The_mission, flags);
3873                 display_parse_diagnostics();
3874
3875                 // close localization
3876                 lcl_ext_close();
3877         }
3878
3879         if (!Fred_running)
3880                 strcpy(Mission_filename, mission_name);
3881
3882         return 0;
3883 }
3884
3885 // sets the arrival lcoation of the ships in wingp.  pass num_to_set since the threshold value
3886 // for wings may have us create more ships in the wing when there are still some remaining
3887 void mission_set_wing_arrival_location( wing *wingp, int num_to_set )
3888 {
3889         int index;
3890
3891         // get the starting index into the ship_index array of the first ship whose location we need set.
3892
3893         index = wingp->current_count - num_to_set;
3894         if ( (wingp->arrival_location == ARRIVE_FROM_DOCK_BAY) || (wingp->arrival_location == ARRIVE_AT_LOCATION) ) {
3895                 while ( index < wingp->current_count ) {
3896                         object *objp;
3897
3898                         objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3899                         mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3900
3901                         index++;
3902                 }
3903         } else {
3904                 object *leader_objp;
3905                 vector pos;
3906                 matrix orient;
3907                 int wing_index;
3908
3909                 // wing is not arriving from a docking bay -- possibly move them based on arriving near
3910                 // or in front of some other ship.
3911                 index = wingp->current_count - num_to_set;
3912                 leader_objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3913                 if (mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(leader_objp), &pos, &orient)) {
3914                         // modify the remaining ships created
3915                         index++;
3916                         wing_index = 1;
3917                         while ( index < wingp->current_count ) {
3918                                 object *objp;
3919
3920                                 objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3921
3922                                 // change the position of the next ships in the wing.  Use the cool function in AiCode.cpp which
3923                                 // Mike K wrote to give new positions to the wing members.
3924                                 get_absolute_wing_pos( &objp->pos, leader_objp, wing_index++, 0);
3925                                 memcpy( &objp->orient, &orient, sizeof(matrix) );
3926
3927                                 index++;
3928                         }
3929                 }
3930         }
3931
3932         // create warp effect if in mission and not arriving from docking bay
3933         if ( (Game_mode & GM_IN_MISSION) && (wingp->arrival_location != ARRIVE_FROM_DOCK_BAY) ) {
3934                 for ( index = wingp->current_count - num_to_set; index < wingp->current_count; index ++ ) {
3935                         shipfx_warpin_start( &Objects[Ships[wingp->ship_index[index]].objnum] );
3936                 }
3937         }
3938 }
3939
3940 // this function is called after a mission is parsed to set the arrival locations of all ships in the
3941 // mission to the apprioriate spot.  Mainly needed because ships might be in dock bays to start
3942 // the mission, so their AI mode must be set appropriately.
3943 void mission_parse_set_arrival_locations()
3944 {
3945         int i;
3946         object *objp;
3947
3948         if ( Fred_running )
3949                 return;
3950
3951         obj_merge_created_list();
3952         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3953                 ship *shipp;
3954
3955                 if ( objp->type != OBJ_SHIP ) 
3956                         continue;
3957
3958                 shipp = &Ships[objp->instance];
3959                 // if the ship is in a wing -- ignore the info and let the wing info handle it
3960                 if ( shipp->wingnum != -1 )
3961                         continue;
3962
3963                 // call function to set arrival location for this ship.
3964                 mission_set_arrival_location( shipp->arrival_anchor, shipp->arrival_location, shipp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3965         }
3966
3967         // do the wings
3968         for ( i = 0; i < num_wings; i++ ) {
3969
3970                 // if wing has no ships, then don't process it.
3971                 if ( Wings[i].current_count == 0 )
3972                         continue;
3973
3974                 mission_set_wing_arrival_location( &Wings[i], Wings[i].current_count );
3975         }
3976 }
3977
3978
3979 // function which iterates through the ship_arrival_list and creates any ship which
3980 // should be intially docked with a ship which currently exists in the mission
3981 void mission_parse_do_initial_docks()
3982 {
3983         p_object *pobjp, *tmp;
3984
3985         pobjp = GET_FIRST( &ship_arrival_list );
3986         while ( pobjp != END_OF_LIST(&ship_arrival_list) ) {
3987                 int shipnum;
3988
3989                 tmp = GET_NEXT(pobjp);
3990
3991                 // see if the flag for initial docked is set
3992                 if ( pobjp->flags & P_SF_INITIALLY_DOCKED ) {
3993                         // see if who this parse object is supposed to be docked with is in the mission
3994                         shipnum = ship_name_lookup( pobjp->docked_with );
3995                         if ( shipnum != -1 ) {
3996                                 int objnum, p1, p2;
3997
3998                                 // the ship exists, so create this object, then dock the two.
3999                                 objnum = parse_create_object( pobjp );
4000                                 Assert ( objnum != -1 );
4001
4002                                 list_remove( &ship_arrival_list, pobjp);
4003
4004                                 // p1 is the parse object's docking point.
4005                                 // p2 is the existing objects docking point.
4006                                 p1 = model_find_dock_name_index(Ships[shipnum].modelnum, pobjp->docker_point);
4007                                 p2 = model_find_dock_name_index(Ships[Objects[objnum].instance].modelnum, pobjp->dockee_point);
4008
4009                                 if ((p1 >= 0) && (p2 >= 0)) {
4010                                         nprintf(("AI", "Initially Docked: %s with %s\n", Ships[shipnum].ship_name, Ships[Objects[objnum].instance].ship_name));
4011                                         if (ship_docking_valid(shipnum, Objects[objnum].instance))  // only dock if they are allowed to be docked.
4012                                                 ai_dock_with_object(&Objects[Ships[shipnum].objnum], &Objects[objnum], 89, AIDO_DOCK_NOW, p1, p2);
4013                                         else
4014                                                 ai_dock_with_object(&Objects[objnum], &Objects[Ships[shipnum].objnum], 89, AIDO_DOCK_NOW, p2, p1);
4015                                                 
4016                                 } else
4017                                         Int3();         //      Curious.  Two ships told to dock, but one of the dock points is bogus.  
4018                                                                         // Get Allender or Hoffoss, one of whom probably wrote the above if ()
4019                         }
4020                 }
4021
4022                 pobjp = tmp;
4023         }
4024 }
4025
4026 // function which returns true or false if the given mission support multiplayers
4027 int mission_parse_is_multi(const char *filename, char *mission_name)
4028 {
4029         int rval, game_type;
4030         int filelength;
4031         CFILE *ftemp;
4032
4033         // new way of getting information.  Open the file, and just get the name and the game_type flags.
4034         // return the flags if a multiplayer mission
4035
4036         game_type = 0;
4037
4038         ftemp = cfopen(filename, "rt");
4039         if (!ftemp)
4040                 return 0;
4041
4042         // 7/9/98 -- MWA -- check for 0 length file.
4043         filelength = cfilelength(ftemp);
4044         cfclose(ftemp);
4045         if ( filelength == 0 )
4046                 return 0;
4047
4048         // open localization
4049         lcl_ext_open();
4050
4051         if ((rval = setjmp(parse_abort)) != 0) {
4052                 Error(LOCATION, "Bogus!  Trying to get multi game type on mission %s returned as a mission from cf_get_filelist\n");
4053         } else  {
4054                 read_file_text(filename, CF_TYPE_MISSIONS);
4055                 reset_parse();
4056                 if ( skip_to_string("$Name:") != 1 ) {
4057                         nprintf(("Network", "Unable to process %s because we couldn't find $Name:", filename));
4058
4059                         // close localization
4060                         lcl_ext_close();
4061
4062                         return 0;
4063                 }
4064                 stuff_string( mission_name, F_NAME, NULL );
4065                 if ( skip_to_string("+Game Type Flags:") != 1 ) {
4066                         nprintf(("Network", "Unable to process %s because we couldn't find +Game Type Flags:\n", filename));
4067
4068                         // close localization
4069                         lcl_ext_close();
4070
4071                         return 0;
4072                 }
4073                 stuff_int(&game_type);
4074         }
4075         if ( game_type & MISSION_TYPE_MULTI ){
4076                 // close localization
4077                 lcl_ext_close();
4078
4079                 return game_type;
4080         }
4081
4082         // close localization
4083         lcl_ext_close();
4084         
4085         return 0;
4086 }
4087
4088 // function which gets called to retrieve useful information about a mission.  We will get the
4089 // name, description, and number of players for a mission.  Probably used for multiplayer only?
4090 // The calling function can use the information in The_mission to get the name/description of the mission
4091 // if needed.
4092
4093 int mission_parse_get_multi_mission_info( const char *filename )
4094 {
4095         if ( parse_main(filename, MISSION_PARSE_MISSION_INFO) ){
4096                 return -1;
4097         }
4098
4099         Assert( The_mission.game_type & MISSION_TYPE_MULTI );           // assume multiplayer only for now?
4100
4101         // return the number of parse_players.  later, we might want to include (optionally?) the number
4102         // of other ships in the main players wing (usually wing 'alpha') for inclusion of number of
4103         // players allowed.
4104
4105         return The_mission.num_players;
4106 }
4107
4108 // returns true or false if this is on the yet to arrive list
4109 int mission_parse_ship_arrived( const char *shipname )
4110 {
4111         p_object *objp;
4112
4113         for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) )     {
4114                 if ( !stricmp( objp->name, shipname) )
4115                         return 0;                       // still on the arrival list
4116         }
4117         return 1;
4118 }
4119
4120 // return the parse object on the ship arrival list associated with the given name
4121 p_object *mission_parse_get_arrival_ship( const char *name )
4122 {
4123         p_object *objp;
4124
4125         for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) )     {
4126                 if ( !stricmp( objp->name, name) )
4127                         return objp;                    // still on the arrival list
4128         }
4129
4130         return NULL;
4131 }
4132
4133 // return the parse object on the ship arrival list associated with the given signature
4134 p_object *mission_parse_get_arrival_ship( ushort net_signature )
4135 {
4136         p_object *objp;
4137
4138         for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) )     {
4139                 if ( objp->net_signature == net_signature )
4140                         return objp;                    // still on the arrival list
4141         }
4142
4143         return NULL;
4144 }
4145
4146 // mission_set_arrival_location() sets the arrival location of a parse object according to the arrival location
4147 // of the object.  Returns true if object set to new position, false if not.
4148 int mission_set_arrival_location(int anchor, int location, int dist, int objnum, vector *new_pos, matrix *new_orient)
4149 {
4150         int shipnum, anchor_objnum;
4151         vector anchor_pos, rand_vec, new_fvec;
4152         matrix orient;
4153
4154         if ( location == ARRIVE_AT_LOCATION )
4155                 return 0;
4156
4157         Assert(anchor >= 0);
4158
4159         // this ship might possibly arrive at another location.  The location is based on the
4160         // proximity of some ship (and some other special tokens)
4161
4162         // if we didn't find the arrival anchor in the list of special nodes, then do a
4163         // ship name lookup on the anchor
4164         if (anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET) {
4165                 shipnum = ship_name_lookup(Parse_names[anchor]);
4166                 if ( shipnum == -1 ) {
4167                         Assert ( location != ARRIVE_FROM_DOCK_BAY );            // bogus data somewhere!!!  get mwa
4168                         nprintf (("allender", "couldn't find ship for arrival anchor -- using location ship created at"));
4169                         return 0;
4170                 }
4171
4172         } else {
4173                 // come up with a position based on the special token names
4174                 shipnum = -1;
4175
4176                 if (anchor == ANY_FRIENDLY) {
4177                         shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ANY_SHIP );
4178                 } else if (anchor == ANY_HOSTILE) {
4179                         shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ANY_SHIP );
4180                 } else if (anchor == ANY_FRIENDLY_PLAYER) {
4181                         shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ONLY_PLAYERS );
4182                 } else if (anchor == ANY_HOSTILE_PLAYER) {
4183                         shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ONLY_PLAYERS );
4184                 } else
4185                         Int3();         // get allender -- unknown special arrival instructions
4186
4187                 // if we didn't get an object from one of the above functions, then make the object
4188                 // arrive at it's placed location
4189                 if ( shipnum == -1 ) {
4190                         nprintf (("Allender", "Couldn't find random ship for arrival anchor -- using default location\n"));
4191                         return 0;
4192                 }
4193         }
4194
4195         // take the shipnum and get the position.  once we have positions, we can determine where
4196         // to make this ship appear
4197         Assert ( shipnum != -1 );
4198         anchor_objnum = Ships[shipnum].objnum;
4199         anchor_pos = Objects[anchor_objnum].pos;
4200
4201         // if arriving from docking bay, then set ai mode and call function as per AL's instructions.
4202         if ( location == ARRIVE_FROM_DOCK_BAY ) {
4203                 vector pos, fvec;
4204
4205                 // if we get an error, just let the ship arrive(?)
4206                 if ( ai_acquire_emerge_path(&Objects[objnum], anchor_objnum, &pos, &fvec) == -1 ) {
4207                         Int3();                 // get MWA or AL -- not sure what to do here when we cannot acquire a path
4208                         return 0;
4209                 }
4210                 Objects[objnum].pos = pos;
4211                 Objects[objnum].orient.v.fvec = fvec;
4212         } else {
4213
4214                 // AL: ensure dist > 0 (otherwise get errors in vecmat)
4215                 // TODO: maybe set distance to 2x ship radius of ship appearing in front of?
4216                 if ( dist <= 0 ) {
4217                         Error(LOCATION, "Distance of %d is invalid in mission_set_arrival_location\n", dist);
4218                         return 0;
4219                 }
4220                 
4221                 // get a vector which is the ships arrival position based on the type of arrival
4222                 // this ship should have.  Arriving near a ship we use a random normalized vector
4223                 // scaled by the distance given by the designer.  Arriving in front of a ship means
4224                 // entering the battle in the view cone.
4225                 if ( location == ARRIVE_NEAR_SHIP ) {
4226                         // get a random vector -- use static randvec if in multiplayer
4227                         if ( Game_mode & GM_NORMAL )
4228                                 vm_vec_rand_vec_quick(&rand_vec);
4229                         else
4230                                 static_randvec( Objects[objnum].net_signature, &rand_vec );
4231                 } else if ( location == ARRIVE_IN_FRONT_OF_SHIP ) {
4232                         vector t1, t2, t3;
4233                         int r1, r2;
4234                         float x;
4235
4236                         // cool function by MK to give a reasonable random vector "in front" of a ship
4237                         // rvec and uvec are the right and up vectors.
4238                         // If these are not available, this would be an expensive method.
4239                         //x = cos(angle)
4240                         x = (float)cos(ANG_TO_RAD(45));
4241                         if ( Game_mode & GM_NORMAL ) {
4242                                 r1 = rand() < RAND_MAX/2 ? -1 : 1;
4243                                 r2 = rand() < RAND_MAX/2 ? -1 : 1;
4244                         } else {
4245                                 // in multiplayer, use the static rand functions so that all clients can get the
4246                                 // same information.
4247                                 r1 = static_rand(Objects[objnum].net_signature) < RAND_MAX/2 ? -1 : 1;
4248                                 r2 = static_rand(Objects[objnum].net_signature+1) < RAND_MAX/2 ? -1 : 1;
4249                         }
4250
4251                         vm_vec_copy_scale(&t1, &(Objects[anchor_objnum].orient.v.fvec), x);
4252                         vm_vec_copy_scale(&t2, &(Objects[anchor_objnum].orient.v.rvec), (1.0f - x) * r1);
4253                         vm_vec_copy_scale(&t3, &(Objects[anchor_objnum].orient.v.uvec), (1.0f - x) * r2);
4254
4255                         vm_vec_add(&rand_vec, &t1, &t2);
4256                         vm_vec_add2(&rand_vec, &t3);
4257                         vm_vec_normalize(&rand_vec);
4258                 }
4259
4260                 // add in the radius of the two ships involved.  This will make the ship arrive further than
4261                 // specified, but will appear more accurate since we are pushing the edge of the model to the
4262                 // specified distance.  large objects appears to be a lot closer without the following line because
4263                 // the object centers were at the correct distance, but the model itself was much closer to the
4264                 // target ship.
4265                 dist += (int)Objects[objnum].radius + (int)Objects[anchor_objnum].radius;
4266                 vm_vec_scale_add(&Objects[objnum].pos, &anchor_pos, &rand_vec, (float)dist);
4267
4268                 // I think that we will always want to orient the ship that is arriving to face towards
4269                 // the ship it is arriving near/in front of.  The effect will be cool!
4270                 //
4271                 // calculate the new fvec of the ship arriving and use only that to get the matrix.  isn't a big
4272                 // deal not getting bank.
4273                 vm_vec_sub(&new_fvec, &anchor_pos, &Objects[objnum].pos );
4274                 vm_vector_2_matrix( &orient, &new_fvec, NULL, NULL );
4275                 Objects[objnum].orient = orient;
4276         }
4277
4278         // set the new_pos parameter since it might be used outside the function (i.e. when dealing with wings).
4279         if ( new_pos )
4280                 memcpy(new_pos, &Objects[objnum].pos, sizeof(vector) );
4281
4282         if ( new_orient )
4283                 memcpy( new_orient, &Objects[objnum].orient, sizeof(matrix) );
4284
4285         return 1;
4286 }
4287
4288 // mark a reinforcement as available
4289 void mission_parse_mark_reinforcement_available(char *name)
4290 {
4291         int i;
4292         reinforcements *rp;
4293
4294         for (i = 0; i < Num_reinforcements; i++) {
4295                 rp = &Reinforcements[i];
4296                 if ( !stricmp(rp->name, name) ) {
4297                         if ( !(rp->flags & RF_IS_AVAILABLE) ) {
4298                                 rp->flags |= RF_IS_AVAILABLE;
4299
4300                                 // tell all of the clients.
4301                                 if ( MULTIPLAYER_MASTER ) {
4302                                         send_reinforcement_avail( i );
4303                                 }
4304                         }
4305                         return;
4306                 }
4307         }
4308
4309         Assert ( i < Num_reinforcements );
4310 }
4311
4312 // mission_did_ship_arrive takes a parse object and checked the arrival cue and delay and
4313 // creates the object if necessary.  Returns -1 if not created.  objnum of created ship otherwise
4314 int mission_did_ship_arrive(p_object *objp)
4315 {
4316         int did_arrive;
4317
4318         // find out in the arrival cue became true
4319         did_arrive = eval_sexp(objp->arrival_cue);
4320
4321         // we must first check to see if this ship is a reinforcement or not.  If so, then don't
4322         // process
4323         if ( objp->flags & P_SF_REINFORCEMENT ) {
4324
4325                 // if this ship did arrive, mark the reinforcement as available, and tell clients if in multiplayer
4326                 // mode
4327                 if ( did_arrive ) {
4328                         mission_parse_mark_reinforcement_available(objp->name);
4329                 }
4330                 return -1;
4331         }
4332
4333         if ( did_arrive ) {             // has the arrival criteria been met?
4334                 int object_num;         
4335
4336                 Assert ( !(objp->flags & P_SF_CANNOT_ARRIVE) );         // get allender
4337
4338                 // check to see if the delay field <= 0.  if so, then create a timestamp and then maybe
4339                 // create the object
4340                 if ( objp->arrival_delay <= 0 ) {
4341                         objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
4342                         Assert( objp->arrival_delay >= 0 );
4343                 }
4344                 
4345                 // if the timestamp hasn't elapsed, move onto the next ship.
4346                 if ( !timestamp_elapsed(objp->arrival_delay) )
4347                         return -1;
4348
4349                 // check to see if this ship is to arrive via a docking bay.  If so, and the ship to arrive from
4350                 // doesn't exist, don't create.
4351                 if ( objp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
4352                         int shipnum;
4353                         char *name;
4354
4355                         Assert( objp->arrival_anchor >= 0 );
4356                         name = Parse_names[objp->arrival_anchor];
4357         
4358                         // see if ship is yet to arrive.  If so, then return -1 so we can evaluate again later.
4359                         if ( mission_parse_get_arrival_ship( name ) )
4360                                 return -1;
4361
4362                         // see if ship is in mission.  If not, then we can assume it was destroyed or departed since
4363                         // it is not on the arrival list (as shown by above if statement).
4364                         shipnum = ship_name_lookup( name );
4365                         if ( shipnum == -1 ) {
4366                                 Sexp_nodes[objp->arrival_cue].value = SEXP_KNOWN_FALSE;
4367                                 return -1;
4368                         }
4369                 }
4370
4371                 object_num = parse_create_object(objp);                                                 // create the ship
4372
4373                 // since this ship is not in a wing, create a SHIP_ARRIVE entry
4374                 //mission_log_add_entry( LOG_SHIP_ARRIVE, objp->name, NULL );
4375                 Assert(object_num >= 0 && object_num < MAX_OBJECTS);
4376                 
4377                 // Play the music track for an arrival
4378                 if ( !(Ships[Objects[object_num].instance].flags & SF_NO_ARRIVAL_MUSIC) )
4379                         if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
4380                                 Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
4381                                 event_music_arrival(Ships[Objects[object_num].instance].team);
4382                         }
4383                 return object_num;
4384         } else {
4385                 // check to see if the arrival cue of this ship is known false -- if so, then remove
4386                 // the parse object from the ship
4387                 if ( Sexp_nodes[objp->arrival_cue].value == SEXP_KNOWN_FALSE )
4388                         objp->flags |= P_SF_CANNOT_ARRIVE;
4389         }
4390
4391         return -1;
4392
4393 }
4394
4395 // funciton to set a flag on all parse objects on ship arrival list which cannot
4396 // arrive in the mission
4397 void mission_parse_mark_non_arrivals()
4398 {
4399         p_object *pobjp;
4400
4401         for ( pobjp = GET_FIRST(&ship_arrival_list); pobjp != END_OF_LIST(&ship_arrival_list); pobjp = GET_NEXT(pobjp) ) {
4402                 if ( pobjp->wingnum != -1 ) {
4403                         if ( Sexp_nodes[Wings[pobjp->wingnum].arrival_cue].value == SEXP_KNOWN_FALSE )
4404                                 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4405                 } else {
4406                         if ( Sexp_nodes[pobjp->arrival_cue].value == SEXP_KNOWN_FALSE )
4407                                 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4408                 }
4409         }
4410 }
4411
4412 // function to deal with support ship arrival.  objnum is the object number of the arriving support
4413 // ship.  This function can get called from either single or multiplayer.  Needed to that clients
4414 // can know when to abort rearm.
4415 void mission_parse_support_arrived( int objnum )
4416 {
4417         int i;
4418
4419         // when the support ship arrives, the shipname it is supposed to repair is in the 'misc'
4420         // field of the parse_object.  If the ship still exists, call ai function which actually
4421         // issues the goal for the repair
4422         for ( i = 0; i < Num_arriving_repair_targets; i++ ) {
4423                 int shipnum;
4424
4425                 shipnum = ship_name_lookup( Arriving_repair_targets[i] );
4426
4427                 if ( shipnum != -1 ) {
4428                         object *requester_objp, *support_objp;
4429
4430                         support_objp = &Objects[objnum];
4431                         requester_objp = &Objects[Ships[shipnum].objnum];
4432                         ai_add_rearm_goal( requester_objp, support_objp );
4433                 }
4434         }
4435
4436         //      MK: A bit of a hack.  If on player's team and player isn't allowed shields, don't give this ship shields.
4437         if ((Player_obj->flags & OF_NO_SHIELDS) && (Player_ship->team == Ships[Objects[objnum].instance].team))
4438                 Objects[objnum].flags |= OF_NO_SHIELDS;
4439
4440         Ships[Objects[objnum].instance].flags |= SF_WARPED_SUPPORT;
4441
4442         Arriving_support_ship = NULL;
4443         Num_arriving_repair_targets = 0;
4444 }
4445
4446 MONITOR(NumShipArrivals);
4447
4448 // mission_parse_arrivals will parse the lists of arriving ships and
4449 // wings -- creating new ships/wings if the arrival criteria have been
4450 // met.
4451 void mission_eval_arrivals()
4452 {
4453         p_object *objp;
4454         wing *wingp;
4455         int i, objnum;
4456
4457         // before checking arrivals, check to see if we should play a message concerning arrivals
4458         // of other wings.  We use the timestamps to delay the arrival message slightly for
4459         // better effect
4460         if ( timestamp_valid(Arrival_message_delay_timestamp) && timestamp_elapsed(Arrival_message_delay_timestamp) && !((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)) ){
4461                 int rship, use_terran;
4462
4463                 // use terran command 25% of time
4464                 use_terran = ((frand() - 0.75) > 0.0f)?1:0;
4465
4466                 rship = ship_get_random_player_wing_ship( SHIP_GET_NO_PLAYERS );
4467                 if ( (rship == -1) || use_terran ){
4468                         message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4469                 } else if ( rship != -1 ) {
4470                         message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4471                 }
4472
4473                 Arrival_message_delay_timestamp = timestamp(-1);                // make the stamp invalid
4474         }
4475
4476 //      if ( !timestamp_elapsed(Mission_arrival_timestamp) )
4477 //              return;
4478
4479         // check the ship_arrival_list
4480         objnum = -1;
4481         objp = GET_FIRST(&ship_arrival_list);
4482         while( objp !=END_OF_LIST(&ship_arrival_list) ) {
4483                 p_object *temp = GET_NEXT(objp);
4484                 if ( objp->wingnum == -1 )      {                                                               // if this object has a wing -- let code for wings determine if it should be created
4485
4486                         objnum = mission_did_ship_arrive( objp );
4487                         if ( objnum != -1 )     {
4488                                 list_remove( &ship_arrival_list, objp);
4489                                 MONITOR_INC(NumShipArrivals,1);
4490                         }
4491
4492                 }
4493                 objp = temp;
4494         }
4495
4496         // check for any initially docked ships.  Do it after all are created since the next function
4497         // messes with the ship_arrival_list
4498         mission_parse_do_initial_docks();                       // maybe create it's docked counterpart
4499
4500         mission_parse_mark_non_arrivals();                      // mark parse objects which can no longer arrive
4501
4502         // check the support ship arrival list
4503         if ( Arriving_support_ship )    {
4504                 int objnum;
4505
4506                 objnum = mission_did_ship_arrive( Arriving_support_ship );
4507
4508                 if ( objnum != -1 ) {
4509                         MONITOR_INC(NumShipArrivals,1);
4510                         mission_parse_support_arrived( objnum );
4511                 }
4512         }
4513
4514         // we must also check to see if there are waves of a wing that must
4515         // reappear if all the ships of the current wing have been destroyed or
4516         // have departed. If this is the case, then create the next wave.
4517
4518         for ( i = 0; i < num_wings; i++ ) {
4519                 wingp = &Wings[i];
4520
4521                 // should we process this wing anymore
4522                 if ( wingp->flags & WF_WING_GONE )
4523                         continue;
4524
4525                 // if we have a reinforcement wing, then don't try to create new ships automatically.
4526                 if ( wingp->flags & WF_REINFORCEMENT ) {
4527
4528                         // check to see in the wings arrival cue is true, and if so, then mark the reinforcement
4529                         // as available
4530                         if ( eval_sexp(wingp->arrival_cue) ) {
4531                                 mission_parse_mark_reinforcement_available(wingp->name);
4532                         }
4533                         continue;
4534                 }
4535                 
4536                 // don't do evaluations for departing wings
4537                 if ( wingp->flags & WF_WING_DEPARTING ){
4538                         continue;
4539                 }
4540
4541                 // must check to see if we are at the last wave.  Code above to determine when a wing is gone only
4542                 // gets run when a ship is destroyed (not every N seconds like it used to).  Do a quick check
4543                 // here.
4544                 if ( wingp->current_wave == wingp->num_waves ){
4545                         continue;
4546                 }
4547
4548                 // if the current wave of this wing is 0, then we haven't created the ships in the wing yet.
4549                 // call parse_wing_create_ships to try and create it.  That function will eval the arrival
4550                 // cue of the wing and create the ships if necessary, or if the threshold of the wing has
4551                 // been reached, then try and create more ships
4552                 if ( (wingp->current_wave == 0) || (wingp->current_count <= wingp->threshold) ) {
4553                         int created;
4554
4555                         created = parse_wing_create_ships( wingp, wingp->wave_count );
4556
4557                         // if we created ships in this wing, check to see if the wings was int the reinforcements
4558                         // array.  If so, then if we have more uses, then reset the reinforcement flag for the wing
4559                         // so the user can call in another set if need be.
4560                         if ( created > 0 ) {
4561                                 int rship;
4562
4563                                 mission_parse_do_initial_docks();               // maybe create other initially docked ships
4564                                 if ( Wings[i].flags & WF_RESET_REINFORCEMENT ) {
4565                                         Wings[i].flags &= ~WF_RESET_REINFORCEMENT;
4566                                         Wings[i].flags |= WF_REINFORCEMENT;
4567                                 }
4568
4569                                 // possibly send a message to the player when this wing arrives.
4570                                 if ( wingp->flags & WF_NO_ARRIVAL_MESSAGE ){
4571                                         continue;
4572                                 }
4573
4574                                 // multiplayer team vs. team
4575                                 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
4576                                         // send a hostile wing arrived message
4577                                         rship = Wings[i].ship_index[0];
4578
4579                                         int multi_team_filter = Ships[rship].team == TEAM_FRIENDLY ? 1 : 0;
4580
4581                                         // there are two timestamps at work here.  One to control how often the player receives
4582                                         // messages about incoming hostile waves, and the other to control how long after
4583                                         // the wing arrives does the player actually get the message.
4584                                         if ( timestamp_elapsed(Allow_arrival_message_timestamp_m[multi_team_filter]) ) {
4585                                                 if ( !timestamp_valid(Arrival_message_delay_timestamp_m[multi_team_filter]) ){
4586                                                         Arrival_message_delay_timestamp_m[multi_team_filter] = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4587                                                 }
4588                                                 Allow_arrival_message_timestamp_m[multi_team_filter] = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);                                       
4589                                                 
4590                                                 // send to the proper team
4591                                                 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, multi_team_filter );
4592                                         }
4593                                 } 
4594                                 // everything else
4595                                         else {
4596                                         // see if this is a starting player wing
4597                                         if ( i == Starting_wings[STARTING_WING_BETA] ) {                                        // this is the beta wing
4598                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4599                                                 if ( rship != -1 ){
4600                                                         message_send_builtin_to_player( MESSAGE_BETA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4601                                                 }
4602                                         } else if ( i == Starting_wings[STARTING_WING_GAMMA] ) {                        // this is the gamma wing
4603                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4604                                                 if ( rship != -1 ) {
4605                                                         message_send_builtin_to_player( MESSAGE_GAMMA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4606                                                 }
4607                                         } else if ( !stricmp( wingp->name, "delta") ) {
4608                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4609                                                 if ( rship != -1 ) {
4610                                                         message_send_builtin_to_player( MESSAGE_DELTA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4611                                                 }
4612                                         } else if ( !stricmp(wingp->name, "epsilon") ) {
4613                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4614                                                 if ( rship != -1 ) {
4615                                                         message_send_builtin_to_player( MESSAGE_EPSILON_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4616                                                 }
4617                                         } else {
4618                                                 // see if we have a hostile wing that arrived
4619                                                 rship = Wings[i].ship_index[0];
4620                                                 if ( Ships[rship].team != TEAM_FRIENDLY ) {
4621
4622                                                         // there are two timestamps at work here.  One to control how often the player receives
4623                                                         // messages about incoming hostile waves, and the other to control how long after
4624                                                         // the wing arrives does the player actually get the message.
4625                                                         if ( timestamp_elapsed(Allow_arrival_message_timestamp) ) {
4626                                                                 if ( !timestamp_valid(Arrival_message_delay_timestamp) ){
4627                                                                         Arrival_message_delay_timestamp = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4628                                                                 }
4629                                                                 Allow_arrival_message_timestamp = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
4630                                                         }
4631                                                 }
4632                                         }
4633                                 }
4634                         }
4635                 }
4636         }
4637         Mission_arrival_timestamp = timestamp(ARRIVAL_TIMESTAMP);
4638 }
4639
4640 MONITOR(NumShipDepartures);
4641
4642 // called to make object objp depart.
4643 void mission_do_departure( object *objp )
4644 {
4645         ship *shipp;
4646 //      vector v;
4647
4648         MONITOR_INC(NumShipDepartures,1);
4649
4650         Assert ( objp->type == OBJ_SHIP );
4651         shipp = &Ships[objp->instance];
4652
4653         // if departing to a docking bay, try to find the anchor ship to depart to.  If not found, then
4654         // just make it warp out like anything else.
4655         if ( shipp->departure_location == DEPART_AT_DOCK_BAY ) {
4656                 int anchor_shipnum;
4657                 char *name;
4658
4659                 Assert( shipp->departure_anchor >= 0 );
4660                 name = Parse_names[shipp->departure_anchor];
4661
4662                 // see if ship is yet to arrive.  If so, then return -1 so we can evaluate again later.
4663                 if ( mission_parse_get_arrival_ship( name ) )
4664                         goto do_departure_warp;
4665
4666                 // see if ship is in mission.  If not, then we can assume it was destroyed or departed since
4667                 // it is not on the arrival list (as shown by above if statement).
4668                 anchor_shipnum = ship_name_lookup( name );
4669                 if ( anchor_shipnum == -1 )
4670                         goto do_departure_warp;
4671
4672                 ai_acquire_depart_path(objp, Ships[anchor_shipnum].objnum);
4673                 return;
4674         }
4675
4676 do_departure_warp:
4677         ai_set_mode_warp_out( objp, &Ai_info[Ships[objp->instance].ai_index] );
4678
4679 }
4680
4681 // put here because mission_eval_arrivals is here.  Might move these to a better location
4682 // later -- MWA
4683 void mission_eval_departures()
4684 {
4685         int i, j;
4686         object *objp;
4687         wing *wingp;
4688
4689 //      if ( !timestamp_elapsed(Mission_departure_timestamp) )
4690 //              return;
4691
4692         // scan through the active ships an evaluate their departure cues.  For those
4693         // ships whose time has come, set their departing flag.
4694
4695         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4696                 if (objp->type == OBJ_SHIP) {
4697                         ship    *shipp;
4698
4699                         Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
4700
4701                         shipp = &Ships[objp->instance];
4702                         
4703                         // don't process a ship that is already departing or dying or disabled
4704                         // AL 12-30-97: Added SF_CANNOT_WARP to check
4705                         if ( (shipp->flags & (SF_DEPARTING | SF_DYING | SF_CANNOT_WARP )) || ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) ) {
4706                                 continue;
4707                         }
4708
4709                         // don't process ships that are part of a wing -- handled in seperate case
4710                         if ( shipp->wingnum != -1 )
4711                                 continue;
4712
4713 //                              && (!timestamp_valid(shipp->departure_delay) || timestamp_elapsed(shipp->departure_delay)) )
4714                         // when the departure cue becomes true, set off the departure delay timer.  We store the
4715                         // timer as -seconds in Freespace which indicates that the timer has not been set.  If the timer
4716                         // is not set, then turn it into a valid timer and keep evaluating the timer until it is elapsed
4717                         if ( eval_sexp(shipp->departure_cue) ) {
4718                                 if ( shipp->departure_delay <= 0 )
4719                                         shipp->departure_delay = timestamp(-shipp->departure_delay * 1000 );
4720                                 if ( timestamp_elapsed(shipp->departure_delay) )
4721                                         mission_do_departure( objp );
4722                         }
4723                 }
4724         }
4725
4726         // now scan through the list of wings and check their departure cues.  For wings with
4727         // that cue being true, we must update internal variables to indicate that the wing is
4728         // departed and that no further waves of this wing will appear
4729
4730         for ( i = 0; i < num_wings; i++ ) {
4731                 wingp = &Wings[i];
4732
4733                 // should we process this wing anymore
4734                 if ( wingp->flags & WF_WING_DEPARTING )
4735                         continue;
4736
4737                 // evaluate the sexpression.  If true, mark all the ships in this wing as departing and increment
4738                 // the num departed in the wing structure.  Then add number of remaining waves * ships/wave to
4739                 // departed count to get total count of ships in the wing which departed.  (We are counting ships
4740                 // that have not yet arrived as departed if they never arrive -- this may be bad, but for some reason
4741                 // seems like the right thing to do).
4742  //&& (!timestamp_valid(wingp->departure_delay) || timestamp_elapsed(wingp->departure_delay)) ) {
4743
4744                 if ( eval_sexp(wingp->departure_cue) ) {
4745                         // if we haven't set up the departure timer yet (would be <= 0) setup the timer to pop N seconds
4746                         // later
4747                         if ( wingp->departure_delay <= 0 )
4748                                 wingp->departure_delay = timestamp( -wingp->departure_delay * 1000 );
4749                         if ( !timestamp_elapsed(wingp->departure_delay) )
4750                                 continue;
4751
4752                         wingp->flags |= WF_WING_DEPARTING;
4753                         for ( j = 0; j < wingp->current_count; j++ ) {
4754                                 ship *shipp;
4755
4756                                 shipp = &Ships[wingp->ship_index[j]];
4757                                 if ( (shipp->flags & SF_DEPARTING) || (shipp->flags & SF_DYING) )
4758                                         continue;
4759
4760 //                              shipp->flags |= SF_DEPARTING;
4761 //                              shipp->final_depart_time = timestamp(3*1000);
4762
4763                                 Assert ( shipp->objnum != -1 );
4764                                 objp = &Objects[shipp->objnum];
4765
4766                                 // copy the wing's depature information to the ship
4767                                 shipp->departure_location = wingp->departure_location;
4768                                 shipp->departure_anchor = wingp->departure_anchor;
4769
4770                                 mission_do_departure( objp );
4771                                 // don't add to wingp->total_departed here -- this is taken care of in ship code.
4772                         }
4773
4774                         // MWA 2/25/98 -- don't do the follwoing wing member updates.  It makes the accurate counts
4775                         // sort of messed up and causes problems for the event log.  The code in ship_wing_cleanup()
4776                         // now keys off of the WF_WING_DEPARTING flag instead of the counts below.
4777
4778                         /*
4779                         // now be sure that we update wing structure members if there are any remaining waves left
4780                         if ( wingp->current_wave < wingp->num_waves ) {
4781                                 int num_remaining;
4782
4783                                 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
4784                                 wingp->total_departed += num_remaining;
4785                                 wingp->total_arrived_count += num_remaining;
4786                                 wingp->current_wave = wingp->num_waves;
4787                         }
4788                         */
4789
4790                 }
4791         }
4792         Mission_departure_timestamp = timestamp(DEPARTURE_TIMESTAMP);
4793 }
4794
4795 // function called from high level game loop to do mission evaluation stuff
4796 void mission_parse_eval_stuff()
4797 {
4798         mission_eval_arrivals();
4799         mission_eval_departures();
4800 }
4801
4802 int allocate_subsys_status()
4803 {
4804         int i;
4805
4806         Assert(Subsys_index < MAX_SUBSYS_STATUS);
4807         Subsys_status[Subsys_index].percent = 0.0f;
4808         Subsys_status[Subsys_index].primary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4809         for (i=1; i<MAX_PRIMARY_BANKS; i++)
4810                 Subsys_status[Subsys_index].primary_banks[i] = -1;  // none
4811
4812         Subsys_status[Subsys_index].secondary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4813         Subsys_status[Subsys_index].secondary_ammo[0] = 100;
4814         for (i=1; i<MAX_SECONDARY_BANKS; i++) {
4815                 Subsys_status[Subsys_index].secondary_banks[i] = -1;
4816                 Subsys_status[Subsys_index].secondary_ammo[i] = 100;
4817         }
4818
4819         Subsys_status[Subsys_index].ai_class = SUBSYS_STATUS_NO_CHANGE;
4820         return Subsys_index++;
4821 }
4822
4823 // find (or add) the name in the list and return an index to it.
4824 int get_parse_name_index(const char *name)
4825 {
4826         int i;
4827
4828         for (i=0; i<Num_parse_names; i++)
4829                 if (!stricmp(name, Parse_names[i]))
4830                         return i;
4831
4832         Assert(i < MAX_SHIPS + MAX_WINGS);
4833         Assert(strlen(name) < NAME_LENGTH);
4834         strcpy(Parse_names[i], name);
4835         return Num_parse_names++;
4836 }
4837
4838 int get_anchor(char *name)
4839 {
4840         int i;
4841
4842         for (i=0; i<MAX_SPECIAL_ARRIVAL_ANCHORS; i++)
4843                 if (!stricmp(name, Special_arrival_anchor_names[i]))
4844                         return SPECIAL_ARRIVAL_ANCHORS_OFFSET + i;
4845
4846         return get_parse_name_index(name);
4847 }
4848
4849 // function to fixup the goals/ai references for player objects in the mission
4850 void mission_parse_fixup_players()
4851 {
4852         object *objp;
4853
4854         // merge created list to have all objects on used list
4855         obj_merge_created_list();
4856         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4857                 if ( (objp->type == OBJ_SHIP) && (objp->flags & OF_PLAYER_SHIP) ) {
4858                         ai_clear_ship_goals( &Ai_info[Ships[objp->instance].ai_index] );
4859                         init_ai_object( OBJ_INDEX(objp) );
4860                 }
4861         }
4862 }
4863
4864 // code to warp in a new support ship.  It works by finding the average position of all ships
4865 // in the mission, creating a vector from that position to the player, and scaling out behind the
4866 // player some distance.  Should be sufficient.
4867
4868 #define WARP_IN_MIN_DISTANCE    1000.0f
4869 #define WARP_IN_TIME_MIN                3000                            // warps in min 3 seconds later
4870 #define WARP_IN_TIME_MAX                6000                            // warps in max 6 seconds later
4871
4872 // function which adds requester_objp onto the queue of ships for the arriving support ship to service
4873 void mission_add_to_arriving_support( object *requester_objp )
4874 {
4875         int i;
4876         ship *shipp;
4877
4878         Assert ( Arriving_support_ship );
4879
4880         if ( Num_arriving_repair_targets == MAX_AI_GOALS ) {
4881                 // Int3();                      // get allender -- ship isn't going to get repair, but I hope they never queue up this far!!!
4882                 mprintf(("Reached MAX_AI_GOALS trying to add repair request!\n"));
4883                 return;
4884         }
4885
4886         shipp = &Ships[requester_objp->instance];
4887         // check for duplicates before adding
4888         for (i = 0; i < Num_arriving_repair_targets; i++ ) {
4889                 if ( !stricmp(Arriving_repair_targets[i], shipp->ship_name) ){
4890                         break;
4891                 }
4892         }
4893         if ( i != Num_arriving_repair_targets ){                // found the ship before reaching the end -- ignore it!
4894                 return;
4895         }
4896
4897         strcpy( Arriving_repair_targets[Num_arriving_repair_targets], Ships[requester_objp->instance].ship_name );
4898         Num_arriving_repair_targets++;
4899
4900         if ( MULTIPLAYER_MASTER ){
4901                 multi_maybe_send_repair_info( requester_objp, NULL, REPAIR_INFO_WARP_ADD );
4902         }       
4903 }
4904
4905 extern int pp_collide_any(vector *curpos, vector *goalpos, float radius, object *ignore_objp1, object *ignore_objp2, int big_only_flag);
4906
4907 //      Set the warp in position for a support ship relative to an object.
4908 //      Caller tries several positions, passing vector in x, y, z.
4909 int get_warp_in_pos(vector *pos, object *objp, float x, float y, float z)
4910 {
4911         float   rand_val;
4912
4913         if ( Game_mode & GM_NORMAL )
4914                 rand_val = frand();
4915         else
4916                 rand_val = static_randf(objp->net_signature);
4917
4918         rand_val = 1.0f + (rand_val - 0.5f)*0.2f;
4919
4920         *pos = objp->pos;
4921
4922         vm_vec_scale_add2( pos, &objp->orient.v.rvec, x*rand_val*800.0f);
4923         vm_vec_scale_add2( pos, &objp->orient.v.uvec, y*rand_val*800.0f);
4924         vm_vec_scale_add2( pos, &objp->orient.v.fvec, z*rand_val*800.0f);
4925
4926         return pp_collide_any(&objp->pos, pos, objp->radius, objp, NULL, 1);
4927 }
4928
4929 void mission_warp_in_support_ship( object *requester_objp )
4930 {
4931         vector center, warp_in_pos;
4932         //float mag;
4933         p_object *pobj;
4934         int i, requester_species;
4935         ship *requester_shipp;
4936
4937         Assert ( requester_objp->type == OBJ_SHIP );
4938         requester_shipp = &Ships[requester_objp->instance];     //      MK, 10/23/97, used to be ->type, bogus, no?
4939
4940         // if the support ship is already arriving, add the requester to the list
4941         if ( Arriving_support_ship ) {
4942                 mission_add_to_arriving_support( requester_objp );
4943                 return;
4944         }
4945         
4946         // get average position of all ships
4947         obj_get_average_ship_pos( &center );
4948         vm_vec_sub( &warp_in_pos, &center, &(requester_objp->pos) );
4949
4950         // be sure to account for case as player being only ship left in mission
4951         /*
4952         if ( !(IS_VEC_NULL( warp_in_pos)) ) {
4953                 mag = vm_vec_mag( &warp_in_pos );
4954                 if ( mag < WARP_IN_MIN_DISTANCE )
4955                         vm_vec_scale( &warp_in_pos, WARP_IN_MIN_DISTANCE/mag);
4956                 else
4957                         vm_vec_scale( &warp
4958         } else {
4959                 // take -player_pos.fvec scaled by 1000.0f;
4960                 warp_in_pos = Player_obj->orient.fvec;
4961                 vm_vec_scale( &warp_in_pos, -1000.0f );
4962         }
4963         */
4964
4965         //      Choose position to warp in ship.
4966         //      Temporary, but changed by MK because it used to be exactly behind the player.
4967         //      This could cause an Assert if the player immediately targeted it (before moving).
4968         //      Tend to put in front of the player to aid him in flying towards the ship.
4969
4970         if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.1f, 1.0f))
4971                 if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.2f, -1.0f))
4972                         if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.2f, -1.0f))
4973                                 if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.1f, 1.0f))
4974                                         get_warp_in_pos(&warp_in_pos, requester_objp, 0.1f, 1.0f, 0.2f);
4975
4976         // create a parse object, and put it onto the ship_arrival_list.  This whole thing kind of sucks.
4977         // I want to put it into a parse object since it needs to arrive just a little later than
4978         // this function is called.  I have to make some assumptions in the code about values for the parse
4979         // object since I'm no longer working with a mission file.  These exceptions will be noted with
4980         // comments
4981
4982         Arriving_support_ship = &Support_ship_pobj;
4983         pobj = Arriving_support_ship;
4984
4985         // create a name for the ship.  use "Support #".  look for collisions until one isn't found anymore
4986         i = 1;
4987         do {
4988                 sprintf(pobj->name, NOX("Support %d"), i);
4989                 if ( (ship_name_lookup(pobj->name) == -1) && (ship_find_exited_ship_by_name(pobj->name) == -1) )
4990                         break;
4991                 i++;
4992         } while(1);
4993
4994         pobj->pos = warp_in_pos;
4995         vm_set_identity( &(pobj->orient) );
4996
4997         // *sigh*.  Gotta get the ship class.  For now, this will amount to finding a ship in the ship_info
4998         // array with the same team as the requester of type SIF_SUPPORT.  Might need to be changed, but who knows
4999         // vasudans use the terran support ship.
5000         requester_species = Ship_info[requester_shipp->ship_info_index].species;
5001
5002         // 5/6/98 -- MWA  Don't need to do anything for multiplayer.  I think that we always want to use
5003         // the species of the caller ship.
5004         Assert( (requester_species == SPECIES_TERRAN) || (requester_species == SPECIES_VASUDAN) );
5005 //      if ( (Game_mode & GM_NORMAL) && (requester_species == SPECIES_VASUDAN) )        {       // make vasundan's use the terran support ship
5006 //              requester_species = SPECIES_TERRAN;
5007 //      }
5008
5009         // get index of correct species support ship
5010         for (i=0; i < Num_ship_types; i++) {
5011                 if ( (Ship_info[i].species == requester_species) && (Ship_info[i].flags & SIF_SUPPORT) )
5012                         break;
5013         }
5014
5015         if ( i < Num_ship_types )
5016                 pobj->ship_class = i;
5017         else
5018                 Int3();                         // BOGUS!!!!  gotta figure something out here
5019
5020         pobj->team = requester_shipp->team;
5021
5022         pobj->behavior = AIM_NONE;              // ASSUMPTION:  the mission file has the string "None" which maps to AIM_NONE
5023
5024         // set the ai_goals to -1.  We will put the requester object shipname in repair target array and then take
5025         // care of setting up the goal when creating the ship!!!!
5026         pobj->ai_goals = -1;
5027         Num_arriving_repair_targets = 0;
5028         mission_add_to_arriving_support( requester_objp );
5029
5030         // need to set ship's cargo to nothing.  scan the cargo_names array looking for the string nothing.
5031         // add it if not found
5032         for (i = 0; i < Num_cargo; i++ )
5033                 if ( !stricmp(Cargo_names[i], NOX("nothing")) )
5034                         break;
5035
5036         if ( i == Num_cargo ) {
5037                 strcpy(Cargo_names[i], NOX("Nothing"));
5038                 Num_cargo++;
5039         }
5040         pobj->cargo1 = char(i);
5041
5042         pobj->status_count = 0;
5043
5044         pobj->arrival_location = 0;                     // ASSUMPTION: this is index to arrival_lcation string array for hyperspace!!!!
5045         pobj->arrival_distance = 0;
5046         pobj->arrival_anchor = -1;
5047         pobj->arrival_cue = Locked_sexp_true;
5048         pobj->arrival_delay = timestamp_rand(WARP_IN_TIME_MIN, WARP_IN_TIME_MAX);
5049
5050         pobj->subsys_count = 0;                         // number of elements used in subsys_status array
5051         pobj->initial_velocity = 100;           // start at 100% velocity
5052         pobj->initial_hull = 100;                       // start at 100% hull   
5053         pobj->initial_shields = 100;            // and 100% shields
5054
5055         pobj->departure_location = 0;           // ASSUMPTION: this is index to departure_lcation string array for hyperspace!!!!
5056         pobj->departure_anchor = -1;
5057         pobj->departure_cue = Locked_sexp_false;
5058         pobj->departure_delay= 0;
5059
5060         pobj->determination = 10;                       // ASSUMPTION:  mission file always had this number written out
5061         pobj->wingnum = -1;
5062         if ( Player_obj->flags & P_OF_NO_SHIELDS )
5063                 pobj->flags = P_OF_NO_SHIELDS;  // support ships have no shields when player has not shields
5064
5065         pobj->ai_class = Ship_info[pobj->ship_class].ai_class;
5066         pobj->hotkey = -1;
5067         pobj->score = 0;
5068
5069         pobj->docked_with[0] = '\0';
5070         pobj->group = -1;
5071         pobj->persona_index = -1;
5072         pobj->net_signature = multi_assign_network_signature(MULTI_SIG_SHIP);
5073         pobj->wing_status_wing_index = -1;
5074         pobj->wing_status_wing_pos = -1;
5075         pobj->respawn_count = 0;
5076         pobj->alt_type_index = -1;
5077
5078 }
5079
5080 // returns true if a support ship is currently in the process of warping in.
5081 int mission_is_support_ship_arriving()
5082 {
5083         if ( Arriving_support_ship )
5084                 return 1;
5085         else
5086                 return 0;
5087 }
5088
5089 // returns true if the given ship is scheduled to be repaired by the arriving support ship
5090 int mission_is_repair_scheduled( object *objp )
5091 {
5092         char *name;
5093         int i;
5094
5095         if ( !Arriving_support_ship )
5096                 return 0;
5097
5098         Assert ( objp->type == OBJ_SHIP );
5099         name = Ships[objp->instance].ship_name;
5100         for (i = 0; i < Num_arriving_repair_targets; i++ ) {
5101                 if ( !strcmp( name, Arriving_repair_targets[i]) )
5102                         return 1;
5103         }
5104
5105         return 0;
5106 }
5107
5108 // function which removed the given ship from the list of ships that are to get repair
5109 // by arriving support ship
5110 int mission_remove_scheduled_repair( object *objp )
5111 {
5112         char *name;
5113         int i, index;
5114
5115         if ( !Arriving_support_ship )
5116                 return 0;
5117
5118         // itereate through the target list looking for this ship name.  If not found, we
5119         // can simply return.
5120         Assert ( objp->type == OBJ_SHIP );
5121         name = Ships[objp->instance].ship_name;
5122         for (index = 0; index < Num_arriving_repair_targets; index++ ) {
5123                 if ( !strcmp( name, Arriving_repair_targets[index]) )
5124                         break;
5125         }
5126         if ( index == Num_arriving_repair_targets )
5127                 return 0;
5128
5129         // ship is found -- compress the array
5130         for ( i = index; i < Num_arriving_repair_targets - 1; i++ )
5131                 strcpy( Arriving_repair_targets[i], Arriving_repair_targets[i+1] );
5132
5133         Num_arriving_repair_targets--;
5134
5135         if ( MULTIPLAYER_MASTER )
5136                 multi_maybe_send_repair_info( objp, NULL, REPAIR_INFO_WARP_REMOVE );
5137
5138         return 1;
5139 }
5140
5141 // alternate name stuff
5142 int mission_parse_lookup_alt(char *name)
5143 {
5144         int idx;
5145
5146         // sanity
5147         if(name == NULL){
5148                 return -1;
5149         }
5150
5151         // lookup
5152         for(idx=0; idx<Mission_alt_type_count; idx++){
5153                 if(!strcmp(Mission_alt_types[idx], name)){
5154                         return idx;
5155                 }
5156         }
5157
5158         // could not find
5159         return -1;
5160 }
5161
5162 static int mission_parse_lookup_alt_index_warn = 1;
5163 void mission_parse_lookup_alt_index(int index, char *out)
5164 {
5165         // sanity
5166         if(out == NULL){
5167                 return;
5168         }
5169         if((index < 0) || (index > Mission_alt_type_count)){
5170                 if (mission_parse_lookup_alt_index_warn) {
5171                         Warning(LOCATION, "Ship with invalid alt_name.  Get a programmer");
5172                         mission_parse_lookup_alt_index_warn = 0;
5173                 }
5174                 return;
5175         }
5176
5177         // stuff it
5178         strcpy(out, Mission_alt_types[index]);
5179 }
5180
5181 int mission_parse_add_alt(char *name)
5182 {
5183         // sanity
5184         if(name == NULL){
5185                 return -1;
5186         }
5187
5188         // maybe add
5189         if(Mission_alt_type_count < MAX_ALT_TYPE_NAMES){
5190                 // stuff the name
5191                 strncpy(Mission_alt_types[Mission_alt_type_count++], name, NAME_LENGTH);
5192
5193                 // done
5194                 return Mission_alt_type_count - 1;
5195         }
5196
5197         return -1;
5198 }
5199
5200 void mission_parse_reset_alt()
5201 {
5202         Mission_alt_type_count = 0;
5203 }
5204
5205 int is_training_mission()
5206 {
5207         return (The_mission.game_type & MISSION_TYPE_TRAINING);
5208 }
5209