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