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