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