]> icculus.org git repositories - taylor/freespace2.git/blob - src/mission/missionparse.cpp
use SDL_arraysize() instead of sizeof() where appropriate
[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         required_string("$Name:");
680         stuff_string(pm->name, F_NAME, NULL);
681
682         required_string("$Author:");
683         stuff_string(pm->author, F_NAME, NULL);
684
685         required_string("$Created:");
686         stuff_string(pm->created, F_DATE, NULL);
687
688         required_string("$Modified:");
689         stuff_string(pm->modified, F_DATE, NULL);
690
691         required_string("$Notes:");
692         stuff_string(pm->notes, F_NOTES, NULL);
693
694         if (optional_string("$Mission Desc:"))
695                 stuff_string(pm->mission_desc, F_MULTITEXT, NULL, MISSION_DESC_LENGTH);
696         else
697                 SDL_strlcpy(pm->mission_desc, NOX("No description\n"), SDL_arraysize(pm->mission_desc));
698
699         pm->game_type = MISSION_TYPE_SINGLE;                            // default to single player only
700         if ( optional_string("+Game Type:")) {
701                 // HACK HACK HACK -- stuff_string was changed to *not* ignore carriage returns.  Since the
702                 // old style missions may have carriage returns, deal with it here.
703                 ignore_white_space();
704                 stuff_string(game_string, F_NAME, NULL);
705                 for ( i = 0; i < OLD_MAX_GAME_TYPES; i++ ) {
706                         if ( !SDL_strcasecmp(game_string, Old_game_types[i]) ) {
707
708                                 // this block of code is now old mission compatibility code.  We specify game
709                                 // type in a different manner than before.
710                                 if ( i == OLD_GAME_TYPE_SINGLE_ONLY )
711                                         pm->game_type = MISSION_TYPE_SINGLE;
712                                 else if ( i == OLD_GAME_TYPE_MULTI_ONLY )
713                                         pm->game_type = MISSION_TYPE_MULTI;
714                                 else if ( i == OLD_GAME_TYPE_SINGLE_MULTI )
715                                         pm->game_type = (MISSION_TYPE_SINGLE | MISSION_TYPE_MULTI );
716                                 else if ( i == OLD_GAME_TYPE_TRAINING )
717                                         pm->game_type = MISSION_TYPE_TRAINING;
718                                 else
719                                         Int3();
720
721                                 if ( pm->game_type & MISSION_TYPE_MULTI )
722                                         pm->game_type |= MISSION_TYPE_MULTI_COOP;
723
724                                 break;
725                         }
726                 }
727         }
728
729         if ( optional_string("+Game Type Flags:") ) {
730                 stuff_int(&pm->game_type);
731         }
732
733         pm->flags = 0;
734         if (optional_string("+Flags:")){
735                 stuff_int(&pm->flags);
736         }
737
738         // nebula mission stuff
739         Neb2_awacs = -1.0f;
740         if(optional_string("+NebAwacs:")){
741                 if(pm->flags & MISSION_FLAG_FULLNEB){
742                         stuff_float(&Neb2_awacs);
743                 } else {
744                         float temp;
745                         stuff_float(&temp);
746                 }
747         }
748         if(optional_string("+Storm:")){
749                 stuff_string(Mission_parse_storm_name, F_NAME, NULL);
750                 nebl_set_storm(Mission_parse_storm_name);
751         }
752
753         // get the number of players if in a multiplayer mission
754         pm->num_players = 1;
755         if ( pm->game_type & MISSION_TYPE_MULTI ) {
756                 if ( optional_string("+Num Players:") ) {
757                         stuff_int( &(pm->num_players) );
758                 }
759         }
760
761         // get the number of respawns
762         pm->num_respawns = 0;
763         if ( pm->game_type & MISSION_TYPE_MULTI ) {
764                 if ( optional_string("+Num Respawns:") ){
765                         stuff_int( (int*)&(pm->num_respawns) );
766                 }
767         }
768
769         pm->red_alert = 0;
770         if ( optional_string("+Red Alert:")) {
771                 stuff_int(&pm->red_alert);
772         } 
773         red_alert_set_status(pm->red_alert);
774
775         pm->scramble = 0;
776         if ( optional_string("+Scramble:")) {
777                 stuff_int(&pm->scramble);
778         }
779
780         pm->disallow_support = 0;
781         if ( optional_string("+Disallow Support:")) {
782                 stuff_int(&pm->disallow_support);
783         }
784
785         if (optional_string("+All Teams Attack")){
786                 Mission_all_attack = 1;
787         } else {
788                 Mission_all_attack = 0;
789         }
790
791         //      Maybe delay the player's entry.
792         if (optional_string("+Player Entry Delay:")) {
793                 float   temp;
794                 
795                 stuff_float(&temp);
796                 SDL_assert(temp >= 0.0f);
797                 Entry_delay_time = fl2f(temp);
798         }
799
800         if (optional_string("+Viewer pos:")){
801                 stuff_vector(&Parse_viewer_pos);
802         }
803
804         if (optional_string("+Viewer orient:")){
805                 stuff_matrix(&Parse_viewer_orient);
806         }
807
808         // possible squadron reassignment
809         SDL_strlcpy(The_mission.squad_name, "", SDL_arraysize(The_mission.squad_name));
810         SDL_strlcpy(The_mission.squad_filename, "", SDL_arraysize(The_mission.squad_filename));
811         if(optional_string("+SquadReassignName:")){
812                 stuff_string(The_mission.squad_name, F_NAME, NULL);
813                 if(optional_string("+SquadReassignLogo:")){
814                         stuff_string(The_mission.squad_filename, F_NAME, NULL);
815                 }
816         }       
817         // always clear out squad reassignments if not single player
818         if(Game_mode & GM_MULTIPLAYER){
819                 SDL_strlcpy(The_mission.squad_name, "", SDL_arraysize(The_mission.squad_name));
820                 SDL_strlcpy(The_mission.squad_filename, "", SDL_arraysize(The_mission.squad_filename));
821                 mprintf(("Ignoring squadron reassignment"));
822         }
823         // reassign the player
824         else {          
825                 if(!Fred_running && (Player != NULL) && (strlen(The_mission.squad_name) > 0) && (Game_mode & GM_CAMPAIGN_MODE)){
826                         mprintf(("Reassigning player to squadron %s\n", The_mission.squad_name));
827                         player_set_squad(Player, The_mission.squad_name);
828                         player_set_squad_bitmap(Player, The_mission.squad_filename);
829                 }
830         }
831
832         // set up the Num_teams variable accoriding to the game_type variable'
833         Num_teams = 1;                          // assume 1
834
835         // multiplayer team v. team games have two teams.  If we have three teams, we need to use
836         // a new mission mode!
837         if ( (pm->game_type & MISSION_TYPE_MULTI) && (pm->game_type & MISSION_TYPE_MULTI_TEAMS) ){
838                 Num_teams = 2;
839         }
840 }
841
842 void parse_player_info(mission *pm)
843 {
844         char alt[NAME_LENGTH + 2] = "";
845         SDL_assert(pm != NULL);
846
847 // alternate type names begin here      
848         mission_parse_reset_alt();
849         if(optional_string("#Alternate Types:")){               
850                 // read them all in
851                 while(!optional_string("#end")){
852                         required_string("$Alt:");
853                         stuff_string(alt, F_NAME, NULL, NAME_LENGTH);
854
855                         // maybe store it
856                         mission_parse_add_alt(alt);                     
857                 }
858         }
859         
860         Player_starts = 0;
861         required_string("#Players");
862
863         while (required_string_either("#Objects", "$")){
864                 parse_player_info2(pm);
865         }
866 }
867
868 void parse_player_info2(mission *pm)
869 {
870         char str[NAME_LENGTH];
871         int nt, i, total, list[MAX_SHIP_TYPES * 2], list2[MAX_WEAPON_TYPES * 2];
872         team_data *ptr;
873         char starting_wings[MAX_PLAYER_WINGS][NAME_LENGTH];
874
875         // read in a ship/weapon pool for each team.
876         for ( nt = 0; nt < Num_teams; nt++ ) {
877                 int num_ship_choices;
878
879                 ptr = &Team_data[nt];
880                 // get the shipname for single player missions
881                 // MWA -- make this required later!!!!
882                 if ( optional_string("$Starting Shipname:") )
883                         stuff_string( Player_start_shipname, F_NAME, NULL );
884
885                 required_string("$Ship Choices:");
886                 total = stuff_int_list(list, MAX_SHIP_TYPES * 2, SHIP_INFO_TYPE);
887
888                 SDL_assert(!(total & 0x01));  // make sure we have an even count
889
890                 num_ship_choices = 0;
891                 total /= 2;                                                     // there are only 1/2 the ships really on the list.
892                 for (i=0; i<total; i++) {
893                         // in a campaign, see if the player is allowed the ships or not.  Remove them from the
894                         // pool if they are not allowed
895                         if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
896                                 if ( !Campaign.ships_allowed[list[i*2]] )
897                                         continue;
898                         }
899
900                         ptr->ship_list[num_ship_choices] = list[i * 2];
901                         ptr->ship_count[num_ship_choices] = list[i * 2 + 1];
902                         num_ship_choices++;
903                 }
904                 ptr->number_choices = num_ship_choices;
905
906                 // --- obsolete data, parsing remains for compatibility reasons ---
907                 if (optional_string("+Starting Wings:"))
908                         stuff_string_list(starting_wings, MAX_PLAYER_WINGS);
909
910                 ptr->default_ship = -1;
911                 if (optional_string("+Default_ship:")) {
912                         stuff_string(str, F_NAME, NULL);
913                         ptr->default_ship = ship_info_lookup(str);
914                         // see if the player's default ship is an allowable ship (campaign only). If not, then what
915                         // do we do?  choose the first allowable one?
916                         if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
917                                 if ( !(Campaign.ships_allowed[ptr->default_ship]) ) {
918                                         for (i = 0; i < MAX_SHIP_TYPES; i++ ) {
919                                                 if ( Campaign.ships_allowed[ptr->default_ship] ) {
920                                                         ptr->default_ship = i;
921                                                         break;
922                                                 }
923                                         }
924                                         SDL_assert( i < MAX_SHIP_TYPES );
925                                 }
926                         }
927                 }
928
929                 if (ptr->default_ship == -1)  // invalid or not specified, make first in list
930                         ptr->default_ship = ptr->ship_list[0];
931
932                 for (i=0; i<MAX_WEAPON_TYPES; i++)
933                         ptr->weaponry_pool[i] = 0;
934
935                 if (optional_string("+Weaponry Pool:")) {
936                         total = stuff_int_list(list2, MAX_WEAPON_TYPES * 2, WEAPON_POOL_TYPE);
937
938                         SDL_assert(!(total & 0x01));  // make sure we have an even count
939                         total /= 2;
940                         for (i=0; i<total; i++) {
941                                 // in a campaign, see if the player is allowed the weapons or not.  Remove them from the
942                                 // pool if they are not allowed
943                                 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
944                                         if ( !Campaign.weapons_allowed[list2[i*2]] )
945                                                 continue;
946                                 }
947
948                                 if ((list2[i * 2] >= 0) && (list2[i * 2] < MAX_WEAPON_TYPES))
949                                         ptr->weaponry_pool[list2[i * 2]] = list2[i * 2 + 1];
950                         }
951                 }
952         }
953
954         if ( nt != Num_teams )
955                 Error(LOCATION, "Not enough ship/weapon pools for mission.  There are %d teams and only %d pools.", Num_teams, nt);
956 }
957
958 void parse_plot_info(mission *pm)
959 {
960         required_string("#Plot Info");
961
962         required_string("$Tour:");
963         stuff_string(pm->tour_name, F_NAME, NULL);
964
965         required_string("$Pre-Briefing Cutscene:");
966         stuff_string(pm->pre_briefing_cutscene, F_FILESPEC, NULL);
967
968         required_string("$Pre-Mission Cutscene:");
969         stuff_string(pm->pre_mission_cutscene, F_FILESPEC, NULL);
970
971         required_string("$Next Mission Success:");
972         stuff_string(pm->next_mission_success, F_NAME, NULL);
973
974         required_string("$Next Mission Partial:");
975         stuff_string(pm->next_mission_partial, F_NAME, NULL);
976
977         required_string("$Next Mission Failure:");
978         stuff_string(pm->next_mission_failure, F_NAME, NULL);
979 }
980
981 void parse_briefing_info(mission *pm)
982 {
983         char junk[4096];
984
985         if ( !optional_string("#Briefing Info") )
986                 return;
987
988         required_string("$Briefing Voice 1:");
989         stuff_string(junk, F_FILESPEC, NULL);
990
991         required_string("$Briefing Text 1:");
992         stuff_string(junk, F_MULTITEXTOLD, NULL);
993
994         required_string("$Briefing Voice 2:");
995         stuff_string(junk, F_FILESPEC, NULL);
996
997         required_string("$Briefing Text 2:");
998         stuff_string(junk, F_MULTITEXTOLD, NULL);
999
1000         required_string("$Briefing Voice 3:");
1001         stuff_string(junk, F_FILESPEC, NULL);
1002
1003         required_string("$Briefing Text 3:");
1004         stuff_string(junk, F_MULTITEXTOLD, NULL);
1005
1006         required_string("$Debriefing Voice 1:");
1007         stuff_string(junk, F_FILESPEC, NULL);
1008
1009         required_string("$Debriefing Text 1:");
1010         stuff_string(junk, F_MULTITEXTOLD, NULL);
1011
1012         required_string("$Debriefing Voice 2:");
1013         stuff_string(junk, F_FILESPEC, NULL);
1014
1015         required_string("$Debriefing Text 2:");
1016         stuff_string(junk, F_MULTITEXTOLD, NULL);
1017
1018         required_string("$Debriefing Voice 3:");
1019         stuff_string(junk, F_FILESPEC, NULL);
1020
1021         required_string("$Debriefing Text 3:");
1022         stuff_string(junk, F_MULTITEXTOLD, NULL);
1023 }
1024
1025 // parse the event music and briefing music for the mission
1026 void parse_music(mission *pm)
1027 {
1028         char    name[NAME_LENGTH];
1029
1030         event_music_reset_choices();
1031
1032         if ( !optional_string("#Music") ) {
1033                 return;
1034         }
1035
1036         required_string("$Event Music:");
1037         stuff_string(name, F_NAME, NULL);
1038         event_music_set_soundtrack(name);
1039
1040         required_string("$Briefing Music:");
1041         stuff_string(name, F_NAME, NULL);
1042         event_music_set_score(SCORE_BRIEFING, name);
1043
1044         if ( optional_string("$Debriefing Success Music:") ) {
1045                 stuff_string(name, F_NAME, NULL);
1046                 event_music_set_score(SCORE_DEBRIEF_SUCCESS, name);
1047         }
1048
1049         if ( optional_string("$Debriefing Fail Music:") ) {
1050                 stuff_string(name, F_NAME, NULL);
1051                 event_music_set_score(SCORE_DEBRIEF_FAIL, name);
1052         }
1053 }
1054
1055 void parse_cmd_brief(mission *pm)
1056 {
1057         int stage;
1058
1059         SDL_assert(!Cur_cmd_brief->num_stages);
1060         stage = 0;
1061
1062         required_string("#Command Briefing");
1063         while (optional_string("$Stage Text:")) {
1064                 SDL_assert(stage < CMD_BRIEF_STAGES_MAX);
1065                 Cur_cmd_brief->stage[stage].text = stuff_and_malloc_string(F_MULTITEXT, NULL, CMD_BRIEF_TEXT_MAX);
1066                 SDL_assert(Cur_cmd_brief->stage[stage].text);
1067
1068                 required_string("$Ani Filename:");
1069                 stuff_string(Cur_cmd_brief->stage[stage].ani_filename, F_FILESPEC, NULL);
1070                 if (optional_string("+Wave Filename:"))
1071                         stuff_string(Cur_cmd_brief->stage[stage].wave_filename, F_FILESPEC, NULL);
1072                 else
1073                         Cur_cmd_brief->stage[stage].wave_filename[0] = 0;
1074
1075                 stage++;
1076         }
1077
1078         Cur_cmd_brief->num_stages = stage;
1079 }
1080
1081 void parse_cmd_briefs(mission *pm)
1082 {
1083         int i;
1084
1085         cmd_brief_reset();
1086         // a hack follows because old missions don't have a command briefing
1087         if (required_string_either("#Command Briefing", "#Briefing"))
1088                 return;
1089
1090         for (i=0; i<Num_teams; i++) {
1091                 Cur_cmd_brief = &Cmd_briefs[i];
1092                 parse_cmd_brief(pm);
1093         }
1094 }
1095
1096 // -------------------------------------------------------------------------------------------------
1097 // parse_briefing()
1098 //
1099 // Parse the data required for the mission briefing
1100 //
1101 // NOTE: This updates the global Briefing struct with all the data necessary to drive the briefing
1102 //
1103 void parse_briefing(mission *pm)
1104 {
1105         int nt, i, j, stage_num = 0, icon_num = 0, team_index;
1106         brief_stage *bs;
1107         brief_icon *bi;
1108         briefing *bp;
1109
1110         char not_used_text[MAX_ICON_TEXT_LEN];
1111         
1112         brief_reset();
1113
1114         // MWA -- 2/3/98.  we can now have multiple briefing and debreifings in a mission
1115         for ( nt = 0; nt < Num_teams; nt++ ) {
1116                 if ( !optional_string("#Briefing") )
1117                         break;
1118
1119                 bp = &Briefings[nt];
1120
1121                 required_string("$start_briefing");
1122                 required_string("$num_stages:");
1123                 stuff_int(&bp->num_stages);
1124                 SDL_assert(bp->num_stages <= MAX_BRIEF_STAGES);
1125
1126                 stage_num = 0;
1127                 while (required_string_either("$end_briefing", "$start_stage")) {
1128                         required_string("$start_stage");
1129                         SDL_assert(stage_num < MAX_BRIEF_STAGES);
1130                         bs = &bp->stages[stage_num++];
1131                         required_string("$multi_text");
1132                         if ( Fred_running )     {
1133                                 stuff_string(bs->new_text, F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1134                         } else {
1135                                 bs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1136                         }
1137                         required_string("$voice:");
1138                         stuff_string(bs->voice, F_FILESPEC, NULL);
1139                         required_string("$camera_pos:");
1140                         stuff_vector(&bs->camera_pos);
1141                         required_string("$camera_orient:");
1142                         stuff_matrix(&bs->camera_orient);
1143                         required_string("$camera_time:");
1144                         stuff_int(&bs->camera_time);
1145
1146                         if ( optional_string("$num_lines:") ) {
1147                                 stuff_int(&bs->num_lines);
1148
1149                                 if ( Fred_running )     {
1150                                         SDL_assert(bs->lines!=NULL);
1151                                 } else {
1152                                         if ( bs->num_lines > 0 )        {
1153                                                 bs->lines = (brief_line *)malloc(sizeof(brief_line)*bs->num_lines);
1154                                                 SDL_assert(bs->lines!=NULL);
1155                                         }
1156                                 }
1157
1158                                 for (i=0; i<bs->num_lines; i++) {
1159                                         required_string("$line_start:");
1160                                         stuff_int(&bs->lines[i].start_icon);
1161                                         required_string("$line_end:");
1162                                         stuff_int(&bs->lines[i].end_icon);
1163                                 }
1164                         }
1165                         else {
1166                                 bs->num_lines = 0;
1167                         }
1168
1169                         required_string("$num_icons:");
1170                         stuff_int(&bs->num_icons);
1171
1172                         if ( Fred_running )     {
1173                                 SDL_assert(bs->lines!=NULL);
1174                         } else {
1175                                 if ( bs->num_icons > 0 )        {
1176                                         bs->icons = (brief_icon *)malloc(sizeof(brief_icon)*bs->num_icons);
1177                                         SDL_assert(bs->icons!=NULL);
1178                                 }
1179                         }
1180
1181                         if ( optional_string("$flags:") )
1182                                 stuff_int(&bs->flags);
1183                         else
1184                                 bs->flags = 0;
1185
1186                         if ( optional_string("$formula:") )
1187                                 bs->formula = get_sexp_main();
1188                         else
1189                                 bs->formula = Locked_sexp_true;
1190
1191                         SDL_assert(bs->num_icons <= MAX_STAGE_ICONS );
1192
1193                         while (required_string_either("$end_stage", "$start_icon")) {
1194                                 required_string("$start_icon");
1195                                 SDL_assert(icon_num < MAX_STAGE_ICONS);
1196                                 bi = &bs->icons[icon_num++];
1197
1198                                 required_string("$type:");
1199                                 stuff_int(&bi->type);
1200
1201                                 find_and_stuff("$team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1202                                 SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1203                                 bi->team = 1 << team_index;
1204
1205                                 find_and_stuff("$class:", &bi->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1206
1207                                 required_string("$pos:");
1208                                 stuff_vector(&bi->pos);
1209
1210                                 bi->label[0] = 0;
1211                                 if (optional_string("$label:"))
1212                                         stuff_string(bi->label, F_MESSAGE, NULL);
1213
1214                                 if (optional_string("+id:")) {
1215                                         stuff_int(&bi->id);
1216                                         if (bi->id >= Cur_brief_id)
1217                                                 Cur_brief_id = bi->id + 1;
1218
1219                                 } else {
1220                                         bi->id = -1;
1221                                         for (i=0; i<stage_num-1; i++)
1222                                                 for (j=0; j < bp->stages[i].num_icons; j++)
1223                                                 {
1224                                                         if (!SDL_strcasecmp(bp->stages[i].icons[j].label, bi->label))
1225                                                                 bi->id = bp->stages[i].icons[j].id;
1226                                                 }
1227
1228                                         if (bi->id < 0)
1229                                                 bi->id = Cur_brief_id++;
1230                                 }
1231
1232                                 required_string("$hlight:");
1233                                 int val;
1234                                 stuff_int(&val);
1235                                 if ( val>0 ) {
1236                                         bi->flags = BI_HIGHLIGHT;
1237                                 } else {
1238                                         bi->flags=0;
1239                                 }
1240
1241                                 required_string("$multi_text");
1242 //                              stuff_string(bi->text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1243                                 stuff_string(not_used_text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1244                                 required_string("$end_icon");
1245                         } // end while
1246                         SDL_assert(bs->num_icons == icon_num);
1247                         icon_num = 0;
1248                         required_string("$end_stage");
1249                 }       // end while
1250
1251                 SDL_assert(bp->num_stages == stage_num);
1252                 required_string("$end_briefing");
1253         }
1254
1255         if ( nt != Num_teams )
1256                 Error(LOCATION, "Not enough briefings in mission file.  There are %d teams and only %d briefings.", Num_teams, nt );
1257 }
1258
1259 // -------------------------------------------------------------------------------------------------
1260 // parse_debriefing_old()
1261 //
1262 // Parse the data required for the mission debriefings
1263 void parse_debriefing_old(mission *pm)
1264 {
1265         int     junk;
1266         char    waste[MAX_DEBRIEF_LEN];
1267         
1268         if ( !optional_string("#Debriefing") )
1269                 return;
1270
1271         required_string("$num_debriefings:");
1272         stuff_int(&junk);
1273
1274         while (required_string_either("#Players", "$start_debriefing")) {
1275                 required_string("$start_debriefing");
1276                 required_string("$formula:");
1277                 junk = get_sexp_main();
1278                 required_string("$num_stages:");
1279                 stuff_int(&junk);
1280                 while (required_string_either("$end_debriefing", "$start_stage")) {
1281                         required_string("$start_stage");
1282                         required_string("$multi_text");
1283                         stuff_string(waste, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1284                         required_string("$voice:");
1285                         stuff_string(waste, F_FILESPEC, NULL);
1286                         required_string("$end_stage");
1287                 } // end while
1288                 required_string("$end_debriefing");
1289         }       // end while
1290 }
1291
1292 // -------------------------------------------------------------------------------------------------
1293 // parse_debriefing_new()
1294 //
1295 // Parse the data required for the mission debriefings
1296 void parse_debriefing_new(mission *pm)
1297 {
1298         int                             stage_num, nt;
1299         debriefing              *db;
1300         debrief_stage   *dbs;
1301         
1302         debrief_reset();
1303
1304         // next code should be old -- hopefully not called anymore
1305         //if (!optional_string("#Debriefing_info")) {
1306         //      parse_debriefing_old(pm);
1307         //      return;
1308         //}
1309
1310         // 2/3/98 -- MWA.  We can now have multiple briefings and debriefings on a team
1311         for ( nt = 0; nt < Num_teams; nt++ ) {
1312
1313                 if ( !optional_string("#Debriefing_info") )
1314                         break;
1315
1316                 stage_num = 0;
1317
1318                 db = &Debriefings[nt];
1319
1320                 required_string("$Num stages:");
1321                 stuff_int(&db->num_stages);
1322                 SDL_assert(db->num_stages <= MAX_DEBRIEF_STAGES);
1323
1324                 while (required_string_either("#", "$Formula")) {
1325                         SDL_assert(stage_num < MAX_DEBRIEF_STAGES);
1326                         dbs = &db->stages[stage_num++];
1327                         required_string("$Formula:");
1328                         dbs->formula = get_sexp_main();
1329                         required_string("$multi text");
1330                         if ( Fred_running )     {
1331                                 stuff_string(dbs->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1332                         } else {
1333                                 dbs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1334                         }
1335                         required_string("$Voice:");
1336                         stuff_string(dbs->voice, F_FILESPEC, NULL);
1337                         required_string("$Recommendation text:");
1338                         if ( Fred_running )     {
1339                                 stuff_string( dbs->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1340                         } else {
1341                                 dbs->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1342                         }
1343                 } // end while
1344
1345                 SDL_assert(db->num_stages == stage_num);
1346         }
1347
1348         if ( nt != Num_teams )
1349                 Error(LOCATION, "Not enough debriefings for mission.  There are %d teams and only %d debriefings;\n", Num_teams, nt );
1350 }
1351
1352 void position_ship_for_knossos_warpin(p_object *objp, int shipnum, int objnum)
1353 {
1354         // Assume no valid knossos device
1355         Ships[shipnum].special_warp_objnum = -1;
1356
1357         // find knossos device
1358         int found = FALSE;
1359         ship_obj *so;
1360         int knossos_num = -1;
1361         for (so=GET_FIRST(&Ship_obj_list); so!=END_OF_LIST(&Ship_obj_list); so=GET_NEXT(so)) {
1362                 knossos_num = Objects[so->objnum].instance;
1363                 if (Ship_info[Ships[knossos_num].ship_info_index].flags & SIF_KNOSSOS_DEVICE) {
1364                         // be close to the right device [allow multiple knossos's
1365                         if (vm_vec_dist_quick(&Objects[knossos_num].pos, &objp->pos) < 2.0f*(Objects[knossos_num].radius + Objects[objnum].radius) ) {
1366                                 found = TRUE;
1367                                 break;
1368                         }
1369                 }
1370         }
1371
1372         if (found) {
1373                 // set ship special_warp_objnum
1374                 Ships[shipnum].special_warp_objnum = knossos_num;
1375
1376                 // position self for warp on plane of device
1377                 vector new_point;
1378                 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);
1379                 polymodel *pm = model_get(Ship_info[Ships[shipnum].ship_info_index].modelnum);
1380                 float desired_dist = -pm->mins.xyz.z;
1381                 vm_vec_scale_add2(&Objects[objnum].pos, &Objects[objnum].orient.v.fvec, (dist - desired_dist));
1382                 // if ship is BIG or HUGE, make it go through the center of the knossos
1383                 if (Ship_info[Ships[shipnum].ship_info_index].flags & SIF_HUGE_SHIP) {
1384                         vector offset;
1385                         vm_vec_sub(&offset, &Objects[knossos_num].pos, &new_point);
1386                         vm_vec_add2(&Objects[objnum].pos, &offset);
1387                 }
1388         }
1389 }
1390
1391 //      Given a stuffed p_object struct, create an object and fill in the necessary fields.
1392 //      Return object number.
1393 int parse_create_object(p_object *objp)
1394 {
1395         int     i, j, k, objnum, shipnum;
1396         ai_info *aip;
1397         ship_subsys *ptr;
1398         ship_info *sip;
1399         subsys_status *sssp;
1400         ship_weapon *wp;
1401
1402         // base level creation
1403         objnum = ship_create(&objp->orient, &objp->pos, objp->ship_class);
1404         SDL_assert(objnum != -1);
1405         shipnum = Objects[objnum].instance;
1406
1407         // if arriving through knossos, adjust objpj->pos to plane of knossos and set flag
1408         // special warp is single player only
1409         if ((objp->flags & P_KNOSSOS_WARP_IN) && !(Game_mode & GM_MULTIPLAYER)) {
1410                 if (!Fred_running) {
1411                         position_ship_for_knossos_warpin(objp, shipnum, objnum);
1412                 }
1413         }
1414
1415         Ships[shipnum].group = objp->group;
1416         Ships[shipnum].team = objp->team;
1417         SDL_strlcpy(Ships[shipnum].ship_name, objp->name, SDL_arraysize(Ships[0].ship_name));
1418         Ships[shipnum].escort_priority = objp->escort_priority;
1419         Ships[shipnum].special_exp_index = objp->special_exp_index;
1420         Ships[shipnum].respawn_priority = objp->respawn_priority;
1421         // if this is a multiplayer dogfight game, and its from a player wing, make it team traitor
1422         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (objp->wingnum >= 0)){
1423                 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
1424                         if ( !SDL_strcasecmp(Starting_wing_names[i], Wings[objp->wingnum].name) ) {
1425                                 Ships[shipnum].team = TEAM_TRAITOR;
1426                         } 
1427                 }
1428         }
1429
1430         sip = &Ship_info[Ships[shipnum].ship_info_index];
1431
1432         if ( !Fred_running ) {
1433                 ship_assign_sound(&Ships[shipnum]);
1434         }
1435
1436         aip = &(Ai_info[Ships[shipnum].ai_index]);
1437         aip->behavior = objp->behavior;
1438         aip->mode = aip->behavior;
1439
1440         // alternate type name
1441         Ships[shipnum].alt_type_index = objp->alt_type_index;
1442
1443         aip->ai_class = objp->ai_class;
1444         Ships[shipnum].weapons.ai_class = objp->ai_class;  // Fred uses this instead of above.
1445
1446         // must reset the number of ai goals when the object is created
1447         for (i = 0; i < MAX_AI_GOALS; i++ ){
1448                 aip->goals[i].ai_mode = AI_GOAL_NONE;
1449         }
1450
1451         Ships[shipnum].cargo1 = objp->cargo1;
1452
1453         Ships[shipnum].arrival_location = objp->arrival_location;
1454         Ships[shipnum].arrival_distance = objp->arrival_distance;
1455         Ships[shipnum].arrival_anchor = objp->arrival_anchor;
1456         Ships[shipnum].arrival_cue = objp->arrival_cue;
1457         Ships[shipnum].arrival_delay = objp->arrival_delay;
1458         Ships[shipnum].departure_location = objp->departure_location;
1459         Ships[shipnum].departure_anchor = objp->departure_anchor;
1460         Ships[shipnum].departure_cue = objp->departure_cue;
1461         Ships[shipnum].departure_delay = objp->departure_delay;
1462         Ships[shipnum].determination = objp->determination;
1463         Ships[shipnum].wingnum = objp->wingnum;
1464         Ships[shipnum].hotkey = objp->hotkey;
1465         Ships[shipnum].score = objp->score;
1466         Ships[shipnum].persona_index = objp->persona_index;
1467
1468         // set the orders that this ship will accept.  It will have already been set to default from the
1469         // ship create code, so only set them if the parse object flags say they are unique
1470         if ( objp->flags & P_SF_USE_UNIQUE_ORDERS ) {
1471                 Ships[shipnum].orders_accepted = objp->orders_accepted;
1472
1473         // MWA  5/15/98 -- Added the following debug code because some orders that ships
1474         // will accept were apparently written out incorrectly with Fred.  This Int3() should
1475         // trap these instances.
1476 #ifndef NDEBUG
1477                 if ( Fred_running ) {
1478                         int default_orders, remaining_orders;
1479                         
1480                         default_orders = ship_get_default_orders_accepted( &Ship_info[Ships[shipnum].ship_info_index] );
1481                         remaining_orders = objp->orders_accepted & ~default_orders;
1482                         if ( remaining_orders ) {
1483                                 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);
1484                         }
1485                 }
1486 #endif
1487         }
1488         
1489         // check the parse object's flags for possible flags to set on this newly created ship
1490         if ( objp->flags & P_OF_PROTECTED ) {
1491                 Objects[objnum].flags |= OF_PROTECTED;
1492         }
1493
1494         if ( objp->flags & P_OF_BEAM_PROTECTED ) {
1495                 Objects[objnum].flags |= OF_BEAM_PROTECTED;
1496         }
1497
1498         if (objp->flags & P_OF_CARGO_KNOWN) {
1499                 Ships[shipnum].flags |= SF_CARGO_REVEALED;
1500         }
1501
1502         if ( objp->flags & P_SF_IGNORE_COUNT )
1503                 Ships[shipnum].flags |= SF_IGNORE_COUNT;
1504
1505         if ( objp->flags & P_SF_REINFORCEMENT )
1506                 Ships[shipnum].flags |= SF_REINFORCEMENT;
1507
1508         if (objp->flags & P_OF_NO_SHIELDS || sip->shields == 0 )
1509                 Objects[objnum].flags |= OF_NO_SHIELDS;
1510
1511         if (objp->flags & P_SF_ESCORT)
1512                 Ships[shipnum].flags |= SF_ESCORT;
1513
1514         if (objp->flags & P_KNOSSOS_WARP_IN) {
1515                 Objects[objnum].flags |= OF_SPECIAL_WARP;
1516         }
1517
1518         // don't set the flag if the mission is ongoing in a multiplayer situation. This will be set by the players in the
1519         // game only before the game or during respawning.
1520         // MWA -- changed the next line to remove the !(Game_mode & GM_MULTIPLAYER).  We shouldn't be setting
1521         // this flag in single player mode -- it gets set in post process mission.
1522         //if ((objp->flags & P_OF_PLAYER_START) && (((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION)) || !(Game_mode & GM_MULTIPLAYER)))
1523         if ( (objp->flags & P_OF_PLAYER_START) && (Fred_running || ((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION))) ) 
1524                 Objects[objnum].flags |= OF_PLAYER_SHIP;
1525
1526         if (objp->flags & P_SF_NO_ARRIVAL_MUSIC)
1527                 Ships[shipnum].flags |= SF_NO_ARRIVAL_MUSIC;
1528
1529         if ( objp->flags & P_SF_NO_ARRIVAL_WARP )
1530                 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1531
1532         if ( objp->flags & P_SF_NO_DEPARTURE_WARP )
1533                 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1534
1535         if ( objp->flags & P_SF_INITIALLY_DOCKED )
1536                 Ships[shipnum].flags |= SF_INITIALLY_DOCKED;
1537
1538         if ( objp->flags & P_SF_LOCKED )
1539                 Ships[shipnum].flags |= SF_LOCKED;
1540
1541         if ( objp->flags & P_SF_WARP_BROKEN )
1542                 Ships[shipnum].flags |= SF_WARP_BROKEN;
1543
1544         if ( objp->flags & P_SF_WARP_NEVER )
1545                 Ships[shipnum].flags |= SF_WARP_NEVER;
1546
1547         if ( objp->flags & P_SF_HIDDEN_FROM_SENSORS )
1548                 Ships[shipnum].flags |= SF_HIDDEN_FROM_SENSORS;
1549
1550         // if ship is in a wing, and the wing's no_warp_effect flag is set, then set the equivalent
1551         // flag for the ship
1552         if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_ARRIVAL_WARP) )
1553                 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1554
1555         if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_DEPARTURE_WARP) )
1556                 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1557
1558         // mwa -- 1/30/98.  Do both flags.  Fred uses the ship flag, and FreeSpace will use the object
1559         // flag. I'm to lazy at this point to deal with consolidating them.
1560         if ( objp->flags & P_SF_INVULNERABLE ) {
1561                 Ships[shipnum].flags |= SF_INVULNERABLE;
1562                 Objects[objnum].flags |= OF_INVULNERABLE;
1563         }
1564
1565         if ( objp->flags & P_SF_GUARDIAN ) {
1566                 Objects[objnum].flags |= OF_GUARDIAN;
1567         }
1568
1569         if ( objp->flags & P_SF_SCANNABLE )
1570                 Ships[shipnum].flags |= SF_SCANNABLE;
1571
1572         if ( objp->flags & P_SF_RED_ALERT_STORE_STATUS ){
1573                 SDL_assert(!(Game_mode & GM_MULTIPLAYER));
1574                 Ships[shipnum].flags |= SF_RED_ALERT_STORE_STATUS;
1575         }
1576
1577         // a couple of ai_info flags.  Also, do a reasonable default for the kamikaze damage regardless of
1578         // whether this flag is set or not
1579         if ( objp->flags & P_AIF_KAMIKAZE ) {
1580                 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_KAMIKAZE;
1581                 Ai_info[Ships[shipnum].ai_index].kamikaze_damage = objp->kamikaze_damage;
1582         }
1583
1584         if ( objp->flags & P_AIF_NO_DYNAMIC )
1585                 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_NO_DYNAMIC;
1586
1587         // if the wing index and wing pos are set for this parse object, set them for the ship.  This
1588         // is useful in multiplayer when ships respawn
1589         Ships[shipnum].wing_status_wing_index = objp->wing_status_wing_index;
1590         Ships[shipnum].wing_status_wing_pos = objp->wing_status_wing_pos;
1591
1592         // set up the ai_goals for this object -- all ships created here are AI controlled.
1593         if ( objp->ai_goals != -1 ) {
1594                 int sexp;
1595
1596                 for ( sexp = CDR(objp->ai_goals); sexp != -1; sexp = CDR(sexp) )
1597                         // make a call to the routine in MissionGoals.cpp to set up the ai goals for this object.
1598                         ai_add_ship_goal_sexp( sexp, AIG_TYPE_EVENT_SHIP, aip );
1599
1600                 if ( objp->wingnum == -1 )                      // free the sexpression nodes only for non-wing ships.  wing code will handle it's own case
1601                         free_sexp2(objp->ai_goals);     // free up sexp nodes for reused, since they aren't needed anymore.
1602         }
1603
1604         SDL_assert(Ships[shipnum].modelnum != -1);
1605
1606         // initialize subsystem statii here.  The subsystems are given a percentage damaged.  So a percent value
1607         // of 20% means that the subsystem is 20% damaged (*not* 20% of max hits).  This is opposite the way
1608         // that the initial velocity/hull strength/shields work
1609         i = objp->subsys_count;
1610         while (i--) {
1611                 sssp = &Subsys_status[objp->subsys_index + i];
1612                 if (!SDL_strcasecmp(sssp->name, NOX("Pilot"))) {
1613                         wp = &Ships[shipnum].weapons;
1614                         if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1615                                 for (j=k=0; j<MAX_PRIMARY_BANKS; j++) {
1616                                         if ( (sssp->primary_banks[j] >= 0) || Fred_running ){
1617                                                 wp->primary_bank_weapons[k] = sssp->primary_banks[j];                                           
1618
1619                                                 // next
1620                                                 k++;
1621                                         }
1622                                 }
1623
1624                                 if (Fred_running){
1625                                         wp->num_primary_banks = sip->num_primary_banks;
1626                                 } else {
1627                                         wp->num_primary_banks = k;
1628                                 }
1629                         }
1630
1631                         if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1632                                 for (j=k=0; j<MAX_SECONDARY_BANKS; j++) {
1633                                         if ( (sssp->secondary_banks[j] >= 0) || Fred_running ){
1634                                                 wp->secondary_bank_weapons[k++] = sssp->secondary_banks[j];
1635                                         }
1636                                 }
1637
1638                                 if (Fred_running){
1639                                         wp->num_secondary_banks = sip->num_secondary_banks;
1640                                 } else {
1641                                         wp->num_secondary_banks = k;
1642                                 }
1643                         }
1644
1645                         for (j=0; j < wp->num_secondary_banks; j++)
1646                                 if (Fred_running){
1647                                         wp->secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1648                                 } else {
1649                                         int capacity = fl2i(sssp->secondary_ammo[j]/100.0f * sip->secondary_bank_ammo_capacity[j] + 0.5f );
1650                                         wp->secondary_bank_ammo[j] = fl2i(capacity / Weapon_info[wp->secondary_bank_weapons[j]].cargo_size + 0.5f);
1651                                 }
1652                         continue;
1653                 }
1654
1655                 ptr = GET_FIRST(&Ships[shipnum].subsys_list);
1656                 while (ptr != END_OF_LIST(&Ships[shipnum].subsys_list)) {
1657                         if (!SDL_strcasecmp(ptr->system_info->subobj_name, sssp->name)) {
1658                                 if (Fred_running)
1659                                         ptr->current_hits = sssp->percent;
1660                                 else {
1661                                         float new_hits;
1662                                         new_hits = ptr->system_info->max_hits * (100.0f - sssp->percent) / 100.f;
1663                                         Ships[shipnum].subsys_info[ptr->system_info->type].current_hits -= (ptr->system_info->max_hits - new_hits);
1664                                         if ( (100.0f - sssp->percent) < 0.5) {
1665                                                 ptr->current_hits = 0.0f;
1666                                                 ptr->submodel_info_1.blown_off = 1;
1667                                         } else {
1668                                                 ptr->current_hits = new_hits;
1669                                         }
1670                                 }
1671
1672                                 if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1673                                         for (j=0; j<MAX_PRIMARY_BANKS; j++)
1674                                                 ptr->weapons.primary_bank_weapons[j] = sssp->primary_banks[j];
1675
1676                                 if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1677                                         for (j=0; j<MAX_SECONDARY_BANKS; j++)
1678                                                 ptr->weapons.secondary_bank_weapons[j] = sssp->secondary_banks[j];
1679
1680                                 for (j=0; j<MAX_SECONDARY_BANKS; j++) {
1681                                         // AL 3-5-98:  This is correct for FRED, but not for FreeSpace... but is this even used?
1682                                         //                                      As far as I know, turrets cannot run out of ammo
1683                                         ptr->weapons.secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1684                                 }
1685
1686                                 ptr->subsys_cargo_name = sssp->subsys_cargo_name;
1687
1688                                 if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
1689                                         ptr->weapons.ai_class = sssp->ai_class;
1690
1691                                 ai_turret_select_default_weapon(ptr);
1692                         }
1693
1694                         ptr = GET_NEXT(ptr);
1695                 }
1696         }
1697
1698         // initial hull strength, shields, and velocity are all expressed as a percentage of the max value/
1699         // so a initial_hull value of 90% means 90% of max.  This way is opposite of how subsystems are dealt
1700         // with
1701         if (Fred_running) {
1702                 Objects[objnum].phys_info.speed = (float) objp->initial_velocity;
1703                 // Ships[shipnum].hull_hit_points_taken = (float) objp->initial_hull;
1704                 Objects[objnum].hull_strength = (float) objp->initial_hull;
1705                 Objects[objnum].shields[0] = (float) objp->initial_shields;
1706
1707         } else {
1708                 int max_allowed_sparks, num_sparks, i;
1709                 polymodel *pm;
1710
1711                 // Ships[shipnum].hull_hit_points_taken = (float)objp->initial_hull * sip->max_hull_hit_points / 100.0f;
1712                 Objects[objnum].hull_strength = objp->initial_hull * sip->initial_hull_strength / 100.0f;
1713                 for (i = 0; i<MAX_SHIELD_SECTIONS; i++)
1714                         Objects[objnum].shields[i] = (float)(objp->initial_shields * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
1715
1716                 // initial velocities now do not apply to ships which warp in after mission starts
1717                 if ( !(Game_mode & GM_IN_MISSION) ) {
1718                         Objects[objnum].phys_info.speed = (float)objp->initial_velocity * sip->max_speed / 100.0f;
1719                         Objects[objnum].phys_info.vel.xyz.z = Objects[objnum].phys_info.speed;
1720                         Objects[objnum].phys_info.prev_ramp_vel = Objects[objnum].phys_info.vel;
1721                         Objects[objnum].phys_info.desired_vel = Objects[objnum].phys_info.vel;
1722                 }
1723
1724                 // recalculate damage of subsystems
1725                 ship_recalc_subsys_strength( &Ships[shipnum] );
1726
1727                 // create sparks on a ship whose hull is damaged.  We will create two sparks for every 20%
1728                 // of hull damage done.  100 means no sparks.  between 80 and 100 do two sparks.  60 and 80 is
1729                 // four, etc.
1730                 pm = model_get( sip->modelnum );
1731                 max_allowed_sparks = get_max_sparks(&Objects[objnum]);
1732                 num_sparks = (int)((100.0f - objp->initial_hull) / 5.0f);
1733                 if (num_sparks > max_allowed_sparks) {
1734                         num_sparks = max_allowed_sparks;
1735                 }
1736
1737                 for (i = 0; i < num_sparks; i++ ) {
1738                         vector v1, v2;
1739
1740                         // DA 10/20/98 - sparks must be chosen on the hull and not any submodel
1741                         submodel_get_two_random_points(sip->modelnum, pm->detail[0], &v1, &v2);
1742                         ship_hit_sparks_no_rotate(&Objects[objnum], &v1);
1743 //                      ship_hit_sparks_no_rotate(&Objects[objnum], &v2);
1744                 }
1745         }
1746
1747         // in mission, we add a log entry -- set ship positions for ships not in wings, and then do
1748         // warpin effect
1749         if ( (Game_mode & GM_IN_MISSION) && (!Fred_running) ) {
1750                 mission_log_add_entry( LOG_SHIP_ARRIVE, Ships[shipnum].ship_name, NULL );
1751
1752                 // if this ship isn't in a wing, determine it's arrival location
1753                 if ( !Game_restoring )  {
1754                         if ( Ships[shipnum].wingnum == -1 ) {
1755                                 int location;
1756                                 // multiplayer clients set the arrival location of ships to be at location since their
1757                                 // position has already been determined.  Don't actually set the variable since we
1758                                 // don't want the warp effect to show if coming from a dock bay.
1759                                 location = objp->arrival_location;
1760                                 if ( MULTIPLAYER_CLIENT )
1761                                         location = ARRIVE_AT_LOCATION;
1762                                 mission_set_arrival_location(objp->arrival_anchor, location, objp->arrival_distance, objnum, NULL, NULL);
1763                                 if ( objp->arrival_location != ARRIVE_FROM_DOCK_BAY )
1764                                         shipfx_warpin_start( &Objects[objnum] );
1765                         }
1766                 }
1767                 
1768                 // possibly add this ship to a hotkey set
1769                 if ( (Ships[shipnum].wingnum == -1) && (Ships[shipnum].hotkey != -1 ) )
1770                         mission_hotkey_mf_add( Ships[shipnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1771                 else if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].hotkey != -1 ) )
1772                         mission_hotkey_mf_add( Wings[Ships[shipnum].wingnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1773
1774                 // possibly add this ship to the hud escort list
1775                 if ( Ships[shipnum].flags & SF_ESCORT ){
1776                         hud_add_remove_ship_escort( objnum, 1 );
1777                 }
1778         }
1779
1780         // for multiplayer games, make a call to the network code to assign the object signature
1781         // of the newly created object.  The network host of the netgame will always assign a signature
1782         // to a newly created object.  The network signature will get to the clients of the game in
1783         // different manners depending on whether or not an individual ship or a wing was created.
1784         if ( Game_mode & GM_MULTIPLAYER ) {
1785                 Objects[objnum].net_signature = objp->net_signature;
1786
1787                 if ( (Game_mode & GM_IN_MISSION) && MULTIPLAYER_MASTER && (objp->wingnum == -1) ){
1788                         send_ship_create_packet( &Objects[objnum], (objp==Arriving_support_ship)?1:0 );
1789                 }
1790         }
1791
1792         // if recording a demo, post the event
1793         if(Game_mode & GM_DEMO_RECORD){
1794                 demo_POST_obj_create(objp->name, Objects[objnum].signature);
1795         }
1796
1797         return objnum;
1798 }
1799
1800 //      Mp points at the text of an object, which begins with the "$Name:" field.
1801 //      Snags all object information and calls parse_create_object to create a ship.
1802 //      Why create a ship?  Why not an object?  Stay tuned...
1803 //
1804 // flag is parameter that is used to tell what kind information we are retrieving from the mission.
1805 // if we are just getting player starts, then don't create the objects
1806 int parse_object(mission *pm, int flag, p_object *objp)
1807 {
1808         // p_object     temp_object;
1809         // p_object     *objp;
1810         int     i, j, count, shipnum, delay, destroy_before_mission_time;
1811         char    name[NAME_LENGTH], flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
1812
1813         SDL_assert(pm != NULL);
1814
1815         // objp = &temp_object;
1816
1817         required_string("$Name:");
1818         stuff_string(objp->name, F_NAME, NULL);
1819         shipnum = ship_name_lookup(objp->name);
1820         if (shipnum != -1)
1821                 error_display(0, NOX("Redundant ship name: %s\n"), objp->name);
1822
1823
1824         find_and_stuff("$Class:", &objp->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1825         if (objp->ship_class < 0) {
1826                 Warning(LOCATION, "Ship \"%s\" has an invalid ship type (ships.tbl probably changed).  Making it type 0", objp->name);
1827
1828                 // if fred is running, maybe notify the user that the mission contains MD content
1829                 if(Fred_running){
1830                         Fred_found_unknown_ship_during_parsing = 1;
1831                 }
1832
1833                 objp->ship_class = 0;
1834         }
1835
1836         // if this is a multiplayer dogfight mission, skip support ships
1837         if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (Ship_info[objp->ship_class].flags & SIF_SUPPORT)){
1838                 return 0;
1839         }               
1840
1841         // optional alternate name type
1842         objp->alt_type_index = -1;
1843         if(optional_string("$Alt:")){
1844                 // alternate name
1845                 stuff_string(name, F_NAME, NULL, NAME_LENGTH);
1846
1847                 // try and find the alternate name
1848                 objp->alt_type_index = (char)mission_parse_lookup_alt(name);
1849                 SDL_assert(objp->alt_type_index >= 0);
1850                 if(objp->alt_type_index < 0){
1851                         mprintf(("Error looking up alternate ship type name!\n"));
1852                 } else {
1853                         mprintf(("Using alternate ship type name : %s\n", name));
1854                 }
1855         }
1856
1857         int     team_index;
1858         find_and_stuff("$Team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1859         SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1860         objp->team = 1 << team_index;
1861
1862         required_string("$Location:");
1863         stuff_vector(&objp->pos);
1864
1865         required_string("$Orientation:");
1866         stuff_matrix(&objp->orient);
1867
1868         find_and_stuff("$IFF:",                 &objp->iff, F_NAME, Iff_names, Num_iff, "IFF");
1869         find_and_stuff("$AI Behavior:", &objp->behavior, F_NAME, Ai_behavior_names, Num_ai_behaviors, "AI behavior");
1870         objp->ai_goals = -1;
1871
1872         if ( optional_string("+AI Class:")) {
1873                 objp->ai_class = match_and_stuff(F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class");
1874                 SDL_assert(objp->ai_class > -1 );
1875         } else {
1876                 objp->ai_class = Ship_info[objp->ship_class].ai_class;
1877         }
1878
1879         if ( optional_string("$AI Goals:") ){
1880                 objp->ai_goals = get_sexp_main();
1881         }
1882
1883         if ( !required_string_either("$AI Goals:", "$Cargo 1:") ) {
1884                 required_string("$AI Goals:");
1885                 objp->ai_goals = get_sexp_main();
1886         }
1887
1888         objp->cargo1 = -1;
1889         int temp;
1890         find_and_stuff_or_add("$Cargo 1:", &temp, F_NAME, Cargo_names, NAME_LENGTH, &Num_cargo, MAX_CARGO, "cargo");
1891         objp->cargo1 = char(temp);
1892         if ( optional_string("$Cargo 2:") ) {
1893                 char buf[NAME_LENGTH];
1894                 stuff_string(buf, F_NAME, NULL);
1895         }
1896
1897         parse_common_object_data(objp);  // get initial conditions and subsys status
1898         count = 0;
1899         while (required_string_either("$Arrival Location:", "$Status Description:"))    {
1900                 SDL_assert(count < MAX_OBJECT_STATUS);
1901
1902                 find_and_stuff("$Status Description:", &objp->status_type[count], F_NAME, Status_desc_names, Num_status_names, "Status Description");
1903                 find_and_stuff("$Status:", &objp->status[count], F_NAME, Status_type_names, Num_status_names, "Status Type");
1904                 find_and_stuff("$Target:", &objp->target[count], F_NAME, Status_target_names, Num_status_names, "Target");
1905                 count++;
1906         }
1907         objp->status_count = count;
1908
1909         objp->arrival_anchor = -1;
1910         objp->arrival_distance = 0;
1911         find_and_stuff("$Arrival Location:", &objp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
1912         if ( optional_string("+Arrival Distance:") ) {
1913                 stuff_int( &objp->arrival_distance );
1914                 if ( objp->arrival_location != ARRIVE_AT_LOCATION ) {
1915                         required_string("$Arrival Anchor:");
1916                         stuff_string(name, F_NAME, NULL);
1917                         objp->arrival_anchor = get_anchor(name);
1918                 }
1919         }
1920
1921         if (optional_string("+Arrival Delay:")) {
1922                 stuff_int(&delay);
1923                 if ( delay < 0 )
1924                         Error(LOCATION, "Cannot have arrival delay < 0 (ship %s)", objp->name);
1925         } else
1926                 delay = 0;
1927
1928         if ( !Fred_running ){
1929                 objp->arrival_delay = -delay;                   // use negative numbers to mean we haven't set up a timer yet
1930         } else {
1931                 objp->arrival_delay = delay;
1932         }
1933
1934         required_string("$Arrival Cue:");
1935         objp->arrival_cue = get_sexp_main();
1936         if ( !Fred_running && (objp->arrival_cue >= 0) ) {
1937                 // eval the arrival cue.  if the cue is true, set up the timestamp for the arrival delay
1938                 SDL_assert ( objp->arrival_delay <= 0 );
1939
1940                 // don't eval arrival_cues when just looking for player information.
1941                 if ( eval_sexp(objp->arrival_cue) ){                    // evaluate to determine if sexp is always false.
1942                         objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
1943                 }
1944         }
1945
1946         find_and_stuff("$Departure Location:", &objp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
1947         objp->departure_anchor = -1;
1948         if ( objp->departure_location == DEPART_AT_DOCK_BAY ) {
1949                 required_string("$Departure Anchor:");
1950                 stuff_string(name, F_NAME, NULL);
1951                 objp->departure_anchor = get_anchor(name);
1952         }
1953
1954         if (optional_string("+Departure Delay:")) {
1955                 stuff_int(&delay);
1956                 if ( delay < 0 ){
1957                         Error(LOCATION, "Cannot have departure delay < 0 (ship %s)", objp->name);
1958                 }
1959         } else {
1960                 delay = 0;
1961         }
1962
1963         if ( !Fred_running ){
1964                 objp->departure_delay = -delay;
1965         } else {
1966                 objp->departure_delay = delay;
1967         }
1968
1969         required_string("$Departure Cue:");
1970         objp->departure_cue = get_sexp_main();
1971
1972         if (optional_string("$Misc Properties:"))
1973                 stuff_string(objp->misc, F_NAME, NULL);
1974
1975         required_string("$Determination:");
1976         stuff_int(&objp->determination);
1977
1978         objp->flags = 0;
1979         if (optional_string("+Flags:")) {
1980                 count = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
1981                 for (i=0; i<count; i++) {
1982                         for (j=0; j<MAX_PARSE_OBJECT_FLAGS; j++) {
1983                                 if (!SDL_strcasecmp(flag_strings[i], Parse_object_flags[j])) {
1984                                         objp->flags |= (1 << j);
1985                                         break;
1986                                 }
1987                         }
1988
1989                         if (j == MAX_PARSE_OBJECT_FLAGS)
1990                                 Warning(LOCATION, "Unknown flag in mission file: %s\n", flag_strings[i]);
1991                 }
1992         }
1993
1994         // always store respawn priority, just for ease of implementation
1995         objp->respawn_priority = 0;
1996         if(optional_string("+Respawn Priority:" )){
1997                 stuff_int(&objp->respawn_priority);     
1998         }
1999
2000         objp->escort_priority = 0;
2001         if ( optional_string("+Escort Priority:" ) ) {
2002                 SDL_assert(objp->flags & P_SF_ESCORT);
2003                 stuff_int(&objp->escort_priority);
2004         }       
2005
2006         if ( objp->flags & P_OF_PLAYER_START ) {
2007                 objp->flags |= P_OF_CARGO_KNOWN;                                // make cargo known for players
2008                 Player_starts++;
2009         }
2010
2011         objp->special_exp_index = -1;
2012         if ( optional_string("+Special Exp index:" ) ) {
2013                 stuff_int(&objp->special_exp_index);
2014         }
2015
2016         // if the kamikaze flag is set, we should have the next flag
2017         if ( optional_string("+Kamikaze Damage:") ) {
2018                 int damage;
2019
2020                 stuff_int(&damage);
2021                 objp->kamikaze_damage = i2fl(damage);
2022         }
2023
2024         objp->hotkey = -1;
2025         if (optional_string("+Hotkey:")) {
2026                 stuff_int(&objp->hotkey);
2027                 SDL_assert((objp->hotkey >= 0) && (objp->hotkey < 10));
2028         }
2029
2030         objp->docked_with[0] = 0;
2031         if (optional_string("+Docked With:")) {
2032                 stuff_string(objp->docked_with, F_NAME, NULL);
2033                 required_string("$Docker Point:");
2034                 stuff_string(objp->docker_point, F_NAME, NULL);
2035                 required_string("$Dockee Point:");
2036                 stuff_string(objp->dockee_point, F_NAME, NULL);
2037
2038                 objp->flags |= P_SF_INITIALLY_DOCKED;
2039
2040                 // put this information into the Initially_docked array.  We will need to use this
2041                 // informatin later since not all ships will initially get created.
2042                 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee, objp->docked_with, NAME_LENGTH);
2043                 SDL_strlcpy(Initially_docked[Total_initially_docked].docker_point, objp->docker_point, NAME_LENGTH);
2044                 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee_point, objp->dockee_point, NAME_LENGTH);
2045                 Initially_docked[Total_initially_docked].docker = objp;
2046                 Total_initially_docked++;
2047         }
2048
2049         // check the optional parameter for destroying the ship before the mission starts.  If this parameter is
2050         // here, then we need to destroy the ship N seconds before the mission starts (for debris purposes).
2051         // store the time value here.  We want to create this object for sure.  Set the arrival cue and arrival
2052         // delay to bogus values
2053         destroy_before_mission_time = -1;
2054         if ( optional_string("+Destroy At:") ) {
2055
2056                 stuff_int(&destroy_before_mission_time);
2057                 SDL_assert ( destroy_before_mission_time >= 0 );
2058                 objp->arrival_cue = Locked_sexp_true;
2059                 objp->arrival_delay = timestamp(0);
2060         }
2061
2062         // check for the optional "orders accepted" string which contains the orders from the default
2063         // set that this ship will actually listen to
2064         if ( optional_string("+Orders Accepted:") ) {
2065                 stuff_int( &objp->orders_accepted );
2066                 if ( objp->orders_accepted != -1 ){
2067                         objp->flags |= P_SF_USE_UNIQUE_ORDERS;
2068                 }
2069         }
2070
2071         if (optional_string("+Group:")){
2072                 stuff_int(&objp->group);
2073         } else {
2074                 objp->group = 0;
2075         }
2076
2077         if (optional_string("+Score:")){
2078                 stuff_int(&objp->score);
2079         } else {
2080                 objp->score = 0;
2081         }
2082
2083         // parse the persona index if present
2084         if ( optional_string("+Persona Index:")){
2085                 stuff_int(&objp->persona_index);
2086         } else {
2087                 objp->persona_index = -1;
2088         }
2089
2090         objp->wingnum = -1;                                     // set the wing number to -1 -- possibly to be set later
2091
2092         // for multiplayer, assign a network signature to this parse object.  Doing this here will
2093         // allow servers to use the signature with clients when creating new ships, instead of having
2094         // to pass ship names all the time
2095         if ( Game_mode & GM_MULTIPLAYER ){
2096                 objp->net_signature = multi_assign_network_signature( MULTI_SIG_SHIP );
2097         }
2098
2099         // set the wing_status position to be -1 for all objects.  This will get set to an appropriate
2100         // value when the wing positions are finally determined.
2101         objp->wing_status_wing_index = -1;
2102         objp->wing_status_wing_pos = -1;
2103         objp->respawn_count = 0;
2104
2105         // if this if the starting player ship, then copy if to Starting_player_pobject (used for ingame join)
2106         if ( !SDL_strcasecmp( objp->name, Player_start_shipname) ) {
2107                 Player_start_pobject = *objp;
2108                 Player_start_pobject.flags |= P_SF_PLAYER_START_VALID;
2109         }
2110         
2111
2112 // Now create the object.
2113 // Don't create the new ship blindly.  First, check the sexp for the arrival cue
2114 // to determine when this ship should arrive.  If not right away, stick this ship
2115 // onto the ship arrival list to be looked at later.  Also check to see if it should use the
2116 // wings arrival cue.  The ship may get created later depending on whether or not the wing
2117 // is created.
2118 // always create ships when FRED is running
2119
2120         // don't create the object if it is intially docked for either FreeSpcae or Fred.  Fred will
2121         // create the object later in post_process_mission
2122         if ( (objp->flags & P_SF_INITIALLY_DOCKED) || (!Fred_running && (!eval_sexp(objp->arrival_cue) || !timestamp_elapsed(objp->arrival_delay) || (objp->flags & P_SF_REINFORCEMENT))) ) {
2123                 SDL_assert ( destroy_before_mission_time == -1 );               // we can't add ships getting destroyed to the arrival list!!!
2124                 SDL_assert ( num_ship_arrivals < MAX_SHIP_ARRIVALS );
2125                 memcpy( &ship_arrivals[num_ship_arrivals], objp, sizeof(p_object) );
2126                 list_append(&ship_arrival_list, &ship_arrivals[num_ship_arrivals]);
2127                 num_ship_arrivals++;
2128         }
2129         // ingame joiners bail here.
2130         else if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_INGAME_JOIN)){
2131                 return 1;
2132         }
2133         else {
2134                 int     real_objnum;
2135
2136                 real_objnum = parse_create_object(objp);                                // this object may later get destroyed depending on wing status!!!!
2137
2138                 Subsys_index = objp->subsys_index;  // free elements that are no longer needed.
2139
2140                 // if the ship is supposed to be destroyed before the mission, then blow up the ship, mark the pieces
2141                 // as last forever.  Only call this stuff when you are blowing up the ship
2142                 if ( destroy_before_mission_time >= 0 ) {
2143                         object *objp;
2144
2145                         objp = &Objects[real_objnum];
2146                         if ( !Fred_running ) {
2147                                 int i;
2148                                 shipfx_blow_up_model( objp, Ships[objp->instance].modelnum, 0, 0, &objp->pos );
2149                                 objp->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                                         objp = &Objects[db->objnum];
2167                                         physics_sim( &objp->pos, &objp->orient, &objp->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[objp->instance].final_death_time = destroy_before_mission_time;
2172                                 Ships[objp->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         objnum = -1;
4476         objp = GET_FIRST(&ship_arrival_list);
4477         while( objp !=END_OF_LIST(&ship_arrival_list) ) {
4478                 p_object *temp = GET_NEXT(objp);
4479                 if ( objp->wingnum == -1 )      {                                                               // if this object has a wing -- let code for wings determine if it should be created
4480
4481                         objnum = mission_did_ship_arrive( objp );
4482                         if ( objnum != -1 )     {
4483                                 list_remove( &ship_arrival_list, objp);
4484                                 MONITOR_INC(NumShipArrivals,1);
4485                         }
4486
4487                 }
4488                 objp = temp;
4489         }
4490
4491         // check for any initially docked ships.  Do it after all are created since the next function
4492         // messes with the ship_arrival_list
4493         mission_parse_do_initial_docks();                       // maybe create it's docked counterpart
4494
4495         mission_parse_mark_non_arrivals();                      // mark parse objects which can no longer arrive
4496
4497         // check the support ship arrival list
4498         if ( Arriving_support_ship )    {
4499                 int objnum;
4500
4501                 objnum = mission_did_ship_arrive( Arriving_support_ship );
4502
4503                 if ( objnum != -1 ) {
4504                         MONITOR_INC(NumShipArrivals,1);
4505                         mission_parse_support_arrived( objnum );
4506                 }
4507         }
4508
4509         // we must also check to see if there are waves of a wing that must
4510         // reappear if all the ships of the current wing have been destroyed or
4511         // have departed. If this is the case, then create the next wave.
4512
4513         for ( i = 0; i < num_wings; i++ ) {
4514                 wingp = &Wings[i];
4515
4516                 // should we process this wing anymore
4517                 if ( wingp->flags & WF_WING_GONE )
4518                         continue;
4519
4520                 // if we have a reinforcement wing, then don't try to create new ships automatically.
4521                 if ( wingp->flags & WF_REINFORCEMENT ) {
4522
4523                         // check to see in the wings arrival cue is true, and if so, then mark the reinforcement
4524                         // as available
4525                         if ( eval_sexp(wingp->arrival_cue) ) {
4526                                 mission_parse_mark_reinforcement_available(wingp->name);
4527                         }
4528                         continue;
4529                 }
4530                 
4531                 // don't do evaluations for departing wings
4532                 if ( wingp->flags & WF_WING_DEPARTING ){
4533                         continue;
4534                 }
4535
4536                 // must check to see if we are at the last wave.  Code above to determine when a wing is gone only
4537                 // gets run when a ship is destroyed (not every N seconds like it used to).  Do a quick check
4538                 // here.
4539                 if ( wingp->current_wave == wingp->num_waves ){
4540                         continue;
4541                 }
4542
4543                 // if the current wave of this wing is 0, then we haven't created the ships in the wing yet.
4544                 // call parse_wing_create_ships to try and create it.  That function will eval the arrival
4545                 // cue of the wing and create the ships if necessary, or if the threshold of the wing has
4546                 // been reached, then try and create more ships
4547                 if ( (wingp->current_wave == 0) || (wingp->current_count <= wingp->threshold) ) {
4548                         int created;
4549
4550                         created = parse_wing_create_ships( wingp, wingp->wave_count );
4551
4552                         // if we created ships in this wing, check to see if the wings was int the reinforcements
4553                         // array.  If so, then if we have more uses, then reset the reinforcement flag for the wing
4554                         // so the user can call in another set if need be.
4555                         if ( created > 0 ) {
4556                                 int rship;
4557
4558                                 mission_parse_do_initial_docks();               // maybe create other initially docked ships
4559                                 if ( Wings[i].flags & WF_RESET_REINFORCEMENT ) {
4560                                         Wings[i].flags &= ~WF_RESET_REINFORCEMENT;
4561                                         Wings[i].flags |= WF_REINFORCEMENT;
4562                                 }
4563
4564                                 // possibly send a message to the player when this wing arrives.
4565                                 if ( wingp->flags & WF_NO_ARRIVAL_MESSAGE ){
4566                                         continue;
4567                                 }
4568
4569                                 // multiplayer team vs. team
4570                                 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
4571                                         // send a hostile wing arrived message
4572                                         rship = Wings[i].ship_index[0];
4573
4574                                         int multi_team_filter = Ships[rship].team == TEAM_FRIENDLY ? 1 : 0;
4575
4576                                         // there are two timestamps at work here.  One to control how often the player receives
4577                                         // messages about incoming hostile waves, and the other to control how long after
4578                                         // the wing arrives does the player actually get the message.
4579                                         if ( timestamp_elapsed(Allow_arrival_message_timestamp_m[multi_team_filter]) ) {
4580                                                 if ( !timestamp_valid(Arrival_message_delay_timestamp_m[multi_team_filter]) ){
4581                                                         Arrival_message_delay_timestamp_m[multi_team_filter] = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4582                                                 }
4583                                                 Allow_arrival_message_timestamp_m[multi_team_filter] = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);                                       
4584                                                 
4585                                                 // send to the proper team
4586                                                 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, multi_team_filter );
4587                                         }
4588                                 } 
4589                                 // everything else
4590                                         else {
4591                                         // see if this is a starting player wing
4592                                         if ( i == Starting_wings[STARTING_WING_BETA] ) {                                        // this is the beta wing
4593                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4594                                                 if ( rship != -1 ){
4595                                                         message_send_builtin_to_player( MESSAGE_BETA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4596                                                 }
4597                                         } else if ( i == Starting_wings[STARTING_WING_GAMMA] ) {                        // this is the gamma wing
4598                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4599                                                 if ( rship != -1 ) {
4600                                                         message_send_builtin_to_player( MESSAGE_GAMMA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4601                                                 }
4602                                         } else if ( !SDL_strcasecmp( wingp->name, "delta") ) {
4603                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4604                                                 if ( rship != -1 ) {
4605                                                         message_send_builtin_to_player( MESSAGE_DELTA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4606                                                 }
4607                                         } else if ( !SDL_strcasecmp(wingp->name, "epsilon") ) {
4608                                                 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4609                                                 if ( rship != -1 ) {
4610                                                         message_send_builtin_to_player( MESSAGE_EPSILON_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4611                                                 }
4612                                         } else {
4613                                                 // see if we have a hostile wing that arrived
4614                                                 rship = Wings[i].ship_index[0];
4615                                                 if ( Ships[rship].team != TEAM_FRIENDLY ) {
4616
4617                                                         // there are two timestamps at work here.  One to control how often the player receives
4618                                                         // messages about incoming hostile waves, and the other to control how long after
4619                                                         // the wing arrives does the player actually get the message.
4620                                                         if ( timestamp_elapsed(Allow_arrival_message_timestamp) ) {
4621                                                                 if ( !timestamp_valid(Arrival_message_delay_timestamp) ){
4622                                                                         Arrival_message_delay_timestamp = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4623                                                                 }
4624                                                                 Allow_arrival_message_timestamp = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
4625                                                         }
4626                                                 }
4627                                         }
4628                                 }
4629                         }
4630                 }
4631         }
4632         Mission_arrival_timestamp = timestamp(ARRIVAL_TIMESTAMP);
4633 }
4634
4635 MONITOR(NumShipDepartures);
4636
4637 // called to make object objp depart.
4638 void mission_do_departure( object *objp )
4639 {
4640         ship *shipp;
4641 //      vector v;
4642
4643         MONITOR_INC(NumShipDepartures,1);
4644
4645         SDL_assert ( objp->type == OBJ_SHIP );
4646         shipp = &Ships[objp->instance];
4647
4648         // if departing to a docking bay, try to find the anchor ship to depart to.  If not found, then
4649         // just make it warp out like anything else.
4650         if ( shipp->departure_location == DEPART_AT_DOCK_BAY ) {
4651                 int anchor_shipnum;
4652                 char *name;
4653
4654                 SDL_assert( shipp->departure_anchor >= 0 );
4655                 name = Parse_names[shipp->departure_anchor];
4656
4657                 // see if ship is yet to arrive.  If so, then return -1 so we can evaluate again later.
4658                 if ( mission_parse_get_arrival_ship( name ) )
4659                         goto do_departure_warp;
4660
4661                 // see if ship is in mission.  If not, then we can assume it was destroyed or departed since
4662                 // it is not on the arrival list (as shown by above if statement).
4663                 anchor_shipnum = ship_name_lookup( name );
4664                 if ( anchor_shipnum == -1 )
4665                         goto do_departure_warp;
4666
4667                 ai_acquire_depart_path(objp, Ships[anchor_shipnum].objnum);
4668                 return;
4669         }
4670
4671 do_departure_warp:
4672         ai_set_mode_warp_out( objp, &Ai_info[Ships[objp->instance].ai_index] );
4673
4674 }
4675
4676 // put here because mission_eval_arrivals is here.  Might move these to a better location
4677 // later -- MWA
4678 void mission_eval_departures()
4679 {
4680         int i, j;
4681         object *objp;
4682         wing *wingp;
4683
4684 //      if ( !timestamp_elapsed(Mission_departure_timestamp) )
4685 //              return;
4686
4687         // scan through the active ships an evaluate their departure cues.  For those
4688         // ships whose time has come, set their departing flag.
4689
4690         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4691                 if (objp->type == OBJ_SHIP) {
4692                         ship    *shipp;
4693
4694                         SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
4695
4696                         shipp = &Ships[objp->instance];
4697                         
4698                         // don't process a ship that is already departing or dying or disabled
4699                         // AL 12-30-97: Added SF_CANNOT_WARP to check
4700                         if ( (shipp->flags & (SF_DEPARTING | SF_DYING | SF_CANNOT_WARP )) || ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) ) {
4701                                 continue;
4702                         }
4703
4704                         // don't process ships that are part of a wing -- handled in seperate case
4705                         if ( shipp->wingnum != -1 )
4706                                 continue;
4707
4708 //                              && (!timestamp_valid(shipp->departure_delay) || timestamp_elapsed(shipp->departure_delay)) )
4709                         // when the departure cue becomes true, set off the departure delay timer.  We store the
4710                         // timer as -seconds in Freespace which indicates that the timer has not been set.  If the timer
4711                         // is not set, then turn it into a valid timer and keep evaluating the timer until it is elapsed
4712                         if ( eval_sexp(shipp->departure_cue) ) {
4713                                 if ( shipp->departure_delay <= 0 )
4714                                         shipp->departure_delay = timestamp(-shipp->departure_delay * 1000 );
4715                                 if ( timestamp_elapsed(shipp->departure_delay) )
4716                                         mission_do_departure( objp );
4717                         }
4718                 }
4719         }
4720
4721         // now scan through the list of wings and check their departure cues.  For wings with
4722         // that cue being true, we must update internal variables to indicate that the wing is
4723         // departed and that no further waves of this wing will appear
4724
4725         for ( i = 0; i < num_wings; i++ ) {
4726                 wingp = &Wings[i];
4727
4728                 // should we process this wing anymore
4729                 if ( wingp->flags & WF_WING_DEPARTING )
4730                         continue;
4731
4732                 // evaluate the sexpression.  If true, mark all the ships in this wing as departing and increment
4733                 // the num departed in the wing structure.  Then add number of remaining waves * ships/wave to
4734                 // departed count to get total count of ships in the wing which departed.  (We are counting ships
4735                 // that have not yet arrived as departed if they never arrive -- this may be bad, but for some reason
4736                 // seems like the right thing to do).
4737  //&& (!timestamp_valid(wingp->departure_delay) || timestamp_elapsed(wingp->departure_delay)) ) {
4738
4739                 if ( eval_sexp(wingp->departure_cue) ) {
4740                         // if we haven't set up the departure timer yet (would be <= 0) setup the timer to pop N seconds
4741                         // later
4742                         if ( wingp->departure_delay <= 0 )
4743                                 wingp->departure_delay = timestamp( -wingp->departure_delay * 1000 );
4744                         if ( !timestamp_elapsed(wingp->departure_delay) )
4745                                 continue;
4746
4747                         wingp->flags |= WF_WING_DEPARTING;
4748                         for ( j = 0; j < wingp->current_count; j++ ) {
4749                                 ship *shipp;
4750
4751                                 shipp = &Ships[wingp->ship_index[j]];
4752                                 if ( (shipp->flags & SF_DEPARTING) || (shipp->flags & SF_DYING) )
4753                                         continue;
4754
4755 //                              shipp->flags |= SF_DEPARTING;
4756 //                              shipp->final_depart_time = timestamp(3*1000);
4757
4758                                 SDL_assert ( shipp->objnum != -1 );
4759                                 objp = &Objects[shipp->objnum];
4760
4761                                 // copy the wing's depature information to the ship
4762                                 shipp->departure_location = wingp->departure_location;
4763                                 shipp->departure_anchor = wingp->departure_anchor;
4764
4765                                 mission_do_departure( objp );
4766                                 // don't add to wingp->total_departed here -- this is taken care of in ship code.
4767                         }
4768
4769                         // MWA 2/25/98 -- don't do the follwoing wing member updates.  It makes the accurate counts
4770                         // sort of messed up and causes problems for the event log.  The code in ship_wing_cleanup()
4771                         // now keys off of the WF_WING_DEPARTING flag instead of the counts below.
4772
4773                         /*
4774                         // now be sure that we update wing structure members if there are any remaining waves left
4775                         if ( wingp->current_wave < wingp->num_waves ) {
4776                                 int num_remaining;
4777
4778                                 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
4779                                 wingp->total_departed += num_remaining;
4780                                 wingp->total_arrived_count += num_remaining;
4781                                 wingp->current_wave = wingp->num_waves;
4782                         }
4783                         */
4784
4785                 }
4786         }
4787         Mission_departure_timestamp = timestamp(DEPARTURE_TIMESTAMP);
4788 }
4789
4790 // function called from high level game loop to do mission evaluation stuff
4791 void mission_parse_eval_stuff()
4792 {
4793         mission_eval_arrivals();
4794         mission_eval_departures();
4795 }
4796
4797 int allocate_subsys_status()
4798 {
4799         int i;
4800
4801         SDL_assert(Subsys_index < MAX_SUBSYS_STATUS);
4802         Subsys_status[Subsys_index].percent = 0.0f;
4803         Subsys_status[Subsys_index].primary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4804         for (i=1; i<MAX_PRIMARY_BANKS; i++)
4805                 Subsys_status[Subsys_index].primary_banks[i] = -1;  // none
4806
4807         Subsys_status[Subsys_index].secondary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4808         Subsys_status[Subsys_index].secondary_ammo[0] = 100;
4809         for (i=1; i<MAX_SECONDARY_BANKS; i++) {
4810                 Subsys_status[Subsys_index].secondary_banks[i] = -1;
4811                 Subsys_status[Subsys_index].secondary_ammo[i] = 100;
4812         }
4813
4814         Subsys_status[Subsys_index].ai_class = SUBSYS_STATUS_NO_CHANGE;
4815         return Subsys_index++;
4816 }
4817
4818 // find (or add) the name in the list and return an index to it.
4819 int get_parse_name_index(const char *name)
4820 {
4821         int i;
4822
4823         for (i=0; i<Num_parse_names; i++)
4824                 if (!SDL_strcasecmp(name, Parse_names[i]))
4825                         return i;
4826
4827         SDL_assert(i < MAX_SHIPS + MAX_WINGS);
4828         SDL_assert(strlen(name) < NAME_LENGTH);
4829         SDL_strlcpy(Parse_names[i], name, NAME_LENGTH);
4830         return Num_parse_names++;
4831 }
4832
4833 int get_anchor(char *name)
4834 {
4835         int i;
4836
4837         for (i=0; i<MAX_SPECIAL_ARRIVAL_ANCHORS; i++)
4838                 if (!SDL_strcasecmp(name, Special_arrival_anchor_names[i]))
4839                         return SPECIAL_ARRIVAL_ANCHORS_OFFSET + i;
4840
4841         return get_parse_name_index(name);
4842 }
4843
4844 // function to fixup the goals/ai references for player objects in the mission
4845 void mission_parse_fixup_players()
4846 {
4847         object *objp;
4848
4849         // merge created list to have all objects on used list
4850         obj_merge_created_list();
4851         for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4852                 if ( (objp->type == OBJ_SHIP) && (objp->flags & OF_PLAYER_SHIP) ) {
4853                         ai_clear_ship_goals( &Ai_info[Ships[objp->instance].ai_index] );
4854                         init_ai_object( OBJ_INDEX(objp) );
4855                 }
4856         }
4857 }
4858
4859 // code to warp in a new support ship.  It works by finding the average position of all ships
4860 // in the mission, creating a vector from that position to the player, and scaling out behind the
4861 // player some distance.  Should be sufficient.
4862
4863 #define WARP_IN_MIN_DISTANCE    1000.0f
4864 #define WARP_IN_TIME_MIN                3000                            // warps in min 3 seconds later
4865 #define WARP_IN_TIME_MAX                6000                            // warps in max 6 seconds later
4866
4867 // function which adds requester_objp onto the queue of ships for the arriving support ship to service
4868 void mission_add_to_arriving_support( object *requester_objp )
4869 {
4870         int i;
4871         ship *shipp;
4872
4873         SDL_assert ( Arriving_support_ship );
4874
4875         if ( Num_arriving_repair_targets == MAX_AI_GOALS ) {
4876                 // Int3();                      // get allender -- ship isn't going to get repair, but I hope they never queue up this far!!!
4877                 mprintf(("Reached MAX_AI_GOALS trying to add repair request!\n"));
4878                 return;
4879         }
4880
4881         shipp = &Ships[requester_objp->instance];
4882         // check for duplicates before adding
4883         for (i = 0; i < Num_arriving_repair_targets; i++ ) {
4884                 if ( !SDL_strcasecmp(Arriving_repair_targets[i], shipp->ship_name) ){
4885                         break;
4886                 }
4887         }
4888         if ( i != Num_arriving_repair_targets ){                // found the ship before reaching the end -- ignore it!
4889                 return;
4890         }
4891
4892         SDL_strlcpy( Arriving_repair_targets[Num_arriving_repair_targets], Ships[requester_objp->instance].ship_name, NAME_LENGTH );
4893         Num_arriving_repair_targets++;
4894
4895         if ( MULTIPLAYER_MASTER ){
4896                 multi_maybe_send_repair_info( requester_objp, NULL, REPAIR_INFO_WARP_ADD );
4897         }       
4898 }
4899
4900 extern int pp_collide_any(vector *curpos, vector *goalpos, float radius, object *ignore_objp1, object *ignore_objp2, int big_only_flag);
4901
4902 //      Set the warp in position for a support ship relative to an object.
4903 //      Caller tries several positions, passing vector in x, y, z.
4904 int get_warp_in_pos(vector *pos, object *objp, float x, float y, float z)
4905 {
4906         float   rand_val;
4907
4908         if ( Game_mode & GM_NORMAL )
4909                 rand_val = frand();
4910         else
4911                 rand_val = static_randf(objp->net_signature);
4912
4913         rand_val = 1.0f + (rand_val - 0.5f)*0.2f;
4914
4915         *pos = objp->pos;
4916
4917         vm_vec_scale_add2( pos, &objp->orient.v.rvec, x*rand_val*800.0f);
4918         vm_vec_scale_add2( pos, &objp->orient.v.uvec, y*rand_val*800.0f);
4919         vm_vec_scale_add2( pos, &objp->orient.v.fvec, z*rand_val*800.0f);
4920
4921         return pp_collide_any(&objp->pos, pos, objp->radius, objp, NULL, 1);
4922 }
4923
4924 void mission_warp_in_support_ship( object *requester_objp )
4925 {
4926         vector center, warp_in_pos;
4927         //float mag;
4928         p_object *pobj;
4929         int i, requester_species;
4930         ship *requester_shipp;
4931
4932         SDL_assert ( requester_objp->type == OBJ_SHIP );
4933         requester_shipp = &Ships[requester_objp->instance];     //      MK, 10/23/97, used to be ->type, bogus, no?
4934
4935         // if the support ship is already arriving, add the requester to the list
4936         if ( Arriving_support_ship ) {
4937                 mission_add_to_arriving_support( requester_objp );
4938                 return;
4939         }
4940         
4941         // get average position of all ships
4942         obj_get_average_ship_pos( &center );
4943         vm_vec_sub( &warp_in_pos, &center, &(requester_objp->pos) );
4944
4945         // be sure to account for case as player being only ship left in mission
4946         /*
4947         if ( !(IS_VEC_NULL( warp_in_pos)) ) {
4948                 mag = vm_vec_mag( &warp_in_pos );
4949                 if ( mag < WARP_IN_MIN_DISTANCE )
4950                         vm_vec_scale( &warp_in_pos, WARP_IN_MIN_DISTANCE/mag);
4951                 else
4952                         vm_vec_scale( &warp
4953         } else {
4954                 // take -player_pos.fvec scaled by 1000.0f;
4955                 warp_in_pos = Player_obj->orient.fvec;
4956                 vm_vec_scale( &warp_in_pos, -1000.0f );
4957         }
4958         */
4959
4960         //      Choose position to warp in ship.
4961         //      Temporary, but changed by MK because it used to be exactly behind the player.
4962         //      This could cause an SDL_assert if the player immediately targeted it (before moving).
4963         //      Tend to put in front of the player to aid him in flying towards the ship.
4964
4965         if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.1f, 1.0f))
4966                 if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.2f, -1.0f))
4967                         if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.2f, -1.0f))
4968                                 if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.1f, 1.0f))
4969                                         get_warp_in_pos(&warp_in_pos, requester_objp, 0.1f, 1.0f, 0.2f);
4970
4971         // create a parse object, and put it onto the ship_arrival_list.  This whole thing kind of sucks.
4972         // I want to put it into a parse object since it needs to arrive just a little later than
4973         // this function is called.  I have to make some assumptions in the code about values for the parse
4974         // object since I'm no longer working with a mission file.  These exceptions will be noted with
4975         // comments
4976
4977         Arriving_support_ship = &Support_ship_pobj;
4978         pobj = Arriving_support_ship;
4979
4980         // create a name for the ship.  use "Support #".  look for collisions until one isn't found anymore
4981         i = 1;
4982         do {
4983                 SDL_snprintf(pobj->name, SDL_arraysize(pobj->name), NOX("Support %d"), i);
4984                 if ( (ship_name_lookup(pobj->name) == -1) && (ship_find_exited_ship_by_name(pobj->name) == -1) )
4985                         break;
4986                 i++;
4987         } while(1);
4988
4989         pobj->pos = warp_in_pos;
4990         vm_set_identity( &(pobj->orient) );
4991
4992         // *sigh*.  Gotta get the ship class.  For now, this will amount to finding a ship in the ship_info
4993         // array with the same team as the requester of type SIF_SUPPORT.  Might need to be changed, but who knows
4994         // vasudans use the terran support ship.
4995         requester_species = Ship_info[requester_shipp->ship_info_index].species;
4996
4997         // 5/6/98 -- MWA  Don't need to do anything for multiplayer.  I think that we always want to use
4998         // the species of the caller ship.
4999         SDL_assert( (requester_species == SPECIES_TERRAN) || (requester_species == SPECIES_VASUDAN) );
5000 //      if ( (Game_mode & GM_NORMAL) && (requester_species == SPECIES_VASUDAN) )        {       // make vasundan's use the terran support ship
5001 //              requester_species = SPECIES_TERRAN;
5002 //      }
5003
5004         // get index of correct species support ship
5005         for (i=0; i < Num_ship_types; i++) {
5006                 if ( (Ship_info[i].species == requester_species) && (Ship_info[i].flags & SIF_SUPPORT) )
5007                         break;
5008         }
5009
5010         if ( i < Num_ship_types )
5011                 pobj->ship_class = i;
5012         else
5013                 Int3();                         // BOGUS!!!!  gotta figure something out here
5014
5015         pobj->team = requester_shipp->team;
5016
5017         pobj->behavior = AIM_NONE;              // ASSUMPTION:  the mission file has the string "None" which maps to AIM_NONE
5018
5019         // set the ai_goals to -1.  We will put the requester object shipname in repair target array and then take
5020         // care of setting up the goal when creating the ship!!!!
5021         pobj->ai_goals = -1;
5022         Num_arriving_repair_targets = 0;
5023         mission_add_to_arriving_support( requester_objp );
5024
5025         // need to set ship's cargo to nothing.  scan the cargo_names array looking for the string nothing.
5026         // add it if not found
5027         for (i = 0; i < Num_cargo; i++ )
5028                 if ( !SDL_strcasecmp(Cargo_names[i], NOX("nothing")) )
5029                         break;
5030
5031         if ( i == Num_cargo ) {
5032                 SDL_strlcpy(Cargo_names[i], NOX("Nothing"), NAME_LENGTH);
5033                 Num_cargo++;
5034         }
5035         pobj->cargo1 = char(i);
5036
5037         pobj->status_count = 0;
5038
5039         pobj->arrival_location = 0;                     // ASSUMPTION: this is index to arrival_lcation string array for hyperspace!!!!
5040         pobj->arrival_distance = 0;
5041         pobj->arrival_anchor = -1;
5042         pobj->arrival_cue = Locked_sexp_true;
5043         pobj->arrival_delay = timestamp_rand(WARP_IN_TIME_MIN, WARP_IN_TIME_MAX);
5044
5045         pobj->subsys_count = 0;                         // number of elements used in subsys_status array
5046         pobj->initial_velocity = 100;           // start at 100% velocity
5047         pobj->initial_hull = 100;                       // start at 100% hull   
5048         pobj->initial_shields = 100;            // and 100% shields
5049
5050         pobj->departure_location = 0;           // ASSUMPTION: this is index to departure_lcation string array for hyperspace!!!!
5051         pobj->departure_anchor = -1;
5052         pobj->departure_cue = Locked_sexp_false;
5053         pobj->departure_delay= 0;
5054
5055         pobj->determination = 10;                       // ASSUMPTION:  mission file always had this number written out
5056         pobj->wingnum = -1;
5057         if ( Player_obj->flags & P_OF_NO_SHIELDS )
5058                 pobj->flags = P_OF_NO_SHIELDS;  // support ships have no shields when player has not shields
5059
5060         pobj->ai_class = Ship_info[pobj->ship_class].ai_class;
5061         pobj->hotkey = -1;
5062         pobj->score = 0;
5063
5064         pobj->docked_with[0] = '\0';
5065         pobj->group = -1;
5066         pobj->persona_index = -1;
5067         pobj->net_signature = multi_assign_network_signature(MULTI_SIG_SHIP);
5068         pobj->wing_status_wing_index = -1;
5069         pobj->wing_status_wing_pos = -1;
5070         pobj->respawn_count = 0;
5071         pobj->alt_type_index = -1;
5072
5073 }
5074
5075 // returns true if a support ship is currently in the process of warping in.
5076 int mission_is_support_ship_arriving()
5077 {
5078         if ( Arriving_support_ship )
5079                 return 1;
5080         else
5081                 return 0;
5082 }
5083
5084 // returns true if the given ship is scheduled to be repaired by the arriving support ship
5085 int mission_is_repair_scheduled( object *objp )
5086 {
5087         char *name;
5088         int i;
5089
5090         if ( !Arriving_support_ship )
5091                 return 0;
5092
5093         SDL_assert ( objp->type == OBJ_SHIP );
5094         name = Ships[objp->instance].ship_name;
5095         for (i = 0; i < Num_arriving_repair_targets; i++ ) {
5096                 if ( !strcmp( name, Arriving_repair_targets[i]) )
5097                         return 1;
5098         }
5099
5100         return 0;
5101 }
5102
5103 // function which removed the given ship from the list of ships that are to get repair
5104 // by arriving support ship
5105 int mission_remove_scheduled_repair( object *objp )
5106 {
5107         char *name;
5108         int i, index;
5109
5110         if ( !Arriving_support_ship )
5111                 return 0;
5112
5113         // itereate through the target list looking for this ship name.  If not found, we
5114         // can simply return.
5115         SDL_assert ( objp->type == OBJ_SHIP );
5116         name = Ships[objp->instance].ship_name;
5117         for (index = 0; index < Num_arriving_repair_targets; index++ ) {
5118                 if ( !strcmp( name, Arriving_repair_targets[index]) )
5119                         break;
5120         }
5121         if ( index == Num_arriving_repair_targets )
5122                 return 0;
5123
5124         // ship is found -- compress the array
5125         for ( i = index; i < Num_arriving_repair_targets - 1; i++ )
5126                 SDL_strlcpy( Arriving_repair_targets[i], Arriving_repair_targets[i+1], NAME_LENGTH );
5127
5128         Num_arriving_repair_targets--;
5129
5130         if ( MULTIPLAYER_MASTER )
5131                 multi_maybe_send_repair_info( objp, NULL, REPAIR_INFO_WARP_REMOVE );
5132
5133         return 1;
5134 }
5135
5136 // alternate name stuff
5137 int mission_parse_lookup_alt(char *name)
5138 {
5139         int idx;
5140
5141         // sanity
5142         if(name == NULL){
5143                 return -1;
5144         }
5145
5146         // lookup
5147         for(idx=0; idx<Mission_alt_type_count; idx++){
5148                 if(!strcmp(Mission_alt_types[idx], name)){
5149                         return idx;
5150                 }
5151         }
5152
5153         // could not find
5154         return -1;
5155 }
5156
5157 static int mission_parse_lookup_alt_index_warn = 1;
5158 void mission_parse_lookup_alt_index(int index, char *out, const int max_outlen)
5159 {
5160         // sanity
5161         if(out == NULL){
5162                 return;
5163         }
5164         if((index < 0) || (index > Mission_alt_type_count)){
5165                 if (mission_parse_lookup_alt_index_warn) {
5166                         Warning(LOCATION, "Ship with invalid alt_name.  Get a programmer");
5167                         mission_parse_lookup_alt_index_warn = 0;
5168                 }
5169                 return;
5170         }
5171
5172         // stuff it
5173         SDL_strlcpy(out, Mission_alt_types[index], max_outlen);
5174 }
5175
5176 int mission_parse_add_alt(char *name)
5177 {
5178         // sanity
5179         if(name == NULL){
5180                 return -1;
5181         }
5182
5183         // maybe add
5184         if(Mission_alt_type_count < MAX_ALT_TYPE_NAMES){
5185                 // stuff the name
5186                 SDL_strlcpy(Mission_alt_types[Mission_alt_type_count++], name, NAME_LENGTH);
5187
5188                 // done
5189                 return Mission_alt_type_count - 1;
5190         }
5191
5192         return -1;
5193 }
5194
5195 void mission_parse_reset_alt()
5196 {
5197         Mission_alt_type_count = 0;
5198 }
5199
5200 int is_training_mission()
5201 {
5202         return (The_mission.game_type & MISSION_TYPE_TRAINING);
5203 }
5204