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