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