2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Mission/MissionParse.cpp $
15 * main upper level code for pasring stuff
18 * Revision 1.7 2005/10/01 22:04:58 taylor
19 * fix FS1 (de)briefing voices, the directory names are different in FS1
20 * hard code the table values so that the fs1.vp file isn't needed
21 * hard code a mission fix for sm2-08a since a have no idea how to fix it otherwise
22 * generally cleanup some FS1 code
23 * fix volume sliders in the options screen that never went all the way up
25 * Revision 1.6 2003/08/14 02:39:11 theoddone33
26 * Removed braces from initializers so GCC 3 will stop complaining.
28 * Revision 1.5 2003/05/25 02:30:43 taylor
31 * Revision 1.4 2002/06/17 06:33:09 relnev
32 * ryan's struct patch for gcc 2.95
34 * Revision 1.3 2002/06/09 04:41:22 relnev
35 * added copyright header
37 * Revision 1.2 2002/05/07 03:16:46 theoddone33
38 * The Great Newline Fix
40 * Revision 1.1.1.1 2002/05/03 03:28:09 root
44 * 63 9/12/99 8:09p Dave
45 * Fixed problem where skip-training button would cause mission messages
46 * not to get paged out for the current mission.
48 * 62 9/09/99 3:53a Andsager
49 * Only reposition HUGE ships to center of knossos device on warp in
51 * 61 8/27/99 9:07p Dave
52 * LOD explosions. Improved beam weapon accuracy.
54 * 60 8/26/99 8:51p Dave
55 * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
57 * 59 8/25/99 10:06a Jefff
58 * vasudan pilots get a vasudan support ship.
60 * 58 8/24/99 5:27p Andsager
61 * Make subsystems with zero strength before mission blown off. Protect
62 * red alert pilot against dying between orders and jump.
64 * 57 8/18/99 10:07p Johnson
65 * Fix Fred bug in positioning of Knossos device (when trying to warp in
68 * 56 8/18/99 3:57p Andsager
69 * Add warning for invalid alt_name.
71 * 55 8/18/99 3:48p Andsager
72 * Make support ship take default name and not 0th alt_name.
74 * 54 8/16/99 3:53p Andsager
75 * Add special warp in interface in Fred and saving / reading.
77 * 53 8/16/99 2:01p Andsager
78 * Knossos warp-in warp-out.
80 * 52 8/03/99 5:35p Andsager
81 * Dont draw target dot for instructor in training mission
83 * 51 7/30/99 7:01p Dave
84 * Dogfight escort gauge. Fixed up laser rendering in Glide.
86 * 50 7/28/99 1:36p Andsager
87 * Modify cargo1 to include flag CARGO_NO_DEPLETE. Add sexp
88 * cargo-no-deplete (only for BIG / HUGE). Modify ship struct to pack
91 * 49 7/26/99 5:50p Dave
92 * Revised ingame join. Better? We'll see....
94 * 48 7/19/99 3:01p Dave
95 * Fixed icons. Added single transport icon.
97 * 47 7/15/99 9:20a Andsager
98 * FS2_DEMO initial checkin
100 * 46 7/13/99 5:03p Alanl
101 * make sure object sounds get assigned to ships
103 * 45 7/11/99 2:14p Dave
104 * Added Fred names for the new icon types.
106 * 44 7/02/99 4:\31p Dave
107 * Much more sophisticated lightning support.
109 * 43 7/01/99 4:23p Dave
110 * Full support for multiple linked ambient engine sounds. Added "big
113 * 42 6/28/99 4:51p Andsager
114 * Add ship-guardian sexp (does not allow ship to be killed)
116 * 41 6/21/99 1:34p Alanl
119 * 40 6/16/99 10:20a Dave
120 * Added send-message-list sexpression.
122 * 39 6/14/99 2:06p Andsager
123 * Default load brown asteroids
125 * 38 6/10/99 11:06a Andsager
126 * Mission designed selection of asteroid types.
128 * 37 6/03/99 6:37p Dave
129 * More TNT fun. Made perspective bitmaps more flexible.
131 * 36 5/20/99 7:00p Dave
132 * Added alternate type names for ships. Changed swarm missile table
135 * 35 4/26/99 8:49p Dave
136 * Made all pof based nebula stuff full customizable through fred.
138 * 34 4/26/99 12:49p Andsager
139 * Add protect object from beam support to Fred
141 * 33 4/16/99 2:34p Andsager
142 * Second pass on debris fields
144 * 32 4/15/99 5:00p Andsager
145 * Frist pass on Debris field
147 * 31 4/07/99 6:22p Dave
148 * Fred and Freespace support for multiple background bitmaps and suns.
149 * Fixed link errors on all subprojects. Moved encrypt_init() to
150 * cfile_init() and lcl_init(), since its safe to call twice.
152 * 30 3/31/99 9:52a Andsager
153 * generalization for debris field
155 * 29 3/30/99 5:40p Dave
156 * Fixed reinforcements for TvT in multiplayer.
158 * 28 3/29/99 6:17p Dave
159 * More work on demo system. Got just about everything in except for
160 * blowing ships up, secondary weapons and player death/warpout.
162 * 27 3/24/99 6:23p Dave
163 * Make sure we only apply squadron changes to the player in single-player
166 * 26 3/24/99 4:05p Dave
167 * Put in support for assigning the player to a specific squadron with a
168 * specific logo. Preliminary work for doing pos/orient checksumming in
169 * multiplayer to reduce bandwidth.
171 * 25 3/01/99 7:39p Dave
172 * Added prioritizing ship respawns. Also fixed respawns in TvT so teams
173 * don't mix respawn points.
175 * 24 2/26/99 6:01p Andsager
176 * Add sexp has-been-tagged-delay and cap-subsys-cargo-known-delay
178 * 23 2/24/99 2:25p Dave
179 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
180 * bug for dogfight more.
182 * 22 2/23/99 8:11p Dave
183 * Tidied up dogfight mode. Fixed TvT ship type problems for alpha wing.
184 * Small pass over todolist items.
186 * 21 2/17/99 2:10p Dave
187 * First full run of squad war. All freespace and tracker side stuff
190 * 20 2/11/99 3:08p Dave
191 * PXO refresh button. Very preliminary squad war support.
193 * 19 2/11/99 2:15p Andsager
194 * Add ship explosion modification to FRED
196 * 18 2/07/99 8:51p Andsager
197 * Add inner bound to asteroid field. Inner bound tries to stay astroid
198 * free. Wrap when within and don't throw at ships inside.
200 * 17 2/05/99 10:38a Johnson
201 * Fixed improper object array reference.
203 * 16 2/04/99 1:23p Andsager
204 * Apply max spark limit to ships created in mission parse
206 * 15 2/03/99 12:42p Andsager
207 * Add escort priority. Modify ship_flags_dlg to include field. Save and
208 * Load. Add escort priority field to ship.
210 * 14 1/27/99 9:56a Dave
211 * Temporary checkin of beam weapons for Dan to make cool sounds.
213 * 13 1/25/99 5:03a Dave
214 * First run of stealth, AWACS and TAG missile support. New mission type
217 * 12 1/19/99 3:57p Andsager
218 * Round 2 of variables
220 * 11 1/07/99 1:52p Andsager
221 * Initial check in of Sexp_variables
223 * 10 11/14/98 5:32p Dave
224 * Lots of nebula work. Put in ship contrails.
226 * 9 11/12/98 12:13a Dave
227 * Tidied code up for multiplayer test. Put in network support for flak
230 * 8 11/05/98 5:55p Dave
231 * Big pass at reducing #includes
233 * 7 11/05/98 4:18p Dave
234 * First run nebula support. Beefed up localization a bit. Removed all
235 * conditional compiles for foreign versions. Modified mission file
238 * 6 10/29/98 9:23p Dave
239 * Removed minor bug concerning externalization of campaign files.
241 * 5 10/23/98 3:51p Dave
242 * Full support for tstrings.tbl and foreign languages. All that remains
243 * is to make it active in Fred.
245 * 4 10/20/98 10:44a Andsager
246 * Add comment for creating sparks before mission starts
248 * 3 10/07/98 6:27p Dave
249 * Globalized mission and campaign file extensions. Removed Silent Threat
250 * special code. Moved \cache \players and \multidata into the \data
253 * 2 10/07/98 10:53a Dave
256 * 1 10/07/98 10:49a Dave
258 * 503 9/21/98 8:46p Dave
259 * Put in special check in fred for identifying unknown ships.
261 * 502 9/14/98 5:09p Dave
262 * Massive hack to always ignore m-clash
264 * 501 9/14/98 3:40p Allender
265 * better error checking for invalid number of waves for player wings in a
266 * multiplayer game. Better popup message in FreeSpace side.
268 * 500 9/11/98 2:05p Allender
269 * make reinforcements work correctly in multiplayer games. There still
270 * may be a team vs team issue that I haven't thought of yet :-(
272 * 499 8/07/98 9:48a Allender
273 * changed how SF_FROM_PLAYER_WING is assigned for team vs. team games
275 * 498 7/16/98 2:22p Allender
276 * don't do wave check in single player
278 * 497 7/13/98 5:19p Dave
280 * 496 7/13/98 3:15p Allender
281 * don't allow multiple waves for any player wings
283 * 495 7/10/98 12:11a Allender
284 * fixed problem where missions files of 0 length would cause game to
287 * 494 5/21/98 3:31p Allender
288 * fix bug where Ship_obj_list was getting overwritten by the exited ships
291 * 493 5/20/98 1:04p Hoffoss
292 * Made credits screen use new artwork and removed rating field usage from
293 * Fred (a goal struct member).
295 * 492 5/18/98 4:41p Comet
296 * allender: fix problem where ships in wings were not deleted on clients
297 * when a new wing create packet came in. A serious hack of all hacks
299 * 491 5/18/98 3:37p Jasen
300 * move Int3() about too many ships in wing to before where ship actually
303 * 490 5/18/98 1:58a Mike
304 * Make Phoenix not be fired at fighters (but yes bombers).
305 * Improve positioning of ships in guard mode.
306 * Make turrets on player ship not fire near end of support ship docking.
308 * 489 5/15/98 9:52a Allender
309 * added code to give Warning when orders accepted don't match the default
312 * 488 5/13/98 4:41p Mike
313 * Make big ships try a tiny bit to avoid collision with each other when
314 * attacking another big ship. Make ships a little less likely to collide
315 * into player when in formation, drop off if player flying wacky.
317 * 487 5/13/98 3:07p Mitri
318 * fixed problem with checking current count of the mission against max
321 * 486 5/11/98 4:33p Allender
322 * fixed ingame join problems -- started to work on new object updating
323 * code (currently ifdef'ed out)
325 * 485 5/08/98 5:05p Dave
326 * Go to the join game screen when quitting multiplayer. Fixed mission
327 * text chat bugs. Put mission type symbols on the create game list.
328 * Started updating standalone gui controls.
340 #include "freespace.h"
342 #include "missionparse.h"
343 #include "missiongoals.h"
344 #include "missionlog.h"
345 #include "missionmessage.h"
347 #include "linklist.h"
353 #include "starfield.h"
355 #include "lighting.h"
356 #include "eventmusic.h"
357 #include "missionbriefcommon.h"
359 #include "multiutil.h"
360 #include "multimsgs.h"
364 #include "fireballs.h"
366 #include "gamesequence.h"
371 #include "missionhotkey.h"
372 #include "hudescort.h"
373 #include "asteroid.h"
375 #include "staticrand.h"
376 #include "missioncmdbrief.h"
377 #include "redalert.h"
378 #include "multi_respawn.h"
379 #include "hudwingmanstatus.h"
380 #include "jumpnode.h"
381 #include "multi_endgame.h"
382 #include "localize.h"
385 #include "neblightning.h"
390 char dockee[NAME_LENGTH];
391 char docker_point[NAME_LENGTH];
392 char dockee_point[NAME_LENGTH];
393 } Initially_docked[MAX_SHIPS];
395 int Total_initially_docked;
398 char Mission_filename[80];
400 int Mission_palette; // index into Nebula_palette_filenames[] of palette file to use for mission
401 int Nebula_index; // index into Nebula_filenames[] of nebula to use in mission.
402 int Num_iff = MAX_IFF;
403 int Num_ai_behaviors = MAX_AI_BEHAVIORS;
405 int Num_status_names = MAX_STATUS_NAMES;
406 int Num_arrival_names = MAX_ARRIVAL_NAMES;
407 int Num_goal_type_names = MAX_GOAL_TYPE_NAMES;
408 int Num_team_names = MAX_TEAM_NAMES;
410 int Player_starts = 1;
412 fix Entry_delay_time;
414 ushort Current_file_checksum = 0;
415 ushort Last_file_checksum = 0;
416 int Current_file_length = 0;
418 // alternate ship type names
419 char Mission_alt_types[MAX_ALT_TYPE_NAMES][NAME_LENGTH];
420 int Mission_alt_type_count = 0;
422 #define SHIP_WARP_TIME 5.0f // how many seconds it takes for ship to warp in
424 // the ship arrival list will contain a list of ships that are yet to arrive. This
425 // list could also include ships that are part of wings!
427 p_object ship_arrivals[MAX_SHIP_ARRIVALS], ship_arrival_list; // for linked list of ships to arrive later
428 int num_ship_arrivals;
430 #define MAX_SHIP_ORIGINAL 100
431 p_object ship_original[MAX_SHIP_ORIGINAL];
432 int num_ship_original;
434 // list for arriving support ship
435 p_object Support_ship_pobj;
436 p_object *Arriving_support_ship;
437 char Arriving_repair_targets[MAX_AI_GOALS][NAME_LENGTH];
438 int Num_arriving_repair_targets;
440 subsys_status Subsys_status[MAX_SUBSYS_STATUS];
443 char Mission_parse_storm_name[NAME_LENGTH] = "none";
445 team_data Team_data[MAX_TEAMS];
447 // variables for player start in single player
448 char Player_start_shipname[NAME_LENGTH];
449 int Player_start_shipnum;
450 p_object Player_start_pobject;
452 // name of all ships to use while parsing a mission (since a ship might be referenced by
453 // something before that ship has even been loaded yet)
454 char Parse_names[MAX_SHIPS + MAX_WINGS][NAME_LENGTH];
459 const char *Nebula_filenames[NUM_NEBULAS] = {
465 const char *Neb2_filenames[NUM_NEBULAS] = {
471 // Note: Nebula_colors[] and Nebula_palette_filenames are linked via index numbers
472 const char *Nebula_colors[NUM_NEBULA_COLORS] = {
484 const char *Iff_names[MAX_IFF] = { "IFF 1", "IFF 2", "IFF 3" };
486 const char *Ai_behavior_names[MAX_AI_BEHAVIORS] = {
510 char *Cargo_names[MAX_CARGO];
511 char Cargo_names_buf[MAX_CARGO][NAME_LENGTH];
513 char *Ship_class_names[MAX_SHIP_TYPES]; // to be filled in from Ship_info array
515 const char *Icon_names[MAX_BRIEF_ICONS] = {
516 "Fighter", "Fighter Wing", "Cargo", "Cargo Wing", "Largeship",
517 "Largeship Wing", "Capital", "Planet", "Asteroid Field", "Waypoint",
518 "Support Ship", "Freighter(no cargo)", "Freighter(has cargo)",
519 "Freighter Wing(no cargo)", "Freighter Wing(has cargo)", "Installation",
520 "Bomber", "Bomber Wing", "Cruiser", "Cruiser Wing", "Unknown", "Unknown Wing",
521 "Player Fighter", "Player Fighter Wing", "Player Bomber", "Player Bomber Wing",
525 "Knossos Device", "Transport Wing", "Corvette", "Gas Miner", "Awacs", "Supercap", "Sentry Gun", "Jump Node", "Transport"
529 // Translate team mask values like TEAM_FRIENDLY to indices in Team_names array.
530 // -1 means an illegal value.
531 int Team_names_index_xlate[MAX_TEAM_NAMES_INDEX+1] = {-1, 0, 1, -1, 2, -1, -1, -1, 3};
533 const char *Team_names[MAX_TEAM_NAMES] = {
534 "Hostile", "Friendly", "Neutral", "Unknown",
537 const char *Status_desc_names[MAX_STATUS_NAMES] = {
538 "Shields Critical", "Engines Damaged", "Fully Operational",
541 const char *Status_type_names[MAX_STATUS_NAMES] = {
542 "Damaged", "Disabled", "Corroded",
545 const char *Status_target_names[MAX_STATUS_NAMES] = {
546 "Weapons", "Engines", "Cable TV",
549 // definitions for arrival locations for ships/wings
550 const char *Arrival_location_names[MAX_ARRIVAL_NAMES] = {
551 "Hyperspace", "Near Ship", "In front of ship", "Docking Bay",
554 const char *Special_arrival_anchor_names[MAX_SPECIAL_ARRIVAL_ANCHORS] =
559 "<any friendly player>",
560 "<any hostile player>",
561 "<any neutral player>",
564 const char *Departure_location_names[MAX_ARRIVAL_NAMES] = {
565 "Hyperspace", "Docking Bay",
568 const char *Goal_type_names[MAX_GOAL_TYPE_NAMES] = {
569 "Primary", "Secondary", "Bonus",
572 const char *Species_names[MAX_SPECIES_NAMES] = {
573 "Terran", "Vasudan", "Shivan",
576 const char *Reinforcement_type_names[] = {
581 const char *Old_game_types[OLD_MAX_GAME_TYPES] = {
582 "Single Player Only",
584 "Single/Multi Player",
588 const char *Parse_object_flags[MAX_PARSE_OBJECT_FLAGS] = {
601 "hidden-from-sensors",
611 const char *Starting_wing_names[MAX_STARTING_WINGS+1] = {
620 int Num_reinforcement_type_names = sizeof(Reinforcement_type_names) / sizeof(char *);
622 vector Parse_viewer_pos;
623 matrix Parse_viewer_orient;
625 // definitions for timestamps for eval'ing arrival/departure cues
626 int Mission_arrival_timestamp;
627 int Mission_departure_timestamp;
628 fix Mission_end_time;
630 #define ARRIVAL_TIMESTAMP 2000 // every 2 seconds
631 #define DEPARTURE_TIMESTAMP 2200 // every 2.2 seconds -- just to be a little different
633 // calculates a "unique" file signature as a ushort (checksum) and an int (file length)
634 // the amount of The_mission we're going to checksum
635 // WARNING : do NOT call this function on the server - it will overwrite goals, etc
636 #define MISSION_CHECKSUM_SIZE (NAME_LENGTH + NAME_LENGTH + 4 + DATE_TIME_LENGTH + DATE_TIME_LENGTH)
638 // timers used to limit arrival messages and music
639 #define ARRIVAL_MUSIC_MIN_SEPARATION 60000
640 #define ARRIVAL_MESSAGE_MIN_SEPARATION 30000
642 #define ARRIVAL_MESSAGE_DELAY_MIN 2000
643 #define ARRIVAL_MESSAGE_DELAY_MAX 3000
645 static int Allow_arrival_music_timestamp;
646 static int Allow_arrival_message_timestamp;
647 static int Arrival_message_delay_timestamp;
650 static int Allow_arrival_music_timestamp_m[2];
651 static int Allow_arrival_message_timestamp_m[2];
652 static int Arrival_message_delay_timestamp_m[2];
655 void parse_player_info2(mission *pm);
656 void post_process_mission();
657 int allocate_subsys_status();
658 void parse_common_object_data(p_object *objp);
659 void parse_asteroid_fields(mission *pm);
660 int mission_set_arrival_location(int anchor, int location, int distance, int objnum, vector *new_pos, matrix *new_orient);
661 int get_parse_name_index(const char *name);
662 int get_anchor(char *name);
663 void mission_parse_do_initial_docks();
664 void mission_parse_set_arrival_locations();
665 void mission_set_wing_arrival_location( wing *wingp, int num_to_set );
666 int parse_lookup_alt_name(char *name);
668 void parse_mission_info(mission *pm)
671 char game_string[NAME_LENGTH];
673 required_string("#Mission Info");
675 required_string("$Version:");
676 stuff_float(&pm->version);
677 if (pm->version != MISSION_VERSION)
678 mprintf(("Older mission, should update it (%.2f<-->%.2f)", pm->version, MISSION_VERSION));
680 required_string("$Name:");
681 stuff_string(pm->name, F_NAME, NULL);
683 required_string("$Author:");
684 stuff_string(pm->author, F_NAME, NULL);
686 required_string("$Created:");
687 stuff_string(pm->created, F_DATE, NULL);
689 required_string("$Modified:");
690 stuff_string(pm->modified, F_DATE, NULL);
692 required_string("$Notes:");
693 stuff_string(pm->notes, F_NOTES, NULL);
695 if (optional_string("$Mission Desc:"))
696 stuff_string(pm->mission_desc, F_MULTITEXT, NULL, MISSION_DESC_LENGTH);
698 SDL_strlcpy(pm->mission_desc, NOX("No description\n"), sizeof(pm->mission_desc));
700 pm->game_type = MISSION_TYPE_SINGLE; // default to single player only
701 if ( optional_string("+Game Type:")) {
702 // HACK HACK HACK -- stuff_string was changed to *not* ignore carriage returns. Since the
703 // old style missions may have carriage returns, deal with it here.
704 ignore_white_space();
705 stuff_string(game_string, F_NAME, NULL);
706 for ( i = 0; i < OLD_MAX_GAME_TYPES; i++ ) {
707 if ( !SDL_strcasecmp(game_string, Old_game_types[i]) ) {
709 // this block of code is now old mission compatibility code. We specify game
710 // type in a different manner than before.
711 if ( i == OLD_GAME_TYPE_SINGLE_ONLY )
712 pm->game_type = MISSION_TYPE_SINGLE;
713 else if ( i == OLD_GAME_TYPE_MULTI_ONLY )
714 pm->game_type = MISSION_TYPE_MULTI;
715 else if ( i == OLD_GAME_TYPE_SINGLE_MULTI )
716 pm->game_type = (MISSION_TYPE_SINGLE | MISSION_TYPE_MULTI );
717 else if ( i == OLD_GAME_TYPE_TRAINING )
718 pm->game_type = MISSION_TYPE_TRAINING;
722 if ( pm->game_type & MISSION_TYPE_MULTI )
723 pm->game_type |= MISSION_TYPE_MULTI_COOP;
730 if ( optional_string("+Game Type Flags:") ) {
731 stuff_int(&pm->game_type);
735 if (optional_string("+Flags:")){
736 stuff_int(&pm->flags);
739 // nebula mission stuff
741 if(optional_string("+NebAwacs:")){
742 if(pm->flags & MISSION_FLAG_FULLNEB){
743 stuff_float(&Neb2_awacs);
749 if(optional_string("+Storm:")){
750 stuff_string(Mission_parse_storm_name, F_NAME, NULL);
751 nebl_set_storm(Mission_parse_storm_name);
754 // get the number of players if in a multiplayer mission
756 if ( pm->game_type & MISSION_TYPE_MULTI ) {
757 if ( optional_string("+Num Players:") ) {
758 stuff_int( &(pm->num_players) );
762 // get the number of respawns
763 pm->num_respawns = 0;
764 if ( pm->game_type & MISSION_TYPE_MULTI ) {
765 if ( optional_string("+Num Respawns:") ){
766 stuff_int( (int*)&(pm->num_respawns) );
771 if ( optional_string("+Red Alert:")) {
772 stuff_int(&pm->red_alert);
774 red_alert_set_status(pm->red_alert);
777 if ( optional_string("+Scramble:")) {
778 stuff_int(&pm->scramble);
781 pm->disallow_support = 0;
782 if ( optional_string("+Disallow Support:")) {
783 stuff_int(&pm->disallow_support);
786 if (optional_string("+All Teams Attack")){
787 Mission_all_attack = 1;
789 Mission_all_attack = 0;
792 // Maybe delay the player's entry.
793 if (optional_string("+Player Entry Delay:")) {
797 SDL_assert(temp >= 0.0f);
798 Entry_delay_time = fl2f(temp);
801 if (optional_string("+Viewer pos:")){
802 stuff_vector(&Parse_viewer_pos);
805 if (optional_string("+Viewer orient:")){
806 stuff_matrix(&Parse_viewer_orient);
809 // possible squadron reassignment
810 SDL_strlcpy(The_mission.squad_name, "", sizeof(The_mission.squad_name));
811 SDL_strlcpy(The_mission.squad_filename, "", sizeof(The_mission.squad_filename));
812 if(optional_string("+SquadReassignName:")){
813 stuff_string(The_mission.squad_name, F_NAME, NULL);
814 if(optional_string("+SquadReassignLogo:")){
815 stuff_string(The_mission.squad_filename, F_NAME, NULL);
818 // always clear out squad reassignments if not single player
819 if(Game_mode & GM_MULTIPLAYER){
820 SDL_strlcpy(The_mission.squad_name, "", sizeof(The_mission.squad_name));
821 SDL_strlcpy(The_mission.squad_filename, "", sizeof(The_mission.squad_filename));
822 mprintf(("Ignoring squadron reassignment"));
824 // reassign the player
826 if(!Fred_running && (Player != NULL) && (strlen(The_mission.squad_name) > 0) && (Game_mode & GM_CAMPAIGN_MODE)){
827 mprintf(("Reassigning player to squadron %s\n", The_mission.squad_name));
828 player_set_squad(Player, The_mission.squad_name);
829 player_set_squad_bitmap(Player, The_mission.squad_filename);
833 // set up the Num_teams variable accoriding to the game_type variable'
834 Num_teams = 1; // assume 1
836 // multiplayer team v. team games have two teams. If we have three teams, we need to use
837 // a new mission mode!
838 if ( (pm->game_type & MISSION_TYPE_MULTI) && (pm->game_type & MISSION_TYPE_MULTI_TEAMS) ){
843 void parse_player_info(mission *pm)
845 char alt[NAME_LENGTH + 2] = "";
846 SDL_assert(pm != NULL);
848 // alternate type names begin here
849 mission_parse_reset_alt();
850 if(optional_string("#Alternate Types:")){
852 while(!optional_string("#end")){
853 required_string("$Alt:");
854 stuff_string(alt, F_NAME, NULL, NAME_LENGTH);
857 mission_parse_add_alt(alt);
862 required_string("#Players");
864 while (required_string_either("#Objects", "$")){
865 parse_player_info2(pm);
869 void parse_player_info2(mission *pm)
871 char str[NAME_LENGTH];
872 int nt, i, total, list[MAX_SHIP_TYPES * 2], list2[MAX_WEAPON_TYPES * 2];
874 char starting_wings[MAX_PLAYER_WINGS][NAME_LENGTH];
876 // read in a ship/weapon pool for each team.
877 for ( nt = 0; nt < Num_teams; nt++ ) {
878 int num_ship_choices;
880 ptr = &Team_data[nt];
881 // get the shipname for single player missions
882 // MWA -- make this required later!!!!
883 if ( optional_string("$Starting Shipname:") )
884 stuff_string( Player_start_shipname, F_NAME, NULL );
886 required_string("$Ship Choices:");
887 total = stuff_int_list(list, MAX_SHIP_TYPES * 2, SHIP_INFO_TYPE);
889 SDL_assert(!(total & 0x01)); // make sure we have an even count
891 num_ship_choices = 0;
892 total /= 2; // there are only 1/2 the ships really on the list.
893 for (i=0; i<total; i++) {
894 // in a campaign, see if the player is allowed the ships or not. Remove them from the
895 // pool if they are not allowed
896 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
897 if ( !Campaign.ships_allowed[list[i*2]] )
901 ptr->ship_list[num_ship_choices] = list[i * 2];
902 ptr->ship_count[num_ship_choices] = list[i * 2 + 1];
905 ptr->number_choices = num_ship_choices;
907 // --- obsolete data, parsing remains for compatibility reasons ---
908 if (optional_string("+Starting Wings:"))
909 stuff_string_list(starting_wings, MAX_PLAYER_WINGS);
911 ptr->default_ship = -1;
912 if (optional_string("+Default_ship:")) {
913 stuff_string(str, F_NAME, NULL);
914 ptr->default_ship = ship_info_lookup(str);
915 // see if the player's default ship is an allowable ship (campaign only). If not, then what
916 // do we do? choose the first allowable one?
917 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
918 if ( !(Campaign.ships_allowed[ptr->default_ship]) ) {
919 for (i = 0; i < MAX_SHIP_TYPES; i++ ) {
920 if ( Campaign.ships_allowed[ptr->default_ship] ) {
921 ptr->default_ship = i;
925 SDL_assert( i < MAX_SHIP_TYPES );
930 if (ptr->default_ship == -1) // invalid or not specified, make first in list
931 ptr->default_ship = ptr->ship_list[0];
933 for (i=0; i<MAX_WEAPON_TYPES; i++)
934 ptr->weaponry_pool[i] = 0;
936 if (optional_string("+Weaponry Pool:")) {
937 total = stuff_int_list(list2, MAX_WEAPON_TYPES * 2, WEAPON_POOL_TYPE);
939 SDL_assert(!(total & 0x01)); // make sure we have an even count
941 for (i=0; i<total; i++) {
942 // in a campaign, see if the player is allowed the weapons or not. Remove them from the
943 // pool if they are not allowed
944 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
945 if ( !Campaign.weapons_allowed[list2[i*2]] )
949 if ((list2[i * 2] >= 0) && (list2[i * 2] < MAX_WEAPON_TYPES))
950 ptr->weaponry_pool[list2[i * 2]] = list2[i * 2 + 1];
955 if ( nt != Num_teams )
956 Error(LOCATION, "Not enough ship/weapon pools for mission. There are %d teams and only %d pools.", Num_teams, nt);
959 void parse_plot_info(mission *pm)
961 required_string("#Plot Info");
963 required_string("$Tour:");
964 stuff_string(pm->tour_name, F_NAME, NULL);
966 required_string("$Pre-Briefing Cutscene:");
967 stuff_string(pm->pre_briefing_cutscene, F_FILESPEC, NULL);
969 required_string("$Pre-Mission Cutscene:");
970 stuff_string(pm->pre_mission_cutscene, F_FILESPEC, NULL);
972 required_string("$Next Mission Success:");
973 stuff_string(pm->next_mission_success, F_NAME, NULL);
975 required_string("$Next Mission Partial:");
976 stuff_string(pm->next_mission_partial, F_NAME, NULL);
978 required_string("$Next Mission Failure:");
979 stuff_string(pm->next_mission_failure, F_NAME, NULL);
982 void parse_briefing_info(mission *pm)
986 if ( !optional_string("#Briefing Info") )
989 required_string("$Briefing Voice 1:");
990 stuff_string(junk, F_FILESPEC, NULL);
992 required_string("$Briefing Text 1:");
993 stuff_string(junk, F_MULTITEXTOLD, NULL);
995 required_string("$Briefing Voice 2:");
996 stuff_string(junk, F_FILESPEC, NULL);
998 required_string("$Briefing Text 2:");
999 stuff_string(junk, F_MULTITEXTOLD, NULL);
1001 required_string("$Briefing Voice 3:");
1002 stuff_string(junk, F_FILESPEC, NULL);
1004 required_string("$Briefing Text 3:");
1005 stuff_string(junk, F_MULTITEXTOLD, NULL);
1007 required_string("$Debriefing Voice 1:");
1008 stuff_string(junk, F_FILESPEC, NULL);
1010 required_string("$Debriefing Text 1:");
1011 stuff_string(junk, F_MULTITEXTOLD, NULL);
1013 required_string("$Debriefing Voice 2:");
1014 stuff_string(junk, F_FILESPEC, NULL);
1016 required_string("$Debriefing Text 2:");
1017 stuff_string(junk, F_MULTITEXTOLD, NULL);
1019 required_string("$Debriefing Voice 3:");
1020 stuff_string(junk, F_FILESPEC, NULL);
1022 required_string("$Debriefing Text 3:");
1023 stuff_string(junk, F_MULTITEXTOLD, NULL);
1026 // parse the event music and briefing music for the mission
1027 void parse_music(mission *pm)
1029 char name[NAME_LENGTH];
1031 event_music_reset_choices();
1033 if ( !optional_string("#Music") ) {
1037 required_string("$Event Music:");
1038 stuff_string(name, F_NAME, NULL);
1039 event_music_set_soundtrack(name);
1041 required_string("$Briefing Music:");
1042 stuff_string(name, F_NAME, NULL);
1043 event_music_set_score(SCORE_BRIEFING, name);
1045 if ( optional_string("$Debriefing Success Music:") ) {
1046 stuff_string(name, F_NAME, NULL);
1047 event_music_set_score(SCORE_DEBRIEF_SUCCESS, name);
1050 if ( optional_string("$Debriefing Fail Music:") ) {
1051 stuff_string(name, F_NAME, NULL);
1052 event_music_set_score(SCORE_DEBRIEF_FAIL, name);
1056 void parse_cmd_brief(mission *pm)
1060 SDL_assert(!Cur_cmd_brief->num_stages);
1063 required_string("#Command Briefing");
1064 while (optional_string("$Stage Text:")) {
1065 SDL_assert(stage < CMD_BRIEF_STAGES_MAX);
1066 Cur_cmd_brief->stage[stage].text = stuff_and_malloc_string(F_MULTITEXT, NULL, CMD_BRIEF_TEXT_MAX);
1067 SDL_assert(Cur_cmd_brief->stage[stage].text);
1069 required_string("$Ani Filename:");
1070 stuff_string(Cur_cmd_brief->stage[stage].ani_filename, F_FILESPEC, NULL);
1071 if (optional_string("+Wave Filename:"))
1072 stuff_string(Cur_cmd_brief->stage[stage].wave_filename, F_FILESPEC, NULL);
1074 Cur_cmd_brief->stage[stage].wave_filename[0] = 0;
1079 Cur_cmd_brief->num_stages = stage;
1082 void parse_cmd_briefs(mission *pm)
1087 // a hack follows because old missions don't have a command briefing
1088 if (required_string_either("#Command Briefing", "#Briefing"))
1091 for (i=0; i<Num_teams; i++) {
1092 Cur_cmd_brief = &Cmd_briefs[i];
1093 parse_cmd_brief(pm);
1097 // -------------------------------------------------------------------------------------------------
1100 // Parse the data required for the mission briefing
1102 // NOTE: This updates the global Briefing struct with all the data necessary to drive the briefing
1104 void parse_briefing(mission *pm)
1106 int nt, i, j, stage_num = 0, icon_num = 0, team_index;
1111 char not_used_text[MAX_ICON_TEXT_LEN];
1115 // MWA -- 2/3/98. we can now have multiple briefing and debreifings in a mission
1116 for ( nt = 0; nt < Num_teams; nt++ ) {
1117 if ( !optional_string("#Briefing") )
1120 bp = &Briefings[nt];
1122 required_string("$start_briefing");
1123 required_string("$num_stages:");
1124 stuff_int(&bp->num_stages);
1125 SDL_assert(bp->num_stages <= MAX_BRIEF_STAGES);
1128 while (required_string_either("$end_briefing", "$start_stage")) {
1129 required_string("$start_stage");
1130 SDL_assert(stage_num < MAX_BRIEF_STAGES);
1131 bs = &bp->stages[stage_num++];
1132 required_string("$multi_text");
1133 if ( Fred_running ) {
1134 stuff_string(bs->new_text, F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1136 bs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1138 required_string("$voice:");
1139 stuff_string(bs->voice, F_FILESPEC, NULL);
1140 required_string("$camera_pos:");
1141 stuff_vector(&bs->camera_pos);
1142 required_string("$camera_orient:");
1143 stuff_matrix(&bs->camera_orient);
1144 required_string("$camera_time:");
1145 stuff_int(&bs->camera_time);
1147 if ( optional_string("$num_lines:") ) {
1148 stuff_int(&bs->num_lines);
1150 if ( Fred_running ) {
1151 SDL_assert(bs->lines!=NULL);
1153 if ( bs->num_lines > 0 ) {
1154 bs->lines = (brief_line *)malloc(sizeof(brief_line)*bs->num_lines);
1155 SDL_assert(bs->lines!=NULL);
1159 for (i=0; i<bs->num_lines; i++) {
1160 required_string("$line_start:");
1161 stuff_int(&bs->lines[i].start_icon);
1162 required_string("$line_end:");
1163 stuff_int(&bs->lines[i].end_icon);
1170 required_string("$num_icons:");
1171 stuff_int(&bs->num_icons);
1173 if ( Fred_running ) {
1174 SDL_assert(bs->lines!=NULL);
1176 if ( bs->num_icons > 0 ) {
1177 bs->icons = (brief_icon *)malloc(sizeof(brief_icon)*bs->num_icons);
1178 SDL_assert(bs->icons!=NULL);
1182 if ( optional_string("$flags:") )
1183 stuff_int(&bs->flags);
1187 if ( optional_string("$formula:") )
1188 bs->formula = get_sexp_main();
1190 bs->formula = Locked_sexp_true;
1192 SDL_assert(bs->num_icons <= MAX_STAGE_ICONS );
1194 while (required_string_either("$end_stage", "$start_icon")) {
1195 required_string("$start_icon");
1196 SDL_assert(icon_num < MAX_STAGE_ICONS);
1197 bi = &bs->icons[icon_num++];
1199 required_string("$type:");
1200 stuff_int(&bi->type);
1202 find_and_stuff("$team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1203 SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1204 bi->team = 1 << team_index;
1206 find_and_stuff("$class:", &bi->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1208 required_string("$pos:");
1209 stuff_vector(&bi->pos);
1212 if (optional_string("$label:"))
1213 stuff_string(bi->label, F_MESSAGE, NULL);
1215 if (optional_string("+id:")) {
1217 if (bi->id >= Cur_brief_id)
1218 Cur_brief_id = bi->id + 1;
1222 for (i=0; i<stage_num-1; i++)
1223 for (j=0; j < bp->stages[i].num_icons; j++)
1225 if (!SDL_strcasecmp(bp->stages[i].icons[j].label, bi->label))
1226 bi->id = bp->stages[i].icons[j].id;
1230 bi->id = Cur_brief_id++;
1233 required_string("$hlight:");
1237 bi->flags = BI_HIGHLIGHT;
1242 required_string("$multi_text");
1243 // stuff_string(bi->text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1244 stuff_string(not_used_text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1245 required_string("$end_icon");
1247 SDL_assert(bs->num_icons == icon_num);
1249 required_string("$end_stage");
1252 SDL_assert(bp->num_stages == stage_num);
1253 required_string("$end_briefing");
1256 if ( nt != Num_teams )
1257 Error(LOCATION, "Not enough briefings in mission file. There are %d teams and only %d briefings.", Num_teams, nt );
1260 // -------------------------------------------------------------------------------------------------
1261 // parse_debriefing_old()
1263 // Parse the data required for the mission debriefings
1264 void parse_debriefing_old(mission *pm)
1267 char waste[MAX_DEBRIEF_LEN];
1269 if ( !optional_string("#Debriefing") )
1272 required_string("$num_debriefings:");
1275 while (required_string_either("#Players", "$start_debriefing")) {
1276 required_string("$start_debriefing");
1277 required_string("$formula:");
1278 junk = get_sexp_main();
1279 required_string("$num_stages:");
1281 while (required_string_either("$end_debriefing", "$start_stage")) {
1282 required_string("$start_stage");
1283 required_string("$multi_text");
1284 stuff_string(waste, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1285 required_string("$voice:");
1286 stuff_string(waste, F_FILESPEC, NULL);
1287 required_string("$end_stage");
1289 required_string("$end_debriefing");
1293 // -------------------------------------------------------------------------------------------------
1294 // parse_debriefing_new()
1296 // Parse the data required for the mission debriefings
1297 void parse_debriefing_new(mission *pm)
1305 // next code should be old -- hopefully not called anymore
1306 //if (!optional_string("#Debriefing_info")) {
1307 // parse_debriefing_old(pm);
1311 // 2/3/98 -- MWA. We can now have multiple briefings and debriefings on a team
1312 for ( nt = 0; nt < Num_teams; nt++ ) {
1314 if ( !optional_string("#Debriefing_info") )
1319 db = &Debriefings[nt];
1321 required_string("$Num stages:");
1322 stuff_int(&db->num_stages);
1323 SDL_assert(db->num_stages <= MAX_DEBRIEF_STAGES);
1325 while (required_string_either("#", "$Formula")) {
1326 SDL_assert(stage_num < MAX_DEBRIEF_STAGES);
1327 dbs = &db->stages[stage_num++];
1328 required_string("$Formula:");
1329 dbs->formula = get_sexp_main();
1330 required_string("$multi text");
1331 if ( Fred_running ) {
1332 stuff_string(dbs->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1334 dbs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1336 required_string("$Voice:");
1337 stuff_string(dbs->voice, F_FILESPEC, NULL);
1338 required_string("$Recommendation text:");
1339 if ( Fred_running ) {
1340 stuff_string( dbs->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1342 dbs->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1346 SDL_assert(db->num_stages == stage_num);
1349 if ( nt != Num_teams )
1350 Error(LOCATION, "Not enough debriefings for mission. There are %d teams and only %d debriefings;\n", Num_teams, nt );
1353 void position_ship_for_knossos_warpin(p_object *objp, int shipnum, int objnum)
1355 // Assume no valid knossos device
1356 Ships[shipnum].special_warp_objnum = -1;
1358 // find knossos device
1361 int knossos_num = -1;
1362 for (so=GET_FIRST(&Ship_obj_list); so!=END_OF_LIST(&Ship_obj_list); so=GET_NEXT(so)) {
1363 knossos_num = Objects[so->objnum].instance;
1364 if (Ship_info[Ships[knossos_num].ship_info_index].flags & SIF_KNOSSOS_DEVICE) {
1365 // be close to the right device [allow multiple knossos's
1366 if (vm_vec_dist_quick(&Objects[knossos_num].pos, &objp->pos) < 2.0f*(Objects[knossos_num].radius + Objects[objnum].radius) ) {
1374 // set ship special_warp_objnum
1375 Ships[shipnum].special_warp_objnum = knossos_num;
1377 // position self for warp on plane of device
1379 float dist = fvi_ray_plane(&new_point, &Objects[knossos_num].pos, &Objects[knossos_num].orient.v.fvec, &objp->pos, &objp->orient.v.fvec, 0.0f);
1380 polymodel *pm = model_get(Ship_info[Ships[shipnum].ship_info_index].modelnum);
1381 float desired_dist = -pm->mins.xyz.z;
1382 vm_vec_scale_add2(&Objects[objnum].pos, &Objects[objnum].orient.v.fvec, (dist - desired_dist));
1383 // if ship is BIG or HUGE, make it go through the center of the knossos
1384 if (Ship_info[Ships[shipnum].ship_info_index].flags & SIF_HUGE_SHIP) {
1386 vm_vec_sub(&offset, &Objects[knossos_num].pos, &new_point);
1387 vm_vec_add2(&Objects[objnum].pos, &offset);
1392 // Given a stuffed p_object struct, create an object and fill in the necessary fields.
1393 // Return object number.
1394 int parse_create_object(p_object *objp)
1396 int i, j, k, objnum, shipnum;
1400 subsys_status *sssp;
1403 // base level creation
1404 objnum = ship_create(&objp->orient, &objp->pos, objp->ship_class);
1405 SDL_assert(objnum != -1);
1406 shipnum = Objects[objnum].instance;
1408 // if arriving through knossos, adjust objpj->pos to plane of knossos and set flag
1409 // special warp is single player only
1410 if ((objp->flags & P_KNOSSOS_WARP_IN) && !(Game_mode & GM_MULTIPLAYER)) {
1411 if (!Fred_running) {
1412 position_ship_for_knossos_warpin(objp, shipnum, objnum);
1416 Ships[shipnum].group = objp->group;
1417 Ships[shipnum].team = objp->team;
1418 SDL_strlcpy(Ships[shipnum].ship_name, objp->name, sizeof(Ships[0].ship_name));
1419 Ships[shipnum].escort_priority = objp->escort_priority;
1420 Ships[shipnum].special_exp_index = objp->special_exp_index;
1421 Ships[shipnum].respawn_priority = objp->respawn_priority;
1422 // if this is a multiplayer dogfight game, and its from a player wing, make it team traitor
1423 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (objp->wingnum >= 0)){
1424 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
1425 if ( !SDL_strcasecmp(Starting_wing_names[i], Wings[objp->wingnum].name) ) {
1426 Ships[shipnum].team = TEAM_TRAITOR;
1431 sip = &Ship_info[Ships[shipnum].ship_info_index];
1433 if ( !Fred_running ) {
1434 ship_assign_sound(&Ships[shipnum]);
1437 aip = &(Ai_info[Ships[shipnum].ai_index]);
1438 aip->behavior = objp->behavior;
1439 aip->mode = aip->behavior;
1441 // alternate type name
1442 Ships[shipnum].alt_type_index = objp->alt_type_index;
1444 aip->ai_class = objp->ai_class;
1445 Ships[shipnum].weapons.ai_class = objp->ai_class; // Fred uses this instead of above.
1447 // must reset the number of ai goals when the object is created
1448 for (i = 0; i < MAX_AI_GOALS; i++ ){
1449 aip->goals[i].ai_mode = AI_GOAL_NONE;
1452 Ships[shipnum].cargo1 = objp->cargo1;
1454 Ships[shipnum].arrival_location = objp->arrival_location;
1455 Ships[shipnum].arrival_distance = objp->arrival_distance;
1456 Ships[shipnum].arrival_anchor = objp->arrival_anchor;
1457 Ships[shipnum].arrival_cue = objp->arrival_cue;
1458 Ships[shipnum].arrival_delay = objp->arrival_delay;
1459 Ships[shipnum].departure_location = objp->departure_location;
1460 Ships[shipnum].departure_anchor = objp->departure_anchor;
1461 Ships[shipnum].departure_cue = objp->departure_cue;
1462 Ships[shipnum].departure_delay = objp->departure_delay;
1463 Ships[shipnum].determination = objp->determination;
1464 Ships[shipnum].wingnum = objp->wingnum;
1465 Ships[shipnum].hotkey = objp->hotkey;
1466 Ships[shipnum].score = objp->score;
1467 Ships[shipnum].persona_index = objp->persona_index;
1469 // set the orders that this ship will accept. It will have already been set to default from the
1470 // ship create code, so only set them if the parse object flags say they are unique
1471 if ( objp->flags & P_SF_USE_UNIQUE_ORDERS ) {
1472 Ships[shipnum].orders_accepted = objp->orders_accepted;
1474 // MWA 5/15/98 -- Added the following debug code because some orders that ships
1475 // will accept were apparently written out incorrectly with Fred. This Int3() should
1476 // trap these instances.
1478 if ( Fred_running ) {
1479 int default_orders, remaining_orders;
1481 default_orders = ship_get_default_orders_accepted( &Ship_info[Ships[shipnum].ship_info_index] );
1482 remaining_orders = objp->orders_accepted & ~default_orders;
1483 if ( remaining_orders ) {
1484 Warning(LOCATION, "Ship %s has orders which it will accept that are\nnot part of default orders accepted.\n\nPlease reedit this ship and change the orders again\n", Ships[shipnum].ship_name);
1490 // check the parse object's flags for possible flags to set on this newly created ship
1491 if ( objp->flags & P_OF_PROTECTED ) {
1492 Objects[objnum].flags |= OF_PROTECTED;
1495 if ( objp->flags & P_OF_BEAM_PROTECTED ) {
1496 Objects[objnum].flags |= OF_BEAM_PROTECTED;
1499 if (objp->flags & P_OF_CARGO_KNOWN) {
1500 Ships[shipnum].flags |= SF_CARGO_REVEALED;
1503 if ( objp->flags & P_SF_IGNORE_COUNT )
1504 Ships[shipnum].flags |= SF_IGNORE_COUNT;
1506 if ( objp->flags & P_SF_REINFORCEMENT )
1507 Ships[shipnum].flags |= SF_REINFORCEMENT;
1509 if (objp->flags & P_OF_NO_SHIELDS || sip->shields == 0 )
1510 Objects[objnum].flags |= OF_NO_SHIELDS;
1512 if (objp->flags & P_SF_ESCORT)
1513 Ships[shipnum].flags |= SF_ESCORT;
1515 if (objp->flags & P_KNOSSOS_WARP_IN) {
1516 Objects[objnum].flags |= OF_SPECIAL_WARP;
1519 // don't set the flag if the mission is ongoing in a multiplayer situation. This will be set by the players in the
1520 // game only before the game or during respawning.
1521 // MWA -- changed the next line to remove the !(Game_mode & GM_MULTIPLAYER). We shouldn't be setting
1522 // this flag in single player mode -- it gets set in post process mission.
1523 //if ((objp->flags & P_OF_PLAYER_START) && (((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION)) || !(Game_mode & GM_MULTIPLAYER)))
1524 if ( (objp->flags & P_OF_PLAYER_START) && (Fred_running || ((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION))) )
1525 Objects[objnum].flags |= OF_PLAYER_SHIP;
1527 if (objp->flags & P_SF_NO_ARRIVAL_MUSIC)
1528 Ships[shipnum].flags |= SF_NO_ARRIVAL_MUSIC;
1530 if ( objp->flags & P_SF_NO_ARRIVAL_WARP )
1531 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1533 if ( objp->flags & P_SF_NO_DEPARTURE_WARP )
1534 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1536 if ( objp->flags & P_SF_INITIALLY_DOCKED )
1537 Ships[shipnum].flags |= SF_INITIALLY_DOCKED;
1539 if ( objp->flags & P_SF_LOCKED )
1540 Ships[shipnum].flags |= SF_LOCKED;
1542 if ( objp->flags & P_SF_WARP_BROKEN )
1543 Ships[shipnum].flags |= SF_WARP_BROKEN;
1545 if ( objp->flags & P_SF_WARP_NEVER )
1546 Ships[shipnum].flags |= SF_WARP_NEVER;
1548 if ( objp->flags & P_SF_HIDDEN_FROM_SENSORS )
1549 Ships[shipnum].flags |= SF_HIDDEN_FROM_SENSORS;
1551 // if ship is in a wing, and the wing's no_warp_effect flag is set, then set the equivalent
1552 // flag for the ship
1553 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_ARRIVAL_WARP) )
1554 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1556 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_DEPARTURE_WARP) )
1557 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1559 // mwa -- 1/30/98. Do both flags. Fred uses the ship flag, and FreeSpace will use the object
1560 // flag. I'm to lazy at this point to deal with consolidating them.
1561 if ( objp->flags & P_SF_INVULNERABLE ) {
1562 Ships[shipnum].flags |= SF_INVULNERABLE;
1563 Objects[objnum].flags |= OF_INVULNERABLE;
1566 if ( objp->flags & P_SF_GUARDIAN ) {
1567 Objects[objnum].flags |= OF_GUARDIAN;
1570 if ( objp->flags & P_SF_SCANNABLE )
1571 Ships[shipnum].flags |= SF_SCANNABLE;
1573 if ( objp->flags & P_SF_RED_ALERT_STORE_STATUS ){
1574 SDL_assert(!(Game_mode & GM_MULTIPLAYER));
1575 Ships[shipnum].flags |= SF_RED_ALERT_STORE_STATUS;
1578 // a couple of ai_info flags. Also, do a reasonable default for the kamikaze damage regardless of
1579 // whether this flag is set or not
1580 if ( objp->flags & P_AIF_KAMIKAZE ) {
1581 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_KAMIKAZE;
1582 Ai_info[Ships[shipnum].ai_index].kamikaze_damage = objp->kamikaze_damage;
1585 if ( objp->flags & P_AIF_NO_DYNAMIC )
1586 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_NO_DYNAMIC;
1588 // if the wing index and wing pos are set for this parse object, set them for the ship. This
1589 // is useful in multiplayer when ships respawn
1590 Ships[shipnum].wing_status_wing_index = objp->wing_status_wing_index;
1591 Ships[shipnum].wing_status_wing_pos = objp->wing_status_wing_pos;
1593 // set up the ai_goals for this object -- all ships created here are AI controlled.
1594 if ( objp->ai_goals != -1 ) {
1597 for ( sexp = CDR(objp->ai_goals); sexp != -1; sexp = CDR(sexp) )
1598 // make a call to the routine in MissionGoals.cpp to set up the ai goals for this object.
1599 ai_add_ship_goal_sexp( sexp, AIG_TYPE_EVENT_SHIP, aip );
1601 if ( objp->wingnum == -1 ) // free the sexpression nodes only for non-wing ships. wing code will handle it's own case
1602 free_sexp2(objp->ai_goals); // free up sexp nodes for reused, since they aren't needed anymore.
1605 SDL_assert(Ships[shipnum].modelnum != -1);
1607 // initialize subsystem statii here. The subsystems are given a percentage damaged. So a percent value
1608 // of 20% means that the subsystem is 20% damaged (*not* 20% of max hits). This is opposite the way
1609 // that the initial velocity/hull strength/shields work
1610 i = objp->subsys_count;
1612 sssp = &Subsys_status[objp->subsys_index + i];
1613 if (!SDL_strcasecmp(sssp->name, NOX("Pilot"))) {
1614 wp = &Ships[shipnum].weapons;
1615 if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1616 for (j=k=0; j<MAX_PRIMARY_BANKS; j++) {
1617 if ( (sssp->primary_banks[j] >= 0) || Fred_running ){
1618 wp->primary_bank_weapons[k] = sssp->primary_banks[j];
1626 wp->num_primary_banks = sip->num_primary_banks;
1628 wp->num_primary_banks = k;
1632 if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1633 for (j=k=0; j<MAX_SECONDARY_BANKS; j++) {
1634 if ( (sssp->secondary_banks[j] >= 0) || Fred_running ){
1635 wp->secondary_bank_weapons[k++] = sssp->secondary_banks[j];
1640 wp->num_secondary_banks = sip->num_secondary_banks;
1642 wp->num_secondary_banks = k;
1646 for (j=0; j < wp->num_secondary_banks; j++)
1648 wp->secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1650 int capacity = fl2i(sssp->secondary_ammo[j]/100.0f * sip->secondary_bank_ammo_capacity[j] + 0.5f );
1651 wp->secondary_bank_ammo[j] = fl2i(capacity / Weapon_info[wp->secondary_bank_weapons[j]].cargo_size + 0.5f);
1656 ptr = GET_FIRST(&Ships[shipnum].subsys_list);
1657 while (ptr != END_OF_LIST(&Ships[shipnum].subsys_list)) {
1658 if (!SDL_strcasecmp(ptr->system_info->subobj_name, sssp->name)) {
1660 ptr->current_hits = sssp->percent;
1663 new_hits = ptr->system_info->max_hits * (100.0f - sssp->percent) / 100.f;
1664 Ships[shipnum].subsys_info[ptr->system_info->type].current_hits -= (ptr->system_info->max_hits - new_hits);
1665 if ( (100.0f - sssp->percent) < 0.5) {
1666 ptr->current_hits = 0.0f;
1667 ptr->submodel_info_1.blown_off = 1;
1669 ptr->current_hits = new_hits;
1673 if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1674 for (j=0; j<MAX_PRIMARY_BANKS; j++)
1675 ptr->weapons.primary_bank_weapons[j] = sssp->primary_banks[j];
1677 if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1678 for (j=0; j<MAX_SECONDARY_BANKS; j++)
1679 ptr->weapons.secondary_bank_weapons[j] = sssp->secondary_banks[j];
1681 for (j=0; j<MAX_SECONDARY_BANKS; j++) {
1682 // AL 3-5-98: This is correct for FRED, but not for FreeSpace... but is this even used?
1683 // As far as I know, turrets cannot run out of ammo
1684 ptr->weapons.secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1687 ptr->subsys_cargo_name = sssp->subsys_cargo_name;
1689 if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
1690 ptr->weapons.ai_class = sssp->ai_class;
1692 ai_turret_select_default_weapon(ptr);
1695 ptr = GET_NEXT(ptr);
1699 // initial hull strength, shields, and velocity are all expressed as a percentage of the max value/
1700 // so a initial_hull value of 90% means 90% of max. This way is opposite of how subsystems are dealt
1703 Objects[objnum].phys_info.speed = (float) objp->initial_velocity;
1704 // Ships[shipnum].hull_hit_points_taken = (float) objp->initial_hull;
1705 Objects[objnum].hull_strength = (float) objp->initial_hull;
1706 Objects[objnum].shields[0] = (float) objp->initial_shields;
1709 int max_allowed_sparks, num_sparks, i;
1712 // Ships[shipnum].hull_hit_points_taken = (float)objp->initial_hull * sip->max_hull_hit_points / 100.0f;
1713 Objects[objnum].hull_strength = objp->initial_hull * sip->initial_hull_strength / 100.0f;
1714 for (i = 0; i<MAX_SHIELD_SECTIONS; i++)
1715 Objects[objnum].shields[i] = (float)(objp->initial_shields * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
1717 // initial velocities now do not apply to ships which warp in after mission starts
1718 if ( !(Game_mode & GM_IN_MISSION) ) {
1719 Objects[objnum].phys_info.speed = (float)objp->initial_velocity * sip->max_speed / 100.0f;
1720 Objects[objnum].phys_info.vel.xyz.z = Objects[objnum].phys_info.speed;
1721 Objects[objnum].phys_info.prev_ramp_vel = Objects[objnum].phys_info.vel;
1722 Objects[objnum].phys_info.desired_vel = Objects[objnum].phys_info.vel;
1725 // recalculate damage of subsystems
1726 ship_recalc_subsys_strength( &Ships[shipnum] );
1728 // create sparks on a ship whose hull is damaged. We will create two sparks for every 20%
1729 // of hull damage done. 100 means no sparks. between 80 and 100 do two sparks. 60 and 80 is
1731 pm = model_get( sip->modelnum );
1732 max_allowed_sparks = get_max_sparks(&Objects[objnum]);
1733 num_sparks = (int)((100.0f - objp->initial_hull) / 5.0f);
1734 if (num_sparks > max_allowed_sparks) {
1735 num_sparks = max_allowed_sparks;
1738 for (i = 0; i < num_sparks; i++ ) {
1741 // DA 10/20/98 - sparks must be chosen on the hull and not any submodel
1742 submodel_get_two_random_points(sip->modelnum, pm->detail[0], &v1, &v2);
1743 ship_hit_sparks_no_rotate(&Objects[objnum], &v1);
1744 // ship_hit_sparks_no_rotate(&Objects[objnum], &v2);
1748 // in mission, we add a log entry -- set ship positions for ships not in wings, and then do
1750 if ( (Game_mode & GM_IN_MISSION) && (!Fred_running) ) {
1751 mission_log_add_entry( LOG_SHIP_ARRIVE, Ships[shipnum].ship_name, NULL );
1753 // if this ship isn't in a wing, determine it's arrival location
1754 if ( !Game_restoring ) {
1755 if ( Ships[shipnum].wingnum == -1 ) {
1757 // multiplayer clients set the arrival location of ships to be at location since their
1758 // position has already been determined. Don't actually set the variable since we
1759 // don't want the warp effect to show if coming from a dock bay.
1760 location = objp->arrival_location;
1761 if ( MULTIPLAYER_CLIENT )
1762 location = ARRIVE_AT_LOCATION;
1763 mission_set_arrival_location(objp->arrival_anchor, location, objp->arrival_distance, objnum, NULL, NULL);
1764 if ( objp->arrival_location != ARRIVE_FROM_DOCK_BAY )
1765 shipfx_warpin_start( &Objects[objnum] );
1769 // possibly add this ship to a hotkey set
1770 if ( (Ships[shipnum].wingnum == -1) && (Ships[shipnum].hotkey != -1 ) )
1771 mission_hotkey_mf_add( Ships[shipnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1772 else if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].hotkey != -1 ) )
1773 mission_hotkey_mf_add( Wings[Ships[shipnum].wingnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1775 // possibly add this ship to the hud escort list
1776 if ( Ships[shipnum].flags & SF_ESCORT ){
1777 hud_add_remove_ship_escort( objnum, 1 );
1781 // for multiplayer games, make a call to the network code to assign the object signature
1782 // of the newly created object. The network host of the netgame will always assign a signature
1783 // to a newly created object. The network signature will get to the clients of the game in
1784 // different manners depending on whether or not an individual ship or a wing was created.
1785 if ( Game_mode & GM_MULTIPLAYER ) {
1786 Objects[objnum].net_signature = objp->net_signature;
1788 if ( (Game_mode & GM_IN_MISSION) && MULTIPLAYER_MASTER && (objp->wingnum == -1) ){
1789 send_ship_create_packet( &Objects[objnum], (objp==Arriving_support_ship)?1:0 );
1793 // if recording a demo, post the event
1794 if(Game_mode & GM_DEMO_RECORD){
1795 demo_POST_obj_create(objp->name, Objects[objnum].signature);
1801 // Mp points at the text of an object, which begins with the "$Name:" field.
1802 // Snags all object information and calls parse_create_object to create a ship.
1803 // Why create a ship? Why not an object? Stay tuned...
1805 // flag is parameter that is used to tell what kind information we are retrieving from the mission.
1806 // if we are just getting player starts, then don't create the objects
1807 int parse_object(mission *pm, int flag, p_object *objp)
1809 // p_object temp_object;
1811 int i, j, count, shipnum, delay, destroy_before_mission_time;
1812 char name[NAME_LENGTH], flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
1814 SDL_assert(pm != NULL);
1816 // objp = &temp_object;
1818 required_string("$Name:");
1819 stuff_string(objp->name, F_NAME, NULL);
1820 shipnum = ship_name_lookup(objp->name);
1822 error_display(0, NOX("Redundant ship name: %s\n"), objp->name);
1825 find_and_stuff("$Class:", &objp->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1826 if (objp->ship_class < 0) {
1827 Warning(LOCATION, "Ship \"%s\" has an invalid ship type (ships.tbl probably changed). Making it type 0", objp->name);
1829 // if fred is running, maybe notify the user that the mission contains MD content
1831 Fred_found_unknown_ship_during_parsing = 1;
1834 objp->ship_class = 0;
1837 // if this is a multiplayer dogfight mission, skip support ships
1838 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (Ship_info[objp->ship_class].flags & SIF_SUPPORT)){
1842 // optional alternate name type
1843 objp->alt_type_index = -1;
1844 if(optional_string("$Alt:")){
1846 stuff_string(name, F_NAME, NULL, NAME_LENGTH);
1848 // try and find the alternate name
1849 objp->alt_type_index = (char)mission_parse_lookup_alt(name);
1850 SDL_assert(objp->alt_type_index >= 0);
1851 if(objp->alt_type_index < 0){
1852 mprintf(("Error looking up alternate ship type name!\n"));
1854 mprintf(("Using alternate ship type name : %s\n", name));
1859 find_and_stuff("$Team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1860 SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1861 objp->team = 1 << team_index;
1863 required_string("$Location:");
1864 stuff_vector(&objp->pos);
1866 required_string("$Orientation:");
1867 stuff_matrix(&objp->orient);
1869 find_and_stuff("$IFF:", &objp->iff, F_NAME, Iff_names, Num_iff, "IFF");
1870 find_and_stuff("$AI Behavior:", &objp->behavior, F_NAME, Ai_behavior_names, Num_ai_behaviors, "AI behavior");
1871 objp->ai_goals = -1;
1873 if ( optional_string("+AI Class:")) {
1874 objp->ai_class = match_and_stuff(F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class");
1875 SDL_assert(objp->ai_class > -1 );
1877 objp->ai_class = Ship_info[objp->ship_class].ai_class;
1880 if ( optional_string("$AI Goals:") ){
1881 objp->ai_goals = get_sexp_main();
1884 if ( !required_string_either("$AI Goals:", "$Cargo 1:") ) {
1885 required_string("$AI Goals:");
1886 objp->ai_goals = get_sexp_main();
1891 find_and_stuff_or_add("$Cargo 1:", &temp, F_NAME, Cargo_names, NAME_LENGTH, &Num_cargo, MAX_CARGO, "cargo");
1892 objp->cargo1 = char(temp);
1893 if ( optional_string("$Cargo 2:") ) {
1894 char buf[NAME_LENGTH];
1895 stuff_string(buf, F_NAME, NULL);
1898 parse_common_object_data(objp); // get initial conditions and subsys status
1900 while (required_string_either("$Arrival Location:", "$Status Description:")) {
1901 SDL_assert(count < MAX_OBJECT_STATUS);
1903 find_and_stuff("$Status Description:", &objp->status_type[count], F_NAME, Status_desc_names, Num_status_names, "Status Description");
1904 find_and_stuff("$Status:", &objp->status[count], F_NAME, Status_type_names, Num_status_names, "Status Type");
1905 find_and_stuff("$Target:", &objp->target[count], F_NAME, Status_target_names, Num_status_names, "Target");
1908 objp->status_count = count;
1910 objp->arrival_anchor = -1;
1911 objp->arrival_distance = 0;
1912 find_and_stuff("$Arrival Location:", &objp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
1913 if ( optional_string("+Arrival Distance:") ) {
1914 stuff_int( &objp->arrival_distance );
1915 if ( objp->arrival_location != ARRIVE_AT_LOCATION ) {
1916 required_string("$Arrival Anchor:");
1917 stuff_string(name, F_NAME, NULL);
1918 objp->arrival_anchor = get_anchor(name);
1922 if (optional_string("+Arrival Delay:")) {
1925 Error(LOCATION, "Cannot have arrival delay < 0 (ship %s)", objp->name);
1929 if ( !Fred_running ){
1930 objp->arrival_delay = -delay; // use negative numbers to mean we haven't set up a timer yet
1932 objp->arrival_delay = delay;
1935 required_string("$Arrival Cue:");
1936 objp->arrival_cue = get_sexp_main();
1937 if ( !Fred_running && (objp->arrival_cue >= 0) ) {
1938 // eval the arrival cue. if the cue is true, set up the timestamp for the arrival delay
1939 SDL_assert ( objp->arrival_delay <= 0 );
1941 // don't eval arrival_cues when just looking for player information.
1942 if ( eval_sexp(objp->arrival_cue) ){ // evaluate to determine if sexp is always false.
1943 objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
1947 find_and_stuff("$Departure Location:", &objp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
1948 objp->departure_anchor = -1;
1949 if ( objp->departure_location == DEPART_AT_DOCK_BAY ) {
1950 required_string("$Departure Anchor:");
1951 stuff_string(name, F_NAME, NULL);
1952 objp->departure_anchor = get_anchor(name);
1955 if (optional_string("+Departure Delay:")) {
1958 Error(LOCATION, "Cannot have departure delay < 0 (ship %s)", objp->name);
1964 if ( !Fred_running ){
1965 objp->departure_delay = -delay;
1967 objp->departure_delay = delay;
1970 required_string("$Departure Cue:");
1971 objp->departure_cue = get_sexp_main();
1973 if (optional_string("$Misc Properties:"))
1974 stuff_string(objp->misc, F_NAME, NULL);
1976 required_string("$Determination:");
1977 stuff_int(&objp->determination);
1980 if (optional_string("+Flags:")) {
1981 count = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
1982 for (i=0; i<count; i++) {
1983 for (j=0; j<MAX_PARSE_OBJECT_FLAGS; j++) {
1984 if (!SDL_strcasecmp(flag_strings[i], Parse_object_flags[j])) {
1985 objp->flags |= (1 << j);
1990 if (j == MAX_PARSE_OBJECT_FLAGS)
1991 Warning(LOCATION, "Unknown flag in mission file: %s\n", flag_strings[i]);
1995 // always store respawn priority, just for ease of implementation
1996 objp->respawn_priority = 0;
1997 if(optional_string("+Respawn Priority:" )){
1998 stuff_int(&objp->respawn_priority);
2001 objp->escort_priority = 0;
2002 if ( optional_string("+Escort Priority:" ) ) {
2003 SDL_assert(objp->flags & P_SF_ESCORT);
2004 stuff_int(&objp->escort_priority);
2007 if ( objp->flags & P_OF_PLAYER_START ) {
2008 objp->flags |= P_OF_CARGO_KNOWN; // make cargo known for players
2012 objp->special_exp_index = -1;
2013 if ( optional_string("+Special Exp index:" ) ) {
2014 stuff_int(&objp->special_exp_index);
2017 // if the kamikaze flag is set, we should have the next flag
2018 if ( optional_string("+Kamikaze Damage:") ) {
2022 objp->kamikaze_damage = i2fl(damage);
2026 if (optional_string("+Hotkey:")) {
2027 stuff_int(&objp->hotkey);
2028 SDL_assert((objp->hotkey >= 0) && (objp->hotkey < 10));
2031 objp->docked_with[0] = 0;
2032 if (optional_string("+Docked With:")) {
2033 stuff_string(objp->docked_with, F_NAME, NULL);
2034 required_string("$Docker Point:");
2035 stuff_string(objp->docker_point, F_NAME, NULL);
2036 required_string("$Dockee Point:");
2037 stuff_string(objp->dockee_point, F_NAME, NULL);
2039 objp->flags |= P_SF_INITIALLY_DOCKED;
2041 // put this information into the Initially_docked array. We will need to use this
2042 // informatin later since not all ships will initially get created.
2043 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee, objp->docked_with, NAME_LENGTH);
2044 SDL_strlcpy(Initially_docked[Total_initially_docked].docker_point, objp->docker_point, NAME_LENGTH);
2045 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee_point, objp->dockee_point, NAME_LENGTH);
2046 Initially_docked[Total_initially_docked].docker = objp;
2047 Total_initially_docked++;
2050 // check the optional parameter for destroying the ship before the mission starts. If this parameter is
2051 // here, then we need to destroy the ship N seconds before the mission starts (for debris purposes).
2052 // store the time value here. We want to create this object for sure. Set the arrival cue and arrival
2053 // delay to bogus values
2054 destroy_before_mission_time = -1;
2055 if ( optional_string("+Destroy At:") ) {
2057 stuff_int(&destroy_before_mission_time);
2058 SDL_assert ( destroy_before_mission_time >= 0 );
2059 objp->arrival_cue = Locked_sexp_true;
2060 objp->arrival_delay = timestamp(0);
2063 // check for the optional "orders accepted" string which contains the orders from the default
2064 // set that this ship will actually listen to
2065 if ( optional_string("+Orders Accepted:") ) {
2066 stuff_int( &objp->orders_accepted );
2067 if ( objp->orders_accepted != -1 ){
2068 objp->flags |= P_SF_USE_UNIQUE_ORDERS;
2072 if (optional_string("+Group:")){
2073 stuff_int(&objp->group);
2078 if (optional_string("+Score:")){
2079 stuff_int(&objp->score);
2084 // parse the persona index if present
2085 if ( optional_string("+Persona Index:")){
2086 stuff_int(&objp->persona_index);
2088 objp->persona_index = -1;
2091 objp->wingnum = -1; // set the wing number to -1 -- possibly to be set later
2093 // for multiplayer, assign a network signature to this parse object. Doing this here will
2094 // allow servers to use the signature with clients when creating new ships, instead of having
2095 // to pass ship names all the time
2096 if ( Game_mode & GM_MULTIPLAYER ){
2097 objp->net_signature = multi_assign_network_signature( MULTI_SIG_SHIP );
2100 // set the wing_status position to be -1 for all objects. This will get set to an appropriate
2101 // value when the wing positions are finally determined.
2102 objp->wing_status_wing_index = -1;
2103 objp->wing_status_wing_pos = -1;
2104 objp->respawn_count = 0;
2106 // if this if the starting player ship, then copy if to Starting_player_pobject (used for ingame join)
2107 if ( !SDL_strcasecmp( objp->name, Player_start_shipname) ) {
2108 Player_start_pobject = *objp;
2109 Player_start_pobject.flags |= P_SF_PLAYER_START_VALID;
2113 // Now create the object.
2114 // Don't create the new ship blindly. First, check the sexp for the arrival cue
2115 // to determine when this ship should arrive. If not right away, stick this ship
2116 // onto the ship arrival list to be looked at later. Also check to see if it should use the
2117 // wings arrival cue. The ship may get created later depending on whether or not the wing
2119 // always create ships when FRED is running
2121 // don't create the object if it is intially docked for either FreeSpcae or Fred. Fred will
2122 // create the object later in post_process_mission
2123 if ( (objp->flags & P_SF_INITIALLY_DOCKED) || (!Fred_running && (!eval_sexp(objp->arrival_cue) || !timestamp_elapsed(objp->arrival_delay) || (objp->flags & P_SF_REINFORCEMENT))) ) {
2124 SDL_assert ( destroy_before_mission_time == -1 ); // we can't add ships getting destroyed to the arrival list!!!
2125 SDL_assert ( num_ship_arrivals < MAX_SHIP_ARRIVALS );
2126 memcpy( &ship_arrivals[num_ship_arrivals], objp, sizeof(p_object) );
2127 list_append(&ship_arrival_list, &ship_arrivals[num_ship_arrivals]);
2128 num_ship_arrivals++;
2130 // ingame joiners bail here.
2131 else if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_INGAME_JOIN)){
2137 real_objnum = parse_create_object(objp); // this object may later get destroyed depending on wing status!!!!
2139 Subsys_index = objp->subsys_index; // free elements that are no longer needed.
2141 // if the ship is supposed to be destroyed before the mission, then blow up the ship, mark the pieces
2142 // as last forever. Only call this stuff when you are blowing up the ship
2143 if ( destroy_before_mission_time >= 0 ) {
2146 objp = &Objects[real_objnum];
2147 if ( !Fred_running ) {
2149 shipfx_blow_up_model( objp, Ships[objp->instance].modelnum, 0, 0, &objp->pos );
2150 objp->flags |= OF_SHOULD_BE_DEAD;
2152 // once the ship is exploded, find the debris pieces belonging to this object, mark them
2153 // as not to expire, and move them forward in time N seconds
2154 for (i = 0; i < MAX_DEBRIS_PIECES; i++ ) {
2158 if ( !db->flags & DEBRIS_USED ) // not used, move onto the next one.
2160 if ( db->source_objnum != real_objnum ) // not from this ship, move to next one
2163 debris_clear_expired_flag(db); // mark as don't expire
2164 db->lifeleft = -1.0f; // be sure that lifeleft == -1.0 so that it really doesn't expire!
2166 // now move the debris along it's path for N seconds
2167 objp = &Objects[db->objnum];
2168 physics_sim( &objp->pos, &objp->orient, &objp->phys_info, (float)destroy_before_mission_time );
2171 // be sure to set the variable in the ships structure for the final death time!!!
2172 Ships[objp->instance].final_death_time = destroy_before_mission_time;
2173 Ships[objp->instance].flags |= SF_KILL_BEFORE_MISSION;
2181 void parse_common_object_data(p_object *objp)
2185 // set some defaults..
2186 objp->initial_velocity = 0;
2187 objp->initial_hull = 100;
2188 objp->initial_shields = 100;
2190 // now change defaults if present
2191 if (optional_string("+Initial Velocity:")) {
2192 stuff_int(&objp->initial_velocity);
2195 if (optional_string("+Initial Hull:"))
2196 stuff_int(&objp->initial_hull);
2197 if (optional_string("+Initial Shields:"))
2198 stuff_int(&objp->initial_shields);
2200 objp->subsys_index = Subsys_index;
2201 objp->subsys_count = 0;
2202 while (optional_string("+Subsystem:")) {
2203 i = allocate_subsys_status();
2205 objp->subsys_count++;
2206 stuff_string(Subsys_status[i].name, F_NAME, NULL);
2208 if (optional_string("$Damage:"))
2209 stuff_float(&Subsys_status[i].percent);
2211 Subsys_status[i].subsys_cargo_name = -1;
2212 if (optional_string("+Cargo Name:")) {
2213 char cargo_name[256];
2214 stuff_string(cargo_name, F_NAME, NULL);
2215 int index = string_lookup(cargo_name, (const char **)Cargo_names, Num_cargo, "cargo", 0);
2216 if (index == -1 && (Num_cargo < MAX_CARGO)) {
2218 SDL_strlcpy(Cargo_names[Num_cargo++], cargo_name, NAME_LENGTH);
2220 Subsys_status[i].subsys_cargo_name = index;
2223 if (optional_string("+AI Class:"))
2224 Subsys_status[i].ai_class = match_and_stuff(F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class");
2226 if (optional_string("+Primary Banks:"))
2227 stuff_int_list(Subsys_status[i].primary_banks, MAX_PRIMARY_BANKS, WEAPON_LIST_TYPE);
2229 if (optional_string("+Secondary Banks:"))
2230 stuff_int_list(Subsys_status[i].secondary_banks, MAX_SECONDARY_BANKS, WEAPON_LIST_TYPE);
2232 if (optional_string("+Sbank Ammo:"))
2233 stuff_int_list(Subsys_status[i].secondary_ammo, MAX_SECONDARY_BANKS, RAW_INTEGER_TYPE);
2238 void parse_objects(mission *pm, int flag)
2242 SDL_assert(pm != NULL);
2244 required_string("#Objects");
2247 num_ship_original = 0;
2248 while (required_string_either("#Wings", "$Name:")){
2249 // not all objects are always valid or legal
2250 if(parse_object(pm, flag, &temp)){
2251 // add to the default list
2252 if(num_ship_original < MAX_SHIP_ORIGINAL){
2253 memcpy(&ship_original[num_ship_original++], &temp, sizeof(p_object));
2259 p_object *mission_parse_get_original_ship( ushort net_signature )
2263 // look for original ships
2264 for(idx=0; idx<num_ship_original; idx++){
2265 if(ship_original[idx].net_signature == net_signature){
2266 return &ship_original[idx];
2274 int find_wing_name(char *name)
2278 for (i=0; i<num_wings; i++){
2279 if (!strcmp(name, Wings[i].name)){
2287 // function to create ships in the wing that need to be created. We psas the wing pointer, it's index
2288 // into the Wings array
2289 int parse_wing_create_ships( wing *wingp, int num_to_create, int force, int specific_instance )
2292 int wingnum, objnum, num_create_save;
2294 int pre_create_count;
2296 // we need to send this in multiplayer
2297 pre_create_count = wingp->total_arrived_count;
2299 // force is used to force creation of the wing -- used for multiplayer
2301 // we only want to evaluate the arrival cue of the wing if:
2303 // 2) multiplayer and I am the host of the game
2304 // can't create any ships if the arrival cue is false or the timestamp has not elapsed.
2306 if ( !eval_sexp(wingp->arrival_cue) ) /* || !timestamp_elapsed(wingp->arrival_delay) ) */
2309 // once the sexpressions becomes true, then check the arrival delay on the wing. The first time, the
2310 // arrival delay will be <= 0 meaning that no timer object has been set yet. Set up the timestamp
2311 // which should always give a number >= 0;
2312 if ( wingp->arrival_delay <= 0 ) {
2313 wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
2314 SDL_assert ( wingp->arrival_delay >= 0 );
2317 if ( !timestamp_elapsed( wingp->arrival_delay ) )
2320 // if wing is coming from docking bay, then be sure that ship we are arriving from actually exists
2322 if ( wingp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
2326 SDL_assert( wingp->arrival_anchor >= 0 );
2327 name = Parse_names[wingp->arrival_anchor];
2329 // see if ship is yet to arrive. If so, then return -1 so we can evaluate again later.
2330 if ( mission_parse_get_arrival_ship( name ) )
2333 // see if ship is in mission. If not, then we can assume it was destroyed or departed since
2334 // it is not on the arrival list (as shown by above if statement).
2335 shipnum = ship_name_lookup( name );
2336 if ( shipnum == -1 ) {
2338 // since this wing cannot arrive from this place, we need to mark the wing as destroyed and
2339 // set the wing variables appropriatly. Good for directives.
2341 // set the gone flag
2342 wingp->flags |= WF_WING_GONE;
2344 // if the current wave is zero, it never existed
2345 wingp->flags |= WF_NEVER_EXISTED;
2347 // mark the number of waves and number of ships destroyed equal to the last wave and the number
2348 // of ships yet to arrive
2349 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
2350 wingp->total_arrived_count += num_remaining;
2351 wingp->current_wave = wingp->num_waves;
2353 // replaced following three lines of code with mission log call because of bug with
2354 // the Ships_exited list.
2355 //index = ship_find_exited_ship_by_name( name );
2356 //SDL_assert( index != -1 );
2357 //if (Ships_exited[index].flags & SEF_DESTROYED ) {
2358 if ( mission_log_get_time(LOG_SHIP_DESTROYED, name, NULL, NULL) ) {
2359 wingp->total_destroyed += num_remaining;
2361 wingp->total_departed += num_remaining;
2364 Sexp_nodes[wingp->arrival_cue].value = SEXP_KNOWN_FALSE;
2369 if ( num_to_create == 0 )
2372 // check the wave_delay_timestamp field. If it is not valid, make it valid (based on wave delay min
2373 // and max valuds). If it is valid, and not elapsed, then return. If it is valid and elasped, then
2375 if ( !timestamp_valid(wingp->wave_delay_timestamp) ) {
2377 // if at least one of these is valid, then reset the timestamp. If they are both zero, we will create the
2379 if ( (wingp->wave_delay_min > 0) || (wingp->wave_delay_max > 0) ) {
2380 SDL_assert ( wingp->wave_delay_min <= wingp->wave_delay_max );
2381 time_to_arrive = wingp->wave_delay_min + (int)(frand() * (wingp->wave_delay_max - wingp->wave_delay_min));
2384 // HACK HACK -- in the presense of Mike Comet and Mitri, I have introduced one of the most
2385 // serious breaches of coding standards. I'm to lazy to fix this the correct way. Insert
2386 // a delay before the next wave of the wing can arrive to that clients in the game have ample
2387 // time to kill off any ships in the wing before the next wave arrives.
2388 if ( Game_mode & GM_MULTIPLAYER ){
2389 time_to_arrive += 7;
2391 wingp->wave_delay_timestamp = timestamp(time_to_arrive * 1000);
2395 // if we get here, both min and max values are 0; See comments above for a most serious hack
2397 if ( Game_mode & GM_MULTIPLAYER )
2398 time_to_arrive += 7;
2399 time_to_arrive *= 1000;
2400 wingp->wave_delay_timestamp = timestamp(time_to_arrive);
2403 // now check to see if the wave_delay_timestamp is elapsed or not
2404 if ( !timestamp_elapsed(wingp->wave_delay_timestamp) )
2408 // finally we can create the wing.
2410 num_create_save = num_to_create;
2412 wingnum = wingp - Wings; // get the wing number
2414 // if there are no ships to create, then all ships must be player start ships -- do nothing in this case.
2415 if ( num_to_create == 0 ){
2419 wingp->current_wave++; // we are creating new ships
2420 // we need to create num_to_create ships. Since the arrival cues for ships in a wing
2421 // are ignored, then *all* ships must be in the ship_arrival_list.
2424 objp = GET_FIRST(&ship_arrival_list);
2425 while( objp != END_OF_LIST(&ship_arrival_list) ) {
2426 p_object *temp = GET_NEXT(objp);
2428 // compare the wingnums. When they are equal, we can create the ship. In the case of
2429 // wings that have multiple waves, this code implies that we essentially creating clones
2430 // of the ships that were created in Fred for the wing when more ships for a new wave
2431 // arrive. The threshold value of a wing can also make one of the ships in a wing be "cloned"
2432 // more often than other ships in the wing. I don't think this matters much.
2433 if ( objp->wingnum == wingnum ) {
2436 // when ingame joining, we need to create a specific ship out of the list of ships for a
2437 // wing. specific_instance is a 0 based integer which specified which ship in the wing
2438 // to create. So, only create the ship we actually need to.
2439 if ( (Game_mode & GM_MULTIPLAYER) && (specific_instance > 0) ) {
2440 specific_instance--;
2445 SDL_assert ( !(objp->flags & P_SF_CANNOT_ARRIVE) ); // get allender
2449 // if we have the maximum number of ships in the wing, we must bail as well
2450 if ( wingp->current_count >= MAX_SHIPS_PER_WING ) {
2451 Int3(); // this is bogus -- we should always allow all ships to be created
2456 // bash the ship name to be the name of the wing + sone number if there is > 1 wave in
2458 // also, if multplayer, set the parse object's net signature to be wing's net signature
2459 // base + total_arrived_count (before adding 1)
2460 if ( Game_mode & GM_MULTIPLAYER ){
2461 objp->net_signature = (ushort)(wingp->net_signature + wingp->total_arrived_count);
2464 wingp->total_arrived_count++;
2465 if ( wingp->num_waves > 1 ){
2466 SDL_snprintf(objp->name, sizeof(objp->name), NOX("%s %d"), wingp->name, wingp->total_arrived_count);
2469 objnum = parse_create_object(objp);
2470 aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
2472 // copy any goals from the wing to the newly created ship
2473 for (index = 0; index < MAX_AI_GOALS; index++) {
2474 if ( wingp->ai_goals[index].ai_mode != AI_GOAL_NONE ){
2475 ai_copy_mission_wing_goal( &wingp->ai_goals[index], aip );
2479 Ai_info[Ships[Objects[objnum].instance].ai_index].wing = wingnum;
2481 if ( wingp->flags & WF_NO_DYNAMIC ){
2482 aip->ai_flags |= AIF_NO_DYNAMIC;
2485 // update housekeeping variables
2486 wingp->ship_index[wingp->current_count] = Objects[objnum].instance;
2488 // set up wingman status index
2489 hud_wingman_status_set_index(wingp->ship_index[wingp->current_count]);
2491 objp->wing_status_wing_index = Ships[Objects[objnum].instance].wing_status_wing_index;
2492 objp->wing_status_wing_pos = Ships[Objects[objnum].instance].wing_status_wing_pos;
2494 wingp->current_count++;
2496 // keep any player ship on the parse object list -- used for respawns
2497 // 5/8/98 -- MWA -- don't remove ships from the list when you are ingame joining
2498 if ( !(objp->flags & P_OF_PLAYER_START) ) {
2499 if ( (Game_mode & GM_NORMAL) || !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2500 if ( wingp->num_waves == wingp->current_wave ) { // only remove ship if one wave in wing
2501 list_remove( &ship_arrival_list, objp); // remove objp from the list
2502 if ( objp->ai_goals != -1 ){
2503 free_sexp2(objp->ai_goals); // free up sexp nodes for reuse
2509 // flag ship with SF_FROM_PLAYER_WING if a member of player starting wings
2510 if ( (Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM) ) {
2511 // but for team vs. team games, then just check the alpha and zeta wings
2512 if ( !(SDL_strcasecmp(Starting_wing_names[STARTING_WING_ALPHA], wingp->name)) || !(SDL_strcasecmp(Starting_wing_names[STARTING_WING_ZETA], wingp->name)) ) {
2513 Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
2516 for (int i = 0; i < MAX_STARTING_WINGS; i++ ) {
2517 if ( !SDL_strcasecmp(Starting_wing_names[i], wingp->name) ) {
2518 Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
2523 // keep track of how many ships to create. Stop when we have done all that we are supposed
2526 if ( !num_to_create ){
2533 SDL_assert ( num_to_create == 0 ); // we should always have enough ships in the list!!!
2535 // possibly play some event driven music here. Send a network packet indicating the wing was
2536 // created. Only do this stuff if actually in the mission.
2537 if ( (objnum != -1) && (Game_mode & GM_IN_MISSION) ) { // if true, we have created at least one new ship.
2540 // see if this wing is a player starting wing, and if so, call the maybe_add_form_goal
2541 // function to possibly make the wing form on the player
2542 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
2543 if ( Starting_wings[i] == wingnum ){
2547 if ( i < MAX_STARTING_WINGS ){
2548 ai_maybe_add_form_goal( wingp );
2551 mission_log_add_entry( LOG_WING_ARRIVE, wingp->name, NULL, wingp->current_wave );
2552 ship_num = wingp->ship_index[0];
2554 if ( !(Ships[ship_num].flags & SF_NO_ARRIVAL_MUSIC) && !(wingp->flags & WF_NO_ARRIVAL_MUSIC) ) {
2555 if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
2556 Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
2557 event_music_arrival(Ships[ship_num].team);
2561 // possibly change the location where these ships arrive based on the wings arrival location
2562 mission_set_wing_arrival_location( wingp, num_create_save );
2564 // if in multiplayer (and I am the host) and in the mission, send a wing create command to all
2566 if ( MULTIPLAYER_MASTER ){
2567 send_wing_create_packet( wingp, num_create_save, pre_create_count );
2571 // test code to check to be sure that all ships in the wing are ignoring the same types
2572 // of orders from the player
2573 if ( Fred_running ) {
2574 SDL_assert( wingp->ship_index[0] != -1 );
2575 int orders = Ships[wingp->ship_index[0]].orders_accepted;
2576 for (i = 1; i < wingp->current_count; i++ ) {
2577 if ( orders != Ships[wingp->ship_index[i]].orders_accepted ) {
2578 Warning(LOCATION, "ships in wing %s are ignoring different player orders. Please find Mark A\nto talk to him about this.", wingp->name );
2587 wingp->wave_delay_timestamp = timestamp(-1); // we will need to set this up properly for the next wave
2588 return num_create_save;
2591 void parse_wing(mission *pm)
2593 int wingnum, i, wing_goals, delay;
2594 char name[NAME_LENGTH], ship_names[MAX_SHIPS_PER_WING][NAME_LENGTH];
2595 char wing_flag_strings[MAX_WING_FLAGS][NAME_LENGTH];
2598 SDL_assert(pm != NULL);
2599 wingp = &Wings[num_wings];
2601 required_string("$Name:");
2602 stuff_string(wingp->name, F_NAME, NULL);
2603 wingnum = find_wing_name(wingp->name);
2605 error_display(0, NOX("Redundant wing name: %s\n"), wingp->name);
2606 wingnum = num_wings;
2608 wingp->total_arrived_count = 0;
2609 wingp->total_destroyed = 0;
2612 required_string("$Waves:");
2613 stuff_int(&wingp->num_waves);
2614 SDL_assert ( wingp->num_waves >= 1 ); // there must be at least 1 wave
2616 wingp->current_wave = 0;
2618 required_string("$Wave Threshold:");
2619 stuff_int(&wingp->threshold);
2621 required_string("$Special Ship:");
2622 stuff_int(&wingp->special_ship);
2624 wingp->arrival_anchor = -1;
2625 find_and_stuff("$Arrival Location:", &wingp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
2626 if ( optional_string("+Arrival Distance:") ) {
2627 stuff_int( &wingp->arrival_distance );
2628 if ( wingp->arrival_location != ARRIVE_AT_LOCATION ) {
2629 required_string("$Arrival Anchor:");
2630 stuff_string(name, F_NAME, NULL);
2631 wingp->arrival_anchor = get_anchor(name);
2635 if (optional_string("+Arrival delay:")) {
2638 Error(LOCATION, "Cannot have arrival delay < 0 on wing %s", wingp->name );
2642 if ( !Fred_running ){
2643 wingp->arrival_delay = -delay;
2645 wingp->arrival_delay = delay;
2648 required_string("$Arrival Cue:");
2649 wingp->arrival_cue = get_sexp_main();
2650 if ( !Fred_running && (wingp->arrival_cue >= 0) ) {
2651 if ( eval_sexp(wingp->arrival_cue) ) // evaluate to determine if sexp is always false.
2652 wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
2656 find_and_stuff("$Departure Location:", &wingp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
2657 wingp->departure_anchor = -1;
2658 if ( wingp->departure_location == DEPART_AT_DOCK_BAY ) {
2659 required_string("$Departure Anchor:");
2660 stuff_string( name, F_NAME, NULL );
2661 wingp->departure_anchor = get_anchor(name);
2664 if (optional_string("+Departure delay:")) {
2667 Error(LOCATION, "Cannot have departure delay < 0 on wing %s", wingp->name );
2672 if ( !Fred_running )
2673 wingp->departure_delay = -delay; // use negative numbers to mean that delay timer not yet set
2675 wingp->departure_delay = delay;
2677 required_string("$Departure Cue:");
2678 wingp->departure_cue = get_sexp_main();
2680 // stores a list of all names of ships in the wing
2681 required_string("$Ships:");
2682 wingp->wave_count = stuff_string_list( ship_names, MAX_SHIPS_PER_WING );
2683 wingp->current_count = 0;
2685 // get the wings goals, if any
2687 if ( optional_string("$AI Goals:") )
2688 wing_goals = get_sexp_main();
2691 if (optional_string("+Hotkey:")) {
2692 stuff_int(&wingp->hotkey);
2693 SDL_assert((wingp->hotkey >= 0) && (wingp->hotkey < 10));
2696 if (optional_string("+Flags:")) {
2699 count = stuff_string_list( wing_flag_strings, MAX_WING_FLAGS );
2700 for (i = 0; i < count; i++ ) {
2701 if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("ignore-count")) )
2702 wingp->flags |= WF_IGNORE_COUNT;
2703 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("reinforcement")) )
2704 wingp->flags |= WF_REINFORCEMENT;
2705 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-music")) )
2706 wingp->flags |= WF_NO_ARRIVAL_MUSIC;
2707 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-message")) )
2708 wingp->flags |= WF_NO_ARRIVAL_MESSAGE;
2709 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-warp")) )
2710 wingp->flags |= WF_NO_ARRIVAL_WARP;
2711 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-departure-warp")) )
2712 wingp->flags |= WF_NO_DEPARTURE_WARP;
2713 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-dynamic")) )
2714 wingp->flags |= WF_NO_DYNAMIC;
2716 Warning(LOCATION, "unknown wing flag\n%s\n\nSkipping.", wing_flag_strings[i]);
2720 // get the wave arrival delay bounds (if present). Used as lower and upper bounds (in seconds)
2721 // which determine when new waves of a wing should arrive.
2722 wingp->wave_delay_min = 0;
2723 wingp->wave_delay_max = 0;
2724 if ( optional_string("+Wave Delay Min:") )
2725 stuff_int( &(wingp->wave_delay_min) );
2726 if ( optional_string("+Wave Delay Max:") )
2727 stuff_int( &(wingp->wave_delay_max) );
2729 // be sure to set the wave arrival timestamp of this wing to pop right away so that the
2730 // wing could be created if it needs to be
2731 wingp->wave_delay_timestamp = timestamp(0);
2733 // initialize wing goals
2734 for (i=0; i<MAX_AI_GOALS; i++) {
2735 wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
2736 wingp->ai_goals[i].priority = -1;
2740 // error checking against the player ship wings to be sure that wave count doesn't exceed one for
2742 if ( Game_mode & GM_MULTIPLAYER ) {
2743 for (i = 0; i < MAX_STARTING_WINGS+1; i++ ) {
2744 if ( !SDL_strcasecmp(Starting_wing_names[i], wingp->name) ) {
2745 if ( wingp->num_waves > 1 ) {
2746 // only end the game if we're the server - clients will eventually find out :)
2747 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2748 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_WAVE_COUNT);
2750 // Error(LOCATION, "Player wings Alpha, Beta, Gamma, or Zeta cannot have more than 1 wave.");
2756 // Get the next starting signature for this in this wing. We want to reserve wave_count * num_waves
2757 // of signature. These can be used to construct wings for ingame joiners.
2758 if ( Game_mode & GM_MULTIPLAYER ) {
2761 wingp->net_signature = multi_assign_network_signature( MULTI_SIG_SHIP );
2762 next_signature = wingp->net_signature + (wingp->wave_count * wingp->num_waves);
2763 if ( next_signature > SHIP_SIG_MAX )
2764 Error(LOCATION, "Too many total ships in mission (%d) for network signature assignment", SHIP_SIG_MAX);
2765 multi_set_network_signature( (ushort)next_signature, MULTI_SIG_SHIP );
2768 for (i=0; i<MAX_SHIPS_PER_WING; i++)
2769 wingp->ship_index[i] = -1;
2771 // set up the ai_goals for this wing -- all ships created from this wing will inherit these goals
2772 // goals for the wing are stored slightly differently than for ships. We simply store the index
2773 // into the sexpression array of each goal (max 10). When a ship in this wing is created, each
2774 // goal in the wings goal array is given to the ship.
2775 if ( wing_goals != -1 ) {
2778 // this will assign the goals to the wings as well as to any ships in the wing that have been
2780 for ( sexp = CDR(wing_goals); sexp != -1; sexp = CDR(sexp) )
2781 ai_add_wing_goal_sexp(sexp, AIG_TYPE_EVENT_WING, wingnum); // used by Fred
2784 free_sexp2(wing_goals); // free up sexp nodes for reused, since they aren't needed anymore.
2787 // set the wing number for all ships in the wing
2788 for (i = 0; i < wingp->wave_count; i++ ) {
2789 //char *ship_name = wingp->ship_names[i];
2791 int num, assigned = 0;
2794 ship_name = ship_names[i];
2796 num = wingp->ship_index[i] = ship_name_lookup(ship_name, 1);
2797 SDL_assert ( num != -1 );
2799 // hack code -- REMOVE
2800 if ( Objects[Ships[num].objnum].flags & OF_PLAYER_SHIP )
2801 Ships[num].wingnum = wingnum;
2804 // determine if this ship is a player ship, and deal with it appropriately.
2805 if ( !SDL_strncasecmp(ship_name, NOX("Player "), 7) ) {
2806 Error(LOCATION, "Old mission file -- please convert by loading/saving in Fred -- see Allender/Hoffoss for help.");
2809 // assign the wing number to the ship -- if the ship has arrived, doulble check that
2810 // there is only one wave of this wing since ships with their own arrival cue cannot be
2811 // in a wing with > 1 wave. Otherwise, find the ship on the ship arrival list and set
2812 // their wing number
2813 if ( (num = ship_name_lookup(ship_name)) != -1 ) {
2814 Int3(); // this is impossible under the new system
2817 objp = GET_FIRST(&ship_arrival_list);
2818 while( objp != END_OF_LIST(&ship_arrival_list) ) {
2819 if ( !strcmp(ship_name, objp->name) ) {
2820 SDL_assert ( objp->wingnum == -1 ); // get Allender -- ship appears to be in multiple wings
2821 objp->wingnum = wingnum;
2824 objp = GET_NEXT(objp);
2828 if ( !assigned || (assigned > 1) )
2829 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);
2833 // Fred doesn't create the wing. otherwise, create the wing if is isn't a reinforcement.
2834 if ( !Fred_running && !(wingp->flags & WF_REINFORCEMENT) )
2835 parse_wing_create_ships( wingp, wingp->wave_count );
2838 void parse_wings(mission *pm)
2840 required_string("#Wings");
2841 while (required_string_either("#Events", "$Name:")) {
2842 SDL_assert(num_wings < MAX_WINGS);
2848 // mission events are sexpressions which cause things to happen based on the outcome
2849 // of other events in a mission. Essentially scripting the different things that can happen
2852 void parse_event(mission *pm)
2855 mission_event *event;
2857 event = &Mission_events[Num_mission_events];
2858 event->chain_delay = -1;
2860 required_string( "$Formula:" );
2861 event->formula = get_sexp_main();
2863 if (optional_string("+Name:")){
2864 stuff_string(event->name, F_NAME, NULL);
2869 if ( optional_string("+Repeat Count:")){
2870 stuff_int( &(event->repeat_count) );
2872 event->repeat_count = 1;
2875 event->interval = -1;
2876 if ( optional_string("+Interval:")){
2877 stuff_int( &(event->interval) );
2881 if ( optional_string("+Score:") ){
2882 stuff_int(&event->score);
2885 if ( optional_string("+Chained:") ){
2886 stuff_int(&event->chain_delay);
2889 if ( optional_string("+Objective:") ) {
2890 stuff_string(buf, F_NAME, NULL);
2891 event->objective_text = strdup(buf);
2893 event->objective_text = NULL;
2896 if ( optional_string("+Objective key:") ) {
2897 stuff_string(buf, F_NAME, NULL);
2898 event->objective_key_text = strdup(buf);
2900 event->objective_key_text = NULL;
2904 if( optional_string("+Team:") ) {
2905 stuff_int(&event->team);
2908 event->timestamp = timestamp(-1);
2910 // sanity check on the repeat count variable
2911 if ( event->repeat_count <= 0 ){
2912 Error (LOCATION, "Repeat count for mission event %s is <=0.\nMust be >= 1!", event->name );
2916 void parse_events(mission *pm)
2918 required_string("#Events");
2920 while (required_string_either( "#Goals", "$Formula:")) {
2921 SDL_assert( Num_mission_events < MAX_MISSION_EVENTS );
2923 Num_mission_events++;
2927 void parse_goal(mission *pm)
2931 mission_goal *goalp;
2933 goalp = &Mission_goals[Num_goals++];
2935 SDL_assert(Num_goals < MAX_GOALS);
2936 SDL_assert(pm != NULL);
2938 find_and_stuff("$Type:", &goalp->type, F_NAME, Goal_type_names, Num_goal_type_names, "goal type");
2940 required_string("+Name:");
2941 stuff_string(goalp->name, F_NAME, NULL);
2943 // backwards compatibility for old Fred missions - all new missions should use $MessageNew
2944 if(optional_string("$Message:")){
2945 stuff_string(goalp->message, F_NAME, NULL, MAX_GOAL_TEXT);
2947 required_string("$MessageNew:");
2948 stuff_string(goalp->message, F_MULTITEXT, NULL, MAX_GOAL_TEXT);
2951 if (optional_string("$Rating:")){
2952 stuff_int(&dummy); // not used
2955 required_string("$Formula:");
2956 goalp->formula = get_sexp_main();
2959 if ( optional_string("+Invalid:") )
2960 goalp->type |= INVALID_GOAL;
2961 if ( optional_string("+Invalid") )
2962 goalp->type |= INVALID_GOAL;
2963 if ( optional_string("+No music") )
2964 goalp->flags |= MGF_NO_MUSIC;
2967 if ( optional_string("+Score:") ){
2968 stuff_int(&goalp->score);
2972 if ( optional_string("+Team:") ){
2973 stuff_int( &goalp->team );
2977 void parse_goals(mission *pm)
2979 required_string("#Goals");
2981 while (required_string_either("#Waypoints", "$Type:")){
2986 void parse_waypoint_list(mission *pm)
2991 SDL_assert(Num_waypoint_lists < MAX_WAYPOINT_LISTS);
2992 SDL_assert(pm != NULL);
2993 wpl = &Waypoint_lists[Num_waypoint_lists];
2995 required_string("$Name:");
2996 stuff_string(wpl->name, F_NAME, NULL);
2998 required_string("$List:");
2999 wpl->count = stuff_vector_list(wpl->waypoints, MAX_WAYPOINTS_PER_LIST);
3002 // AAAAHH! I don't like to hard code a mission fix but I have no clue what to do
3003 // to fix this properly. In the FS1 mission "Playing Judas" you have to try and fly
3004 // into one of the docking bays on the Lucifer. Due to some change in the code the
3005 // waypoints and the Lucifer's position don't match up so we have to change the
3006 // waypoint position to compensate.
3007 if ( !SDL_strcasecmp(pm->name, "Playing Judas") ) {
3008 if ( !SDL_strcasecmp(wpl->name, "Docking Bay 1") ) {
3009 wpl->waypoints[0].xyz.x = -1262.550903;
3010 wpl->waypoints[0].xyz.y = 27.676950;
3011 wpl->waypoints[0].xyz.z = 4461.702930;
3012 } else if ( !SDL_strcasecmp(wpl->name, "Docking Bat 2") ) { // it really is spelled "Bat" in the mission
3013 wpl->waypoints[0].xyz.x = -1105.347976;
3014 wpl->waypoints[0].xyz.y = 27.676950;
3015 wpl->waypoints[0].xyz.z = 3900.236867;
3020 Num_waypoint_lists++;
3023 void parse_waypoints(mission *pm)
3028 required_string("#Waypoints");
3031 while (optional_string("$Jump Node:")) {
3032 SDL_assert(Num_jump_nodes < MAX_JUMP_NODES);
3034 z = jumpnode_create(&pos);
3037 if (optional_string("$Jump Node Name:")) {
3038 stuff_string(Jump_nodes[Num_jump_nodes - 1].name, F_NAME, NULL);
3041 // If no name exists, then use a standard name
3042 if ( Jump_nodes[Num_jump_nodes - 1].name[0] == 0 ) {
3043 SDL_snprintf(Jump_nodes[Num_jump_nodes - 1].name, NAME_LENGTH, "Jump Node %d", Num_jump_nodes);
3047 while (required_string_either("#Messages", "$Name:"))
3048 parse_waypoint_list(pm);
3051 void parse_messages(mission *pm)
3053 required_string("#Messages");
3055 mprintf(("Starting mission message count : %d\n", Num_message_waves));
3057 // the message_parse function can be found in MissionMessage.h. The format in the
3058 // mission file takes the same format as the messages in messages,tbl. Make parsing
3059 // a whole lot easier!!!
3060 while ( required_string_either("#Reinforcements", "$Name")){
3061 message_parse(); // call the message parsing system
3064 mprintf(("Ending mission message count : %d\n", Num_message_waves));
3067 void parse_reinforcement(mission *pm)
3069 reinforcements *ptr;
3072 SDL_assert(Num_reinforcements < MAX_REINFORCEMENTS);
3073 SDL_assert(pm != NULL);
3074 ptr = &Reinforcements[Num_reinforcements];
3076 required_string("$Name:");
3077 stuff_string(ptr->name, F_NAME, NULL);
3079 find_and_stuff("$Type:", &ptr->type, F_NAME, Reinforcement_type_names, Num_reinforcement_type_names, "reinforcement type");
3081 required_string("$Num times:");
3082 stuff_int(&ptr->uses);
3085 // reset the flags to 0
3088 if ( optional_string("+Arrival delay:") ){
3089 stuff_int( &(ptr->arrival_delay) );
3092 if ( optional_string("+No Messages:") ){
3093 stuff_string_list( ptr->no_messages, MAX_REINFORCEMENT_MESSAGES );
3096 if ( optional_string("+Yes Messages:") ){
3097 stuff_string_list( ptr->yes_messages, MAX_REINFORCEMENT_MESSAGES );
3100 // sanity check on the names of reinforcements -- must either be wings/ships/arrival list.
3101 if ( ship_name_lookup(ptr->name) == -1 ) {
3102 if ( wing_name_lookup(ptr->name, 1) == -1 ) {
3105 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3106 if ( !SDL_strcasecmp(ptr->name, p_objp->name) ){
3111 if ( p_objp == END_OF_LIST(&ship_arrival_list) ) {
3112 Warning(LOCATION, "Reinforcement %s not found as ship or wing", ptr->name);
3118 // now, if the reinforcement is a wing, then set the number of waves of the wing == number of
3119 // uses of the reinforcement
3120 instance = wing_name_lookup(ptr->name, 1);
3121 if ( instance != -1 )
3122 Wings[instance].num_waves = ptr->uses;
3124 Num_reinforcements++;
3127 void parse_reinforcements(mission *pm)
3129 Num_reinforcements = 0;
3130 required_string("#Reinforcements");
3132 while (required_string_either("#Background bitmaps", "$Name:"))
3133 parse_reinforcement(pm);
3136 void parse_bitmap(mission *pm)
3139 starfield_bitmap_instance b;
3143 SDL_assert(pm != NULL);
3145 while(optional_string("$Bitmap:")) {
3146 stuff_string(b.filename, F_NAME, NULL);
3148 required_string("$Orientation:");
3151 required_string("$Rotation rate:");
3152 stuff_float(&b.rot);
3154 required_string("$Distance:");
3155 stuff_float(&b.scale_x);
3156 b.scale_y = b.scale_x;
3160 required_string("$Light:");
3161 stuff_int(&b.sun_light);
3163 if(Num_suns < MAX_STARFIELD_BITMAPS){
3165 SDL_strlcpy(Suns[Num_suns].filename, b.filename, sizeof(b.filename));
3171 char name[NAME_LENGTH];
3173 starfield_bitmaps *ptr;
3175 SDL_assert(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS);
3176 SDL_assert(pm != NULL);
3177 ptr = &Starfield_bitmaps[Num_starfield_bitmaps];
3179 required_string("$Bitmap:");
3180 stuff_string(name, F_NAME, NULL);
3181 for (z=0; z<Num_starfield_bitmap_lists; z++) {
3182 if (!SDL_strcasecmp(name, Starfield_bitmap_list[z].name)){
3187 if ( z >= Num_starfield_bitmap_lists ) {
3188 Warning( LOCATION, "Bitmap specified in mission not in game!\n" );
3192 ptr->bitmap_index = z;
3193 required_string("$Orientation:");
3194 stuff_matrix(&ptr->m);
3196 required_string("$Rotation rate:");
3197 stuff_float(&ptr->rot);
3199 required_string("$Distance:");
3200 stuff_float(&ptr->dist);
3202 required_string("$Light:");
3203 stuff_int(&ptr->light);
3204 Num_starfield_bitmaps++;
3205 calculate_bitmap_points(ptr);
3211 void parse_bitmaps(mission *pm)
3213 char str[MAX_FILENAME_LEN+1] = "";
3214 starfield_bitmap_instance b;
3217 Num_starfield_bitmaps = 0;
3218 required_string("#Background bitmaps");
3220 required_string("$Num stars:");
3221 stuff_int(&Num_stars);
3222 if (Num_stars >= MAX_STARS)
3223 Num_stars = MAX_STARS;
3225 int Ambient_light_level;
3226 required_string("$Ambient light level:");
3227 stuff_int(&Ambient_light_level);
3229 // This should call light_set_ambient() to
3230 // set the ambient light
3233 Mission_palette = 1;
3235 if(The_mission.flags & MISSION_FLAG_FULLNEB){
3236 // no regular nebula stuff
3240 SDL_strlcpy(Neb2_texture_name, "Eraseme3", sizeof(Neb2_texture_name));
3241 Neb2_poof_flags = ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
3242 if(optional_string("+Neb2:")){
3243 stuff_string(Neb2_texture_name, F_NAME, NULL);
3245 required_string("+Neb2Flags:");
3246 stuff_int(&Neb2_poof_flags);
3248 // initialize neb effect. its gross to do this here, but Fred is dumb so I have no choice ... :(
3254 if (optional_string("+Nebula:")) {
3255 stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3257 // parse the proper nebula type (full or not)
3258 for (z=0; z<NUM_NEBULAS; z++){
3259 if(The_mission.flags & MISSION_FLAG_FULLNEB){
3260 if (!SDL_strcasecmp(str, Neb2_filenames[z])) {
3265 if (!SDL_strcasecmp(str, Nebula_filenames[z])) {
3272 if (optional_string("+Color:")) {
3273 stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3274 for (z=0; z<NUM_NEBULA_COLORS; z++){
3275 if (!SDL_strcasecmp(str, Nebula_colors[z])) {
3276 Mission_palette = z;
3282 if (optional_string("+Pitch:")){
3283 stuff_int(&Nebula_pitch);
3288 if (optional_string("+Bank:")){
3289 stuff_int(&Nebula_bank);
3294 if (optional_string("+Heading:")){
3295 stuff_int(&Nebula_heading);
3301 if (Nebula_index >= 0){
3302 nebula_init(Nebula_filenames[Nebula_index], Nebula_pitch, Nebula_bank, Nebula_heading);
3310 while(optional_string("$Sun:")){
3312 stuff_string(b.filename, F_NAME, NULL);
3315 required_string("+Angles:");
3316 stuff_float(&b.ang.p);
3317 stuff_float(&b.ang.b);
3318 stuff_float(&b.ang.h);
3321 required_string("+Scale:");
3322 stuff_float(&b.scale_x);
3323 b.scale_y = b.scale_x;
3327 // if we have room, store it
3328 if(Num_suns < MAX_STARFIELD_BITMAPS){
3330 SDL_strlcpy(Suns[Num_suns].filename, b.filename, sizeof(b.filename));
3335 // parse background bitmaps
3336 Num_starfield_bitmaps = 0;
3337 while(optional_string("$Starbitmap:")){
3339 stuff_string(b.filename, F_NAME, NULL);
3342 required_string("+Angles:");
3343 stuff_float(&b.ang.p);
3344 stuff_float(&b.ang.b);
3345 stuff_float(&b.ang.h);
3349 if(optional_string("+Scale:")){
3350 stuff_float(&b.scale_x);
3351 b.scale_y = b.scale_x;
3355 required_string("+ScaleX:");
3356 stuff_float(&b.scale_x);
3358 required_string("+ScaleY:");
3359 stuff_float(&b.scale_y);
3361 required_string("+DivX:");
3362 stuff_int(&b.div_x);
3364 required_string("+DivY:");
3365 stuff_int(&b.div_y);
3368 // if we have room, store it
3369 if(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS){
3370 Starfield_bitmap_instance[Num_starfield_bitmaps] = b;
3371 SDL_strlcpy(Starfield_bitmap_instance[Num_starfield_bitmaps].filename, b.filename, sizeof(b.filename));
3372 Num_starfield_bitmaps++;
3380 if ( optional_string("#Asteroid Fields") ){
3381 parse_asteroid_fields(pm);
3385 void parse_asteroid_fields(mission *pm)
3387 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
3389 int i, count, subtype;
3391 SDL_assert(pm != NULL);
3392 for (i=0; i<MAX_ASTEROID_FIELDS; i++)
3393 Asteroid_field.num_initial_asteroids = 0;
3397 // required_string("#Asteroid Fields");
3399 while (required_string_either("#", "$Density:")) {
3401 while (required_string_either("#", "$density:")) {
3403 float speed, density;
3406 required_string("$Density:");
3407 stuff_float(&density);
3409 Asteroid_field.num_initial_asteroids = (int) density;
3411 Asteroid_field.field_type = FT_ACTIVE;
3412 if (optional_string("+Field Type:")) {
3413 stuff_int((int*)&Asteroid_field.field_type);
3416 Asteroid_field.debris_genre = DG_ASTEROID;
3417 if (optional_string("+Debris Genre:")) {
3418 stuff_int((int*)&Asteroid_field.debris_genre);
3421 Asteroid_field.field_debris_type[0] = -1;
3422 Asteroid_field.field_debris_type[1] = -1;
3423 Asteroid_field.field_debris_type[2] = -1;
3424 if (Asteroid_field.debris_genre == DG_SHIP) {
3425 if (optional_string("+Field Debris Type:")) {
3426 stuff_int(&Asteroid_field.field_debris_type[0]);
3428 if (optional_string("+Field Debris Type:")) {
3429 stuff_int(&Asteroid_field.field_debris_type[1]);
3431 if (optional_string("+Field Debris Type:")) {
3432 stuff_int(&Asteroid_field.field_debris_type[2]);
3436 if (optional_string("+Field Debris Type:")) {
3437 stuff_int(&subtype);
3438 Asteroid_field.field_debris_type[subtype] = 1;
3441 if (optional_string("+Field Debris Type:")) {
3442 stuff_int(&subtype);
3443 Asteroid_field.field_debris_type[subtype] = 1;
3446 if (optional_string("+Field Debris Type:")) {
3447 stuff_int(&subtype);
3448 Asteroid_field.field_debris_type[subtype] = 1;
3453 // backward compatibility
3454 if ( (Asteroid_field.debris_genre == DG_ASTEROID) && (count == 0) ) {
3455 Asteroid_field.field_debris_type[0] = 0;
3458 required_string("$Average Speed:");
3459 stuff_float(&speed);
3461 vm_vec_rand_vec_quick(&Asteroid_field.vel);
3462 vm_vec_scale(&Asteroid_field.vel, speed);
3464 Asteroid_field.speed = speed;
3466 required_string("$Minimum:");
3467 stuff_vector(&Asteroid_field.min_bound);
3469 required_string("$Maximum:");
3470 stuff_vector(&Asteroid_field.max_bound);
3472 if (optional_string("+Inner Bound:")) {
3473 Asteroid_field.has_inner_bound = 1;
3475 required_string("$Minimum:");
3476 stuff_vector(&Asteroid_field.inner_min_bound);
3478 required_string("$Maximum:");
3479 stuff_vector(&Asteroid_field.inner_max_bound);
3481 Asteroid_field.has_inner_bound = 0;
3488 void parse_variables()
3490 if (! optional_string("#Sexp_variables") ) {
3493 stuff_sexp_variable_list();
3498 void parse_mission(mission *pm, int flag)
3502 Player_starts = Num_cargo = Num_waypoint_lists = Num_goals = num_wings = num_ship_arrivals = 0;
3503 Player_start_shipnum = -1;
3504 *Player_start_shipname = 0; // make the string 0 length for checking later
3505 memset( &Player_start_pobject, 0, sizeof(Player_start_pobject) );
3507 // initialize the initially_docked array.
3508 for ( i = 0; i < MAX_SHIPS; i++ ) {
3509 Initially_docked[i].docker = NULL;
3510 Initially_docked[i].dockee[0] = '\0';
3511 Initially_docked[i].docker_point[0] = '\0';
3512 Initially_docked[i].dockee_point[0] = '\0';
3514 Total_initially_docked = 0;
3516 list_init( &ship_arrival_list ); // init lists for arrival objects and wings
3521 parse_mission_info(pm);
3522 Current_file_checksum = netmisc_calc_checksum(pm,MISSION_CHECKSUM_SIZE);
3523 if ( flag == MISSION_PARSE_MISSION_INFO )
3525 parse_plot_info(pm);
3527 parse_briefing_info(pm); // TODO: obsolete code, keeping so we don't obsolete existing mission files
3528 parse_cmd_briefs(pm);
3530 parse_debriefing_new(pm);
3531 parse_player_info(pm);
3532 parse_objects(pm, flag);
3536 parse_waypoints(pm);
3538 parse_reinforcements(pm);
3542 post_process_mission();
3545 void post_process_mission()
3548 int indices[MAX_SHIPS], objnum;
3553 // the player_start_shipname had better exist at this point!
3554 Player_start_shipnum = ship_name_lookup( Player_start_shipname );
3555 SDL_assert ( Player_start_shipnum != -1 );
3556 SDL_assert ( Player_start_pobject.flags & P_SF_PLAYER_START_VALID );
3558 // Assign objnum, shipnum, etc. to the player structure
3559 objnum = Ships[Player_start_shipnum].objnum;
3560 Player_obj = &Objects[objnum];
3562 Player->objnum = objnum;
3565 Player_obj->flags |= OF_PLAYER_SHIP; // make this object a player controlled ship.
3566 Player_ship = &Ships[Player_start_shipnum];
3567 Player_ai = &Ai_info[Player_ship->ai_index];
3569 Player_ai->targeted_subsys = NULL;
3570 Player_ai->targeted_subsys_parent = -1;
3572 // determine if player start has initial velocity and set forward cruise percent to relect this
3573 if ( Player_obj->phys_info.vel.xyz.z > 0.0f )
3574 Player->ci.forward_cruise_percent = Player_obj->phys_info.vel.xyz.z / Player_ship->current_max_speed * 100.0f;
3576 // put in hard coded starting wing names.
3577 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3578 Starting_wings[0] = wing_name_lookup(Starting_wing_names[0],1);
3579 Starting_wings[1] = wing_name_lookup(Starting_wing_names[MAX_STARTING_WINGS],1);
3581 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
3582 Starting_wings[i] = wing_name_lookup(Starting_wing_names[i], 1);
3588 // call a function to deal with intially docked ships
3589 mission_parse_do_initial_docks();
3591 // deal with setting up arrival location for all ships. Must do this now after all ships are created
3592 mission_parse_set_arrival_locations();
3594 // clear out information about arriving support ships
3595 Arriving_support_ship = NULL;
3596 Num_arriving_repair_targets = 0;
3598 // convert all ship name indices to ship indices now that mission has been loaded
3600 for (i=0; i<Num_parse_names; i++) {
3601 indices[i] = ship_name_lookup(Parse_names[i], 1);
3603 Warning(LOCATION, "Ship name \"%s\" referenced, but this ship doesn't exist", Parse_names[i]);
3606 for (i=0; i<MAX_SHIPS; i++) {
3607 if ((Ships[i].objnum >= 0) && (Ships[i].arrival_anchor >= 0) && (Ships[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3608 Ships[i].arrival_anchor = indices[Ships[i].arrival_anchor];
3610 if ( (Ships[i].objnum >= 0) && (Ships[i].departure_anchor >= 0) )
3611 Ships[i].departure_anchor = indices[Ships[i].departure_anchor];
3614 for (i=0; i<MAX_WINGS; i++) {
3615 if (Wings[i].wave_count && (Wings[i].arrival_anchor >= 0) && (Wings[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3616 Wings[i].arrival_anchor = indices[Wings[i].arrival_anchor];
3618 if (Wings[i].wave_count && (Wings[i].departure_anchor >= 0) )
3619 Wings[i].departure_anchor = indices[Wings[i].departure_anchor];
3624 // before doing anything else, we must validate all of the sexpressions that were loaded into the mission.
3625 // Loop through the Sexp_nodes array and send the top level functions to the check_sexp_syntax parser
3627 for (i = 0; i < MAX_SEXP_NODES; i++) {
3628 if ( is_sexp_top_level(i) && (!Fred_running || (i != Sexp_clipboard))) {
3629 int result, bindex, op;
3631 op = identify_operator(CTEXT(i));
3632 SDL_assert(op != -1); // need to make sure it is an operator before we treat it like one..
3633 result = check_sexp_syntax( i, query_operator_return_type(op), 1, &bindex);
3635 // entering this if statement will result in program termination!!!!!
3636 // print out an error based on the return value from check_sexp_syntax()
3638 char sexp_str[8192], text[8192];
3640 convert_sexp_to_string( i, sexp_str, sizeof(sexp_str), SEXP_ERROR_CHECK_MODE);
3641 SDL_snprintf(text, sizeof(text), "%s.\n\nIn sexpression: %s\n(Error appears to be: %s)",
3642 sexp_error_message(result), sexp_str, Sexp_nodes[bindex].text);
3645 Error( LOCATION, text );
3647 Warning( LOCATION, text );
3652 ai_post_process_mission();
3656 for (i=0; i<Total_initially_docked; i++) {
3657 z = ship_name_lookup(Initially_docked[i].dockee);
3659 SDL_assert(Initially_docked[i].docker->type == OBJ_SHIP);
3660 p1 = model_find_dock_name_index(Ships[Initially_docked[i].docker->instance].modelnum,
3661 Initially_docked[i].docker_point);
3662 SDL_assert(Objects[z].type == OBJ_SHIP);
3663 p2 = model_find_dock_name_index(Ships[Objects[z].instance].modelnum,
3664 Initially_docked[i].dockee_point);
3666 if ((p1 >= 0) && (p2 >= 0)) {
3667 nprintf(("AI", "Initially Docked: %s with %s\n", Ships[Initially_docked[i].docker->instance].ship_name, Ships[Objects[z].instance].ship_name));
3668 if (ship_docking_valid(Initially_docked[i].docker->instance, Objects[z].instance)) // only dock if they are allowed to be docked.
3669 ai_dock_with_object(Initially_docked[i].docker, &Objects[z], 89, AIDO_DOCK_NOW, p1, p2);
3672 Int3(); // Curious. Two ships told to dock, but one of the dock points is bogus.
3673 // Get Allender or Hoffoss, one of whom probably wrote the above if ()
3678 // we must also count all of the ships of particular types. We count all of the ships that do not have
3679 // their SF_IGNORE_COUNT flag set. We don't count ships in wings when the equivalent wing flag is set.
3680 // in counting ships in wings, we increment the count by the wing's wave count to account for everyone.
3681 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
3682 int siflags, num, shipnum;
3684 shipnum = Objects[so->objnum].instance;
3685 // pass over non-ship objects and player ship objects
3686 if ( Ships[shipnum].objnum == -1 || (Objects[Ships[shipnum].objnum].flags & OF_PLAYER_SHIP) )
3688 if ( Ships[shipnum].flags & SF_IGNORE_COUNT )
3690 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_IGNORE_COUNT) )
3693 siflags = Ship_info[Ships[shipnum].ship_info_index].flags;
3695 // determine the number of times we need to add this ship into the count
3696 // if ( Ships[i].wingnum == -1 )
3699 // num = Wings[Ships[i].wingnum].num_waves;
3701 ship_add_ship_type_count( siflags, num );
3703 // now go through the list of ships yet to arrive
3704 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3707 // go through similar motions as above
3708 if ( p_objp->flags & P_SF_IGNORE_COUNT )
3710 if ( (p_objp->wingnum != -1) && (Wings[p_objp->wingnum].flags & WF_IGNORE_COUNT) )
3713 siflags = Ship_info[p_objp->ship_class].flags;
3715 if ( p_objp->wingnum == -1 )
3718 num = Wings[p_objp->wingnum].num_waves - 1; // subtract one since we already counted the first wave
3720 ship_add_ship_type_count( siflags, num );
3723 // set player weapons that are selected by default
3724 // AL 09/17/97: I added this code to select the first primary/secondary weapons,
3725 // since I noticed the player ship sometimes doesn't get default weapons selected
3727 // DB: modified 4/23/98 to take multiplayer into account. Under certain circumstances, multiplayer netplayer ships
3728 // had their current_primary_bank and current_secondary_bank set to -1 (from ship_set()) and left there since
3729 // Player_ship is not the only one we need to need about.
3730 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
3731 ship *shipp = &Ships[Objects[so->objnum].instance];
3733 // don't process non player wing ships
3734 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
3737 swp = &shipp->weapons;
3739 // swp = &Player_ship->weapons;
3740 if ( swp->num_primary_banks > 0 ) {
3741 swp->current_primary_bank = 0; // currently selected primary bank
3744 if ( swp->num_secondary_banks > 0 ) {
3745 swp->current_secondary_bank = 0; // currently selected secondary bank
3749 ets_init_ship(Player_obj); // init ETS data for the player
3751 // put the timestamp stuff here for now
3752 Mission_arrival_timestamp = timestamp( ARRIVAL_TIMESTAMP );
3753 Mission_departure_timestamp = timestamp( DEPARTURE_TIMESTAMP );
3754 Mission_end_time = -1;
3756 if(Game_mode & GM_MULTIPLAYER){
3757 multi_respawn_build_points();
3760 // maybe reset hotkey defaults when loading new mission
3761 if ( Last_file_checksum != Current_file_checksum ){
3762 mission_hotkey_reset_saved();
3765 Allow_arrival_music_timestamp=timestamp(0);
3766 Allow_arrival_message_timestamp=timestamp(0);
3767 Arrival_message_delay_timestamp = timestamp(-1);
3770 for(idx=0; idx<2; idx++){
3771 Allow_arrival_music_timestamp_m[idx]=timestamp(0);
3772 Allow_arrival_message_timestamp_m[idx]=timestamp(0);
3773 Arrival_message_delay_timestamp_m[idx] = timestamp(-1);
3776 Last_file_checksum = Current_file_checksum;
3779 int get_mission_info(char *filename, mission *mission_p)
3783 // if mission_p is NULL, make it point to The_mission
3784 if ( mission_p == NULL )
3785 mission_p = &The_mission;
3787 if ((rval = setjmp(parse_abort)) != 0) {
3788 nprintf(("Error", "Error abort! Code = %d", rval));
3794 // open localization
3797 CFILE *ftemp = cfopen(filename, "rt");
3799 // close localization
3805 // 7/9/98 -- MWA -- check for 0 length file.
3806 filelength = cfilelength(ftemp);
3808 if ( filelength == 0 ){
3809 // close localization
3815 read_file_text(filename, CF_TYPE_MISSIONS);
3816 memset( mission_p, 0, sizeof(mission) );
3818 parse_mission_info(mission_p);
3820 // close localization
3827 // mai parse routine for parsing a mission. The default parameter flags tells us which information
3828 // to get when parsing the mission. 0 means get everything (default). Other flags just gets us basic
3829 // info such as game type, number of players etc.
3830 int parse_main(const char *mission_name, int flags)
3834 // fill in Ship_class_names array with the names from the ship_info struct;
3835 Num_parse_names = 0;
3836 Mission_all_attack = 0; // Might get set in mission load.
3837 SDL_assert(Num_ship_types < MAX_SHIP_TYPES);
3839 for (i = 0; i < Num_ship_types; i++)
3840 Ship_class_names[i] = Ship_info[i].name;
3842 if ((rval = setjmp(parse_abort)) != 0) {
3843 nprintf(("Error", "Error abort! Code = %i.", rval));
3847 // open localization
3850 CFILE *ftemp = cfopen(mission_name, "rt", CFILE_NORMAL, CF_TYPE_MISSIONS);
3854 Error( LOCATION, "Couldn't open mission '%s'\n", mission_name );
3856 Current_file_length = -1;
3857 Current_file_checksum = 0;
3859 // close localization
3865 Current_file_length = cfilelength(ftemp);
3868 read_file_text(mission_name, CF_TYPE_MISSIONS);
3869 memset(&The_mission, 0, sizeof(The_mission));
3870 parse_mission(&The_mission, flags);
3871 display_parse_diagnostics();
3873 // close localization
3878 SDL_strlcpy(Mission_filename, mission_name, sizeof(Mission_filename));
3883 // sets the arrival lcoation of the ships in wingp. pass num_to_set since the threshold value
3884 // for wings may have us create more ships in the wing when there are still some remaining
3885 void mission_set_wing_arrival_location( wing *wingp, int num_to_set )
3889 // get the starting index into the ship_index array of the first ship whose location we need set.
3891 index = wingp->current_count - num_to_set;
3892 if ( (wingp->arrival_location == ARRIVE_FROM_DOCK_BAY) || (wingp->arrival_location == ARRIVE_AT_LOCATION) ) {
3893 while ( index < wingp->current_count ) {
3896 objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3897 mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3902 object *leader_objp;
3907 // wing is not arriving from a docking bay -- possibly move them based on arriving near
3908 // or in front of some other ship.
3909 index = wingp->current_count - num_to_set;
3910 leader_objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3911 if (mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(leader_objp), &pos, &orient)) {
3912 // modify the remaining ships created
3915 while ( index < wingp->current_count ) {
3918 objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3920 // change the position of the next ships in the wing. Use the cool function in AiCode.cpp which
3921 // Mike K wrote to give new positions to the wing members.
3922 get_absolute_wing_pos( &objp->pos, leader_objp, wing_index++, 0);
3923 memcpy( &objp->orient, &orient, sizeof(matrix) );
3930 // create warp effect if in mission and not arriving from docking bay
3931 if ( (Game_mode & GM_IN_MISSION) && (wingp->arrival_location != ARRIVE_FROM_DOCK_BAY) ) {
3932 for ( index = wingp->current_count - num_to_set; index < wingp->current_count; index ++ ) {
3933 shipfx_warpin_start( &Objects[Ships[wingp->ship_index[index]].objnum] );
3938 // this function is called after a mission is parsed to set the arrival locations of all ships in the
3939 // mission to the apprioriate spot. Mainly needed because ships might be in dock bays to start
3940 // the mission, so their AI mode must be set appropriately.
3941 void mission_parse_set_arrival_locations()
3949 obj_merge_created_list();
3950 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3953 if ( objp->type != OBJ_SHIP )
3956 shipp = &Ships[objp->instance];
3957 // if the ship is in a wing -- ignore the info and let the wing info handle it
3958 if ( shipp->wingnum != -1 )
3961 // call function to set arrival location for this ship.
3962 mission_set_arrival_location( shipp->arrival_anchor, shipp->arrival_location, shipp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3966 for ( i = 0; i < num_wings; i++ ) {
3968 // if wing has no ships, then don't process it.
3969 if ( Wings[i].current_count == 0 )
3972 mission_set_wing_arrival_location( &Wings[i], Wings[i].current_count );
3977 // function which iterates through the ship_arrival_list and creates any ship which
3978 // should be intially docked with a ship which currently exists in the mission
3979 void mission_parse_do_initial_docks()
3981 p_object *pobjp, *tmp;
3983 pobjp = GET_FIRST( &ship_arrival_list );
3984 while ( pobjp != END_OF_LIST(&ship_arrival_list) ) {
3987 tmp = GET_NEXT(pobjp);
3989 // see if the flag for initial docked is set
3990 if ( pobjp->flags & P_SF_INITIALLY_DOCKED ) {
3991 // see if who this parse object is supposed to be docked with is in the mission
3992 shipnum = ship_name_lookup( pobjp->docked_with );
3993 if ( shipnum != -1 ) {
3996 // the ship exists, so create this object, then dock the two.
3997 objnum = parse_create_object( pobjp );
3998 SDL_assert ( objnum != -1 );
4000 list_remove( &ship_arrival_list, pobjp);
4002 // p1 is the parse object's docking point.
4003 // p2 is the existing objects docking point.
4004 p1 = model_find_dock_name_index(Ships[shipnum].modelnum, pobjp->docker_point);
4005 p2 = model_find_dock_name_index(Ships[Objects[objnum].instance].modelnum, pobjp->dockee_point);
4007 if ((p1 >= 0) && (p2 >= 0)) {
4008 nprintf(("AI", "Initially Docked: %s with %s\n", Ships[shipnum].ship_name, Ships[Objects[objnum].instance].ship_name));
4009 if (ship_docking_valid(shipnum, Objects[objnum].instance)) // only dock if they are allowed to be docked.
4010 ai_dock_with_object(&Objects[Ships[shipnum].objnum], &Objects[objnum], 89, AIDO_DOCK_NOW, p1, p2);
4012 ai_dock_with_object(&Objects[objnum], &Objects[Ships[shipnum].objnum], 89, AIDO_DOCK_NOW, p2, p1);
4015 Int3(); // Curious. Two ships told to dock, but one of the dock points is bogus.
4016 // Get Allender or Hoffoss, one of whom probably wrote the above if ()
4024 // function which returns true or false if the given mission support multiplayers
4025 int mission_parse_is_multi(const char *filename, char *mission_name)
4027 int rval, game_type;
4031 // new way of getting information. Open the file, and just get the name and the game_type flags.
4032 // return the flags if a multiplayer mission
4036 ftemp = cfopen(filename, "rt");
4040 // 7/9/98 -- MWA -- check for 0 length file.
4041 filelength = cfilelength(ftemp);
4043 if ( filelength == 0 )
4046 // open localization
4049 if ((rval = setjmp(parse_abort)) != 0) {
4050 Error(LOCATION, "Bogus! Trying to get multi game type on mission %s returned as a mission from cf_get_filelist\n");
4052 read_file_text(filename, CF_TYPE_MISSIONS);
4054 if ( skip_to_string("$Name:") != 1 ) {
4055 nprintf(("Network", "Unable to process %s because we couldn't find $Name:", filename));
4057 // close localization
4062 stuff_string( mission_name, F_NAME, NULL );
4063 if ( skip_to_string("+Game Type Flags:") != 1 ) {
4064 nprintf(("Network", "Unable to process %s because we couldn't find +Game Type Flags:\n", filename));
4066 // close localization
4071 stuff_int(&game_type);
4073 if ( game_type & MISSION_TYPE_MULTI ){
4074 // close localization
4080 // close localization
4086 // function which gets called to retrieve useful information about a mission. We will get the
4087 // name, description, and number of players for a mission. Probably used for multiplayer only?
4088 // The calling function can use the information in The_mission to get the name/description of the mission
4091 int mission_parse_get_multi_mission_info( const char *filename )
4093 if ( parse_main(filename, MISSION_PARSE_MISSION_INFO) ){
4097 SDL_assert( The_mission.game_type & MISSION_TYPE_MULTI ); // assume multiplayer only for now?
4099 // return the number of parse_players. later, we might want to include (optionally?) the number
4100 // of other ships in the main players wing (usually wing 'alpha') for inclusion of number of
4103 return The_mission.num_players;
4106 // returns true or false if this is on the yet to arrive list
4107 int mission_parse_ship_arrived( const char *shipname )
4111 for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) ) {
4112 if ( !SDL_strcasecmp( objp->name, shipname) )
4113 return 0; // still on the arrival list
4118 // return the parse object on the ship arrival list associated with the given name
4119 p_object *mission_parse_get_arrival_ship( const char *name )
4123 for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) ) {
4124 if ( !SDL_strcasecmp( objp->name, name) )
4125 return objp; // still on the arrival list
4131 // return the parse object on the ship arrival list associated with the given signature
4132 p_object *mission_parse_get_arrival_ship( ushort net_signature )
4136 for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) ) {
4137 if ( objp->net_signature == net_signature )
4138 return objp; // still on the arrival list
4144 // mission_set_arrival_location() sets the arrival location of a parse object according to the arrival location
4145 // of the object. Returns true if object set to new position, false if not.
4146 int mission_set_arrival_location(int anchor, int location, int dist, int objnum, vector *new_pos, matrix *new_orient)
4148 int shipnum, anchor_objnum;
4149 vector anchor_pos, rand_vec, new_fvec;
4152 if ( location == ARRIVE_AT_LOCATION )
4155 SDL_assert(anchor >= 0);
4157 // this ship might possibly arrive at another location. The location is based on the
4158 // proximity of some ship (and some other special tokens)
4160 // if we didn't find the arrival anchor in the list of special nodes, then do a
4161 // ship name lookup on the anchor
4162 if (anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET) {
4163 shipnum = ship_name_lookup(Parse_names[anchor]);
4164 if ( shipnum == -1 ) {
4165 SDL_assert ( location != ARRIVE_FROM_DOCK_BAY ); // bogus data somewhere!!! get mwa
4166 nprintf (("allender", "couldn't find ship for arrival anchor -- using location ship created at"));
4171 // come up with a position based on the special token names
4174 if (anchor == ANY_FRIENDLY) {
4175 shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ANY_SHIP );
4176 } else if (anchor == ANY_HOSTILE) {
4177 shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ANY_SHIP );
4178 } else if (anchor == ANY_FRIENDLY_PLAYER) {
4179 shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ONLY_PLAYERS );
4180 } else if (anchor == ANY_HOSTILE_PLAYER) {
4181 shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ONLY_PLAYERS );
4183 Int3(); // get allender -- unknown special arrival instructions
4185 // if we didn't get an object from one of the above functions, then make the object
4186 // arrive at it's placed location
4187 if ( shipnum == -1 ) {
4188 nprintf (("Allender", "Couldn't find random ship for arrival anchor -- using default location\n"));
4193 // take the shipnum and get the position. once we have positions, we can determine where
4194 // to make this ship appear
4195 SDL_assert ( shipnum != -1 );
4196 anchor_objnum = Ships[shipnum].objnum;
4197 anchor_pos = Objects[anchor_objnum].pos;
4199 // if arriving from docking bay, then set ai mode and call function as per AL's instructions.
4200 if ( location == ARRIVE_FROM_DOCK_BAY ) {
4203 // if we get an error, just let the ship arrive(?)
4204 if ( ai_acquire_emerge_path(&Objects[objnum], anchor_objnum, &pos, &fvec) == -1 ) {
4205 Int3(); // get MWA or AL -- not sure what to do here when we cannot acquire a path
4208 Objects[objnum].pos = pos;
4209 Objects[objnum].orient.v.fvec = fvec;
4212 // AL: ensure dist > 0 (otherwise get errors in vecmat)
4213 // TODO: maybe set distance to 2x ship radius of ship appearing in front of?
4215 Error(LOCATION, "Distance of %d is invalid in mission_set_arrival_location\n", dist);
4219 // get a vector which is the ships arrival position based on the type of arrival
4220 // this ship should have. Arriving near a ship we use a random normalized vector
4221 // scaled by the distance given by the designer. Arriving in front of a ship means
4222 // entering the battle in the view cone.
4223 if ( location == ARRIVE_NEAR_SHIP ) {
4224 // get a random vector -- use static randvec if in multiplayer
4225 if ( Game_mode & GM_NORMAL )
4226 vm_vec_rand_vec_quick(&rand_vec);
4228 static_randvec( Objects[objnum].net_signature, &rand_vec );
4229 } else if ( location == ARRIVE_IN_FRONT_OF_SHIP ) {
4234 // cool function by MK to give a reasonable random vector "in front" of a ship
4235 // rvec and uvec are the right and up vectors.
4236 // If these are not available, this would be an expensive method.
4238 x = (float)cos(ANG_TO_RAD(45));
4239 if ( Game_mode & GM_NORMAL ) {
4240 r1 = myrand() < MY_RAND_MAX/2 ? -1 : 1;
4241 r2 = myrand() < MY_RAND_MAX/2 ? -1 : 1;
4243 // in multiplayer, use the static rand functions so that all clients can get the
4244 // same information.
4245 r1 = static_rand(Objects[objnum].net_signature) < MY_RAND_MAX/2 ? -1 : 1;
4246 r2 = static_rand(Objects[objnum].net_signature+1) < MY_RAND_MAX/2 ? -1 : 1;
4249 vm_vec_copy_scale(&t1, &(Objects[anchor_objnum].orient.v.fvec), x);
4250 vm_vec_copy_scale(&t2, &(Objects[anchor_objnum].orient.v.rvec), (1.0f - x) * r1);
4251 vm_vec_copy_scale(&t3, &(Objects[anchor_objnum].orient.v.uvec), (1.0f - x) * r2);
4253 vm_vec_add(&rand_vec, &t1, &t2);
4254 vm_vec_add2(&rand_vec, &t3);
4255 vm_vec_normalize(&rand_vec);
4258 // add in the radius of the two ships involved. This will make the ship arrive further than
4259 // specified, but will appear more accurate since we are pushing the edge of the model to the
4260 // specified distance. large objects appears to be a lot closer without the following line because
4261 // the object centers were at the correct distance, but the model itself was much closer to the
4263 dist += (int)Objects[objnum].radius + (int)Objects[anchor_objnum].radius;
4264 vm_vec_scale_add(&Objects[objnum].pos, &anchor_pos, &rand_vec, (float)dist);
4266 // I think that we will always want to orient the ship that is arriving to face towards
4267 // the ship it is arriving near/in front of. The effect will be cool!
4269 // calculate the new fvec of the ship arriving and use only that to get the matrix. isn't a big
4270 // deal not getting bank.
4271 vm_vec_sub(&new_fvec, &anchor_pos, &Objects[objnum].pos );
4272 vm_vector_2_matrix( &orient, &new_fvec, NULL, NULL );
4273 Objects[objnum].orient = orient;
4276 // set the new_pos parameter since it might be used outside the function (i.e. when dealing with wings).
4278 memcpy(new_pos, &Objects[objnum].pos, sizeof(vector) );
4281 memcpy( new_orient, &Objects[objnum].orient, sizeof(matrix) );
4286 // mark a reinforcement as available
4287 void mission_parse_mark_reinforcement_available(char *name)
4292 for (i = 0; i < Num_reinforcements; i++) {
4293 rp = &Reinforcements[i];
4294 if ( !SDL_strcasecmp(rp->name, name) ) {
4295 if ( !(rp->flags & RF_IS_AVAILABLE) ) {
4296 rp->flags |= RF_IS_AVAILABLE;
4298 // tell all of the clients.
4299 if ( MULTIPLAYER_MASTER ) {
4300 send_reinforcement_avail( i );
4307 SDL_assert ( i < Num_reinforcements );
4310 // mission_did_ship_arrive takes a parse object and checked the arrival cue and delay and
4311 // creates the object if necessary. Returns -1 if not created. objnum of created ship otherwise
4312 int mission_did_ship_arrive(p_object *objp)
4316 // find out in the arrival cue became true
4317 did_arrive = eval_sexp(objp->arrival_cue);
4319 // we must first check to see if this ship is a reinforcement or not. If so, then don't
4321 if ( objp->flags & P_SF_REINFORCEMENT ) {
4323 // if this ship did arrive, mark the reinforcement as available, and tell clients if in multiplayer
4326 mission_parse_mark_reinforcement_available(objp->name);
4331 if ( did_arrive ) { // has the arrival criteria been met?
4334 SDL_assert ( !(objp->flags & P_SF_CANNOT_ARRIVE) ); // get allender
4336 // check to see if the delay field <= 0. if so, then create a timestamp and then maybe
4337 // create the object
4338 if ( objp->arrival_delay <= 0 ) {
4339 objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
4340 SDL_assert( objp->arrival_delay >= 0 );
4343 // if the timestamp hasn't elapsed, move onto the next ship.
4344 if ( !timestamp_elapsed(objp->arrival_delay) )
4347 // check to see if this ship is to arrive via a docking bay. If so, and the ship to arrive from
4348 // doesn't exist, don't create.
4349 if ( objp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
4353 SDL_assert( objp->arrival_anchor >= 0 );
4354 name = Parse_names[objp->arrival_anchor];
4356 // see if ship is yet to arrive. If so, then return -1 so we can evaluate again later.
4357 if ( mission_parse_get_arrival_ship( name ) )
4360 // see if ship is in mission. If not, then we can assume it was destroyed or departed since
4361 // it is not on the arrival list (as shown by above if statement).
4362 shipnum = ship_name_lookup( name );
4363 if ( shipnum == -1 ) {
4364 Sexp_nodes[objp->arrival_cue].value = SEXP_KNOWN_FALSE;
4369 object_num = parse_create_object(objp); // create the ship
4371 // since this ship is not in a wing, create a SHIP_ARRIVE entry
4372 //mission_log_add_entry( LOG_SHIP_ARRIVE, objp->name, NULL );
4373 SDL_assert(object_num >= 0 && object_num < MAX_OBJECTS);
4375 // Play the music track for an arrival
4376 if ( !(Ships[Objects[object_num].instance].flags & SF_NO_ARRIVAL_MUSIC) )
4377 if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
4378 Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
4379 event_music_arrival(Ships[Objects[object_num].instance].team);
4383 // check to see if the arrival cue of this ship is known false -- if so, then remove
4384 // the parse object from the ship
4385 if ( Sexp_nodes[objp->arrival_cue].value == SEXP_KNOWN_FALSE )
4386 objp->flags |= P_SF_CANNOT_ARRIVE;
4393 // funciton to set a flag on all parse objects on ship arrival list which cannot
4394 // arrive in the mission
4395 void mission_parse_mark_non_arrivals()
4399 for ( pobjp = GET_FIRST(&ship_arrival_list); pobjp != END_OF_LIST(&ship_arrival_list); pobjp = GET_NEXT(pobjp) ) {
4400 if ( pobjp->wingnum != -1 ) {
4401 if ( Sexp_nodes[Wings[pobjp->wingnum].arrival_cue].value == SEXP_KNOWN_FALSE )
4402 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4404 if ( Sexp_nodes[pobjp->arrival_cue].value == SEXP_KNOWN_FALSE )
4405 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4410 // function to deal with support ship arrival. objnum is the object number of the arriving support
4411 // ship. This function can get called from either single or multiplayer. Needed to that clients
4412 // can know when to abort rearm.
4413 void mission_parse_support_arrived( int objnum )
4417 // when the support ship arrives, the shipname it is supposed to repair is in the 'misc'
4418 // field of the parse_object. If the ship still exists, call ai function which actually
4419 // issues the goal for the repair
4420 for ( i = 0; i < Num_arriving_repair_targets; i++ ) {
4423 shipnum = ship_name_lookup( Arriving_repair_targets[i] );
4425 if ( shipnum != -1 ) {
4426 object *requester_objp, *support_objp;
4428 support_objp = &Objects[objnum];
4429 requester_objp = &Objects[Ships[shipnum].objnum];
4430 ai_add_rearm_goal( requester_objp, support_objp );
4434 // MK: A bit of a hack. If on player's team and player isn't allowed shields, don't give this ship shields.
4435 if ((Player_obj->flags & OF_NO_SHIELDS) && (Player_ship->team == Ships[Objects[objnum].instance].team))
4436 Objects[objnum].flags |= OF_NO_SHIELDS;
4438 Ships[Objects[objnum].instance].flags |= SF_WARPED_SUPPORT;
4440 Arriving_support_ship = NULL;
4441 Num_arriving_repair_targets = 0;
4444 MONITOR(NumShipArrivals);
4446 // mission_parse_arrivals will parse the lists of arriving ships and
4447 // wings -- creating new ships/wings if the arrival criteria have been
4449 void mission_eval_arrivals()
4455 // before checking arrivals, check to see if we should play a message concerning arrivals
4456 // of other wings. We use the timestamps to delay the arrival message slightly for
4458 if ( timestamp_valid(Arrival_message_delay_timestamp) && timestamp_elapsed(Arrival_message_delay_timestamp) && !((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)) ){
4459 int rship, use_terran;
4461 // use terran command 25% of time
4462 use_terran = ((frand() - 0.75) > 0.0f)?1:0;
4464 rship = ship_get_random_player_wing_ship( SHIP_GET_NO_PLAYERS );
4465 if ( (rship == -1) || use_terran ){
4466 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4467 } else if ( rship != -1 ) {
4468 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4471 Arrival_message_delay_timestamp = timestamp(-1); // make the stamp invalid
4474 // if ( !timestamp_elapsed(Mission_arrival_timestamp) )
4477 // check the ship_arrival_list
4479 objp = GET_FIRST(&ship_arrival_list);
4480 while( objp !=END_OF_LIST(&ship_arrival_list) ) {
4481 p_object *temp = GET_NEXT(objp);
4482 if ( objp->wingnum == -1 ) { // if this object has a wing -- let code for wings determine if it should be created
4484 objnum = mission_did_ship_arrive( objp );
4485 if ( objnum != -1 ) {
4486 list_remove( &ship_arrival_list, objp);
4487 MONITOR_INC(NumShipArrivals,1);
4494 // check for any initially docked ships. Do it after all are created since the next function
4495 // messes with the ship_arrival_list
4496 mission_parse_do_initial_docks(); // maybe create it's docked counterpart
4498 mission_parse_mark_non_arrivals(); // mark parse objects which can no longer arrive
4500 // check the support ship arrival list
4501 if ( Arriving_support_ship ) {
4504 objnum = mission_did_ship_arrive( Arriving_support_ship );
4506 if ( objnum != -1 ) {
4507 MONITOR_INC(NumShipArrivals,1);
4508 mission_parse_support_arrived( objnum );
4512 // we must also check to see if there are waves of a wing that must
4513 // reappear if all the ships of the current wing have been destroyed or
4514 // have departed. If this is the case, then create the next wave.
4516 for ( i = 0; i < num_wings; i++ ) {
4519 // should we process this wing anymore
4520 if ( wingp->flags & WF_WING_GONE )
4523 // if we have a reinforcement wing, then don't try to create new ships automatically.
4524 if ( wingp->flags & WF_REINFORCEMENT ) {
4526 // check to see in the wings arrival cue is true, and if so, then mark the reinforcement
4528 if ( eval_sexp(wingp->arrival_cue) ) {
4529 mission_parse_mark_reinforcement_available(wingp->name);
4534 // don't do evaluations for departing wings
4535 if ( wingp->flags & WF_WING_DEPARTING ){
4539 // must check to see if we are at the last wave. Code above to determine when a wing is gone only
4540 // gets run when a ship is destroyed (not every N seconds like it used to). Do a quick check
4542 if ( wingp->current_wave == wingp->num_waves ){
4546 // if the current wave of this wing is 0, then we haven't created the ships in the wing yet.
4547 // call parse_wing_create_ships to try and create it. That function will eval the arrival
4548 // cue of the wing and create the ships if necessary, or if the threshold of the wing has
4549 // been reached, then try and create more ships
4550 if ( (wingp->current_wave == 0) || (wingp->current_count <= wingp->threshold) ) {
4553 created = parse_wing_create_ships( wingp, wingp->wave_count );
4555 // if we created ships in this wing, check to see if the wings was int the reinforcements
4556 // array. If so, then if we have more uses, then reset the reinforcement flag for the wing
4557 // so the user can call in another set if need be.
4558 if ( created > 0 ) {
4561 mission_parse_do_initial_docks(); // maybe create other initially docked ships
4562 if ( Wings[i].flags & WF_RESET_REINFORCEMENT ) {
4563 Wings[i].flags &= ~WF_RESET_REINFORCEMENT;
4564 Wings[i].flags |= WF_REINFORCEMENT;
4567 // possibly send a message to the player when this wing arrives.
4568 if ( wingp->flags & WF_NO_ARRIVAL_MESSAGE ){
4572 // multiplayer team vs. team
4573 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
4574 // send a hostile wing arrived message
4575 rship = Wings[i].ship_index[0];
4577 int multi_team_filter = Ships[rship].team == TEAM_FRIENDLY ? 1 : 0;
4579 // there are two timestamps at work here. One to control how often the player receives
4580 // messages about incoming hostile waves, and the other to control how long after
4581 // the wing arrives does the player actually get the message.
4582 if ( timestamp_elapsed(Allow_arrival_message_timestamp_m[multi_team_filter]) ) {
4583 if ( !timestamp_valid(Arrival_message_delay_timestamp_m[multi_team_filter]) ){
4584 Arrival_message_delay_timestamp_m[multi_team_filter] = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4586 Allow_arrival_message_timestamp_m[multi_team_filter] = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
4588 // send to the proper team
4589 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, multi_team_filter );
4594 // see if this is a starting player wing
4595 if ( i == Starting_wings[STARTING_WING_BETA] ) { // this is the beta wing
4596 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4598 message_send_builtin_to_player( MESSAGE_BETA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4600 } else if ( i == Starting_wings[STARTING_WING_GAMMA] ) { // this is the gamma wing
4601 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4602 if ( rship != -1 ) {
4603 message_send_builtin_to_player( MESSAGE_GAMMA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4605 } else if ( !SDL_strcasecmp( wingp->name, "delta") ) {
4606 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4607 if ( rship != -1 ) {
4608 message_send_builtin_to_player( MESSAGE_DELTA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4610 } else if ( !SDL_strcasecmp(wingp->name, "epsilon") ) {
4611 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4612 if ( rship != -1 ) {
4613 message_send_builtin_to_player( MESSAGE_EPSILON_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4616 // see if we have a hostile wing that arrived
4617 rship = Wings[i].ship_index[0];
4618 if ( Ships[rship].team != TEAM_FRIENDLY ) {
4620 // there are two timestamps at work here. One to control how often the player receives
4621 // messages about incoming hostile waves, and the other to control how long after
4622 // the wing arrives does the player actually get the message.
4623 if ( timestamp_elapsed(Allow_arrival_message_timestamp) ) {
4624 if ( !timestamp_valid(Arrival_message_delay_timestamp) ){
4625 Arrival_message_delay_timestamp = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4627 Allow_arrival_message_timestamp = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
4635 Mission_arrival_timestamp = timestamp(ARRIVAL_TIMESTAMP);
4638 MONITOR(NumShipDepartures);
4640 // called to make object objp depart.
4641 void mission_do_departure( object *objp )
4646 MONITOR_INC(NumShipDepartures,1);
4648 SDL_assert ( objp->type == OBJ_SHIP );
4649 shipp = &Ships[objp->instance];
4651 // if departing to a docking bay, try to find the anchor ship to depart to. If not found, then
4652 // just make it warp out like anything else.
4653 if ( shipp->departure_location == DEPART_AT_DOCK_BAY ) {
4657 SDL_assert( shipp->departure_anchor >= 0 );
4658 name = Parse_names[shipp->departure_anchor];
4660 // see if ship is yet to arrive. If so, then return -1 so we can evaluate again later.
4661 if ( mission_parse_get_arrival_ship( name ) )
4662 goto do_departure_warp;
4664 // see if ship is in mission. If not, then we can assume it was destroyed or departed since
4665 // it is not on the arrival list (as shown by above if statement).
4666 anchor_shipnum = ship_name_lookup( name );
4667 if ( anchor_shipnum == -1 )
4668 goto do_departure_warp;
4670 ai_acquire_depart_path(objp, Ships[anchor_shipnum].objnum);
4675 ai_set_mode_warp_out( objp, &Ai_info[Ships[objp->instance].ai_index] );
4679 // put here because mission_eval_arrivals is here. Might move these to a better location
4681 void mission_eval_departures()
4687 // if ( !timestamp_elapsed(Mission_departure_timestamp) )
4690 // scan through the active ships an evaluate their departure cues. For those
4691 // ships whose time has come, set their departing flag.
4693 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4694 if (objp->type == OBJ_SHIP) {
4697 SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
4699 shipp = &Ships[objp->instance];
4701 // don't process a ship that is already departing or dying or disabled
4702 // AL 12-30-97: Added SF_CANNOT_WARP to check
4703 if ( (shipp->flags & (SF_DEPARTING | SF_DYING | SF_CANNOT_WARP )) || ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) ) {
4707 // don't process ships that are part of a wing -- handled in seperate case
4708 if ( shipp->wingnum != -1 )
4711 // && (!timestamp_valid(shipp->departure_delay) || timestamp_elapsed(shipp->departure_delay)) )
4712 // when the departure cue becomes true, set off the departure delay timer. We store the
4713 // timer as -seconds in Freespace which indicates that the timer has not been set. If the timer
4714 // is not set, then turn it into a valid timer and keep evaluating the timer until it is elapsed
4715 if ( eval_sexp(shipp->departure_cue) ) {
4716 if ( shipp->departure_delay <= 0 )
4717 shipp->departure_delay = timestamp(-shipp->departure_delay * 1000 );
4718 if ( timestamp_elapsed(shipp->departure_delay) )
4719 mission_do_departure( objp );
4724 // now scan through the list of wings and check their departure cues. For wings with
4725 // that cue being true, we must update internal variables to indicate that the wing is
4726 // departed and that no further waves of this wing will appear
4728 for ( i = 0; i < num_wings; i++ ) {
4731 // should we process this wing anymore
4732 if ( wingp->flags & WF_WING_DEPARTING )
4735 // evaluate the sexpression. If true, mark all the ships in this wing as departing and increment
4736 // the num departed in the wing structure. Then add number of remaining waves * ships/wave to
4737 // departed count to get total count of ships in the wing which departed. (We are counting ships
4738 // that have not yet arrived as departed if they never arrive -- this may be bad, but for some reason
4739 // seems like the right thing to do).
4740 //&& (!timestamp_valid(wingp->departure_delay) || timestamp_elapsed(wingp->departure_delay)) ) {
4742 if ( eval_sexp(wingp->departure_cue) ) {
4743 // if we haven't set up the departure timer yet (would be <= 0) setup the timer to pop N seconds
4745 if ( wingp->departure_delay <= 0 )
4746 wingp->departure_delay = timestamp( -wingp->departure_delay * 1000 );
4747 if ( !timestamp_elapsed(wingp->departure_delay) )
4750 wingp->flags |= WF_WING_DEPARTING;
4751 for ( j = 0; j < wingp->current_count; j++ ) {
4754 shipp = &Ships[wingp->ship_index[j]];
4755 if ( (shipp->flags & SF_DEPARTING) || (shipp->flags & SF_DYING) )
4758 // shipp->flags |= SF_DEPARTING;
4759 // shipp->final_depart_time = timestamp(3*1000);
4761 SDL_assert ( shipp->objnum != -1 );
4762 objp = &Objects[shipp->objnum];
4764 // copy the wing's depature information to the ship
4765 shipp->departure_location = wingp->departure_location;
4766 shipp->departure_anchor = wingp->departure_anchor;
4768 mission_do_departure( objp );
4769 // don't add to wingp->total_departed here -- this is taken care of in ship code.
4772 // MWA 2/25/98 -- don't do the follwoing wing member updates. It makes the accurate counts
4773 // sort of messed up and causes problems for the event log. The code in ship_wing_cleanup()
4774 // now keys off of the WF_WING_DEPARTING flag instead of the counts below.
4777 // now be sure that we update wing structure members if there are any remaining waves left
4778 if ( wingp->current_wave < wingp->num_waves ) {
4781 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
4782 wingp->total_departed += num_remaining;
4783 wingp->total_arrived_count += num_remaining;
4784 wingp->current_wave = wingp->num_waves;
4790 Mission_departure_timestamp = timestamp(DEPARTURE_TIMESTAMP);
4793 // function called from high level game loop to do mission evaluation stuff
4794 void mission_parse_eval_stuff()
4796 mission_eval_arrivals();
4797 mission_eval_departures();
4800 int allocate_subsys_status()
4804 SDL_assert(Subsys_index < MAX_SUBSYS_STATUS);
4805 Subsys_status[Subsys_index].percent = 0.0f;
4806 Subsys_status[Subsys_index].primary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4807 for (i=1; i<MAX_PRIMARY_BANKS; i++)
4808 Subsys_status[Subsys_index].primary_banks[i] = -1; // none
4810 Subsys_status[Subsys_index].secondary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4811 Subsys_status[Subsys_index].secondary_ammo[0] = 100;
4812 for (i=1; i<MAX_SECONDARY_BANKS; i++) {
4813 Subsys_status[Subsys_index].secondary_banks[i] = -1;
4814 Subsys_status[Subsys_index].secondary_ammo[i] = 100;
4817 Subsys_status[Subsys_index].ai_class = SUBSYS_STATUS_NO_CHANGE;
4818 return Subsys_index++;
4821 // find (or add) the name in the list and return an index to it.
4822 int get_parse_name_index(const char *name)
4826 for (i=0; i<Num_parse_names; i++)
4827 if (!SDL_strcasecmp(name, Parse_names[i]))
4830 SDL_assert(i < MAX_SHIPS + MAX_WINGS);
4831 SDL_assert(strlen(name) < NAME_LENGTH);
4832 SDL_strlcpy(Parse_names[i], name, NAME_LENGTH);
4833 return Num_parse_names++;
4836 int get_anchor(char *name)
4840 for (i=0; i<MAX_SPECIAL_ARRIVAL_ANCHORS; i++)
4841 if (!SDL_strcasecmp(name, Special_arrival_anchor_names[i]))
4842 return SPECIAL_ARRIVAL_ANCHORS_OFFSET + i;
4844 return get_parse_name_index(name);
4847 // function to fixup the goals/ai references for player objects in the mission
4848 void mission_parse_fixup_players()
4852 // merge created list to have all objects on used list
4853 obj_merge_created_list();
4854 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4855 if ( (objp->type == OBJ_SHIP) && (objp->flags & OF_PLAYER_SHIP) ) {
4856 ai_clear_ship_goals( &Ai_info[Ships[objp->instance].ai_index] );
4857 init_ai_object( OBJ_INDEX(objp) );
4862 // code to warp in a new support ship. It works by finding the average position of all ships
4863 // in the mission, creating a vector from that position to the player, and scaling out behind the
4864 // player some distance. Should be sufficient.
4866 #define WARP_IN_MIN_DISTANCE 1000.0f
4867 #define WARP_IN_TIME_MIN 3000 // warps in min 3 seconds later
4868 #define WARP_IN_TIME_MAX 6000 // warps in max 6 seconds later
4870 // function which adds requester_objp onto the queue of ships for the arriving support ship to service
4871 void mission_add_to_arriving_support( object *requester_objp )
4876 SDL_assert ( Arriving_support_ship );
4878 if ( Num_arriving_repair_targets == MAX_AI_GOALS ) {
4879 // Int3(); // get allender -- ship isn't going to get repair, but I hope they never queue up this far!!!
4880 mprintf(("Reached MAX_AI_GOALS trying to add repair request!\n"));
4884 shipp = &Ships[requester_objp->instance];
4885 // check for duplicates before adding
4886 for (i = 0; i < Num_arriving_repair_targets; i++ ) {
4887 if ( !SDL_strcasecmp(Arriving_repair_targets[i], shipp->ship_name) ){
4891 if ( i != Num_arriving_repair_targets ){ // found the ship before reaching the end -- ignore it!
4895 SDL_strlcpy( Arriving_repair_targets[Num_arriving_repair_targets], Ships[requester_objp->instance].ship_name, NAME_LENGTH );
4896 Num_arriving_repair_targets++;
4898 if ( MULTIPLAYER_MASTER ){
4899 multi_maybe_send_repair_info( requester_objp, NULL, REPAIR_INFO_WARP_ADD );
4903 extern int pp_collide_any(vector *curpos, vector *goalpos, float radius, object *ignore_objp1, object *ignore_objp2, int big_only_flag);
4905 // Set the warp in position for a support ship relative to an object.
4906 // Caller tries several positions, passing vector in x, y, z.
4907 int get_warp_in_pos(vector *pos, object *objp, float x, float y, float z)
4911 if ( Game_mode & GM_NORMAL )
4914 rand_val = static_randf(objp->net_signature);
4916 rand_val = 1.0f + (rand_val - 0.5f)*0.2f;
4920 vm_vec_scale_add2( pos, &objp->orient.v.rvec, x*rand_val*800.0f);
4921 vm_vec_scale_add2( pos, &objp->orient.v.uvec, y*rand_val*800.0f);
4922 vm_vec_scale_add2( pos, &objp->orient.v.fvec, z*rand_val*800.0f);
4924 return pp_collide_any(&objp->pos, pos, objp->radius, objp, NULL, 1);
4927 void mission_warp_in_support_ship( object *requester_objp )
4929 vector center, warp_in_pos;
4932 int i, requester_species;
4933 ship *requester_shipp;
4935 SDL_assert ( requester_objp->type == OBJ_SHIP );
4936 requester_shipp = &Ships[requester_objp->instance]; // MK, 10/23/97, used to be ->type, bogus, no?
4938 // if the support ship is already arriving, add the requester to the list
4939 if ( Arriving_support_ship ) {
4940 mission_add_to_arriving_support( requester_objp );
4944 // get average position of all ships
4945 obj_get_average_ship_pos( ¢er );
4946 vm_vec_sub( &warp_in_pos, ¢er, &(requester_objp->pos) );
4948 // be sure to account for case as player being only ship left in mission
4950 if ( !(IS_VEC_NULL( warp_in_pos)) ) {
4951 mag = vm_vec_mag( &warp_in_pos );
4952 if ( mag < WARP_IN_MIN_DISTANCE )
4953 vm_vec_scale( &warp_in_pos, WARP_IN_MIN_DISTANCE/mag);
4957 // take -player_pos.fvec scaled by 1000.0f;
4958 warp_in_pos = Player_obj->orient.fvec;
4959 vm_vec_scale( &warp_in_pos, -1000.0f );
4963 // Choose position to warp in ship.
4964 // Temporary, but changed by MK because it used to be exactly behind the player.
4965 // This could cause an SDL_assert if the player immediately targeted it (before moving).
4966 // Tend to put in front of the player to aid him in flying towards the ship.
4968 if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.1f, 1.0f))
4969 if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.2f, -1.0f))
4970 if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.2f, -1.0f))
4971 if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.1f, 1.0f))
4972 get_warp_in_pos(&warp_in_pos, requester_objp, 0.1f, 1.0f, 0.2f);
4974 // create a parse object, and put it onto the ship_arrival_list. This whole thing kind of sucks.
4975 // I want to put it into a parse object since it needs to arrive just a little later than
4976 // this function is called. I have to make some assumptions in the code about values for the parse
4977 // object since I'm no longer working with a mission file. These exceptions will be noted with
4980 Arriving_support_ship = &Support_ship_pobj;
4981 pobj = Arriving_support_ship;
4983 // create a name for the ship. use "Support #". look for collisions until one isn't found anymore
4986 SDL_snprintf(pobj->name, sizeof(pobj->name), NOX("Support %d"), i);
4987 if ( (ship_name_lookup(pobj->name) == -1) && (ship_find_exited_ship_by_name(pobj->name) == -1) )
4992 pobj->pos = warp_in_pos;
4993 vm_set_identity( &(pobj->orient) );
4995 // *sigh*. Gotta get the ship class. For now, this will amount to finding a ship in the ship_info
4996 // array with the same team as the requester of type SIF_SUPPORT. Might need to be changed, but who knows
4997 // vasudans use the terran support ship.
4998 requester_species = Ship_info[requester_shipp->ship_info_index].species;
5000 // 5/6/98 -- MWA Don't need to do anything for multiplayer. I think that we always want to use
5001 // the species of the caller ship.
5002 SDL_assert( (requester_species == SPECIES_TERRAN) || (requester_species == SPECIES_VASUDAN) );
5003 // if ( (Game_mode & GM_NORMAL) && (requester_species == SPECIES_VASUDAN) ) { // make vasundan's use the terran support ship
5004 // requester_species = SPECIES_TERRAN;
5007 // get index of correct species support ship
5008 for (i=0; i < Num_ship_types; i++) {
5009 if ( (Ship_info[i].species == requester_species) && (Ship_info[i].flags & SIF_SUPPORT) )
5013 if ( i < Num_ship_types )
5014 pobj->ship_class = i;
5016 Int3(); // BOGUS!!!! gotta figure something out here
5018 pobj->team = requester_shipp->team;
5020 pobj->behavior = AIM_NONE; // ASSUMPTION: the mission file has the string "None" which maps to AIM_NONE
5022 // set the ai_goals to -1. We will put the requester object shipname in repair target array and then take
5023 // care of setting up the goal when creating the ship!!!!
5024 pobj->ai_goals = -1;
5025 Num_arriving_repair_targets = 0;
5026 mission_add_to_arriving_support( requester_objp );
5028 // need to set ship's cargo to nothing. scan the cargo_names array looking for the string nothing.
5029 // add it if not found
5030 for (i = 0; i < Num_cargo; i++ )
5031 if ( !SDL_strcasecmp(Cargo_names[i], NOX("nothing")) )
5034 if ( i == Num_cargo ) {
5035 SDL_strlcpy(Cargo_names[i], NOX("Nothing"), NAME_LENGTH);
5038 pobj->cargo1 = char(i);
5040 pobj->status_count = 0;
5042 pobj->arrival_location = 0; // ASSUMPTION: this is index to arrival_lcation string array for hyperspace!!!!
5043 pobj->arrival_distance = 0;
5044 pobj->arrival_anchor = -1;
5045 pobj->arrival_cue = Locked_sexp_true;
5046 pobj->arrival_delay = timestamp_rand(WARP_IN_TIME_MIN, WARP_IN_TIME_MAX);
5048 pobj->subsys_count = 0; // number of elements used in subsys_status array
5049 pobj->initial_velocity = 100; // start at 100% velocity
5050 pobj->initial_hull = 100; // start at 100% hull
5051 pobj->initial_shields = 100; // and 100% shields
5053 pobj->departure_location = 0; // ASSUMPTION: this is index to departure_lcation string array for hyperspace!!!!
5054 pobj->departure_anchor = -1;
5055 pobj->departure_cue = Locked_sexp_false;
5056 pobj->departure_delay= 0;
5058 pobj->determination = 10; // ASSUMPTION: mission file always had this number written out
5060 if ( Player_obj->flags & P_OF_NO_SHIELDS )
5061 pobj->flags = P_OF_NO_SHIELDS; // support ships have no shields when player has not shields
5063 pobj->ai_class = Ship_info[pobj->ship_class].ai_class;
5067 pobj->docked_with[0] = '\0';
5069 pobj->persona_index = -1;
5070 pobj->net_signature = multi_assign_network_signature(MULTI_SIG_SHIP);
5071 pobj->wing_status_wing_index = -1;
5072 pobj->wing_status_wing_pos = -1;
5073 pobj->respawn_count = 0;
5074 pobj->alt_type_index = -1;
5078 // returns true if a support ship is currently in the process of warping in.
5079 int mission_is_support_ship_arriving()
5081 if ( Arriving_support_ship )
5087 // returns true if the given ship is scheduled to be repaired by the arriving support ship
5088 int mission_is_repair_scheduled( object *objp )
5093 if ( !Arriving_support_ship )
5096 SDL_assert ( objp->type == OBJ_SHIP );
5097 name = Ships[objp->instance].ship_name;
5098 for (i = 0; i < Num_arriving_repair_targets; i++ ) {
5099 if ( !strcmp( name, Arriving_repair_targets[i]) )
5106 // function which removed the given ship from the list of ships that are to get repair
5107 // by arriving support ship
5108 int mission_remove_scheduled_repair( object *objp )
5113 if ( !Arriving_support_ship )
5116 // itereate through the target list looking for this ship name. If not found, we
5117 // can simply return.
5118 SDL_assert ( objp->type == OBJ_SHIP );
5119 name = Ships[objp->instance].ship_name;
5120 for (index = 0; index < Num_arriving_repair_targets; index++ ) {
5121 if ( !strcmp( name, Arriving_repair_targets[index]) )
5124 if ( index == Num_arriving_repair_targets )
5127 // ship is found -- compress the array
5128 for ( i = index; i < Num_arriving_repair_targets - 1; i++ )
5129 SDL_strlcpy( Arriving_repair_targets[i], Arriving_repair_targets[i+1], NAME_LENGTH );
5131 Num_arriving_repair_targets--;
5133 if ( MULTIPLAYER_MASTER )
5134 multi_maybe_send_repair_info( objp, NULL, REPAIR_INFO_WARP_REMOVE );
5139 // alternate name stuff
5140 int mission_parse_lookup_alt(char *name)
5150 for(idx=0; idx<Mission_alt_type_count; idx++){
5151 if(!strcmp(Mission_alt_types[idx], name)){
5160 static int mission_parse_lookup_alt_index_warn = 1;
5161 void mission_parse_lookup_alt_index(int index, char *out, const int max_outlen)
5167 if((index < 0) || (index > Mission_alt_type_count)){
5168 if (mission_parse_lookup_alt_index_warn) {
5169 Warning(LOCATION, "Ship with invalid alt_name. Get a programmer");
5170 mission_parse_lookup_alt_index_warn = 0;
5176 SDL_strlcpy(out, Mission_alt_types[index], max_outlen);
5179 int mission_parse_add_alt(char *name)
5187 if(Mission_alt_type_count < MAX_ALT_TYPE_NAMES){
5189 SDL_strlcpy(Mission_alt_types[Mission_alt_type_count++], name, NAME_LENGTH);
5192 return Mission_alt_type_count - 1;
5198 void mission_parse_reset_alt()
5200 Mission_alt_type_count = 0;
5203 int is_training_mission()
5205 return (The_mission.game_type & MISSION_TYPE_TRAINING);