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.
339 #include "freespace.h"
341 #include "missionparse.h"
342 #include "missiongoals.h"
343 #include "missionlog.h"
344 #include "missionmessage.h"
346 #include "linklist.h"
352 #include "starfield.h"
354 #include "lighting.h"
355 #include "eventmusic.h"
356 #include "missionbriefcommon.h"
358 #include "multiutil.h"
359 #include "multimsgs.h"
363 #include "fireballs.h"
365 #include "gamesequence.h"
370 #include "missionhotkey.h"
371 #include "hudescort.h"
372 #include "asteroid.h"
374 #include "staticrand.h"
375 #include "missioncmdbrief.h"
376 #include "redalert.h"
377 #include "multi_respawn.h"
378 #include "hudwingmanstatus.h"
379 #include "jumpnode.h"
380 #include "multi_endgame.h"
381 #include "localize.h"
384 #include "neblightning.h"
389 char dockee[NAME_LENGTH];
390 char docker_point[NAME_LENGTH];
391 char dockee_point[NAME_LENGTH];
392 } Initially_docked[MAX_SHIPS];
394 int Total_initially_docked;
397 char Mission_filename[80];
399 int Mission_palette; // index into Nebula_palette_filenames[] of palette file to use for mission
400 int Nebula_index; // index into Nebula_filenames[] of nebula to use in mission.
401 int Num_iff = MAX_IFF;
402 int Num_ai_behaviors = MAX_AI_BEHAVIORS;
404 int Num_status_names = MAX_STATUS_NAMES;
405 int Num_arrival_names = MAX_ARRIVAL_NAMES;
406 int Num_goal_type_names = MAX_GOAL_TYPE_NAMES;
407 int Num_team_names = MAX_TEAM_NAMES;
409 int Player_starts = 1;
411 fix Entry_delay_time;
413 ushort Current_file_checksum = 0;
414 ushort Last_file_checksum = 0;
415 int Current_file_length = 0;
417 // alternate ship type names
418 char Mission_alt_types[MAX_ALT_TYPE_NAMES][NAME_LENGTH];
419 int Mission_alt_type_count = 0;
421 #define SHIP_WARP_TIME 5.0f // how many seconds it takes for ship to warp in
423 // the ship arrival list will contain a list of ships that are yet to arrive. This
424 // list could also include ships that are part of wings!
426 p_object ship_arrivals[MAX_SHIP_ARRIVALS], ship_arrival_list; // for linked list of ships to arrive later
427 int num_ship_arrivals;
429 #define MAX_SHIP_ORIGINAL 100
430 p_object ship_original[MAX_SHIP_ORIGINAL];
431 int num_ship_original;
433 // list for arriving support ship
434 p_object Support_ship_pobj;
435 p_object *Arriving_support_ship;
436 char Arriving_repair_targets[MAX_AI_GOALS][NAME_LENGTH];
437 int Num_arriving_repair_targets;
439 subsys_status Subsys_status[MAX_SUBSYS_STATUS];
442 char Mission_parse_storm_name[NAME_LENGTH] = "none";
444 team_data Team_data[MAX_TEAMS];
446 // variables for player start in single player
447 char Player_start_shipname[NAME_LENGTH];
448 int Player_start_shipnum;
449 p_object Player_start_pobject;
451 // name of all ships to use while parsing a mission (since a ship might be referenced by
452 // something before that ship has even been loaded yet)
453 char Parse_names[MAX_SHIPS + MAX_WINGS][NAME_LENGTH];
458 const char *Nebula_filenames[NUM_NEBULAS] = {
464 const char *Neb2_filenames[NUM_NEBULAS] = {
470 // Note: Nebula_colors[] and Nebula_palette_filenames are linked via index numbers
471 const char *Nebula_colors[NUM_NEBULA_COLORS] = {
483 const char *Iff_names[MAX_IFF] = { "IFF 1", "IFF 2", "IFF 3" };
485 const char *Ai_behavior_names[MAX_AI_BEHAVIORS] = {
509 char *Cargo_names[MAX_CARGO];
510 char Cargo_names_buf[MAX_CARGO][NAME_LENGTH];
512 char *Ship_class_names[MAX_SHIP_TYPES]; // to be filled in from Ship_info array
514 const char *Icon_names[MAX_BRIEF_ICONS] = {
515 "Fighter", "Fighter Wing", "Cargo", "Cargo Wing", "Largeship",
516 "Largeship Wing", "Capital", "Planet", "Asteroid Field", "Waypoint",
517 "Support Ship", "Freighter(no cargo)", "Freighter(has cargo)",
518 "Freighter Wing(no cargo)", "Freighter Wing(has cargo)", "Installation",
519 "Bomber", "Bomber Wing", "Cruiser", "Cruiser Wing", "Unknown", "Unknown Wing",
520 "Player Fighter", "Player Fighter Wing", "Player Bomber", "Player Bomber Wing",
524 "Knossos Device", "Transport Wing", "Corvette", "Gas Miner", "Awacs", "Supercap", "Sentry Gun", "Jump Node", "Transport"
528 // Translate team mask values like TEAM_FRIENDLY to indices in Team_names array.
529 // -1 means an illegal value.
530 int Team_names_index_xlate[MAX_TEAM_NAMES_INDEX+1] = {-1, 0, 1, -1, 2, -1, -1, -1, 3};
532 const char *Team_names[MAX_TEAM_NAMES] = {
533 "Hostile", "Friendly", "Neutral", "Unknown",
536 const char *Status_desc_names[MAX_STATUS_NAMES] = {
537 "Shields Critical", "Engines Damaged", "Fully Operational",
540 const char *Status_type_names[MAX_STATUS_NAMES] = {
541 "Damaged", "Disabled", "Corroded",
544 const char *Status_target_names[MAX_STATUS_NAMES] = {
545 "Weapons", "Engines", "Cable TV",
548 // definitions for arrival locations for ships/wings
549 const char *Arrival_location_names[MAX_ARRIVAL_NAMES] = {
550 "Hyperspace", "Near Ship", "In front of ship", "Docking Bay",
553 const char *Special_arrival_anchor_names[MAX_SPECIAL_ARRIVAL_ANCHORS] =
558 "<any friendly player>",
559 "<any hostile player>",
560 "<any neutral player>",
563 const char *Departure_location_names[MAX_ARRIVAL_NAMES] = {
564 "Hyperspace", "Docking Bay",
567 const char *Goal_type_names[MAX_GOAL_TYPE_NAMES] = {
568 "Primary", "Secondary", "Bonus",
571 const char *Species_names[MAX_SPECIES_NAMES] = {
572 "Terran", "Vasudan", "Shivan",
575 const char *Reinforcement_type_names[] = {
580 const char *Old_game_types[OLD_MAX_GAME_TYPES] = {
581 "Single Player Only",
583 "Single/Multi Player",
587 const char *Parse_object_flags[MAX_PARSE_OBJECT_FLAGS] = {
600 "hidden-from-sensors",
610 const char *Starting_wing_names[MAX_STARTING_WINGS+1] = {
619 int Num_reinforcement_type_names = sizeof(Reinforcement_type_names) / sizeof(char *);
621 vector Parse_viewer_pos;
622 matrix Parse_viewer_orient;
624 // definitions for timestamps for eval'ing arrival/departure cues
625 int Mission_arrival_timestamp;
626 int Mission_departure_timestamp;
627 fix Mission_end_time;
629 #define ARRIVAL_TIMESTAMP 2000 // every 2 seconds
630 #define DEPARTURE_TIMESTAMP 2200 // every 2.2 seconds -- just to be a little different
632 // calculates a "unique" file signature as a ushort (checksum) and an int (file length)
633 // the amount of The_mission we're going to checksum
634 // WARNING : do NOT call this function on the server - it will overwrite goals, etc
635 #define MISSION_CHECKSUM_SIZE (NAME_LENGTH + NAME_LENGTH + 4 + DATE_TIME_LENGTH + DATE_TIME_LENGTH)
637 // timers used to limit arrival messages and music
638 #define ARRIVAL_MUSIC_MIN_SEPARATION 60000
639 #define ARRIVAL_MESSAGE_MIN_SEPARATION 30000
641 #define ARRIVAL_MESSAGE_DELAY_MIN 2000
642 #define ARRIVAL_MESSAGE_DELAY_MAX 3000
644 static int Allow_arrival_music_timestamp;
645 static int Allow_arrival_message_timestamp;
646 static int Arrival_message_delay_timestamp;
649 static int Allow_arrival_music_timestamp_m[2];
650 static int Allow_arrival_message_timestamp_m[2];
651 static int Arrival_message_delay_timestamp_m[2];
654 void parse_player_info2(mission *pm);
655 void post_process_mission();
656 int allocate_subsys_status();
657 void parse_common_object_data(p_object *objp);
658 void parse_asteroid_fields(mission *pm);
659 int mission_set_arrival_location(int anchor, int location, int distance, int objnum, vector *new_pos, matrix *new_orient);
660 int get_parse_name_index(const char *name);
661 int get_anchor(char *name);
662 void mission_parse_do_initial_docks();
663 void mission_parse_set_arrival_locations();
664 void mission_set_wing_arrival_location( wing *wingp, int num_to_set );
665 int parse_lookup_alt_name(char *name);
667 void parse_mission_info(mission *pm)
670 char game_string[NAME_LENGTH];
672 required_string("#Mission Info");
674 required_string("$Version:");
675 stuff_float(&pm->version);
676 if (pm->version != MISSION_VERSION)
677 mprintf(("Older mission, should update it (%.2f<-->%.2f)", pm->version, MISSION_VERSION));
679 required_string("$Name:");
680 stuff_string(pm->name, F_NAME, NULL);
682 required_string("$Author:");
683 stuff_string(pm->author, F_NAME, NULL);
685 required_string("$Created:");
686 stuff_string(pm->created, F_DATE, NULL);
688 required_string("$Modified:");
689 stuff_string(pm->modified, F_DATE, NULL);
691 required_string("$Notes:");
692 stuff_string(pm->notes, F_NOTES, NULL);
694 if (optional_string("$Mission Desc:"))
695 stuff_string(pm->mission_desc, F_MULTITEXT, NULL, MISSION_DESC_LENGTH);
697 SDL_strlcpy(pm->mission_desc, NOX("No description\n"), sizeof(pm->mission_desc));
699 pm->game_type = MISSION_TYPE_SINGLE; // default to single player only
700 if ( optional_string("+Game Type:")) {
701 // HACK HACK HACK -- stuff_string was changed to *not* ignore carriage returns. Since the
702 // old style missions may have carriage returns, deal with it here.
703 ignore_white_space();
704 stuff_string(game_string, F_NAME, NULL);
705 for ( i = 0; i < OLD_MAX_GAME_TYPES; i++ ) {
706 if ( !SDL_strcasecmp(game_string, Old_game_types[i]) ) {
708 // this block of code is now old mission compatibility code. We specify game
709 // type in a different manner than before.
710 if ( i == OLD_GAME_TYPE_SINGLE_ONLY )
711 pm->game_type = MISSION_TYPE_SINGLE;
712 else if ( i == OLD_GAME_TYPE_MULTI_ONLY )
713 pm->game_type = MISSION_TYPE_MULTI;
714 else if ( i == OLD_GAME_TYPE_SINGLE_MULTI )
715 pm->game_type = (MISSION_TYPE_SINGLE | MISSION_TYPE_MULTI );
716 else if ( i == OLD_GAME_TYPE_TRAINING )
717 pm->game_type = MISSION_TYPE_TRAINING;
721 if ( pm->game_type & MISSION_TYPE_MULTI )
722 pm->game_type |= MISSION_TYPE_MULTI_COOP;
729 if ( optional_string("+Game Type Flags:") ) {
730 stuff_int(&pm->game_type);
734 if (optional_string("+Flags:")){
735 stuff_int(&pm->flags);
738 // nebula mission stuff
740 if(optional_string("+NebAwacs:")){
741 if(pm->flags & MISSION_FLAG_FULLNEB){
742 stuff_float(&Neb2_awacs);
748 if(optional_string("+Storm:")){
749 stuff_string(Mission_parse_storm_name, F_NAME, NULL);
750 nebl_set_storm(Mission_parse_storm_name);
753 // get the number of players if in a multiplayer mission
755 if ( pm->game_type & MISSION_TYPE_MULTI ) {
756 if ( optional_string("+Num Players:") ) {
757 stuff_int( &(pm->num_players) );
761 // get the number of respawns
762 pm->num_respawns = 0;
763 if ( pm->game_type & MISSION_TYPE_MULTI ) {
764 if ( optional_string("+Num Respawns:") ){
765 stuff_int( (int*)&(pm->num_respawns) );
770 if ( optional_string("+Red Alert:")) {
771 stuff_int(&pm->red_alert);
773 red_alert_set_status(pm->red_alert);
776 if ( optional_string("+Scramble:")) {
777 stuff_int(&pm->scramble);
780 pm->disallow_support = 0;
781 if ( optional_string("+Disallow Support:")) {
782 stuff_int(&pm->disallow_support);
785 if (optional_string("+All Teams Attack")){
786 Mission_all_attack = 1;
788 Mission_all_attack = 0;
791 // Maybe delay the player's entry.
792 if (optional_string("+Player Entry Delay:")) {
796 SDL_assert(temp >= 0.0f);
797 Entry_delay_time = fl2f(temp);
800 if (optional_string("+Viewer pos:")){
801 stuff_vector(&Parse_viewer_pos);
804 if (optional_string("+Viewer orient:")){
805 stuff_matrix(&Parse_viewer_orient);
808 // possible squadron reassignment
809 SDL_strlcpy(The_mission.squad_name, "", sizeof(The_mission.squad_name));
810 SDL_strlcpy(The_mission.squad_filename, "", sizeof(The_mission.squad_filename));
811 if(optional_string("+SquadReassignName:")){
812 stuff_string(The_mission.squad_name, F_NAME, NULL);
813 if(optional_string("+SquadReassignLogo:")){
814 stuff_string(The_mission.squad_filename, F_NAME, NULL);
817 // always clear out squad reassignments if not single player
818 if(Game_mode & GM_MULTIPLAYER){
819 SDL_strlcpy(The_mission.squad_name, "", sizeof(The_mission.squad_name));
820 SDL_strlcpy(The_mission.squad_filename, "", sizeof(The_mission.squad_filename));
821 mprintf(("Ignoring squadron reassignment"));
823 // reassign the player
825 if(!Fred_running && (Player != NULL) && (strlen(The_mission.squad_name) > 0) && (Game_mode & GM_CAMPAIGN_MODE)){
826 mprintf(("Reassigning player to squadron %s\n", The_mission.squad_name));
827 player_set_squad(Player, The_mission.squad_name);
828 player_set_squad_bitmap(Player, The_mission.squad_filename);
832 // set up the Num_teams variable accoriding to the game_type variable'
833 Num_teams = 1; // assume 1
835 // multiplayer team v. team games have two teams. If we have three teams, we need to use
836 // a new mission mode!
837 if ( (pm->game_type & MISSION_TYPE_MULTI) && (pm->game_type & MISSION_TYPE_MULTI_TEAMS) ){
842 void parse_player_info(mission *pm)
844 char alt[NAME_LENGTH + 2] = "";
845 SDL_assert(pm != NULL);
847 // alternate type names begin here
848 mission_parse_reset_alt();
849 if(optional_string("#Alternate Types:")){
851 while(!optional_string("#end")){
852 required_string("$Alt:");
853 stuff_string(alt, F_NAME, NULL, NAME_LENGTH);
856 mission_parse_add_alt(alt);
861 required_string("#Players");
863 while (required_string_either("#Objects", "$")){
864 parse_player_info2(pm);
868 void parse_player_info2(mission *pm)
870 char str[NAME_LENGTH];
871 int nt, i, total, list[MAX_SHIP_TYPES * 2], list2[MAX_WEAPON_TYPES * 2];
873 char starting_wings[MAX_PLAYER_WINGS][NAME_LENGTH];
875 // read in a ship/weapon pool for each team.
876 for ( nt = 0; nt < Num_teams; nt++ ) {
877 int num_ship_choices;
879 ptr = &Team_data[nt];
880 // get the shipname for single player missions
881 // MWA -- make this required later!!!!
882 if ( optional_string("$Starting Shipname:") )
883 stuff_string( Player_start_shipname, F_NAME, NULL );
885 required_string("$Ship Choices:");
886 total = stuff_int_list(list, MAX_SHIP_TYPES * 2, SHIP_INFO_TYPE);
888 SDL_assert(!(total & 0x01)); // make sure we have an even count
890 num_ship_choices = 0;
891 total /= 2; // there are only 1/2 the ships really on the list.
892 for (i=0; i<total; i++) {
893 // in a campaign, see if the player is allowed the ships or not. Remove them from the
894 // pool if they are not allowed
895 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
896 if ( !Campaign.ships_allowed[list[i*2]] )
900 ptr->ship_list[num_ship_choices] = list[i * 2];
901 ptr->ship_count[num_ship_choices] = list[i * 2 + 1];
904 ptr->number_choices = num_ship_choices;
906 // --- obsolete data, parsing remains for compatibility reasons ---
907 if (optional_string("+Starting Wings:"))
908 stuff_string_list(starting_wings, MAX_PLAYER_WINGS);
910 ptr->default_ship = -1;
911 if (optional_string("+Default_ship:")) {
912 stuff_string(str, F_NAME, NULL);
913 ptr->default_ship = ship_info_lookup(str);
914 // see if the player's default ship is an allowable ship (campaign only). If not, then what
915 // do we do? choose the first allowable one?
916 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
917 if ( !(Campaign.ships_allowed[ptr->default_ship]) ) {
918 for (i = 0; i < MAX_SHIP_TYPES; i++ ) {
919 if ( Campaign.ships_allowed[ptr->default_ship] ) {
920 ptr->default_ship = i;
924 SDL_assert( i < MAX_SHIP_TYPES );
929 if (ptr->default_ship == -1) // invalid or not specified, make first in list
930 ptr->default_ship = ptr->ship_list[0];
932 for (i=0; i<MAX_WEAPON_TYPES; i++)
933 ptr->weaponry_pool[i] = 0;
935 if (optional_string("+Weaponry Pool:")) {
936 total = stuff_int_list(list2, MAX_WEAPON_TYPES * 2, WEAPON_POOL_TYPE);
938 SDL_assert(!(total & 0x01)); // make sure we have an even count
940 for (i=0; i<total; i++) {
941 // in a campaign, see if the player is allowed the weapons or not. Remove them from the
942 // pool if they are not allowed
943 if (Game_mode & GM_CAMPAIGN_MODE || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER))) {
944 if ( !Campaign.weapons_allowed[list2[i*2]] )
948 if ((list2[i * 2] >= 0) && (list2[i * 2] < MAX_WEAPON_TYPES))
949 ptr->weaponry_pool[list2[i * 2]] = list2[i * 2 + 1];
954 if ( nt != Num_teams )
955 Error(LOCATION, "Not enough ship/weapon pools for mission. There are %d teams and only %d pools.", Num_teams, nt);
958 void parse_plot_info(mission *pm)
960 required_string("#Plot Info");
962 required_string("$Tour:");
963 stuff_string(pm->tour_name, F_NAME, NULL);
965 required_string("$Pre-Briefing Cutscene:");
966 stuff_string(pm->pre_briefing_cutscene, F_FILESPEC, NULL);
968 required_string("$Pre-Mission Cutscene:");
969 stuff_string(pm->pre_mission_cutscene, F_FILESPEC, NULL);
971 required_string("$Next Mission Success:");
972 stuff_string(pm->next_mission_success, F_NAME, NULL);
974 required_string("$Next Mission Partial:");
975 stuff_string(pm->next_mission_partial, F_NAME, NULL);
977 required_string("$Next Mission Failure:");
978 stuff_string(pm->next_mission_failure, F_NAME, NULL);
981 void parse_briefing_info(mission *pm)
985 if ( !optional_string("#Briefing Info") )
988 required_string("$Briefing Voice 1:");
989 stuff_string(junk, F_FILESPEC, NULL);
991 required_string("$Briefing Text 1:");
992 stuff_string(junk, F_MULTITEXTOLD, NULL);
994 required_string("$Briefing Voice 2:");
995 stuff_string(junk, F_FILESPEC, NULL);
997 required_string("$Briefing Text 2:");
998 stuff_string(junk, F_MULTITEXTOLD, NULL);
1000 required_string("$Briefing Voice 3:");
1001 stuff_string(junk, F_FILESPEC, NULL);
1003 required_string("$Briefing Text 3:");
1004 stuff_string(junk, F_MULTITEXTOLD, NULL);
1006 required_string("$Debriefing Voice 1:");
1007 stuff_string(junk, F_FILESPEC, NULL);
1009 required_string("$Debriefing Text 1:");
1010 stuff_string(junk, F_MULTITEXTOLD, NULL);
1012 required_string("$Debriefing Voice 2:");
1013 stuff_string(junk, F_FILESPEC, NULL);
1015 required_string("$Debriefing Text 2:");
1016 stuff_string(junk, F_MULTITEXTOLD, NULL);
1018 required_string("$Debriefing Voice 3:");
1019 stuff_string(junk, F_FILESPEC, NULL);
1021 required_string("$Debriefing Text 3:");
1022 stuff_string(junk, F_MULTITEXTOLD, NULL);
1025 // parse the event music and briefing music for the mission
1026 void parse_music(mission *pm)
1028 char name[NAME_LENGTH];
1030 event_music_reset_choices();
1032 if ( !optional_string("#Music") ) {
1036 required_string("$Event Music:");
1037 stuff_string(name, F_NAME, NULL);
1038 event_music_set_soundtrack(name);
1040 required_string("$Briefing Music:");
1041 stuff_string(name, F_NAME, NULL);
1042 event_music_set_score(SCORE_BRIEFING, name);
1044 if ( optional_string("$Debriefing Success Music:") ) {
1045 stuff_string(name, F_NAME, NULL);
1046 event_music_set_score(SCORE_DEBRIEF_SUCCESS, name);
1049 if ( optional_string("$Debriefing Fail Music:") ) {
1050 stuff_string(name, F_NAME, NULL);
1051 event_music_set_score(SCORE_DEBRIEF_FAIL, name);
1055 void parse_cmd_brief(mission *pm)
1059 SDL_assert(!Cur_cmd_brief->num_stages);
1062 required_string("#Command Briefing");
1063 while (optional_string("$Stage Text:")) {
1064 SDL_assert(stage < CMD_BRIEF_STAGES_MAX);
1065 Cur_cmd_brief->stage[stage].text = stuff_and_malloc_string(F_MULTITEXT, NULL, CMD_BRIEF_TEXT_MAX);
1066 SDL_assert(Cur_cmd_brief->stage[stage].text);
1068 required_string("$Ani Filename:");
1069 stuff_string(Cur_cmd_brief->stage[stage].ani_filename, F_FILESPEC, NULL);
1070 if (optional_string("+Wave Filename:"))
1071 stuff_string(Cur_cmd_brief->stage[stage].wave_filename, F_FILESPEC, NULL);
1073 Cur_cmd_brief->stage[stage].wave_filename[0] = 0;
1078 Cur_cmd_brief->num_stages = stage;
1081 void parse_cmd_briefs(mission *pm)
1086 // a hack follows because old missions don't have a command briefing
1087 if (required_string_either("#Command Briefing", "#Briefing"))
1090 for (i=0; i<Num_teams; i++) {
1091 Cur_cmd_brief = &Cmd_briefs[i];
1092 parse_cmd_brief(pm);
1096 // -------------------------------------------------------------------------------------------------
1099 // Parse the data required for the mission briefing
1101 // NOTE: This updates the global Briefing struct with all the data necessary to drive the briefing
1103 void parse_briefing(mission *pm)
1105 int nt, i, j, stage_num = 0, icon_num = 0, team_index;
1110 char not_used_text[MAX_ICON_TEXT_LEN];
1114 // MWA -- 2/3/98. we can now have multiple briefing and debreifings in a mission
1115 for ( nt = 0; nt < Num_teams; nt++ ) {
1116 if ( !optional_string("#Briefing") )
1119 bp = &Briefings[nt];
1121 required_string("$start_briefing");
1122 required_string("$num_stages:");
1123 stuff_int(&bp->num_stages);
1124 SDL_assert(bp->num_stages <= MAX_BRIEF_STAGES);
1127 while (required_string_either("$end_briefing", "$start_stage")) {
1128 required_string("$start_stage");
1129 SDL_assert(stage_num < MAX_BRIEF_STAGES);
1130 bs = &bp->stages[stage_num++];
1131 required_string("$multi_text");
1132 if ( Fred_running ) {
1133 stuff_string(bs->new_text, F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1135 bs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_BRIEF_LEN);
1137 required_string("$voice:");
1138 stuff_string(bs->voice, F_FILESPEC, NULL);
1139 required_string("$camera_pos:");
1140 stuff_vector(&bs->camera_pos);
1141 required_string("$camera_orient:");
1142 stuff_matrix(&bs->camera_orient);
1143 required_string("$camera_time:");
1144 stuff_int(&bs->camera_time);
1146 if ( optional_string("$num_lines:") ) {
1147 stuff_int(&bs->num_lines);
1149 if ( Fred_running ) {
1150 SDL_assert(bs->lines!=NULL);
1152 if ( bs->num_lines > 0 ) {
1153 bs->lines = (brief_line *)malloc(sizeof(brief_line)*bs->num_lines);
1154 SDL_assert(bs->lines!=NULL);
1158 for (i=0; i<bs->num_lines; i++) {
1159 required_string("$line_start:");
1160 stuff_int(&bs->lines[i].start_icon);
1161 required_string("$line_end:");
1162 stuff_int(&bs->lines[i].end_icon);
1169 required_string("$num_icons:");
1170 stuff_int(&bs->num_icons);
1172 if ( Fred_running ) {
1173 SDL_assert(bs->lines!=NULL);
1175 if ( bs->num_icons > 0 ) {
1176 bs->icons = (brief_icon *)malloc(sizeof(brief_icon)*bs->num_icons);
1177 SDL_assert(bs->icons!=NULL);
1181 if ( optional_string("$flags:") )
1182 stuff_int(&bs->flags);
1186 if ( optional_string("$formula:") )
1187 bs->formula = get_sexp_main();
1189 bs->formula = Locked_sexp_true;
1191 SDL_assert(bs->num_icons <= MAX_STAGE_ICONS );
1193 while (required_string_either("$end_stage", "$start_icon")) {
1194 required_string("$start_icon");
1195 SDL_assert(icon_num < MAX_STAGE_ICONS);
1196 bi = &bs->icons[icon_num++];
1198 required_string("$type:");
1199 stuff_int(&bi->type);
1201 find_and_stuff("$team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1202 SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1203 bi->team = 1 << team_index;
1205 find_and_stuff("$class:", &bi->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1207 required_string("$pos:");
1208 stuff_vector(&bi->pos);
1211 if (optional_string("$label:"))
1212 stuff_string(bi->label, F_MESSAGE, NULL);
1214 if (optional_string("+id:")) {
1216 if (bi->id >= Cur_brief_id)
1217 Cur_brief_id = bi->id + 1;
1221 for (i=0; i<stage_num-1; i++)
1222 for (j=0; j < bp->stages[i].num_icons; j++)
1224 if (!SDL_strcasecmp(bp->stages[i].icons[j].label, bi->label))
1225 bi->id = bp->stages[i].icons[j].id;
1229 bi->id = Cur_brief_id++;
1232 required_string("$hlight:");
1236 bi->flags = BI_HIGHLIGHT;
1241 required_string("$multi_text");
1242 // stuff_string(bi->text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1243 stuff_string(not_used_text, F_MULTITEXT, NULL, MAX_ICON_TEXT_LEN);
1244 required_string("$end_icon");
1246 SDL_assert(bs->num_icons == icon_num);
1248 required_string("$end_stage");
1251 SDL_assert(bp->num_stages == stage_num);
1252 required_string("$end_briefing");
1255 if ( nt != Num_teams )
1256 Error(LOCATION, "Not enough briefings in mission file. There are %d teams and only %d briefings.", Num_teams, nt );
1259 // -------------------------------------------------------------------------------------------------
1260 // parse_debriefing_old()
1262 // Parse the data required for the mission debriefings
1263 void parse_debriefing_old(mission *pm)
1266 char waste[MAX_DEBRIEF_LEN];
1268 if ( !optional_string("#Debriefing") )
1271 required_string("$num_debriefings:");
1274 while (required_string_either("#Players", "$start_debriefing")) {
1275 required_string("$start_debriefing");
1276 required_string("$formula:");
1277 junk = get_sexp_main();
1278 required_string("$num_stages:");
1280 while (required_string_either("$end_debriefing", "$start_stage")) {
1281 required_string("$start_stage");
1282 required_string("$multi_text");
1283 stuff_string(waste, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1284 required_string("$voice:");
1285 stuff_string(waste, F_FILESPEC, NULL);
1286 required_string("$end_stage");
1288 required_string("$end_debriefing");
1292 // -------------------------------------------------------------------------------------------------
1293 // parse_debriefing_new()
1295 // Parse the data required for the mission debriefings
1296 void parse_debriefing_new(mission *pm)
1304 // next code should be old -- hopefully not called anymore
1305 //if (!optional_string("#Debriefing_info")) {
1306 // parse_debriefing_old(pm);
1310 // 2/3/98 -- MWA. We can now have multiple briefings and debriefings on a team
1311 for ( nt = 0; nt < Num_teams; nt++ ) {
1313 if ( !optional_string("#Debriefing_info") )
1318 db = &Debriefings[nt];
1320 required_string("$Num stages:");
1321 stuff_int(&db->num_stages);
1322 SDL_assert(db->num_stages <= MAX_DEBRIEF_STAGES);
1324 while (required_string_either("#", "$Formula")) {
1325 SDL_assert(stage_num < MAX_DEBRIEF_STAGES);
1326 dbs = &db->stages[stage_num++];
1327 required_string("$Formula:");
1328 dbs->formula = get_sexp_main();
1329 required_string("$multi text");
1330 if ( Fred_running ) {
1331 stuff_string(dbs->new_text, F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1333 dbs->new_text = stuff_and_malloc_string(F_MULTITEXT, NULL, MAX_DEBRIEF_LEN);
1335 required_string("$Voice:");
1336 stuff_string(dbs->voice, F_FILESPEC, NULL);
1337 required_string("$Recommendation text:");
1338 if ( Fred_running ) {
1339 stuff_string( dbs->new_recommendation_text, F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1341 dbs->new_recommendation_text = stuff_and_malloc_string( F_MULTITEXT, NULL, MAX_RECOMMENDATION_LEN);
1345 SDL_assert(db->num_stages == stage_num);
1348 if ( nt != Num_teams )
1349 Error(LOCATION, "Not enough debriefings for mission. There are %d teams and only %d debriefings;\n", Num_teams, nt );
1352 void position_ship_for_knossos_warpin(p_object *objp, int shipnum, int objnum)
1354 // Assume no valid knossos device
1355 Ships[shipnum].special_warp_objnum = -1;
1357 // find knossos device
1360 int knossos_num = -1;
1361 for (so=GET_FIRST(&Ship_obj_list); so!=END_OF_LIST(&Ship_obj_list); so=GET_NEXT(so)) {
1362 knossos_num = Objects[so->objnum].instance;
1363 if (Ship_info[Ships[knossos_num].ship_info_index].flags & SIF_KNOSSOS_DEVICE) {
1364 // be close to the right device [allow multiple knossos's
1365 if (vm_vec_dist_quick(&Objects[knossos_num].pos, &objp->pos) < 2.0f*(Objects[knossos_num].radius + Objects[objnum].radius) ) {
1373 // set ship special_warp_objnum
1374 Ships[shipnum].special_warp_objnum = knossos_num;
1376 // position self for warp on plane of device
1378 float dist = fvi_ray_plane(&new_point, &Objects[knossos_num].pos, &Objects[knossos_num].orient.v.fvec, &objp->pos, &objp->orient.v.fvec, 0.0f);
1379 polymodel *pm = model_get(Ship_info[Ships[shipnum].ship_info_index].modelnum);
1380 float desired_dist = -pm->mins.xyz.z;
1381 vm_vec_scale_add2(&Objects[objnum].pos, &Objects[objnum].orient.v.fvec, (dist - desired_dist));
1382 // if ship is BIG or HUGE, make it go through the center of the knossos
1383 if (Ship_info[Ships[shipnum].ship_info_index].flags & SIF_HUGE_SHIP) {
1385 vm_vec_sub(&offset, &Objects[knossos_num].pos, &new_point);
1386 vm_vec_add2(&Objects[objnum].pos, &offset);
1391 // Given a stuffed p_object struct, create an object and fill in the necessary fields.
1392 // Return object number.
1393 int parse_create_object(p_object *objp)
1395 int i, j, k, objnum, shipnum;
1399 subsys_status *sssp;
1402 // base level creation
1403 objnum = ship_create(&objp->orient, &objp->pos, objp->ship_class);
1404 SDL_assert(objnum != -1);
1405 shipnum = Objects[objnum].instance;
1407 // if arriving through knossos, adjust objpj->pos to plane of knossos and set flag
1408 // special warp is single player only
1409 if ((objp->flags & P_KNOSSOS_WARP_IN) && !(Game_mode & GM_MULTIPLAYER)) {
1410 if (!Fred_running) {
1411 position_ship_for_knossos_warpin(objp, shipnum, objnum);
1415 Ships[shipnum].group = objp->group;
1416 Ships[shipnum].team = objp->team;
1417 SDL_strlcpy(Ships[shipnum].ship_name, objp->name, sizeof(Ships[0].ship_name));
1418 Ships[shipnum].escort_priority = objp->escort_priority;
1419 Ships[shipnum].special_exp_index = objp->special_exp_index;
1420 Ships[shipnum].respawn_priority = objp->respawn_priority;
1421 // if this is a multiplayer dogfight game, and its from a player wing, make it team traitor
1422 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (objp->wingnum >= 0)){
1423 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
1424 if ( !SDL_strcasecmp(Starting_wing_names[i], Wings[objp->wingnum].name) ) {
1425 Ships[shipnum].team = TEAM_TRAITOR;
1430 sip = &Ship_info[Ships[shipnum].ship_info_index];
1432 if ( !Fred_running ) {
1433 ship_assign_sound(&Ships[shipnum]);
1436 aip = &(Ai_info[Ships[shipnum].ai_index]);
1437 aip->behavior = objp->behavior;
1438 aip->mode = aip->behavior;
1440 // alternate type name
1441 Ships[shipnum].alt_type_index = objp->alt_type_index;
1443 aip->ai_class = objp->ai_class;
1444 Ships[shipnum].weapons.ai_class = objp->ai_class; // Fred uses this instead of above.
1446 // must reset the number of ai goals when the object is created
1447 for (i = 0; i < MAX_AI_GOALS; i++ ){
1448 aip->goals[i].ai_mode = AI_GOAL_NONE;
1451 Ships[shipnum].cargo1 = objp->cargo1;
1453 Ships[shipnum].arrival_location = objp->arrival_location;
1454 Ships[shipnum].arrival_distance = objp->arrival_distance;
1455 Ships[shipnum].arrival_anchor = objp->arrival_anchor;
1456 Ships[shipnum].arrival_cue = objp->arrival_cue;
1457 Ships[shipnum].arrival_delay = objp->arrival_delay;
1458 Ships[shipnum].departure_location = objp->departure_location;
1459 Ships[shipnum].departure_anchor = objp->departure_anchor;
1460 Ships[shipnum].departure_cue = objp->departure_cue;
1461 Ships[shipnum].departure_delay = objp->departure_delay;
1462 Ships[shipnum].determination = objp->determination;
1463 Ships[shipnum].wingnum = objp->wingnum;
1464 Ships[shipnum].hotkey = objp->hotkey;
1465 Ships[shipnum].score = objp->score;
1466 Ships[shipnum].persona_index = objp->persona_index;
1468 // set the orders that this ship will accept. It will have already been set to default from the
1469 // ship create code, so only set them if the parse object flags say they are unique
1470 if ( objp->flags & P_SF_USE_UNIQUE_ORDERS ) {
1471 Ships[shipnum].orders_accepted = objp->orders_accepted;
1473 // MWA 5/15/98 -- Added the following debug code because some orders that ships
1474 // will accept were apparently written out incorrectly with Fred. This Int3() should
1475 // trap these instances.
1477 if ( Fred_running ) {
1478 int default_orders, remaining_orders;
1480 default_orders = ship_get_default_orders_accepted( &Ship_info[Ships[shipnum].ship_info_index] );
1481 remaining_orders = objp->orders_accepted & ~default_orders;
1482 if ( remaining_orders ) {
1483 Warning(LOCATION, "Ship %s has orders which it will accept that are\nnot part of default orders accepted.\n\nPlease reedit this ship and change the orders again\n", Ships[shipnum].ship_name);
1489 // check the parse object's flags for possible flags to set on this newly created ship
1490 if ( objp->flags & P_OF_PROTECTED ) {
1491 Objects[objnum].flags |= OF_PROTECTED;
1494 if ( objp->flags & P_OF_BEAM_PROTECTED ) {
1495 Objects[objnum].flags |= OF_BEAM_PROTECTED;
1498 if (objp->flags & P_OF_CARGO_KNOWN) {
1499 Ships[shipnum].flags |= SF_CARGO_REVEALED;
1502 if ( objp->flags & P_SF_IGNORE_COUNT )
1503 Ships[shipnum].flags |= SF_IGNORE_COUNT;
1505 if ( objp->flags & P_SF_REINFORCEMENT )
1506 Ships[shipnum].flags |= SF_REINFORCEMENT;
1508 if (objp->flags & P_OF_NO_SHIELDS || sip->shields == 0 )
1509 Objects[objnum].flags |= OF_NO_SHIELDS;
1511 if (objp->flags & P_SF_ESCORT)
1512 Ships[shipnum].flags |= SF_ESCORT;
1514 if (objp->flags & P_KNOSSOS_WARP_IN) {
1515 Objects[objnum].flags |= OF_SPECIAL_WARP;
1518 // don't set the flag if the mission is ongoing in a multiplayer situation. This will be set by the players in the
1519 // game only before the game or during respawning.
1520 // MWA -- changed the next line to remove the !(Game_mode & GM_MULTIPLAYER). We shouldn't be setting
1521 // this flag in single player mode -- it gets set in post process mission.
1522 //if ((objp->flags & P_OF_PLAYER_START) && (((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION)) || !(Game_mode & GM_MULTIPLAYER)))
1523 if ( (objp->flags & P_OF_PLAYER_START) && (Fred_running || ((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION))) )
1524 Objects[objnum].flags |= OF_PLAYER_SHIP;
1526 if (objp->flags & P_SF_NO_ARRIVAL_MUSIC)
1527 Ships[shipnum].flags |= SF_NO_ARRIVAL_MUSIC;
1529 if ( objp->flags & P_SF_NO_ARRIVAL_WARP )
1530 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1532 if ( objp->flags & P_SF_NO_DEPARTURE_WARP )
1533 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1535 if ( objp->flags & P_SF_INITIALLY_DOCKED )
1536 Ships[shipnum].flags |= SF_INITIALLY_DOCKED;
1538 if ( objp->flags & P_SF_LOCKED )
1539 Ships[shipnum].flags |= SF_LOCKED;
1541 if ( objp->flags & P_SF_WARP_BROKEN )
1542 Ships[shipnum].flags |= SF_WARP_BROKEN;
1544 if ( objp->flags & P_SF_WARP_NEVER )
1545 Ships[shipnum].flags |= SF_WARP_NEVER;
1547 if ( objp->flags & P_SF_HIDDEN_FROM_SENSORS )
1548 Ships[shipnum].flags |= SF_HIDDEN_FROM_SENSORS;
1550 // if ship is in a wing, and the wing's no_warp_effect flag is set, then set the equivalent
1551 // flag for the ship
1552 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_ARRIVAL_WARP) )
1553 Ships[shipnum].flags |= SF_NO_ARRIVAL_WARP;
1555 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_NO_DEPARTURE_WARP) )
1556 Ships[shipnum].flags |= SF_NO_DEPARTURE_WARP;
1558 // mwa -- 1/30/98. Do both flags. Fred uses the ship flag, and FreeSpace will use the object
1559 // flag. I'm to lazy at this point to deal with consolidating them.
1560 if ( objp->flags & P_SF_INVULNERABLE ) {
1561 Ships[shipnum].flags |= SF_INVULNERABLE;
1562 Objects[objnum].flags |= OF_INVULNERABLE;
1565 if ( objp->flags & P_SF_GUARDIAN ) {
1566 Objects[objnum].flags |= OF_GUARDIAN;
1569 if ( objp->flags & P_SF_SCANNABLE )
1570 Ships[shipnum].flags |= SF_SCANNABLE;
1572 if ( objp->flags & P_SF_RED_ALERT_STORE_STATUS ){
1573 SDL_assert(!(Game_mode & GM_MULTIPLAYER));
1574 Ships[shipnum].flags |= SF_RED_ALERT_STORE_STATUS;
1577 // a couple of ai_info flags. Also, do a reasonable default for the kamikaze damage regardless of
1578 // whether this flag is set or not
1579 if ( objp->flags & P_AIF_KAMIKAZE ) {
1580 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_KAMIKAZE;
1581 Ai_info[Ships[shipnum].ai_index].kamikaze_damage = objp->kamikaze_damage;
1584 if ( objp->flags & P_AIF_NO_DYNAMIC )
1585 Ai_info[Ships[shipnum].ai_index].ai_flags |= AIF_NO_DYNAMIC;
1587 // if the wing index and wing pos are set for this parse object, set them for the ship. This
1588 // is useful in multiplayer when ships respawn
1589 Ships[shipnum].wing_status_wing_index = objp->wing_status_wing_index;
1590 Ships[shipnum].wing_status_wing_pos = objp->wing_status_wing_pos;
1592 // set up the ai_goals for this object -- all ships created here are AI controlled.
1593 if ( objp->ai_goals != -1 ) {
1596 for ( sexp = CDR(objp->ai_goals); sexp != -1; sexp = CDR(sexp) )
1597 // make a call to the routine in MissionGoals.cpp to set up the ai goals for this object.
1598 ai_add_ship_goal_sexp( sexp, AIG_TYPE_EVENT_SHIP, aip );
1600 if ( objp->wingnum == -1 ) // free the sexpression nodes only for non-wing ships. wing code will handle it's own case
1601 free_sexp2(objp->ai_goals); // free up sexp nodes for reused, since they aren't needed anymore.
1604 SDL_assert(Ships[shipnum].modelnum != -1);
1606 // initialize subsystem statii here. The subsystems are given a percentage damaged. So a percent value
1607 // of 20% means that the subsystem is 20% damaged (*not* 20% of max hits). This is opposite the way
1608 // that the initial velocity/hull strength/shields work
1609 i = objp->subsys_count;
1611 sssp = &Subsys_status[objp->subsys_index + i];
1612 if (!SDL_strcasecmp(sssp->name, NOX("Pilot"))) {
1613 wp = &Ships[shipnum].weapons;
1614 if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1615 for (j=k=0; j<MAX_PRIMARY_BANKS; j++) {
1616 if ( (sssp->primary_banks[j] >= 0) || Fred_running ){
1617 wp->primary_bank_weapons[k] = sssp->primary_banks[j];
1625 wp->num_primary_banks = sip->num_primary_banks;
1627 wp->num_primary_banks = k;
1631 if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE) {
1632 for (j=k=0; j<MAX_SECONDARY_BANKS; j++) {
1633 if ( (sssp->secondary_banks[j] >= 0) || Fred_running ){
1634 wp->secondary_bank_weapons[k++] = sssp->secondary_banks[j];
1639 wp->num_secondary_banks = sip->num_secondary_banks;
1641 wp->num_secondary_banks = k;
1645 for (j=0; j < wp->num_secondary_banks; j++)
1647 wp->secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1649 int capacity = fl2i(sssp->secondary_ammo[j]/100.0f * sip->secondary_bank_ammo_capacity[j] + 0.5f );
1650 wp->secondary_bank_ammo[j] = fl2i(capacity / Weapon_info[wp->secondary_bank_weapons[j]].cargo_size + 0.5f);
1655 ptr = GET_FIRST(&Ships[shipnum].subsys_list);
1656 while (ptr != END_OF_LIST(&Ships[shipnum].subsys_list)) {
1657 if (!SDL_strcasecmp(ptr->system_info->subobj_name, sssp->name)) {
1659 ptr->current_hits = sssp->percent;
1662 new_hits = ptr->system_info->max_hits * (100.0f - sssp->percent) / 100.f;
1663 Ships[shipnum].subsys_info[ptr->system_info->type].current_hits -= (ptr->system_info->max_hits - new_hits);
1664 if ( (100.0f - sssp->percent) < 0.5) {
1665 ptr->current_hits = 0.0f;
1666 ptr->submodel_info_1.blown_off = 1;
1668 ptr->current_hits = new_hits;
1672 if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1673 for (j=0; j<MAX_PRIMARY_BANKS; j++)
1674 ptr->weapons.primary_bank_weapons[j] = sssp->primary_banks[j];
1676 if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
1677 for (j=0; j<MAX_SECONDARY_BANKS; j++)
1678 ptr->weapons.secondary_bank_weapons[j] = sssp->secondary_banks[j];
1680 for (j=0; j<MAX_SECONDARY_BANKS; j++) {
1681 // AL 3-5-98: This is correct for FRED, but not for FreeSpace... but is this even used?
1682 // As far as I know, turrets cannot run out of ammo
1683 ptr->weapons.secondary_bank_ammo[j] = sssp->secondary_ammo[j];
1686 ptr->subsys_cargo_name = sssp->subsys_cargo_name;
1688 if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
1689 ptr->weapons.ai_class = sssp->ai_class;
1691 ai_turret_select_default_weapon(ptr);
1694 ptr = GET_NEXT(ptr);
1698 // initial hull strength, shields, and velocity are all expressed as a percentage of the max value/
1699 // so a initial_hull value of 90% means 90% of max. This way is opposite of how subsystems are dealt
1702 Objects[objnum].phys_info.speed = (float) objp->initial_velocity;
1703 // Ships[shipnum].hull_hit_points_taken = (float) objp->initial_hull;
1704 Objects[objnum].hull_strength = (float) objp->initial_hull;
1705 Objects[objnum].shields[0] = (float) objp->initial_shields;
1708 int max_allowed_sparks, num_sparks, i;
1711 // Ships[shipnum].hull_hit_points_taken = (float)objp->initial_hull * sip->max_hull_hit_points / 100.0f;
1712 Objects[objnum].hull_strength = objp->initial_hull * sip->initial_hull_strength / 100.0f;
1713 for (i = 0; i<MAX_SHIELD_SECTIONS; i++)
1714 Objects[objnum].shields[i] = (float)(objp->initial_shields * sip->shields / 100.0f) / MAX_SHIELD_SECTIONS;
1716 // initial velocities now do not apply to ships which warp in after mission starts
1717 if ( !(Game_mode & GM_IN_MISSION) ) {
1718 Objects[objnum].phys_info.speed = (float)objp->initial_velocity * sip->max_speed / 100.0f;
1719 Objects[objnum].phys_info.vel.xyz.z = Objects[objnum].phys_info.speed;
1720 Objects[objnum].phys_info.prev_ramp_vel = Objects[objnum].phys_info.vel;
1721 Objects[objnum].phys_info.desired_vel = Objects[objnum].phys_info.vel;
1724 // recalculate damage of subsystems
1725 ship_recalc_subsys_strength( &Ships[shipnum] );
1727 // create sparks on a ship whose hull is damaged. We will create two sparks for every 20%
1728 // of hull damage done. 100 means no sparks. between 80 and 100 do two sparks. 60 and 80 is
1730 pm = model_get( sip->modelnum );
1731 max_allowed_sparks = get_max_sparks(&Objects[objnum]);
1732 num_sparks = (int)((100.0f - objp->initial_hull) / 5.0f);
1733 if (num_sparks > max_allowed_sparks) {
1734 num_sparks = max_allowed_sparks;
1737 for (i = 0; i < num_sparks; i++ ) {
1740 // DA 10/20/98 - sparks must be chosen on the hull and not any submodel
1741 submodel_get_two_random_points(sip->modelnum, pm->detail[0], &v1, &v2);
1742 ship_hit_sparks_no_rotate(&Objects[objnum], &v1);
1743 // ship_hit_sparks_no_rotate(&Objects[objnum], &v2);
1747 // in mission, we add a log entry -- set ship positions for ships not in wings, and then do
1749 if ( (Game_mode & GM_IN_MISSION) && (!Fred_running) ) {
1750 mission_log_add_entry( LOG_SHIP_ARRIVE, Ships[shipnum].ship_name, NULL );
1752 // if this ship isn't in a wing, determine it's arrival location
1753 if ( !Game_restoring ) {
1754 if ( Ships[shipnum].wingnum == -1 ) {
1756 // multiplayer clients set the arrival location of ships to be at location since their
1757 // position has already been determined. Don't actually set the variable since we
1758 // don't want the warp effect to show if coming from a dock bay.
1759 location = objp->arrival_location;
1760 if ( MULTIPLAYER_CLIENT )
1761 location = ARRIVE_AT_LOCATION;
1762 mission_set_arrival_location(objp->arrival_anchor, location, objp->arrival_distance, objnum, NULL, NULL);
1763 if ( objp->arrival_location != ARRIVE_FROM_DOCK_BAY )
1764 shipfx_warpin_start( &Objects[objnum] );
1768 // possibly add this ship to a hotkey set
1769 if ( (Ships[shipnum].wingnum == -1) && (Ships[shipnum].hotkey != -1 ) )
1770 mission_hotkey_mf_add( Ships[shipnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1771 else if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].hotkey != -1 ) )
1772 mission_hotkey_mf_add( Wings[Ships[shipnum].wingnum].hotkey, Ships[shipnum].objnum, HOTKEY_MISSION_FILE_ADDED );
1774 // possibly add this ship to the hud escort list
1775 if ( Ships[shipnum].flags & SF_ESCORT ){
1776 hud_add_remove_ship_escort( objnum, 1 );
1780 // for multiplayer games, make a call to the network code to assign the object signature
1781 // of the newly created object. The network host of the netgame will always assign a signature
1782 // to a newly created object. The network signature will get to the clients of the game in
1783 // different manners depending on whether or not an individual ship or a wing was created.
1784 if ( Game_mode & GM_MULTIPLAYER ) {
1785 Objects[objnum].net_signature = objp->net_signature;
1787 if ( (Game_mode & GM_IN_MISSION) && MULTIPLAYER_MASTER && (objp->wingnum == -1) ){
1788 send_ship_create_packet( &Objects[objnum], (objp==Arriving_support_ship)?1:0 );
1792 // if recording a demo, post the event
1793 if(Game_mode & GM_DEMO_RECORD){
1794 demo_POST_obj_create(objp->name, Objects[objnum].signature);
1800 // Mp points at the text of an object, which begins with the "$Name:" field.
1801 // Snags all object information and calls parse_create_object to create a ship.
1802 // Why create a ship? Why not an object? Stay tuned...
1804 // flag is parameter that is used to tell what kind information we are retrieving from the mission.
1805 // if we are just getting player starts, then don't create the objects
1806 int parse_object(mission *pm, int flag, p_object *objp)
1808 // p_object temp_object;
1810 int i, j, count, shipnum, delay, destroy_before_mission_time;
1811 char name[NAME_LENGTH], flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
1813 SDL_assert(pm != NULL);
1815 // objp = &temp_object;
1817 required_string("$Name:");
1818 stuff_string(objp->name, F_NAME, NULL);
1819 shipnum = ship_name_lookup(objp->name);
1821 error_display(0, NOX("Redundant ship name: %s\n"), objp->name);
1824 find_and_stuff("$Class:", &objp->ship_class, F_NAME, (const char **)Ship_class_names, Num_ship_types, "ship class");
1825 if (objp->ship_class < 0) {
1826 Warning(LOCATION, "Ship \"%s\" has an invalid ship type (ships.tbl probably changed). Making it type 0", objp->name);
1828 // if fred is running, maybe notify the user that the mission contains MD content
1830 Fred_found_unknown_ship_during_parsing = 1;
1833 objp->ship_class = 0;
1836 // if this is a multiplayer dogfight mission, skip support ships
1837 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (Ship_info[objp->ship_class].flags & SIF_SUPPORT)){
1841 // optional alternate name type
1842 objp->alt_type_index = -1;
1843 if(optional_string("$Alt:")){
1845 stuff_string(name, F_NAME, NULL, NAME_LENGTH);
1847 // try and find the alternate name
1848 objp->alt_type_index = (char)mission_parse_lookup_alt(name);
1849 SDL_assert(objp->alt_type_index >= 0);
1850 if(objp->alt_type_index < 0){
1851 mprintf(("Error looking up alternate ship type name!\n"));
1853 mprintf(("Using alternate ship type name : %s\n", name));
1858 find_and_stuff("$Team:", &team_index, F_NAME, Team_names, Num_team_names, "team name");
1859 SDL_assert((team_index >= 0) && (team_index < MAX_TEAM_NAMES));
1860 objp->team = 1 << team_index;
1862 required_string("$Location:");
1863 stuff_vector(&objp->pos);
1865 required_string("$Orientation:");
1866 stuff_matrix(&objp->orient);
1868 find_and_stuff("$IFF:", &objp->iff, F_NAME, Iff_names, Num_iff, "IFF");
1869 find_and_stuff("$AI Behavior:", &objp->behavior, F_NAME, Ai_behavior_names, Num_ai_behaviors, "AI behavior");
1870 objp->ai_goals = -1;
1872 if ( optional_string("+AI Class:")) {
1873 objp->ai_class = match_and_stuff(F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class");
1874 SDL_assert(objp->ai_class > -1 );
1876 objp->ai_class = Ship_info[objp->ship_class].ai_class;
1879 if ( optional_string("$AI Goals:") ){
1880 objp->ai_goals = get_sexp_main();
1883 if ( !required_string_either("$AI Goals:", "$Cargo 1:") ) {
1884 required_string("$AI Goals:");
1885 objp->ai_goals = get_sexp_main();
1890 find_and_stuff_or_add("$Cargo 1:", &temp, F_NAME, Cargo_names, NAME_LENGTH, &Num_cargo, MAX_CARGO, "cargo");
1891 objp->cargo1 = char(temp);
1892 if ( optional_string("$Cargo 2:") ) {
1893 char buf[NAME_LENGTH];
1894 stuff_string(buf, F_NAME, NULL);
1897 parse_common_object_data(objp); // get initial conditions and subsys status
1899 while (required_string_either("$Arrival Location:", "$Status Description:")) {
1900 SDL_assert(count < MAX_OBJECT_STATUS);
1902 find_and_stuff("$Status Description:", &objp->status_type[count], F_NAME, Status_desc_names, Num_status_names, "Status Description");
1903 find_and_stuff("$Status:", &objp->status[count], F_NAME, Status_type_names, Num_status_names, "Status Type");
1904 find_and_stuff("$Target:", &objp->target[count], F_NAME, Status_target_names, Num_status_names, "Target");
1907 objp->status_count = count;
1909 objp->arrival_anchor = -1;
1910 objp->arrival_distance = 0;
1911 find_and_stuff("$Arrival Location:", &objp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
1912 if ( optional_string("+Arrival Distance:") ) {
1913 stuff_int( &objp->arrival_distance );
1914 if ( objp->arrival_location != ARRIVE_AT_LOCATION ) {
1915 required_string("$Arrival Anchor:");
1916 stuff_string(name, F_NAME, NULL);
1917 objp->arrival_anchor = get_anchor(name);
1921 if (optional_string("+Arrival Delay:")) {
1924 Error(LOCATION, "Cannot have arrival delay < 0 (ship %s)", objp->name);
1928 if ( !Fred_running ){
1929 objp->arrival_delay = -delay; // use negative numbers to mean we haven't set up a timer yet
1931 objp->arrival_delay = delay;
1934 required_string("$Arrival Cue:");
1935 objp->arrival_cue = get_sexp_main();
1936 if ( !Fred_running && (objp->arrival_cue >= 0) ) {
1937 // eval the arrival cue. if the cue is true, set up the timestamp for the arrival delay
1938 SDL_assert ( objp->arrival_delay <= 0 );
1940 // don't eval arrival_cues when just looking for player information.
1941 if ( eval_sexp(objp->arrival_cue) ){ // evaluate to determine if sexp is always false.
1942 objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
1946 find_and_stuff("$Departure Location:", &objp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
1947 objp->departure_anchor = -1;
1948 if ( objp->departure_location == DEPART_AT_DOCK_BAY ) {
1949 required_string("$Departure Anchor:");
1950 stuff_string(name, F_NAME, NULL);
1951 objp->departure_anchor = get_anchor(name);
1954 if (optional_string("+Departure Delay:")) {
1957 Error(LOCATION, "Cannot have departure delay < 0 (ship %s)", objp->name);
1963 if ( !Fred_running ){
1964 objp->departure_delay = -delay;
1966 objp->departure_delay = delay;
1969 required_string("$Departure Cue:");
1970 objp->departure_cue = get_sexp_main();
1972 if (optional_string("$Misc Properties:"))
1973 stuff_string(objp->misc, F_NAME, NULL);
1975 required_string("$Determination:");
1976 stuff_int(&objp->determination);
1979 if (optional_string("+Flags:")) {
1980 count = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
1981 for (i=0; i<count; i++) {
1982 for (j=0; j<MAX_PARSE_OBJECT_FLAGS; j++) {
1983 if (!SDL_strcasecmp(flag_strings[i], Parse_object_flags[j])) {
1984 objp->flags |= (1 << j);
1989 if (j == MAX_PARSE_OBJECT_FLAGS)
1990 Warning(LOCATION, "Unknown flag in mission file: %s\n", flag_strings[i]);
1994 // always store respawn priority, just for ease of implementation
1995 objp->respawn_priority = 0;
1996 if(optional_string("+Respawn Priority:" )){
1997 stuff_int(&objp->respawn_priority);
2000 objp->escort_priority = 0;
2001 if ( optional_string("+Escort Priority:" ) ) {
2002 SDL_assert(objp->flags & P_SF_ESCORT);
2003 stuff_int(&objp->escort_priority);
2006 if ( objp->flags & P_OF_PLAYER_START ) {
2007 objp->flags |= P_OF_CARGO_KNOWN; // make cargo known for players
2011 objp->special_exp_index = -1;
2012 if ( optional_string("+Special Exp index:" ) ) {
2013 stuff_int(&objp->special_exp_index);
2016 // if the kamikaze flag is set, we should have the next flag
2017 if ( optional_string("+Kamikaze Damage:") ) {
2021 objp->kamikaze_damage = i2fl(damage);
2025 if (optional_string("+Hotkey:")) {
2026 stuff_int(&objp->hotkey);
2027 SDL_assert((objp->hotkey >= 0) && (objp->hotkey < 10));
2030 objp->docked_with[0] = 0;
2031 if (optional_string("+Docked With:")) {
2032 stuff_string(objp->docked_with, F_NAME, NULL);
2033 required_string("$Docker Point:");
2034 stuff_string(objp->docker_point, F_NAME, NULL);
2035 required_string("$Dockee Point:");
2036 stuff_string(objp->dockee_point, F_NAME, NULL);
2038 objp->flags |= P_SF_INITIALLY_DOCKED;
2040 // put this information into the Initially_docked array. We will need to use this
2041 // informatin later since not all ships will initially get created.
2042 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee, objp->docked_with, NAME_LENGTH);
2043 SDL_strlcpy(Initially_docked[Total_initially_docked].docker_point, objp->docker_point, NAME_LENGTH);
2044 SDL_strlcpy(Initially_docked[Total_initially_docked].dockee_point, objp->dockee_point, NAME_LENGTH);
2045 Initially_docked[Total_initially_docked].docker = objp;
2046 Total_initially_docked++;
2049 // check the optional parameter for destroying the ship before the mission starts. If this parameter is
2050 // here, then we need to destroy the ship N seconds before the mission starts (for debris purposes).
2051 // store the time value here. We want to create this object for sure. Set the arrival cue and arrival
2052 // delay to bogus values
2053 destroy_before_mission_time = -1;
2054 if ( optional_string("+Destroy At:") ) {
2056 stuff_int(&destroy_before_mission_time);
2057 SDL_assert ( destroy_before_mission_time >= 0 );
2058 objp->arrival_cue = Locked_sexp_true;
2059 objp->arrival_delay = timestamp(0);
2062 // check for the optional "orders accepted" string which contains the orders from the default
2063 // set that this ship will actually listen to
2064 if ( optional_string("+Orders Accepted:") ) {
2065 stuff_int( &objp->orders_accepted );
2066 if ( objp->orders_accepted != -1 ){
2067 objp->flags |= P_SF_USE_UNIQUE_ORDERS;
2071 if (optional_string("+Group:")){
2072 stuff_int(&objp->group);
2077 if (optional_string("+Score:")){
2078 stuff_int(&objp->score);
2083 // parse the persona index if present
2084 if ( optional_string("+Persona Index:")){
2085 stuff_int(&objp->persona_index);
2087 objp->persona_index = -1;
2090 objp->wingnum = -1; // set the wing number to -1 -- possibly to be set later
2092 // for multiplayer, assign a network signature to this parse object. Doing this here will
2093 // allow servers to use the signature with clients when creating new ships, instead of having
2094 // to pass ship names all the time
2095 if ( Game_mode & GM_MULTIPLAYER ){
2096 objp->net_signature = multi_assign_network_signature( MULTI_SIG_SHIP );
2099 // set the wing_status position to be -1 for all objects. This will get set to an appropriate
2100 // value when the wing positions are finally determined.
2101 objp->wing_status_wing_index = -1;
2102 objp->wing_status_wing_pos = -1;
2103 objp->respawn_count = 0;
2105 // if this if the starting player ship, then copy if to Starting_player_pobject (used for ingame join)
2106 if ( !SDL_strcasecmp( objp->name, Player_start_shipname) ) {
2107 Player_start_pobject = *objp;
2108 Player_start_pobject.flags |= P_SF_PLAYER_START_VALID;
2112 // Now create the object.
2113 // Don't create the new ship blindly. First, check the sexp for the arrival cue
2114 // to determine when this ship should arrive. If not right away, stick this ship
2115 // onto the ship arrival list to be looked at later. Also check to see if it should use the
2116 // wings arrival cue. The ship may get created later depending on whether or not the wing
2118 // always create ships when FRED is running
2120 // don't create the object if it is intially docked for either FreeSpcae or Fred. Fred will
2121 // create the object later in post_process_mission
2122 if ( (objp->flags & P_SF_INITIALLY_DOCKED) || (!Fred_running && (!eval_sexp(objp->arrival_cue) || !timestamp_elapsed(objp->arrival_delay) || (objp->flags & P_SF_REINFORCEMENT))) ) {
2123 SDL_assert ( destroy_before_mission_time == -1 ); // we can't add ships getting destroyed to the arrival list!!!
2124 SDL_assert ( num_ship_arrivals < MAX_SHIP_ARRIVALS );
2125 memcpy( &ship_arrivals[num_ship_arrivals], objp, sizeof(p_object) );
2126 list_append(&ship_arrival_list, &ship_arrivals[num_ship_arrivals]);
2127 num_ship_arrivals++;
2129 // ingame joiners bail here.
2130 else if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_INGAME_JOIN)){
2136 real_objnum = parse_create_object(objp); // this object may later get destroyed depending on wing status!!!!
2138 Subsys_index = objp->subsys_index; // free elements that are no longer needed.
2140 // if the ship is supposed to be destroyed before the mission, then blow up the ship, mark the pieces
2141 // as last forever. Only call this stuff when you are blowing up the ship
2142 if ( destroy_before_mission_time >= 0 ) {
2145 objp = &Objects[real_objnum];
2146 if ( !Fred_running ) {
2148 shipfx_blow_up_model( objp, Ships[objp->instance].modelnum, 0, 0, &objp->pos );
2149 objp->flags |= OF_SHOULD_BE_DEAD;
2151 // once the ship is exploded, find the debris pieces belonging to this object, mark them
2152 // as not to expire, and move them forward in time N seconds
2153 for (i = 0; i < MAX_DEBRIS_PIECES; i++ ) {
2157 if ( !db->flags & DEBRIS_USED ) // not used, move onto the next one.
2159 if ( db->source_objnum != real_objnum ) // not from this ship, move to next one
2162 debris_clear_expired_flag(db); // mark as don't expire
2163 db->lifeleft = -1.0f; // be sure that lifeleft == -1.0 so that it really doesn't expire!
2165 // now move the debris along it's path for N seconds
2166 objp = &Objects[db->objnum];
2167 physics_sim( &objp->pos, &objp->orient, &objp->phys_info, (float)destroy_before_mission_time );
2170 // be sure to set the variable in the ships structure for the final death time!!!
2171 Ships[objp->instance].final_death_time = destroy_before_mission_time;
2172 Ships[objp->instance].flags |= SF_KILL_BEFORE_MISSION;
2180 void parse_common_object_data(p_object *objp)
2184 // set some defaults..
2185 objp->initial_velocity = 0;
2186 objp->initial_hull = 100;
2187 objp->initial_shields = 100;
2189 // now change defaults if present
2190 if (optional_string("+Initial Velocity:")) {
2191 stuff_int(&objp->initial_velocity);
2194 if (optional_string("+Initial Hull:"))
2195 stuff_int(&objp->initial_hull);
2196 if (optional_string("+Initial Shields:"))
2197 stuff_int(&objp->initial_shields);
2199 objp->subsys_index = Subsys_index;
2200 objp->subsys_count = 0;
2201 while (optional_string("+Subsystem:")) {
2202 i = allocate_subsys_status();
2204 objp->subsys_count++;
2205 stuff_string(Subsys_status[i].name, F_NAME, NULL);
2207 if (optional_string("$Damage:"))
2208 stuff_float(&Subsys_status[i].percent);
2210 Subsys_status[i].subsys_cargo_name = -1;
2211 if (optional_string("+Cargo Name:")) {
2212 char cargo_name[256];
2213 stuff_string(cargo_name, F_NAME, NULL);
2214 int index = string_lookup(cargo_name, (const char **)Cargo_names, Num_cargo, "cargo", 0);
2215 if (index == -1 && (Num_cargo < MAX_CARGO)) {
2217 SDL_strlcpy(Cargo_names[Num_cargo++], cargo_name, NAME_LENGTH);
2219 Subsys_status[i].subsys_cargo_name = index;
2222 if (optional_string("+AI Class:"))
2223 Subsys_status[i].ai_class = match_and_stuff(F_NAME, (const char **)Ai_class_names, Num_ai_classes, "AI class");
2225 if (optional_string("+Primary Banks:"))
2226 stuff_int_list(Subsys_status[i].primary_banks, MAX_PRIMARY_BANKS, WEAPON_LIST_TYPE);
2228 if (optional_string("+Secondary Banks:"))
2229 stuff_int_list(Subsys_status[i].secondary_banks, MAX_SECONDARY_BANKS, WEAPON_LIST_TYPE);
2231 if (optional_string("+Sbank Ammo:"))
2232 stuff_int_list(Subsys_status[i].secondary_ammo, MAX_SECONDARY_BANKS, RAW_INTEGER_TYPE);
2237 void parse_objects(mission *pm, int flag)
2241 SDL_assert(pm != NULL);
2243 required_string("#Objects");
2246 num_ship_original = 0;
2247 while (required_string_either("#Wings", "$Name:")){
2248 // not all objects are always valid or legal
2249 if(parse_object(pm, flag, &temp)){
2250 // add to the default list
2251 if(num_ship_original < MAX_SHIP_ORIGINAL){
2252 memcpy(&ship_original[num_ship_original++], &temp, sizeof(p_object));
2258 p_object *mission_parse_get_original_ship( ushort net_signature )
2262 // look for original ships
2263 for(idx=0; idx<num_ship_original; idx++){
2264 if(ship_original[idx].net_signature == net_signature){
2265 return &ship_original[idx];
2273 int find_wing_name(char *name)
2277 for (i=0; i<num_wings; i++){
2278 if (!strcmp(name, Wings[i].name)){
2286 // function to create ships in the wing that need to be created. We psas the wing pointer, it's index
2287 // into the Wings array
2288 int parse_wing_create_ships( wing *wingp, int num_to_create, int force, int specific_instance )
2291 int wingnum, objnum, num_create_save;
2293 int pre_create_count;
2295 // we need to send this in multiplayer
2296 pre_create_count = wingp->total_arrived_count;
2298 // force is used to force creation of the wing -- used for multiplayer
2300 // we only want to evaluate the arrival cue of the wing if:
2302 // 2) multiplayer and I am the host of the game
2303 // can't create any ships if the arrival cue is false or the timestamp has not elapsed.
2305 if ( !eval_sexp(wingp->arrival_cue) ) /* || !timestamp_elapsed(wingp->arrival_delay) ) */
2308 // once the sexpressions becomes true, then check the arrival delay on the wing. The first time, the
2309 // arrival delay will be <= 0 meaning that no timer object has been set yet. Set up the timestamp
2310 // which should always give a number >= 0;
2311 if ( wingp->arrival_delay <= 0 ) {
2312 wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
2313 SDL_assert ( wingp->arrival_delay >= 0 );
2316 if ( !timestamp_elapsed( wingp->arrival_delay ) )
2319 // if wing is coming from docking bay, then be sure that ship we are arriving from actually exists
2321 if ( wingp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
2325 SDL_assert( wingp->arrival_anchor >= 0 );
2326 name = Parse_names[wingp->arrival_anchor];
2328 // see if ship is yet to arrive. If so, then return -1 so we can evaluate again later.
2329 if ( mission_parse_get_arrival_ship( name ) )
2332 // see if ship is in mission. If not, then we can assume it was destroyed or departed since
2333 // it is not on the arrival list (as shown by above if statement).
2334 shipnum = ship_name_lookup( name );
2335 if ( shipnum == -1 ) {
2337 // since this wing cannot arrive from this place, we need to mark the wing as destroyed and
2338 // set the wing variables appropriatly. Good for directives.
2340 // set the gone flag
2341 wingp->flags |= WF_WING_GONE;
2343 // if the current wave is zero, it never existed
2344 wingp->flags |= WF_NEVER_EXISTED;
2346 // mark the number of waves and number of ships destroyed equal to the last wave and the number
2347 // of ships yet to arrive
2348 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
2349 wingp->total_arrived_count += num_remaining;
2350 wingp->current_wave = wingp->num_waves;
2352 // replaced following three lines of code with mission log call because of bug with
2353 // the Ships_exited list.
2354 //index = ship_find_exited_ship_by_name( name );
2355 //SDL_assert( index != -1 );
2356 //if (Ships_exited[index].flags & SEF_DESTROYED ) {
2357 if ( mission_log_get_time(LOG_SHIP_DESTROYED, name, NULL, NULL) ) {
2358 wingp->total_destroyed += num_remaining;
2360 wingp->total_departed += num_remaining;
2363 Sexp_nodes[wingp->arrival_cue].value = SEXP_KNOWN_FALSE;
2368 if ( num_to_create == 0 )
2371 // check the wave_delay_timestamp field. If it is not valid, make it valid (based on wave delay min
2372 // and max valuds). If it is valid, and not elapsed, then return. If it is valid and elasped, then
2374 if ( !timestamp_valid(wingp->wave_delay_timestamp) ) {
2376 // if at least one of these is valid, then reset the timestamp. If they are both zero, we will create the
2378 if ( (wingp->wave_delay_min > 0) || (wingp->wave_delay_max > 0) ) {
2379 SDL_assert ( wingp->wave_delay_min <= wingp->wave_delay_max );
2380 time_to_arrive = wingp->wave_delay_min + (int)(frand() * (wingp->wave_delay_max - wingp->wave_delay_min));
2383 // HACK HACK -- in the presense of Mike Comet and Mitri, I have introduced one of the most
2384 // serious breaches of coding standards. I'm to lazy to fix this the correct way. Insert
2385 // a delay before the next wave of the wing can arrive to that clients in the game have ample
2386 // time to kill off any ships in the wing before the next wave arrives.
2387 if ( Game_mode & GM_MULTIPLAYER ){
2388 time_to_arrive += 7;
2390 wingp->wave_delay_timestamp = timestamp(time_to_arrive * 1000);
2394 // if we get here, both min and max values are 0; See comments above for a most serious hack
2396 if ( Game_mode & GM_MULTIPLAYER )
2397 time_to_arrive += 7;
2398 time_to_arrive *= 1000;
2399 wingp->wave_delay_timestamp = timestamp(time_to_arrive);
2402 // now check to see if the wave_delay_timestamp is elapsed or not
2403 if ( !timestamp_elapsed(wingp->wave_delay_timestamp) )
2407 // finally we can create the wing.
2409 num_create_save = num_to_create;
2411 wingnum = wingp - Wings; // get the wing number
2413 // if there are no ships to create, then all ships must be player start ships -- do nothing in this case.
2414 if ( num_to_create == 0 ){
2418 wingp->current_wave++; // we are creating new ships
2419 // we need to create num_to_create ships. Since the arrival cues for ships in a wing
2420 // are ignored, then *all* ships must be in the ship_arrival_list.
2423 objp = GET_FIRST(&ship_arrival_list);
2424 while( objp != END_OF_LIST(&ship_arrival_list) ) {
2425 p_object *temp = GET_NEXT(objp);
2427 // compare the wingnums. When they are equal, we can create the ship. In the case of
2428 // wings that have multiple waves, this code implies that we essentially creating clones
2429 // of the ships that were created in Fred for the wing when more ships for a new wave
2430 // arrive. The threshold value of a wing can also make one of the ships in a wing be "cloned"
2431 // more often than other ships in the wing. I don't think this matters much.
2432 if ( objp->wingnum == wingnum ) {
2435 // when ingame joining, we need to create a specific ship out of the list of ships for a
2436 // wing. specific_instance is a 0 based integer which specified which ship in the wing
2437 // to create. So, only create the ship we actually need to.
2438 if ( (Game_mode & GM_MULTIPLAYER) && (specific_instance > 0) ) {
2439 specific_instance--;
2444 SDL_assert ( !(objp->flags & P_SF_CANNOT_ARRIVE) ); // get allender
2448 // if we have the maximum number of ships in the wing, we must bail as well
2449 if ( wingp->current_count >= MAX_SHIPS_PER_WING ) {
2450 Int3(); // this is bogus -- we should always allow all ships to be created
2455 // bash the ship name to be the name of the wing + sone number if there is > 1 wave in
2457 // also, if multplayer, set the parse object's net signature to be wing's net signature
2458 // base + total_arrived_count (before adding 1)
2459 if ( Game_mode & GM_MULTIPLAYER ){
2460 objp->net_signature = (ushort)(wingp->net_signature + wingp->total_arrived_count);
2463 wingp->total_arrived_count++;
2464 if ( wingp->num_waves > 1 ){
2465 SDL_snprintf(objp->name, sizeof(objp->name), NOX("%s %d"), wingp->name, wingp->total_arrived_count);
2468 objnum = parse_create_object(objp);
2469 aip = &Ai_info[Ships[Objects[objnum].instance].ai_index];
2471 // copy any goals from the wing to the newly created ship
2472 for (index = 0; index < MAX_AI_GOALS; index++) {
2473 if ( wingp->ai_goals[index].ai_mode != AI_GOAL_NONE ){
2474 ai_copy_mission_wing_goal( &wingp->ai_goals[index], aip );
2478 Ai_info[Ships[Objects[objnum].instance].ai_index].wing = wingnum;
2480 if ( wingp->flags & WF_NO_DYNAMIC ){
2481 aip->ai_flags |= AIF_NO_DYNAMIC;
2484 // update housekeeping variables
2485 wingp->ship_index[wingp->current_count] = Objects[objnum].instance;
2487 // set up wingman status index
2488 hud_wingman_status_set_index(wingp->ship_index[wingp->current_count]);
2490 objp->wing_status_wing_index = Ships[Objects[objnum].instance].wing_status_wing_index;
2491 objp->wing_status_wing_pos = Ships[Objects[objnum].instance].wing_status_wing_pos;
2493 wingp->current_count++;
2495 // keep any player ship on the parse object list -- used for respawns
2496 // 5/8/98 -- MWA -- don't remove ships from the list when you are ingame joining
2497 if ( !(objp->flags & P_OF_PLAYER_START) ) {
2498 if ( (Game_mode & GM_NORMAL) || !(Net_player->flags & NETINFO_FLAG_INGAME_JOIN) ) {
2499 if ( wingp->num_waves == wingp->current_wave ) { // only remove ship if one wave in wing
2500 list_remove( &ship_arrival_list, objp); // remove objp from the list
2501 if ( objp->ai_goals != -1 ){
2502 free_sexp2(objp->ai_goals); // free up sexp nodes for reuse
2508 // flag ship with SF_FROM_PLAYER_WING if a member of player starting wings
2509 if ( (Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM) ) {
2510 // but for team vs. team games, then just check the alpha and zeta wings
2511 if ( !(SDL_strcasecmp(Starting_wing_names[STARTING_WING_ALPHA], wingp->name)) || !(SDL_strcasecmp(Starting_wing_names[STARTING_WING_ZETA], wingp->name)) ) {
2512 Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
2515 for (int i = 0; i < MAX_STARTING_WINGS; i++ ) {
2516 if ( !SDL_strcasecmp(Starting_wing_names[i], wingp->name) ) {
2517 Ships[Objects[objnum].instance].flags |= SF_FROM_PLAYER_WING;
2522 // keep track of how many ships to create. Stop when we have done all that we are supposed
2525 if ( !num_to_create ){
2532 SDL_assert ( num_to_create == 0 ); // we should always have enough ships in the list!!!
2534 // possibly play some event driven music here. Send a network packet indicating the wing was
2535 // created. Only do this stuff if actually in the mission.
2536 if ( (objnum != -1) && (Game_mode & GM_IN_MISSION) ) { // if true, we have created at least one new ship.
2539 // see if this wing is a player starting wing, and if so, call the maybe_add_form_goal
2540 // function to possibly make the wing form on the player
2541 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
2542 if ( Starting_wings[i] == wingnum ){
2546 if ( i < MAX_STARTING_WINGS ){
2547 ai_maybe_add_form_goal( wingp );
2550 mission_log_add_entry( LOG_WING_ARRIVE, wingp->name, NULL, wingp->current_wave );
2551 ship_num = wingp->ship_index[0];
2553 if ( !(Ships[ship_num].flags & SF_NO_ARRIVAL_MUSIC) && !(wingp->flags & WF_NO_ARRIVAL_MUSIC) ) {
2554 if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
2555 Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
2556 event_music_arrival(Ships[ship_num].team);
2560 // possibly change the location where these ships arrive based on the wings arrival location
2561 mission_set_wing_arrival_location( wingp, num_create_save );
2563 // if in multiplayer (and I am the host) and in the mission, send a wing create command to all
2565 if ( MULTIPLAYER_MASTER ){
2566 send_wing_create_packet( wingp, num_create_save, pre_create_count );
2570 // test code to check to be sure that all ships in the wing are ignoring the same types
2571 // of orders from the player
2572 if ( Fred_running ) {
2573 SDL_assert( wingp->ship_index[0] != -1 );
2574 int orders = Ships[wingp->ship_index[0]].orders_accepted;
2575 for (i = 1; i < wingp->current_count; i++ ) {
2576 if ( orders != Ships[wingp->ship_index[i]].orders_accepted ) {
2577 Warning(LOCATION, "ships in wing %s are ignoring different player orders. Please find Mark A\nto talk to him about this.", wingp->name );
2586 wingp->wave_delay_timestamp = timestamp(-1); // we will need to set this up properly for the next wave
2587 return num_create_save;
2590 void parse_wing(mission *pm)
2592 int wingnum, i, wing_goals, delay;
2593 char name[NAME_LENGTH], ship_names[MAX_SHIPS_PER_WING][NAME_LENGTH];
2594 char wing_flag_strings[MAX_WING_FLAGS][NAME_LENGTH];
2597 SDL_assert(pm != NULL);
2598 wingp = &Wings[num_wings];
2600 required_string("$Name:");
2601 stuff_string(wingp->name, F_NAME, NULL);
2602 wingnum = find_wing_name(wingp->name);
2604 error_display(0, NOX("Redundant wing name: %s\n"), wingp->name);
2605 wingnum = num_wings;
2607 wingp->total_arrived_count = 0;
2608 wingp->total_destroyed = 0;
2611 required_string("$Waves:");
2612 stuff_int(&wingp->num_waves);
2613 SDL_assert ( wingp->num_waves >= 1 ); // there must be at least 1 wave
2615 wingp->current_wave = 0;
2617 required_string("$Wave Threshold:");
2618 stuff_int(&wingp->threshold);
2620 required_string("$Special Ship:");
2621 stuff_int(&wingp->special_ship);
2623 wingp->arrival_anchor = -1;
2624 find_and_stuff("$Arrival Location:", &wingp->arrival_location, F_NAME, Arrival_location_names, Num_arrival_names, "Arrival Location");
2625 if ( optional_string("+Arrival Distance:") ) {
2626 stuff_int( &wingp->arrival_distance );
2627 if ( wingp->arrival_location != ARRIVE_AT_LOCATION ) {
2628 required_string("$Arrival Anchor:");
2629 stuff_string(name, F_NAME, NULL);
2630 wingp->arrival_anchor = get_anchor(name);
2634 if (optional_string("+Arrival delay:")) {
2637 Error(LOCATION, "Cannot have arrival delay < 0 on wing %s", wingp->name );
2641 if ( !Fred_running ){
2642 wingp->arrival_delay = -delay;
2644 wingp->arrival_delay = delay;
2647 required_string("$Arrival Cue:");
2648 wingp->arrival_cue = get_sexp_main();
2649 if ( !Fred_running && (wingp->arrival_cue >= 0) ) {
2650 if ( eval_sexp(wingp->arrival_cue) ) // evaluate to determine if sexp is always false.
2651 wingp->arrival_delay = timestamp( -wingp->arrival_delay * 1000 );
2655 find_and_stuff("$Departure Location:", &wingp->departure_location, F_NAME, Departure_location_names, Num_arrival_names, "Departure Location");
2656 wingp->departure_anchor = -1;
2657 if ( wingp->departure_location == DEPART_AT_DOCK_BAY ) {
2658 required_string("$Departure Anchor:");
2659 stuff_string( name, F_NAME, NULL );
2660 wingp->departure_anchor = get_anchor(name);
2663 if (optional_string("+Departure delay:")) {
2666 Error(LOCATION, "Cannot have departure delay < 0 on wing %s", wingp->name );
2671 if ( !Fred_running )
2672 wingp->departure_delay = -delay; // use negative numbers to mean that delay timer not yet set
2674 wingp->departure_delay = delay;
2676 required_string("$Departure Cue:");
2677 wingp->departure_cue = get_sexp_main();
2679 // stores a list of all names of ships in the wing
2680 required_string("$Ships:");
2681 wingp->wave_count = stuff_string_list( ship_names, MAX_SHIPS_PER_WING );
2682 wingp->current_count = 0;
2684 // get the wings goals, if any
2686 if ( optional_string("$AI Goals:") )
2687 wing_goals = get_sexp_main();
2690 if (optional_string("+Hotkey:")) {
2691 stuff_int(&wingp->hotkey);
2692 SDL_assert((wingp->hotkey >= 0) && (wingp->hotkey < 10));
2695 if (optional_string("+Flags:")) {
2698 count = stuff_string_list( wing_flag_strings, MAX_WING_FLAGS );
2699 for (i = 0; i < count; i++ ) {
2700 if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("ignore-count")) )
2701 wingp->flags |= WF_IGNORE_COUNT;
2702 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("reinforcement")) )
2703 wingp->flags |= WF_REINFORCEMENT;
2704 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-music")) )
2705 wingp->flags |= WF_NO_ARRIVAL_MUSIC;
2706 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-message")) )
2707 wingp->flags |= WF_NO_ARRIVAL_MESSAGE;
2708 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-arrival-warp")) )
2709 wingp->flags |= WF_NO_ARRIVAL_WARP;
2710 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-departure-warp")) )
2711 wingp->flags |= WF_NO_DEPARTURE_WARP;
2712 else if ( !SDL_strcasecmp( wing_flag_strings[i], NOX("no-dynamic")) )
2713 wingp->flags |= WF_NO_DYNAMIC;
2715 Warning(LOCATION, "unknown wing flag\n%s\n\nSkipping.", wing_flag_strings[i]);
2719 // get the wave arrival delay bounds (if present). Used as lower and upper bounds (in seconds)
2720 // which determine when new waves of a wing should arrive.
2721 wingp->wave_delay_min = 0;
2722 wingp->wave_delay_max = 0;
2723 if ( optional_string("+Wave Delay Min:") )
2724 stuff_int( &(wingp->wave_delay_min) );
2725 if ( optional_string("+Wave Delay Max:") )
2726 stuff_int( &(wingp->wave_delay_max) );
2728 // be sure to set the wave arrival timestamp of this wing to pop right away so that the
2729 // wing could be created if it needs to be
2730 wingp->wave_delay_timestamp = timestamp(0);
2732 // initialize wing goals
2733 for (i=0; i<MAX_AI_GOALS; i++) {
2734 wingp->ai_goals[i].ai_mode = AI_GOAL_NONE;
2735 wingp->ai_goals[i].priority = -1;
2739 // error checking against the player ship wings to be sure that wave count doesn't exceed one for
2741 if ( Game_mode & GM_MULTIPLAYER ) {
2742 for (i = 0; i < MAX_STARTING_WINGS+1; i++ ) {
2743 if ( !SDL_strcasecmp(Starting_wing_names[i], wingp->name) ) {
2744 if ( wingp->num_waves > 1 ) {
2745 // only end the game if we're the server - clients will eventually find out :)
2746 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2747 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_WAVE_COUNT);
2749 // Error(LOCATION, "Player wings Alpha, Beta, Gamma, or Zeta cannot have more than 1 wave.");
2755 // Get the next starting signature for this in this wing. We want to reserve wave_count * num_waves
2756 // of signature. These can be used to construct wings for ingame joiners.
2757 if ( Game_mode & GM_MULTIPLAYER ) {
2760 wingp->net_signature = multi_assign_network_signature( MULTI_SIG_SHIP );
2761 next_signature = wingp->net_signature + (wingp->wave_count * wingp->num_waves);
2762 if ( next_signature > SHIP_SIG_MAX )
2763 Error(LOCATION, "Too many total ships in mission (%d) for network signature assignment", SHIP_SIG_MAX);
2764 multi_set_network_signature( (ushort)next_signature, MULTI_SIG_SHIP );
2767 for (i=0; i<MAX_SHIPS_PER_WING; i++)
2768 wingp->ship_index[i] = -1;
2770 // set up the ai_goals for this wing -- all ships created from this wing will inherit these goals
2771 // goals for the wing are stored slightly differently than for ships. We simply store the index
2772 // into the sexpression array of each goal (max 10). When a ship in this wing is created, each
2773 // goal in the wings goal array is given to the ship.
2774 if ( wing_goals != -1 ) {
2777 // this will assign the goals to the wings as well as to any ships in the wing that have been
2779 for ( sexp = CDR(wing_goals); sexp != -1; sexp = CDR(sexp) )
2780 ai_add_wing_goal_sexp(sexp, AIG_TYPE_EVENT_WING, wingnum); // used by Fred
2783 free_sexp2(wing_goals); // free up sexp nodes for reused, since they aren't needed anymore.
2786 // set the wing number for all ships in the wing
2787 for (i = 0; i < wingp->wave_count; i++ ) {
2788 //char *ship_name = wingp->ship_names[i];
2790 int num, assigned = 0;
2793 ship_name = ship_names[i];
2795 num = wingp->ship_index[i] = ship_name_lookup(ship_name, 1);
2796 SDL_assert ( num != -1 );
2798 // hack code -- REMOVE
2799 if ( Objects[Ships[num].objnum].flags & OF_PLAYER_SHIP )
2800 Ships[num].wingnum = wingnum;
2803 // determine if this ship is a player ship, and deal with it appropriately.
2804 if ( !SDL_strncasecmp(ship_name, NOX("Player "), 7) ) {
2805 Error(LOCATION, "Old mission file -- please convert by loading/saving in Fred -- see Allender/Hoffoss for help.");
2808 // assign the wing number to the ship -- if the ship has arrived, doulble check that
2809 // there is only one wave of this wing since ships with their own arrival cue cannot be
2810 // in a wing with > 1 wave. Otherwise, find the ship on the ship arrival list and set
2811 // their wing number
2812 if ( (num = ship_name_lookup(ship_name)) != -1 ) {
2813 Int3(); // this is impossible under the new system
2816 objp = GET_FIRST(&ship_arrival_list);
2817 while( objp != END_OF_LIST(&ship_arrival_list) ) {
2818 if ( !strcmp(ship_name, objp->name) ) {
2819 SDL_assert ( objp->wingnum == -1 ); // get Allender -- ship appears to be in multiple wings
2820 objp->wingnum = wingnum;
2823 objp = GET_NEXT(objp);
2827 if ( !assigned || (assigned > 1) )
2828 Error(LOCATION, "Cannot load mission -- wing %s -- ship %s not present in #Objects section (or specified multiple times in wing.\n", wingp->name, ship_name);
2832 // Fred doesn't create the wing. otherwise, create the wing if is isn't a reinforcement.
2833 if ( !Fred_running && !(wingp->flags & WF_REINFORCEMENT) )
2834 parse_wing_create_ships( wingp, wingp->wave_count );
2837 void parse_wings(mission *pm)
2839 required_string("#Wings");
2840 while (required_string_either("#Events", "$Name:")) {
2841 SDL_assert(num_wings < MAX_WINGS);
2847 // mission events are sexpressions which cause things to happen based on the outcome
2848 // of other events in a mission. Essentially scripting the different things that can happen
2851 void parse_event(mission *pm)
2854 mission_event *event;
2856 event = &Mission_events[Num_mission_events];
2857 event->chain_delay = -1;
2859 required_string( "$Formula:" );
2860 event->formula = get_sexp_main();
2862 if (optional_string("+Name:")){
2863 stuff_string(event->name, F_NAME, NULL);
2868 if ( optional_string("+Repeat Count:")){
2869 stuff_int( &(event->repeat_count) );
2871 event->repeat_count = 1;
2874 event->interval = -1;
2875 if ( optional_string("+Interval:")){
2876 stuff_int( &(event->interval) );
2880 if ( optional_string("+Score:") ){
2881 stuff_int(&event->score);
2884 if ( optional_string("+Chained:") ){
2885 stuff_int(&event->chain_delay);
2888 if ( optional_string("+Objective:") ) {
2889 stuff_string(buf, F_NAME, NULL);
2890 event->objective_text = strdup(buf);
2892 event->objective_text = NULL;
2895 if ( optional_string("+Objective key:") ) {
2896 stuff_string(buf, F_NAME, NULL);
2897 event->objective_key_text = strdup(buf);
2899 event->objective_key_text = NULL;
2903 if( optional_string("+Team:") ) {
2904 stuff_int(&event->team);
2907 event->timestamp = timestamp(-1);
2909 // sanity check on the repeat count variable
2910 if ( event->repeat_count <= 0 ){
2911 Error (LOCATION, "Repeat count for mission event %s is <=0.\nMust be >= 1!", event->name );
2915 void parse_events(mission *pm)
2917 required_string("#Events");
2919 while (required_string_either( "#Goals", "$Formula:")) {
2920 SDL_assert( Num_mission_events < MAX_MISSION_EVENTS );
2922 Num_mission_events++;
2926 void parse_goal(mission *pm)
2930 mission_goal *goalp;
2932 goalp = &Mission_goals[Num_goals++];
2934 SDL_assert(Num_goals < MAX_GOALS);
2935 SDL_assert(pm != NULL);
2937 find_and_stuff("$Type:", &goalp->type, F_NAME, Goal_type_names, Num_goal_type_names, "goal type");
2939 required_string("+Name:");
2940 stuff_string(goalp->name, F_NAME, NULL);
2942 // backwards compatibility for old Fred missions - all new missions should use $MessageNew
2943 if(optional_string("$Message:")){
2944 stuff_string(goalp->message, F_NAME, NULL, MAX_GOAL_TEXT);
2946 required_string("$MessageNew:");
2947 stuff_string(goalp->message, F_MULTITEXT, NULL, MAX_GOAL_TEXT);
2950 if (optional_string("$Rating:")){
2951 stuff_int(&dummy); // not used
2954 required_string("$Formula:");
2955 goalp->formula = get_sexp_main();
2958 if ( optional_string("+Invalid:") )
2959 goalp->type |= INVALID_GOAL;
2960 if ( optional_string("+Invalid") )
2961 goalp->type |= INVALID_GOAL;
2962 if ( optional_string("+No music") )
2963 goalp->flags |= MGF_NO_MUSIC;
2966 if ( optional_string("+Score:") ){
2967 stuff_int(&goalp->score);
2971 if ( optional_string("+Team:") ){
2972 stuff_int( &goalp->team );
2976 void parse_goals(mission *pm)
2978 required_string("#Goals");
2980 while (required_string_either("#Waypoints", "$Type:")){
2985 void parse_waypoint_list(mission *pm)
2990 SDL_assert(Num_waypoint_lists < MAX_WAYPOINT_LISTS);
2991 SDL_assert(pm != NULL);
2992 wpl = &Waypoint_lists[Num_waypoint_lists];
2994 required_string("$Name:");
2995 stuff_string(wpl->name, F_NAME, NULL);
2997 required_string("$List:");
2998 wpl->count = stuff_vector_list(wpl->waypoints, MAX_WAYPOINTS_PER_LIST);
3001 // AAAAHH! I don't like to hard code a mission fix but I have no clue what to do
3002 // to fix this properly. In the FS1 mission "Playing Judas" you have to try and fly
3003 // into one of the docking bays on the Lucifer. Due to some change in the code the
3004 // waypoints and the Lucifer's position don't match up so we have to change the
3005 // waypoint position to compensate.
3006 if ( !SDL_strcasecmp(pm->name, "Playing Judas") ) {
3007 if ( !SDL_strcasecmp(wpl->name, "Docking Bay 1") ) {
3008 wpl->waypoints[0].xyz.x = -1262.550903;
3009 wpl->waypoints[0].xyz.y = 27.676950;
3010 wpl->waypoints[0].xyz.z = 4461.702930;
3011 } else if ( !SDL_strcasecmp(wpl->name, "Docking Bat 2") ) { // it really is spelled "Bat" in the mission
3012 wpl->waypoints[0].xyz.x = -1105.347976;
3013 wpl->waypoints[0].xyz.y = 27.676950;
3014 wpl->waypoints[0].xyz.z = 3900.236867;
3019 Num_waypoint_lists++;
3022 void parse_waypoints(mission *pm)
3027 required_string("#Waypoints");
3030 while (optional_string("$Jump Node:")) {
3031 SDL_assert(Num_jump_nodes < MAX_JUMP_NODES);
3033 z = jumpnode_create(&pos);
3036 if (optional_string("$Jump Node Name:")) {
3037 stuff_string(Jump_nodes[Num_jump_nodes - 1].name, F_NAME, NULL);
3040 // If no name exists, then use a standard name
3041 if ( Jump_nodes[Num_jump_nodes - 1].name[0] == 0 ) {
3042 SDL_snprintf(Jump_nodes[Num_jump_nodes - 1].name, NAME_LENGTH, "Jump Node %d", Num_jump_nodes);
3046 while (required_string_either("#Messages", "$Name:"))
3047 parse_waypoint_list(pm);
3050 void parse_messages(mission *pm)
3052 required_string("#Messages");
3054 mprintf(("Starting mission message count : %d\n", Num_message_waves));
3056 // the message_parse function can be found in MissionMessage.h. The format in the
3057 // mission file takes the same format as the messages in messages,tbl. Make parsing
3058 // a whole lot easier!!!
3059 while ( required_string_either("#Reinforcements", "$Name")){
3060 message_parse(); // call the message parsing system
3063 mprintf(("Ending mission message count : %d\n", Num_message_waves));
3066 void parse_reinforcement(mission *pm)
3068 reinforcements *ptr;
3071 SDL_assert(Num_reinforcements < MAX_REINFORCEMENTS);
3072 SDL_assert(pm != NULL);
3073 ptr = &Reinforcements[Num_reinforcements];
3075 required_string("$Name:");
3076 stuff_string(ptr->name, F_NAME, NULL);
3078 find_and_stuff("$Type:", &ptr->type, F_NAME, Reinforcement_type_names, Num_reinforcement_type_names, "reinforcement type");
3080 required_string("$Num times:");
3081 stuff_int(&ptr->uses);
3084 // reset the flags to 0
3087 if ( optional_string("+Arrival delay:") ){
3088 stuff_int( &(ptr->arrival_delay) );
3091 if ( optional_string("+No Messages:") ){
3092 stuff_string_list( ptr->no_messages, MAX_REINFORCEMENT_MESSAGES );
3095 if ( optional_string("+Yes Messages:") ){
3096 stuff_string_list( ptr->yes_messages, MAX_REINFORCEMENT_MESSAGES );
3099 // sanity check on the names of reinforcements -- must either be wings/ships/arrival list.
3100 if ( ship_name_lookup(ptr->name) == -1 ) {
3101 if ( wing_name_lookup(ptr->name, 1) == -1 ) {
3104 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3105 if ( !SDL_strcasecmp(ptr->name, p_objp->name) ){
3110 if ( p_objp == END_OF_LIST(&ship_arrival_list) ) {
3111 Warning(LOCATION, "Reinforcement %s not found as ship or wing", ptr->name);
3117 // now, if the reinforcement is a wing, then set the number of waves of the wing == number of
3118 // uses of the reinforcement
3119 instance = wing_name_lookup(ptr->name, 1);
3120 if ( instance != -1 )
3121 Wings[instance].num_waves = ptr->uses;
3123 Num_reinforcements++;
3126 void parse_reinforcements(mission *pm)
3128 Num_reinforcements = 0;
3129 required_string("#Reinforcements");
3131 while (required_string_either("#Background bitmaps", "$Name:"))
3132 parse_reinforcement(pm);
3135 void parse_bitmap(mission *pm)
3138 starfield_bitmap_instance b;
3142 SDL_assert(pm != NULL);
3144 while(optional_string("$Bitmap:")) {
3145 stuff_string(b.filename, F_NAME, NULL);
3147 required_string("$Orientation:");
3150 required_string("$Rotation rate:");
3151 stuff_float(&b.rot);
3153 required_string("$Distance:");
3154 stuff_float(&b.scale_x);
3155 b.scale_y = b.scale_x;
3159 required_string("$Light:");
3160 stuff_int(&b.sun_light);
3162 if(Num_suns < MAX_STARFIELD_BITMAPS){
3164 SDL_strlcpy(Suns[Num_suns].filename, b.filename, sizeof(b.filename));
3170 char name[NAME_LENGTH];
3172 starfield_bitmaps *ptr;
3174 SDL_assert(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS);
3175 SDL_assert(pm != NULL);
3176 ptr = &Starfield_bitmaps[Num_starfield_bitmaps];
3178 required_string("$Bitmap:");
3179 stuff_string(name, F_NAME, NULL);
3180 for (z=0; z<Num_starfield_bitmap_lists; z++) {
3181 if (!SDL_strcasecmp(name, Starfield_bitmap_list[z].name)){
3186 if ( z >= Num_starfield_bitmap_lists ) {
3187 Warning( LOCATION, "Bitmap specified in mission not in game!\n" );
3191 ptr->bitmap_index = z;
3192 required_string("$Orientation:");
3193 stuff_matrix(&ptr->m);
3195 required_string("$Rotation rate:");
3196 stuff_float(&ptr->rot);
3198 required_string("$Distance:");
3199 stuff_float(&ptr->dist);
3201 required_string("$Light:");
3202 stuff_int(&ptr->light);
3203 Num_starfield_bitmaps++;
3204 calculate_bitmap_points(ptr);
3210 void parse_bitmaps(mission *pm)
3212 char str[MAX_FILENAME_LEN+1] = "";
3213 starfield_bitmap_instance b;
3216 Num_starfield_bitmaps = 0;
3217 required_string("#Background bitmaps");
3219 required_string("$Num stars:");
3220 stuff_int(&Num_stars);
3221 if (Num_stars >= MAX_STARS)
3222 Num_stars = MAX_STARS;
3224 int Ambient_light_level;
3225 required_string("$Ambient light level:");
3226 stuff_int(&Ambient_light_level);
3228 // This should call light_set_ambient() to
3229 // set the ambient light
3232 Mission_palette = 1;
3234 if(The_mission.flags & MISSION_FLAG_FULLNEB){
3235 // no regular nebula stuff
3239 SDL_strlcpy(Neb2_texture_name, "Eraseme3", sizeof(Neb2_texture_name));
3240 Neb2_poof_flags = ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5));
3241 if(optional_string("+Neb2:")){
3242 stuff_string(Neb2_texture_name, F_NAME, NULL);
3244 required_string("+Neb2Flags:");
3245 stuff_int(&Neb2_poof_flags);
3247 // initialize neb effect. its gross to do this here, but Fred is dumb so I have no choice ... :(
3253 if (optional_string("+Nebula:")) {
3254 stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3256 // parse the proper nebula type (full or not)
3257 for (z=0; z<NUM_NEBULAS; z++){
3258 if(The_mission.flags & MISSION_FLAG_FULLNEB){
3259 if (!SDL_strcasecmp(str, Neb2_filenames[z])) {
3264 if (!SDL_strcasecmp(str, Nebula_filenames[z])) {
3271 if (optional_string("+Color:")) {
3272 stuff_string(str, F_NAME, NULL, MAX_FILENAME_LEN);
3273 for (z=0; z<NUM_NEBULA_COLORS; z++){
3274 if (!SDL_strcasecmp(str, Nebula_colors[z])) {
3275 Mission_palette = z;
3281 if (optional_string("+Pitch:")){
3282 stuff_int(&Nebula_pitch);
3287 if (optional_string("+Bank:")){
3288 stuff_int(&Nebula_bank);
3293 if (optional_string("+Heading:")){
3294 stuff_int(&Nebula_heading);
3300 if (Nebula_index >= 0){
3301 nebula_init(Nebula_filenames[Nebula_index], Nebula_pitch, Nebula_bank, Nebula_heading);
3309 while(optional_string("$Sun:")){
3311 stuff_string(b.filename, F_NAME, NULL);
3314 required_string("+Angles:");
3315 stuff_float(&b.ang.p);
3316 stuff_float(&b.ang.b);
3317 stuff_float(&b.ang.h);
3320 required_string("+Scale:");
3321 stuff_float(&b.scale_x);
3322 b.scale_y = b.scale_x;
3326 // if we have room, store it
3327 if(Num_suns < MAX_STARFIELD_BITMAPS){
3329 SDL_strlcpy(Suns[Num_suns].filename, b.filename, sizeof(b.filename));
3334 // parse background bitmaps
3335 Num_starfield_bitmaps = 0;
3336 while(optional_string("$Starbitmap:")){
3338 stuff_string(b.filename, F_NAME, NULL);
3341 required_string("+Angles:");
3342 stuff_float(&b.ang.p);
3343 stuff_float(&b.ang.b);
3344 stuff_float(&b.ang.h);
3348 if(optional_string("+Scale:")){
3349 stuff_float(&b.scale_x);
3350 b.scale_y = b.scale_x;
3354 required_string("+ScaleX:");
3355 stuff_float(&b.scale_x);
3357 required_string("+ScaleY:");
3358 stuff_float(&b.scale_y);
3360 required_string("+DivX:");
3361 stuff_int(&b.div_x);
3363 required_string("+DivY:");
3364 stuff_int(&b.div_y);
3367 // if we have room, store it
3368 if(Num_starfield_bitmaps < MAX_STARFIELD_BITMAPS){
3369 Starfield_bitmap_instance[Num_starfield_bitmaps] = b;
3370 SDL_strlcpy(Starfield_bitmap_instance[Num_starfield_bitmaps].filename, b.filename, sizeof(b.filename));
3371 Num_starfield_bitmaps++;
3379 if ( optional_string("#Asteroid Fields") ){
3380 parse_asteroid_fields(pm);
3384 void parse_asteroid_fields(mission *pm)
3386 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
3388 int i, count, subtype;
3390 SDL_assert(pm != NULL);
3391 for (i=0; i<MAX_ASTEROID_FIELDS; i++)
3392 Asteroid_field.num_initial_asteroids = 0;
3396 // required_string("#Asteroid Fields");
3398 while (required_string_either("#", "$Density:")) {
3400 while (required_string_either("#", "$density:")) {
3402 float speed, density;
3405 required_string("$Density:");
3406 stuff_float(&density);
3408 Asteroid_field.num_initial_asteroids = (int) density;
3410 Asteroid_field.field_type = FT_ACTIVE;
3411 if (optional_string("+Field Type:")) {
3412 stuff_int((int*)&Asteroid_field.field_type);
3415 Asteroid_field.debris_genre = DG_ASTEROID;
3416 if (optional_string("+Debris Genre:")) {
3417 stuff_int((int*)&Asteroid_field.debris_genre);
3420 Asteroid_field.field_debris_type[0] = -1;
3421 Asteroid_field.field_debris_type[1] = -1;
3422 Asteroid_field.field_debris_type[2] = -1;
3423 if (Asteroid_field.debris_genre == DG_SHIP) {
3424 if (optional_string("+Field Debris Type:")) {
3425 stuff_int(&Asteroid_field.field_debris_type[0]);
3427 if (optional_string("+Field Debris Type:")) {
3428 stuff_int(&Asteroid_field.field_debris_type[1]);
3430 if (optional_string("+Field Debris Type:")) {
3431 stuff_int(&Asteroid_field.field_debris_type[2]);
3435 if (optional_string("+Field Debris Type:")) {
3436 stuff_int(&subtype);
3437 Asteroid_field.field_debris_type[subtype] = 1;
3440 if (optional_string("+Field Debris Type:")) {
3441 stuff_int(&subtype);
3442 Asteroid_field.field_debris_type[subtype] = 1;
3445 if (optional_string("+Field Debris Type:")) {
3446 stuff_int(&subtype);
3447 Asteroid_field.field_debris_type[subtype] = 1;
3452 // backward compatibility
3453 if ( (Asteroid_field.debris_genre == DG_ASTEROID) && (count == 0) ) {
3454 Asteroid_field.field_debris_type[0] = 0;
3457 required_string("$Average Speed:");
3458 stuff_float(&speed);
3460 vm_vec_rand_vec_quick(&Asteroid_field.vel);
3461 vm_vec_scale(&Asteroid_field.vel, speed);
3463 Asteroid_field.speed = speed;
3465 required_string("$Minimum:");
3466 stuff_vector(&Asteroid_field.min_bound);
3468 required_string("$Maximum:");
3469 stuff_vector(&Asteroid_field.max_bound);
3471 if (optional_string("+Inner Bound:")) {
3472 Asteroid_field.has_inner_bound = 1;
3474 required_string("$Minimum:");
3475 stuff_vector(&Asteroid_field.inner_min_bound);
3477 required_string("$Maximum:");
3478 stuff_vector(&Asteroid_field.inner_max_bound);
3480 Asteroid_field.has_inner_bound = 0;
3487 void parse_variables()
3489 if (! optional_string("#Sexp_variables") ) {
3492 stuff_sexp_variable_list();
3497 void parse_mission(mission *pm, int flag)
3501 Player_starts = Num_cargo = Num_waypoint_lists = Num_goals = num_wings = num_ship_arrivals = 0;
3502 Player_start_shipnum = -1;
3503 *Player_start_shipname = 0; // make the string 0 length for checking later
3504 memset( &Player_start_pobject, 0, sizeof(Player_start_pobject) );
3506 // initialize the initially_docked array.
3507 for ( i = 0; i < MAX_SHIPS; i++ ) {
3508 Initially_docked[i].docker = NULL;
3509 Initially_docked[i].dockee[0] = '\0';
3510 Initially_docked[i].docker_point[0] = '\0';
3511 Initially_docked[i].dockee_point[0] = '\0';
3513 Total_initially_docked = 0;
3515 list_init( &ship_arrival_list ); // init lists for arrival objects and wings
3520 parse_mission_info(pm);
3521 Current_file_checksum = netmisc_calc_checksum(pm,MISSION_CHECKSUM_SIZE);
3522 if ( flag == MISSION_PARSE_MISSION_INFO )
3524 parse_plot_info(pm);
3526 parse_briefing_info(pm); // TODO: obsolete code, keeping so we don't obsolete existing mission files
3527 parse_cmd_briefs(pm);
3529 parse_debriefing_new(pm);
3530 parse_player_info(pm);
3531 parse_objects(pm, flag);
3535 parse_waypoints(pm);
3537 parse_reinforcements(pm);
3541 post_process_mission();
3544 void post_process_mission()
3547 int indices[MAX_SHIPS], objnum;
3552 // the player_start_shipname had better exist at this point!
3553 Player_start_shipnum = ship_name_lookup( Player_start_shipname );
3554 SDL_assert ( Player_start_shipnum != -1 );
3555 SDL_assert ( Player_start_pobject.flags & P_SF_PLAYER_START_VALID );
3557 // Assign objnum, shipnum, etc. to the player structure
3558 objnum = Ships[Player_start_shipnum].objnum;
3559 Player_obj = &Objects[objnum];
3561 Player->objnum = objnum;
3564 Player_obj->flags |= OF_PLAYER_SHIP; // make this object a player controlled ship.
3565 Player_ship = &Ships[Player_start_shipnum];
3566 Player_ai = &Ai_info[Player_ship->ai_index];
3568 Player_ai->targeted_subsys = NULL;
3569 Player_ai->targeted_subsys_parent = -1;
3571 // determine if player start has initial velocity and set forward cruise percent to relect this
3572 if ( Player_obj->phys_info.vel.xyz.z > 0.0f )
3573 Player->ci.forward_cruise_percent = Player_obj->phys_info.vel.xyz.z / Player_ship->current_max_speed * 100.0f;
3575 // put in hard coded starting wing names.
3576 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
3577 Starting_wings[0] = wing_name_lookup(Starting_wing_names[0],1);
3578 Starting_wings[1] = wing_name_lookup(Starting_wing_names[MAX_STARTING_WINGS],1);
3580 for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
3581 Starting_wings[i] = wing_name_lookup(Starting_wing_names[i], 1);
3587 // call a function to deal with intially docked ships
3588 mission_parse_do_initial_docks();
3590 // deal with setting up arrival location for all ships. Must do this now after all ships are created
3591 mission_parse_set_arrival_locations();
3593 // clear out information about arriving support ships
3594 Arriving_support_ship = NULL;
3595 Num_arriving_repair_targets = 0;
3597 // convert all ship name indices to ship indices now that mission has been loaded
3599 for (i=0; i<Num_parse_names; i++) {
3600 indices[i] = ship_name_lookup(Parse_names[i], 1);
3602 Warning(LOCATION, "Ship name \"%s\" referenced, but this ship doesn't exist", Parse_names[i]);
3605 for (i=0; i<MAX_SHIPS; i++) {
3606 if ((Ships[i].objnum >= 0) && (Ships[i].arrival_anchor >= 0) && (Ships[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3607 Ships[i].arrival_anchor = indices[Ships[i].arrival_anchor];
3609 if ( (Ships[i].objnum >= 0) && (Ships[i].departure_anchor >= 0) )
3610 Ships[i].departure_anchor = indices[Ships[i].departure_anchor];
3613 for (i=0; i<MAX_WINGS; i++) {
3614 if (Wings[i].wave_count && (Wings[i].arrival_anchor >= 0) && (Wings[i].arrival_anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET))
3615 Wings[i].arrival_anchor = indices[Wings[i].arrival_anchor];
3617 if (Wings[i].wave_count && (Wings[i].departure_anchor >= 0) )
3618 Wings[i].departure_anchor = indices[Wings[i].departure_anchor];
3623 // before doing anything else, we must validate all of the sexpressions that were loaded into the mission.
3624 // Loop through the Sexp_nodes array and send the top level functions to the check_sexp_syntax parser
3626 for (i = 0; i < MAX_SEXP_NODES; i++) {
3627 if ( is_sexp_top_level(i) && (!Fred_running || (i != Sexp_clipboard))) {
3628 int result, bindex, op;
3630 op = identify_operator(CTEXT(i));
3631 SDL_assert(op != -1); // need to make sure it is an operator before we treat it like one..
3632 result = check_sexp_syntax( i, query_operator_return_type(op), 1, &bindex);
3634 // entering this if statement will result in program termination!!!!!
3635 // print out an error based on the return value from check_sexp_syntax()
3637 char sexp_str[8192], text[8192];
3639 convert_sexp_to_string( i, sexp_str, sizeof(sexp_str), SEXP_ERROR_CHECK_MODE);
3640 SDL_snprintf(text, sizeof(text), "%s.\n\nIn sexpression: %s\n(Error appears to be: %s)",
3641 sexp_error_message(result), sexp_str, Sexp_nodes[bindex].text);
3644 Error( LOCATION, text );
3646 Warning( LOCATION, text );
3651 ai_post_process_mission();
3655 for (i=0; i<Total_initially_docked; i++) {
3656 z = ship_name_lookup(Initially_docked[i].dockee);
3658 SDL_assert(Initially_docked[i].docker->type == OBJ_SHIP);
3659 p1 = model_find_dock_name_index(Ships[Initially_docked[i].docker->instance].modelnum,
3660 Initially_docked[i].docker_point);
3661 SDL_assert(Objects[z].type == OBJ_SHIP);
3662 p2 = model_find_dock_name_index(Ships[Objects[z].instance].modelnum,
3663 Initially_docked[i].dockee_point);
3665 if ((p1 >= 0) && (p2 >= 0)) {
3666 nprintf(("AI", "Initially Docked: %s with %s\n", Ships[Initially_docked[i].docker->instance].ship_name, Ships[Objects[z].instance].ship_name));
3667 if (ship_docking_valid(Initially_docked[i].docker->instance, Objects[z].instance)) // only dock if they are allowed to be docked.
3668 ai_dock_with_object(Initially_docked[i].docker, &Objects[z], 89, AIDO_DOCK_NOW, p1, p2);
3671 Int3(); // Curious. Two ships told to dock, but one of the dock points is bogus.
3672 // Get Allender or Hoffoss, one of whom probably wrote the above if ()
3677 // we must also count all of the ships of particular types. We count all of the ships that do not have
3678 // their SF_IGNORE_COUNT flag set. We don't count ships in wings when the equivalent wing flag is set.
3679 // in counting ships in wings, we increment the count by the wing's wave count to account for everyone.
3680 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
3681 int siflags, num, shipnum;
3683 shipnum = Objects[so->objnum].instance;
3684 // pass over non-ship objects and player ship objects
3685 if ( Ships[shipnum].objnum == -1 || (Objects[Ships[shipnum].objnum].flags & OF_PLAYER_SHIP) )
3687 if ( Ships[shipnum].flags & SF_IGNORE_COUNT )
3689 if ( (Ships[shipnum].wingnum != -1) && (Wings[Ships[shipnum].wingnum].flags & WF_IGNORE_COUNT) )
3692 siflags = Ship_info[Ships[shipnum].ship_info_index].flags;
3694 // determine the number of times we need to add this ship into the count
3695 // if ( Ships[i].wingnum == -1 )
3698 // num = Wings[Ships[i].wingnum].num_waves;
3700 ship_add_ship_type_count( siflags, num );
3702 // now go through the list of ships yet to arrive
3703 for ( p_objp = GET_FIRST(&ship_arrival_list); p_objp != END_OF_LIST(&ship_arrival_list); p_objp = GET_NEXT(p_objp) ) {
3706 // go through similar motions as above
3707 if ( p_objp->flags & P_SF_IGNORE_COUNT )
3709 if ( (p_objp->wingnum != -1) && (Wings[p_objp->wingnum].flags & WF_IGNORE_COUNT) )
3712 siflags = Ship_info[p_objp->ship_class].flags;
3714 if ( p_objp->wingnum == -1 )
3717 num = Wings[p_objp->wingnum].num_waves - 1; // subtract one since we already counted the first wave
3719 ship_add_ship_type_count( siflags, num );
3722 // set player weapons that are selected by default
3723 // AL 09/17/97: I added this code to select the first primary/secondary weapons,
3724 // since I noticed the player ship sometimes doesn't get default weapons selected
3726 // DB: modified 4/23/98 to take multiplayer into account. Under certain circumstances, multiplayer netplayer ships
3727 // had their current_primary_bank and current_secondary_bank set to -1 (from ship_set()) and left there since
3728 // Player_ship is not the only one we need to need about.
3729 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
3730 ship *shipp = &Ships[Objects[so->objnum].instance];
3732 // don't process non player wing ships
3733 if ( !(shipp->flags & SF_FROM_PLAYER_WING ) )
3736 swp = &shipp->weapons;
3738 // swp = &Player_ship->weapons;
3739 if ( swp->num_primary_banks > 0 ) {
3740 swp->current_primary_bank = 0; // currently selected primary bank
3743 if ( swp->num_secondary_banks > 0 ) {
3744 swp->current_secondary_bank = 0; // currently selected secondary bank
3748 ets_init_ship(Player_obj); // init ETS data for the player
3750 // put the timestamp stuff here for now
3751 Mission_arrival_timestamp = timestamp( ARRIVAL_TIMESTAMP );
3752 Mission_departure_timestamp = timestamp( DEPARTURE_TIMESTAMP );
3753 Mission_end_time = -1;
3755 if(Game_mode & GM_MULTIPLAYER){
3756 multi_respawn_build_points();
3759 // maybe reset hotkey defaults when loading new mission
3760 if ( Last_file_checksum != Current_file_checksum ){
3761 mission_hotkey_reset_saved();
3764 Allow_arrival_music_timestamp=timestamp(0);
3765 Allow_arrival_message_timestamp=timestamp(0);
3766 Arrival_message_delay_timestamp = timestamp(-1);
3769 for(idx=0; idx<2; idx++){
3770 Allow_arrival_music_timestamp_m[idx]=timestamp(0);
3771 Allow_arrival_message_timestamp_m[idx]=timestamp(0);
3772 Arrival_message_delay_timestamp_m[idx] = timestamp(-1);
3775 Last_file_checksum = Current_file_checksum;
3778 int get_mission_info(char *filename, mission *mission_p)
3780 // if mission_p is NULL, make it point to The_mission
3781 if ( mission_p == NULL )
3782 mission_p = &The_mission;
3786 // open localization
3789 CFILE *ftemp = cfopen(filename, "rt");
3791 // close localization
3797 // 7/9/98 -- MWA -- check for 0 length file.
3798 filelength = cfilelength(ftemp);
3800 if ( filelength == 0 ){
3801 // close localization
3808 read_file_text(filename, CF_TYPE_MISSIONS);
3809 memset( mission_p, 0, sizeof(mission) );
3811 parse_mission_info(mission_p);
3812 } catch (parse_error_t rval) {
3813 nprintf(("Error", "Error abort! Code = %d", (int)rval));
3817 // close localization
3823 // mai parse routine for parsing a mission. The default parameter flags tells us which information
3824 // to get when parsing the mission. 0 means get everything (default). Other flags just gets us basic
3825 // info such as game type, number of players etc.
3826 int parse_main(const char *mission_name, int flags)
3830 // fill in Ship_class_names array with the names from the ship_info struct;
3831 Num_parse_names = 0;
3832 Mission_all_attack = 0; // Might get set in mission load.
3833 SDL_assert(Num_ship_types < MAX_SHIP_TYPES);
3835 for (i = 0; i < Num_ship_types; i++)
3836 Ship_class_names[i] = Ship_info[i].name;
3839 // open localization
3842 CFILE *ftemp = cfopen(mission_name, "rt", CFILE_NORMAL, CF_TYPE_MISSIONS);
3846 Error( LOCATION, "Couldn't open mission '%s'\n", mission_name );
3848 Current_file_length = -1;
3849 Current_file_checksum = 0;
3851 // close localization
3857 Current_file_length = cfilelength(ftemp);
3861 read_file_text(mission_name, CF_TYPE_MISSIONS);
3862 memset(&The_mission, 0, sizeof(The_mission));
3863 parse_mission(&The_mission, flags);
3864 display_parse_diagnostics();
3865 } catch (parse_error_t rval) {
3866 nprintf(("Error", "Error abort! Code = %i.", (int)rval));
3870 // close localization
3874 SDL_strlcpy(Mission_filename, mission_name, sizeof(Mission_filename));
3879 // sets the arrival lcoation of the ships in wingp. pass num_to_set since the threshold value
3880 // for wings may have us create more ships in the wing when there are still some remaining
3881 void mission_set_wing_arrival_location( wing *wingp, int num_to_set )
3885 // get the starting index into the ship_index array of the first ship whose location we need set.
3887 index = wingp->current_count - num_to_set;
3888 if ( (wingp->arrival_location == ARRIVE_FROM_DOCK_BAY) || (wingp->arrival_location == ARRIVE_AT_LOCATION) ) {
3889 while ( index < wingp->current_count ) {
3892 objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3893 mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3898 object *leader_objp;
3903 // wing is not arriving from a docking bay -- possibly move them based on arriving near
3904 // or in front of some other ship.
3905 index = wingp->current_count - num_to_set;
3906 leader_objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3907 if (mission_set_arrival_location(wingp->arrival_anchor, wingp->arrival_location, wingp->arrival_distance, OBJ_INDEX(leader_objp), &pos, &orient)) {
3908 // modify the remaining ships created
3911 while ( index < wingp->current_count ) {
3914 objp = &Objects[Ships[wingp->ship_index[index]].objnum];
3916 // change the position of the next ships in the wing. Use the cool function in AiCode.cpp which
3917 // Mike K wrote to give new positions to the wing members.
3918 get_absolute_wing_pos( &objp->pos, leader_objp, wing_index++, 0);
3919 memcpy( &objp->orient, &orient, sizeof(matrix) );
3926 // create warp effect if in mission and not arriving from docking bay
3927 if ( (Game_mode & GM_IN_MISSION) && (wingp->arrival_location != ARRIVE_FROM_DOCK_BAY) ) {
3928 for ( index = wingp->current_count - num_to_set; index < wingp->current_count; index ++ ) {
3929 shipfx_warpin_start( &Objects[Ships[wingp->ship_index[index]].objnum] );
3934 // this function is called after a mission is parsed to set the arrival locations of all ships in the
3935 // mission to the apprioriate spot. Mainly needed because ships might be in dock bays to start
3936 // the mission, so their AI mode must be set appropriately.
3937 void mission_parse_set_arrival_locations()
3945 obj_merge_created_list();
3946 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
3949 if ( objp->type != OBJ_SHIP )
3952 shipp = &Ships[objp->instance];
3953 // if the ship is in a wing -- ignore the info and let the wing info handle it
3954 if ( shipp->wingnum != -1 )
3957 // call function to set arrival location for this ship.
3958 mission_set_arrival_location( shipp->arrival_anchor, shipp->arrival_location, shipp->arrival_distance, OBJ_INDEX(objp), NULL, NULL);
3962 for ( i = 0; i < num_wings; i++ ) {
3964 // if wing has no ships, then don't process it.
3965 if ( Wings[i].current_count == 0 )
3968 mission_set_wing_arrival_location( &Wings[i], Wings[i].current_count );
3973 // function which iterates through the ship_arrival_list and creates any ship which
3974 // should be intially docked with a ship which currently exists in the mission
3975 void mission_parse_do_initial_docks()
3977 p_object *pobjp, *tmp;
3979 pobjp = GET_FIRST( &ship_arrival_list );
3980 while ( pobjp != END_OF_LIST(&ship_arrival_list) ) {
3983 tmp = GET_NEXT(pobjp);
3985 // see if the flag for initial docked is set
3986 if ( pobjp->flags & P_SF_INITIALLY_DOCKED ) {
3987 // see if who this parse object is supposed to be docked with is in the mission
3988 shipnum = ship_name_lookup( pobjp->docked_with );
3989 if ( shipnum != -1 ) {
3992 // the ship exists, so create this object, then dock the two.
3993 objnum = parse_create_object( pobjp );
3994 SDL_assert ( objnum != -1 );
3996 list_remove( &ship_arrival_list, pobjp);
3998 // p1 is the parse object's docking point.
3999 // p2 is the existing objects docking point.
4000 p1 = model_find_dock_name_index(Ships[shipnum].modelnum, pobjp->docker_point);
4001 p2 = model_find_dock_name_index(Ships[Objects[objnum].instance].modelnum, pobjp->dockee_point);
4003 if ((p1 >= 0) && (p2 >= 0)) {
4004 nprintf(("AI", "Initially Docked: %s with %s\n", Ships[shipnum].ship_name, Ships[Objects[objnum].instance].ship_name));
4005 if (ship_docking_valid(shipnum, Objects[objnum].instance)) // only dock if they are allowed to be docked.
4006 ai_dock_with_object(&Objects[Ships[shipnum].objnum], &Objects[objnum], 89, AIDO_DOCK_NOW, p1, p2);
4008 ai_dock_with_object(&Objects[objnum], &Objects[Ships[shipnum].objnum], 89, AIDO_DOCK_NOW, p2, p1);
4011 Int3(); // Curious. Two ships told to dock, but one of the dock points is bogus.
4012 // Get Allender or Hoffoss, one of whom probably wrote the above if ()
4020 // function which returns true or false if the given mission support multiplayers
4021 int mission_parse_is_multi(const char *filename, char *mission_name)
4027 // new way of getting information. Open the file, and just get the name and the game_type flags.
4028 // return the flags if a multiplayer mission
4032 ftemp = cfopen(filename, "rt");
4036 // 7/9/98 -- MWA -- check for 0 length file.
4037 filelength = cfilelength(ftemp);
4039 if ( filelength == 0 )
4042 // open localization
4046 read_file_text(filename, CF_TYPE_MISSIONS);
4048 if ( skip_to_string("$Name:") != 1 ) {
4049 nprintf(("Network", "Unable to process %s because we couldn't find $Name:", filename));
4051 // close localization
4056 stuff_string( mission_name, F_NAME, NULL );
4057 if ( skip_to_string("+Game Type Flags:") != 1 ) {
4058 nprintf(("Network", "Unable to process %s because we couldn't find +Game Type Flags:\n", filename));
4060 // close localization
4065 stuff_int(&game_type);
4066 } catch (parse_error_t) {
4067 Error(LOCATION, "Bogus! Trying to get multi game type on mission %s returned as a mission from cf_get_filelist\n", filename);
4070 if ( game_type & MISSION_TYPE_MULTI ){
4071 // close localization
4077 // close localization
4083 // function which gets called to retrieve useful information about a mission. We will get the
4084 // name, description, and number of players for a mission. Probably used for multiplayer only?
4085 // The calling function can use the information in The_mission to get the name/description of the mission
4088 int mission_parse_get_multi_mission_info( const char *filename )
4090 if ( parse_main(filename, MISSION_PARSE_MISSION_INFO) ){
4094 SDL_assert( The_mission.game_type & MISSION_TYPE_MULTI ); // assume multiplayer only for now?
4096 // return the number of parse_players. later, we might want to include (optionally?) the number
4097 // of other ships in the main players wing (usually wing 'alpha') for inclusion of number of
4100 return The_mission.num_players;
4103 // returns true or false if this is on the yet to arrive list
4104 int mission_parse_ship_arrived( const char *shipname )
4108 for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) ) {
4109 if ( !SDL_strcasecmp( objp->name, shipname) )
4110 return 0; // still on the arrival list
4115 // return the parse object on the ship arrival list associated with the given name
4116 p_object *mission_parse_get_arrival_ship( const char *name )
4120 for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) ) {
4121 if ( !SDL_strcasecmp( objp->name, name) )
4122 return objp; // still on the arrival list
4128 // return the parse object on the ship arrival list associated with the given signature
4129 p_object *mission_parse_get_arrival_ship( ushort net_signature )
4133 for ( objp = GET_FIRST(&ship_arrival_list); objp !=END_OF_LIST(&ship_arrival_list); objp = GET_NEXT(objp) ) {
4134 if ( objp->net_signature == net_signature )
4135 return objp; // still on the arrival list
4141 // mission_set_arrival_location() sets the arrival location of a parse object according to the arrival location
4142 // of the object. Returns true if object set to new position, false if not.
4143 int mission_set_arrival_location(int anchor, int location, int dist, int objnum, vector *new_pos, matrix *new_orient)
4145 int shipnum, anchor_objnum;
4146 vector anchor_pos, rand_vec, new_fvec;
4149 if ( location == ARRIVE_AT_LOCATION )
4152 SDL_assert(anchor >= 0);
4154 // this ship might possibly arrive at another location. The location is based on the
4155 // proximity of some ship (and some other special tokens)
4157 // if we didn't find the arrival anchor in the list of special nodes, then do a
4158 // ship name lookup on the anchor
4159 if (anchor < SPECIAL_ARRIVAL_ANCHORS_OFFSET) {
4160 shipnum = ship_name_lookup(Parse_names[anchor]);
4161 if ( shipnum == -1 ) {
4162 SDL_assert ( location != ARRIVE_FROM_DOCK_BAY ); // bogus data somewhere!!! get mwa
4163 nprintf (("allender", "couldn't find ship for arrival anchor -- using location ship created at"));
4168 // come up with a position based on the special token names
4171 if (anchor == ANY_FRIENDLY) {
4172 shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ANY_SHIP );
4173 } else if (anchor == ANY_HOSTILE) {
4174 shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ANY_SHIP );
4175 } else if (anchor == ANY_FRIENDLY_PLAYER) {
4176 shipnum = ship_get_random_team_ship( TEAM_FRIENDLY, SHIP_GET_ONLY_PLAYERS );
4177 } else if (anchor == ANY_HOSTILE_PLAYER) {
4178 shipnum = ship_get_random_team_ship( opposing_team_mask(Player_ship->team), SHIP_GET_ONLY_PLAYERS );
4180 Int3(); // get allender -- unknown special arrival instructions
4182 // if we didn't get an object from one of the above functions, then make the object
4183 // arrive at it's placed location
4184 if ( shipnum == -1 ) {
4185 nprintf (("Allender", "Couldn't find random ship for arrival anchor -- using default location\n"));
4190 // take the shipnum and get the position. once we have positions, we can determine where
4191 // to make this ship appear
4192 SDL_assert ( shipnum != -1 );
4193 anchor_objnum = Ships[shipnum].objnum;
4194 anchor_pos = Objects[anchor_objnum].pos;
4196 // if arriving from docking bay, then set ai mode and call function as per AL's instructions.
4197 if ( location == ARRIVE_FROM_DOCK_BAY ) {
4200 // if we get an error, just let the ship arrive(?)
4201 if ( ai_acquire_emerge_path(&Objects[objnum], anchor_objnum, &pos, &fvec) == -1 ) {
4202 Int3(); // get MWA or AL -- not sure what to do here when we cannot acquire a path
4205 Objects[objnum].pos = pos;
4206 Objects[objnum].orient.v.fvec = fvec;
4209 // AL: ensure dist > 0 (otherwise get errors in vecmat)
4210 // TODO: maybe set distance to 2x ship radius of ship appearing in front of?
4212 Error(LOCATION, "Distance of %d is invalid in mission_set_arrival_location\n", dist);
4216 // get a vector which is the ships arrival position based on the type of arrival
4217 // this ship should have. Arriving near a ship we use a random normalized vector
4218 // scaled by the distance given by the designer. Arriving in front of a ship means
4219 // entering the battle in the view cone.
4220 if ( location == ARRIVE_NEAR_SHIP ) {
4221 // get a random vector -- use static randvec if in multiplayer
4222 if ( Game_mode & GM_NORMAL )
4223 vm_vec_rand_vec_quick(&rand_vec);
4225 static_randvec( Objects[objnum].net_signature, &rand_vec );
4226 } else if ( location == ARRIVE_IN_FRONT_OF_SHIP ) {
4231 // cool function by MK to give a reasonable random vector "in front" of a ship
4232 // rvec and uvec are the right and up vectors.
4233 // If these are not available, this would be an expensive method.
4235 x = (float)cos(ANG_TO_RAD(45));
4236 if ( Game_mode & GM_NORMAL ) {
4237 r1 = myrand() < MY_RAND_MAX/2 ? -1 : 1;
4238 r2 = myrand() < MY_RAND_MAX/2 ? -1 : 1;
4240 // in multiplayer, use the static rand functions so that all clients can get the
4241 // same information.
4242 r1 = static_rand(Objects[objnum].net_signature) < MY_RAND_MAX/2 ? -1 : 1;
4243 r2 = static_rand(Objects[objnum].net_signature+1) < MY_RAND_MAX/2 ? -1 : 1;
4246 vm_vec_copy_scale(&t1, &(Objects[anchor_objnum].orient.v.fvec), x);
4247 vm_vec_copy_scale(&t2, &(Objects[anchor_objnum].orient.v.rvec), (1.0f - x) * r1);
4248 vm_vec_copy_scale(&t3, &(Objects[anchor_objnum].orient.v.uvec), (1.0f - x) * r2);
4250 vm_vec_add(&rand_vec, &t1, &t2);
4251 vm_vec_add2(&rand_vec, &t3);
4252 vm_vec_normalize(&rand_vec);
4255 // add in the radius of the two ships involved. This will make the ship arrive further than
4256 // specified, but will appear more accurate since we are pushing the edge of the model to the
4257 // specified distance. large objects appears to be a lot closer without the following line because
4258 // the object centers were at the correct distance, but the model itself was much closer to the
4260 dist += (int)Objects[objnum].radius + (int)Objects[anchor_objnum].radius;
4261 vm_vec_scale_add(&Objects[objnum].pos, &anchor_pos, &rand_vec, (float)dist);
4263 // I think that we will always want to orient the ship that is arriving to face towards
4264 // the ship it is arriving near/in front of. The effect will be cool!
4266 // calculate the new fvec of the ship arriving and use only that to get the matrix. isn't a big
4267 // deal not getting bank.
4268 vm_vec_sub(&new_fvec, &anchor_pos, &Objects[objnum].pos );
4269 vm_vector_2_matrix( &orient, &new_fvec, NULL, NULL );
4270 Objects[objnum].orient = orient;
4273 // set the new_pos parameter since it might be used outside the function (i.e. when dealing with wings).
4275 memcpy(new_pos, &Objects[objnum].pos, sizeof(vector) );
4278 memcpy( new_orient, &Objects[objnum].orient, sizeof(matrix) );
4283 // mark a reinforcement as available
4284 void mission_parse_mark_reinforcement_available(char *name)
4289 for (i = 0; i < Num_reinforcements; i++) {
4290 rp = &Reinforcements[i];
4291 if ( !SDL_strcasecmp(rp->name, name) ) {
4292 if ( !(rp->flags & RF_IS_AVAILABLE) ) {
4293 rp->flags |= RF_IS_AVAILABLE;
4295 // tell all of the clients.
4296 if ( MULTIPLAYER_MASTER ) {
4297 send_reinforcement_avail( i );
4304 SDL_assert ( i < Num_reinforcements );
4307 // mission_did_ship_arrive takes a parse object and checked the arrival cue and delay and
4308 // creates the object if necessary. Returns -1 if not created. objnum of created ship otherwise
4309 int mission_did_ship_arrive(p_object *objp)
4313 // find out in the arrival cue became true
4314 did_arrive = eval_sexp(objp->arrival_cue);
4316 // we must first check to see if this ship is a reinforcement or not. If so, then don't
4318 if ( objp->flags & P_SF_REINFORCEMENT ) {
4320 // if this ship did arrive, mark the reinforcement as available, and tell clients if in multiplayer
4323 mission_parse_mark_reinforcement_available(objp->name);
4328 if ( did_arrive ) { // has the arrival criteria been met?
4331 SDL_assert ( !(objp->flags & P_SF_CANNOT_ARRIVE) ); // get allender
4333 // check to see if the delay field <= 0. if so, then create a timestamp and then maybe
4334 // create the object
4335 if ( objp->arrival_delay <= 0 ) {
4336 objp->arrival_delay = timestamp( -objp->arrival_delay * 1000 );
4337 SDL_assert( objp->arrival_delay >= 0 );
4340 // if the timestamp hasn't elapsed, move onto the next ship.
4341 if ( !timestamp_elapsed(objp->arrival_delay) )
4344 // check to see if this ship is to arrive via a docking bay. If so, and the ship to arrive from
4345 // doesn't exist, don't create.
4346 if ( objp->arrival_location == ARRIVE_FROM_DOCK_BAY ) {
4350 SDL_assert( objp->arrival_anchor >= 0 );
4351 name = Parse_names[objp->arrival_anchor];
4353 // see if ship is yet to arrive. If so, then return -1 so we can evaluate again later.
4354 if ( mission_parse_get_arrival_ship( name ) )
4357 // see if ship is in mission. If not, then we can assume it was destroyed or departed since
4358 // it is not on the arrival list (as shown by above if statement).
4359 shipnum = ship_name_lookup( name );
4360 if ( shipnum == -1 ) {
4361 Sexp_nodes[objp->arrival_cue].value = SEXP_KNOWN_FALSE;
4366 object_num = parse_create_object(objp); // create the ship
4368 // since this ship is not in a wing, create a SHIP_ARRIVE entry
4369 //mission_log_add_entry( LOG_SHIP_ARRIVE, objp->name, NULL );
4370 SDL_assert(object_num >= 0 && object_num < MAX_OBJECTS);
4372 // Play the music track for an arrival
4373 if ( !(Ships[Objects[object_num].instance].flags & SF_NO_ARRIVAL_MUSIC) )
4374 if ( timestamp_elapsed(Allow_arrival_music_timestamp) ) {
4375 Allow_arrival_music_timestamp = timestamp(ARRIVAL_MUSIC_MIN_SEPARATION);
4376 event_music_arrival(Ships[Objects[object_num].instance].team);
4380 // check to see if the arrival cue of this ship is known false -- if so, then remove
4381 // the parse object from the ship
4382 if ( Sexp_nodes[objp->arrival_cue].value == SEXP_KNOWN_FALSE )
4383 objp->flags |= P_SF_CANNOT_ARRIVE;
4390 // funciton to set a flag on all parse objects on ship arrival list which cannot
4391 // arrive in the mission
4392 void mission_parse_mark_non_arrivals()
4396 for ( pobjp = GET_FIRST(&ship_arrival_list); pobjp != END_OF_LIST(&ship_arrival_list); pobjp = GET_NEXT(pobjp) ) {
4397 if ( pobjp->wingnum != -1 ) {
4398 if ( Sexp_nodes[Wings[pobjp->wingnum].arrival_cue].value == SEXP_KNOWN_FALSE )
4399 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4401 if ( Sexp_nodes[pobjp->arrival_cue].value == SEXP_KNOWN_FALSE )
4402 pobjp->flags |= P_SF_CANNOT_ARRIVE;
4407 // function to deal with support ship arrival. objnum is the object number of the arriving support
4408 // ship. This function can get called from either single or multiplayer. Needed to that clients
4409 // can know when to abort rearm.
4410 void mission_parse_support_arrived( int objnum )
4414 // when the support ship arrives, the shipname it is supposed to repair is in the 'misc'
4415 // field of the parse_object. If the ship still exists, call ai function which actually
4416 // issues the goal for the repair
4417 for ( i = 0; i < Num_arriving_repair_targets; i++ ) {
4420 shipnum = ship_name_lookup( Arriving_repair_targets[i] );
4422 if ( shipnum != -1 ) {
4423 object *requester_objp, *support_objp;
4425 support_objp = &Objects[objnum];
4426 requester_objp = &Objects[Ships[shipnum].objnum];
4427 ai_add_rearm_goal( requester_objp, support_objp );
4431 // MK: A bit of a hack. If on player's team and player isn't allowed shields, don't give this ship shields.
4432 if ((Player_obj->flags & OF_NO_SHIELDS) && (Player_ship->team == Ships[Objects[objnum].instance].team))
4433 Objects[objnum].flags |= OF_NO_SHIELDS;
4435 Ships[Objects[objnum].instance].flags |= SF_WARPED_SUPPORT;
4437 Arriving_support_ship = NULL;
4438 Num_arriving_repair_targets = 0;
4441 MONITOR(NumShipArrivals);
4443 // mission_parse_arrivals will parse the lists of arriving ships and
4444 // wings -- creating new ships/wings if the arrival criteria have been
4446 void mission_eval_arrivals()
4452 // before checking arrivals, check to see if we should play a message concerning arrivals
4453 // of other wings. We use the timestamps to delay the arrival message slightly for
4455 if ( timestamp_valid(Arrival_message_delay_timestamp) && timestamp_elapsed(Arrival_message_delay_timestamp) && !((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)) ){
4456 int rship, use_terran;
4458 // use terran command 25% of time
4459 use_terran = ((frand() - 0.75) > 0.0f)?1:0;
4461 rship = ship_get_random_player_wing_ship( SHIP_GET_NO_PLAYERS );
4462 if ( (rship == -1) || use_terran ){
4463 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4464 } else if ( rship != -1 ) {
4465 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4468 Arrival_message_delay_timestamp = timestamp(-1); // make the stamp invalid
4471 // if ( !timestamp_elapsed(Mission_arrival_timestamp) )
4474 // check the ship_arrival_list
4476 objp = GET_FIRST(&ship_arrival_list);
4477 while( objp !=END_OF_LIST(&ship_arrival_list) ) {
4478 p_object *temp = GET_NEXT(objp);
4479 if ( objp->wingnum == -1 ) { // if this object has a wing -- let code for wings determine if it should be created
4481 objnum = mission_did_ship_arrive( objp );
4482 if ( objnum != -1 ) {
4483 list_remove( &ship_arrival_list, objp);
4484 MONITOR_INC(NumShipArrivals,1);
4491 // check for any initially docked ships. Do it after all are created since the next function
4492 // messes with the ship_arrival_list
4493 mission_parse_do_initial_docks(); // maybe create it's docked counterpart
4495 mission_parse_mark_non_arrivals(); // mark parse objects which can no longer arrive
4497 // check the support ship arrival list
4498 if ( Arriving_support_ship ) {
4501 objnum = mission_did_ship_arrive( Arriving_support_ship );
4503 if ( objnum != -1 ) {
4504 MONITOR_INC(NumShipArrivals,1);
4505 mission_parse_support_arrived( objnum );
4509 // we must also check to see if there are waves of a wing that must
4510 // reappear if all the ships of the current wing have been destroyed or
4511 // have departed. If this is the case, then create the next wave.
4513 for ( i = 0; i < num_wings; i++ ) {
4516 // should we process this wing anymore
4517 if ( wingp->flags & WF_WING_GONE )
4520 // if we have a reinforcement wing, then don't try to create new ships automatically.
4521 if ( wingp->flags & WF_REINFORCEMENT ) {
4523 // check to see in the wings arrival cue is true, and if so, then mark the reinforcement
4525 if ( eval_sexp(wingp->arrival_cue) ) {
4526 mission_parse_mark_reinforcement_available(wingp->name);
4531 // don't do evaluations for departing wings
4532 if ( wingp->flags & WF_WING_DEPARTING ){
4536 // must check to see if we are at the last wave. Code above to determine when a wing is gone only
4537 // gets run when a ship is destroyed (not every N seconds like it used to). Do a quick check
4539 if ( wingp->current_wave == wingp->num_waves ){
4543 // if the current wave of this wing is 0, then we haven't created the ships in the wing yet.
4544 // call parse_wing_create_ships to try and create it. That function will eval the arrival
4545 // cue of the wing and create the ships if necessary, or if the threshold of the wing has
4546 // been reached, then try and create more ships
4547 if ( (wingp->current_wave == 0) || (wingp->current_count <= wingp->threshold) ) {
4550 created = parse_wing_create_ships( wingp, wingp->wave_count );
4552 // if we created ships in this wing, check to see if the wings was int the reinforcements
4553 // array. If so, then if we have more uses, then reset the reinforcement flag for the wing
4554 // so the user can call in another set if need be.
4555 if ( created > 0 ) {
4558 mission_parse_do_initial_docks(); // maybe create other initially docked ships
4559 if ( Wings[i].flags & WF_RESET_REINFORCEMENT ) {
4560 Wings[i].flags &= ~WF_RESET_REINFORCEMENT;
4561 Wings[i].flags |= WF_REINFORCEMENT;
4564 // possibly send a message to the player when this wing arrives.
4565 if ( wingp->flags & WF_NO_ARRIVAL_MESSAGE ){
4569 // multiplayer team vs. team
4570 if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM)){
4571 // send a hostile wing arrived message
4572 rship = Wings[i].ship_index[0];
4574 int multi_team_filter = Ships[rship].team == TEAM_FRIENDLY ? 1 : 0;
4576 // there are two timestamps at work here. One to control how often the player receives
4577 // messages about incoming hostile waves, and the other to control how long after
4578 // the wing arrives does the player actually get the message.
4579 if ( timestamp_elapsed(Allow_arrival_message_timestamp_m[multi_team_filter]) ) {
4580 if ( !timestamp_valid(Arrival_message_delay_timestamp_m[multi_team_filter]) ){
4581 Arrival_message_delay_timestamp_m[multi_team_filter] = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4583 Allow_arrival_message_timestamp_m[multi_team_filter] = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
4585 // send to the proper team
4586 message_send_builtin_to_player( MESSAGE_ARRIVE_ENEMY, NULL, MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, multi_team_filter );
4591 // see if this is a starting player wing
4592 if ( i == Starting_wings[STARTING_WING_BETA] ) { // this is the beta wing
4593 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4595 message_send_builtin_to_player( MESSAGE_BETA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4597 } else if ( i == Starting_wings[STARTING_WING_GAMMA] ) { // this is the gamma wing
4598 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4599 if ( rship != -1 ) {
4600 message_send_builtin_to_player( MESSAGE_GAMMA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4602 } else if ( !SDL_strcasecmp( wingp->name, "delta") ) {
4603 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4604 if ( rship != -1 ) {
4605 message_send_builtin_to_player( MESSAGE_DELTA_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4607 } else if ( !SDL_strcasecmp(wingp->name, "epsilon") ) {
4608 rship = ship_get_random_ship_in_wing( i, SHIP_GET_NO_PLAYERS );
4609 if ( rship != -1 ) {
4610 message_send_builtin_to_player( MESSAGE_EPSILON_ARRIVED, &Ships[rship], MESSAGE_PRIORITY_LOW, MESSAGE_TIME_SOON, 0, 0, -1, -1 );
4613 // see if we have a hostile wing that arrived
4614 rship = Wings[i].ship_index[0];
4615 if ( Ships[rship].team != TEAM_FRIENDLY ) {
4617 // there are two timestamps at work here. One to control how often the player receives
4618 // messages about incoming hostile waves, and the other to control how long after
4619 // the wing arrives does the player actually get the message.
4620 if ( timestamp_elapsed(Allow_arrival_message_timestamp) ) {
4621 if ( !timestamp_valid(Arrival_message_delay_timestamp) ){
4622 Arrival_message_delay_timestamp = timestamp_rand(ARRIVAL_MESSAGE_DELAY_MIN, ARRIVAL_MESSAGE_DELAY_MAX );
4624 Allow_arrival_message_timestamp = timestamp(ARRIVAL_MESSAGE_MIN_SEPARATION);
4632 Mission_arrival_timestamp = timestamp(ARRIVAL_TIMESTAMP);
4635 MONITOR(NumShipDepartures);
4637 // called to make object objp depart.
4638 void mission_do_departure( object *objp )
4643 MONITOR_INC(NumShipDepartures,1);
4645 SDL_assert ( objp->type == OBJ_SHIP );
4646 shipp = &Ships[objp->instance];
4648 // if departing to a docking bay, try to find the anchor ship to depart to. If not found, then
4649 // just make it warp out like anything else.
4650 if ( shipp->departure_location == DEPART_AT_DOCK_BAY ) {
4654 SDL_assert( shipp->departure_anchor >= 0 );
4655 name = Parse_names[shipp->departure_anchor];
4657 // see if ship is yet to arrive. If so, then return -1 so we can evaluate again later.
4658 if ( mission_parse_get_arrival_ship( name ) )
4659 goto do_departure_warp;
4661 // see if ship is in mission. If not, then we can assume it was destroyed or departed since
4662 // it is not on the arrival list (as shown by above if statement).
4663 anchor_shipnum = ship_name_lookup( name );
4664 if ( anchor_shipnum == -1 )
4665 goto do_departure_warp;
4667 ai_acquire_depart_path(objp, Ships[anchor_shipnum].objnum);
4672 ai_set_mode_warp_out( objp, &Ai_info[Ships[objp->instance].ai_index] );
4676 // put here because mission_eval_arrivals is here. Might move these to a better location
4678 void mission_eval_departures()
4684 // if ( !timestamp_elapsed(Mission_departure_timestamp) )
4687 // scan through the active ships an evaluate their departure cues. For those
4688 // ships whose time has come, set their departing flag.
4690 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4691 if (objp->type == OBJ_SHIP) {
4694 SDL_assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
4696 shipp = &Ships[objp->instance];
4698 // don't process a ship that is already departing or dying or disabled
4699 // AL 12-30-97: Added SF_CANNOT_WARP to check
4700 if ( (shipp->flags & (SF_DEPARTING | SF_DYING | SF_CANNOT_WARP )) || ship_subsys_disrupted(shipp, SUBSYSTEM_ENGINE) ) {
4704 // don't process ships that are part of a wing -- handled in seperate case
4705 if ( shipp->wingnum != -1 )
4708 // && (!timestamp_valid(shipp->departure_delay) || timestamp_elapsed(shipp->departure_delay)) )
4709 // when the departure cue becomes true, set off the departure delay timer. We store the
4710 // timer as -seconds in Freespace which indicates that the timer has not been set. If the timer
4711 // is not set, then turn it into a valid timer and keep evaluating the timer until it is elapsed
4712 if ( eval_sexp(shipp->departure_cue) ) {
4713 if ( shipp->departure_delay <= 0 )
4714 shipp->departure_delay = timestamp(-shipp->departure_delay * 1000 );
4715 if ( timestamp_elapsed(shipp->departure_delay) )
4716 mission_do_departure( objp );
4721 // now scan through the list of wings and check their departure cues. For wings with
4722 // that cue being true, we must update internal variables to indicate that the wing is
4723 // departed and that no further waves of this wing will appear
4725 for ( i = 0; i < num_wings; i++ ) {
4728 // should we process this wing anymore
4729 if ( wingp->flags & WF_WING_DEPARTING )
4732 // evaluate the sexpression. If true, mark all the ships in this wing as departing and increment
4733 // the num departed in the wing structure. Then add number of remaining waves * ships/wave to
4734 // departed count to get total count of ships in the wing which departed. (We are counting ships
4735 // that have not yet arrived as departed if they never arrive -- this may be bad, but for some reason
4736 // seems like the right thing to do).
4737 //&& (!timestamp_valid(wingp->departure_delay) || timestamp_elapsed(wingp->departure_delay)) ) {
4739 if ( eval_sexp(wingp->departure_cue) ) {
4740 // if we haven't set up the departure timer yet (would be <= 0) setup the timer to pop N seconds
4742 if ( wingp->departure_delay <= 0 )
4743 wingp->departure_delay = timestamp( -wingp->departure_delay * 1000 );
4744 if ( !timestamp_elapsed(wingp->departure_delay) )
4747 wingp->flags |= WF_WING_DEPARTING;
4748 for ( j = 0; j < wingp->current_count; j++ ) {
4751 shipp = &Ships[wingp->ship_index[j]];
4752 if ( (shipp->flags & SF_DEPARTING) || (shipp->flags & SF_DYING) )
4755 // shipp->flags |= SF_DEPARTING;
4756 // shipp->final_depart_time = timestamp(3*1000);
4758 SDL_assert ( shipp->objnum != -1 );
4759 objp = &Objects[shipp->objnum];
4761 // copy the wing's depature information to the ship
4762 shipp->departure_location = wingp->departure_location;
4763 shipp->departure_anchor = wingp->departure_anchor;
4765 mission_do_departure( objp );
4766 // don't add to wingp->total_departed here -- this is taken care of in ship code.
4769 // MWA 2/25/98 -- don't do the follwoing wing member updates. It makes the accurate counts
4770 // sort of messed up and causes problems for the event log. The code in ship_wing_cleanup()
4771 // now keys off of the WF_WING_DEPARTING flag instead of the counts below.
4774 // now be sure that we update wing structure members if there are any remaining waves left
4775 if ( wingp->current_wave < wingp->num_waves ) {
4778 num_remaining = ( (wingp->num_waves - wingp->current_wave) * wingp->wave_count);
4779 wingp->total_departed += num_remaining;
4780 wingp->total_arrived_count += num_remaining;
4781 wingp->current_wave = wingp->num_waves;
4787 Mission_departure_timestamp = timestamp(DEPARTURE_TIMESTAMP);
4790 // function called from high level game loop to do mission evaluation stuff
4791 void mission_parse_eval_stuff()
4793 mission_eval_arrivals();
4794 mission_eval_departures();
4797 int allocate_subsys_status()
4801 SDL_assert(Subsys_index < MAX_SUBSYS_STATUS);
4802 Subsys_status[Subsys_index].percent = 0.0f;
4803 Subsys_status[Subsys_index].primary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4804 for (i=1; i<MAX_PRIMARY_BANKS; i++)
4805 Subsys_status[Subsys_index].primary_banks[i] = -1; // none
4807 Subsys_status[Subsys_index].secondary_banks[0] = SUBSYS_STATUS_NO_CHANGE;
4808 Subsys_status[Subsys_index].secondary_ammo[0] = 100;
4809 for (i=1; i<MAX_SECONDARY_BANKS; i++) {
4810 Subsys_status[Subsys_index].secondary_banks[i] = -1;
4811 Subsys_status[Subsys_index].secondary_ammo[i] = 100;
4814 Subsys_status[Subsys_index].ai_class = SUBSYS_STATUS_NO_CHANGE;
4815 return Subsys_index++;
4818 // find (or add) the name in the list and return an index to it.
4819 int get_parse_name_index(const char *name)
4823 for (i=0; i<Num_parse_names; i++)
4824 if (!SDL_strcasecmp(name, Parse_names[i]))
4827 SDL_assert(i < MAX_SHIPS + MAX_WINGS);
4828 SDL_assert(strlen(name) < NAME_LENGTH);
4829 SDL_strlcpy(Parse_names[i], name, NAME_LENGTH);
4830 return Num_parse_names++;
4833 int get_anchor(char *name)
4837 for (i=0; i<MAX_SPECIAL_ARRIVAL_ANCHORS; i++)
4838 if (!SDL_strcasecmp(name, Special_arrival_anchor_names[i]))
4839 return SPECIAL_ARRIVAL_ANCHORS_OFFSET + i;
4841 return get_parse_name_index(name);
4844 // function to fixup the goals/ai references for player objects in the mission
4845 void mission_parse_fixup_players()
4849 // merge created list to have all objects on used list
4850 obj_merge_created_list();
4851 for ( objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
4852 if ( (objp->type == OBJ_SHIP) && (objp->flags & OF_PLAYER_SHIP) ) {
4853 ai_clear_ship_goals( &Ai_info[Ships[objp->instance].ai_index] );
4854 init_ai_object( OBJ_INDEX(objp) );
4859 // code to warp in a new support ship. It works by finding the average position of all ships
4860 // in the mission, creating a vector from that position to the player, and scaling out behind the
4861 // player some distance. Should be sufficient.
4863 #define WARP_IN_MIN_DISTANCE 1000.0f
4864 #define WARP_IN_TIME_MIN 3000 // warps in min 3 seconds later
4865 #define WARP_IN_TIME_MAX 6000 // warps in max 6 seconds later
4867 // function which adds requester_objp onto the queue of ships for the arriving support ship to service
4868 void mission_add_to_arriving_support( object *requester_objp )
4873 SDL_assert ( Arriving_support_ship );
4875 if ( Num_arriving_repair_targets == MAX_AI_GOALS ) {
4876 // Int3(); // get allender -- ship isn't going to get repair, but I hope they never queue up this far!!!
4877 mprintf(("Reached MAX_AI_GOALS trying to add repair request!\n"));
4881 shipp = &Ships[requester_objp->instance];
4882 // check for duplicates before adding
4883 for (i = 0; i < Num_arriving_repair_targets; i++ ) {
4884 if ( !SDL_strcasecmp(Arriving_repair_targets[i], shipp->ship_name) ){
4888 if ( i != Num_arriving_repair_targets ){ // found the ship before reaching the end -- ignore it!
4892 SDL_strlcpy( Arriving_repair_targets[Num_arriving_repair_targets], Ships[requester_objp->instance].ship_name, NAME_LENGTH );
4893 Num_arriving_repair_targets++;
4895 if ( MULTIPLAYER_MASTER ){
4896 multi_maybe_send_repair_info( requester_objp, NULL, REPAIR_INFO_WARP_ADD );
4900 extern int pp_collide_any(vector *curpos, vector *goalpos, float radius, object *ignore_objp1, object *ignore_objp2, int big_only_flag);
4902 // Set the warp in position for a support ship relative to an object.
4903 // Caller tries several positions, passing vector in x, y, z.
4904 int get_warp_in_pos(vector *pos, object *objp, float x, float y, float z)
4908 if ( Game_mode & GM_NORMAL )
4911 rand_val = static_randf(objp->net_signature);
4913 rand_val = 1.0f + (rand_val - 0.5f)*0.2f;
4917 vm_vec_scale_add2( pos, &objp->orient.v.rvec, x*rand_val*800.0f);
4918 vm_vec_scale_add2( pos, &objp->orient.v.uvec, y*rand_val*800.0f);
4919 vm_vec_scale_add2( pos, &objp->orient.v.fvec, z*rand_val*800.0f);
4921 return pp_collide_any(&objp->pos, pos, objp->radius, objp, NULL, 1);
4924 void mission_warp_in_support_ship( object *requester_objp )
4926 vector center, warp_in_pos;
4929 int i, requester_species;
4930 ship *requester_shipp;
4932 SDL_assert ( requester_objp->type == OBJ_SHIP );
4933 requester_shipp = &Ships[requester_objp->instance]; // MK, 10/23/97, used to be ->type, bogus, no?
4935 // if the support ship is already arriving, add the requester to the list
4936 if ( Arriving_support_ship ) {
4937 mission_add_to_arriving_support( requester_objp );
4941 // get average position of all ships
4942 obj_get_average_ship_pos( ¢er );
4943 vm_vec_sub( &warp_in_pos, ¢er, &(requester_objp->pos) );
4945 // be sure to account for case as player being only ship left in mission
4947 if ( !(IS_VEC_NULL( warp_in_pos)) ) {
4948 mag = vm_vec_mag( &warp_in_pos );
4949 if ( mag < WARP_IN_MIN_DISTANCE )
4950 vm_vec_scale( &warp_in_pos, WARP_IN_MIN_DISTANCE/mag);
4954 // take -player_pos.fvec scaled by 1000.0f;
4955 warp_in_pos = Player_obj->orient.fvec;
4956 vm_vec_scale( &warp_in_pos, -1000.0f );
4960 // Choose position to warp in ship.
4961 // Temporary, but changed by MK because it used to be exactly behind the player.
4962 // This could cause an SDL_assert if the player immediately targeted it (before moving).
4963 // Tend to put in front of the player to aid him in flying towards the ship.
4965 if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.1f, 1.0f))
4966 if (!get_warp_in_pos(&warp_in_pos, requester_objp, 1.0f, 0.2f, -1.0f))
4967 if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.2f, -1.0f))
4968 if (!get_warp_in_pos(&warp_in_pos, requester_objp, -1.0f, -0.1f, 1.0f))
4969 get_warp_in_pos(&warp_in_pos, requester_objp, 0.1f, 1.0f, 0.2f);
4971 // create a parse object, and put it onto the ship_arrival_list. This whole thing kind of sucks.
4972 // I want to put it into a parse object since it needs to arrive just a little later than
4973 // this function is called. I have to make some assumptions in the code about values for the parse
4974 // object since I'm no longer working with a mission file. These exceptions will be noted with
4977 Arriving_support_ship = &Support_ship_pobj;
4978 pobj = Arriving_support_ship;
4980 // create a name for the ship. use "Support #". look for collisions until one isn't found anymore
4983 SDL_snprintf(pobj->name, sizeof(pobj->name), NOX("Support %d"), i);
4984 if ( (ship_name_lookup(pobj->name) == -1) && (ship_find_exited_ship_by_name(pobj->name) == -1) )
4989 pobj->pos = warp_in_pos;
4990 vm_set_identity( &(pobj->orient) );
4992 // *sigh*. Gotta get the ship class. For now, this will amount to finding a ship in the ship_info
4993 // array with the same team as the requester of type SIF_SUPPORT. Might need to be changed, but who knows
4994 // vasudans use the terran support ship.
4995 requester_species = Ship_info[requester_shipp->ship_info_index].species;
4997 // 5/6/98 -- MWA Don't need to do anything for multiplayer. I think that we always want to use
4998 // the species of the caller ship.
4999 SDL_assert( (requester_species == SPECIES_TERRAN) || (requester_species == SPECIES_VASUDAN) );
5000 // if ( (Game_mode & GM_NORMAL) && (requester_species == SPECIES_VASUDAN) ) { // make vasundan's use the terran support ship
5001 // requester_species = SPECIES_TERRAN;
5004 // get index of correct species support ship
5005 for (i=0; i < Num_ship_types; i++) {
5006 if ( (Ship_info[i].species == requester_species) && (Ship_info[i].flags & SIF_SUPPORT) )
5010 if ( i < Num_ship_types )
5011 pobj->ship_class = i;
5013 Int3(); // BOGUS!!!! gotta figure something out here
5015 pobj->team = requester_shipp->team;
5017 pobj->behavior = AIM_NONE; // ASSUMPTION: the mission file has the string "None" which maps to AIM_NONE
5019 // set the ai_goals to -1. We will put the requester object shipname in repair target array and then take
5020 // care of setting up the goal when creating the ship!!!!
5021 pobj->ai_goals = -1;
5022 Num_arriving_repair_targets = 0;
5023 mission_add_to_arriving_support( requester_objp );
5025 // need to set ship's cargo to nothing. scan the cargo_names array looking for the string nothing.
5026 // add it if not found
5027 for (i = 0; i < Num_cargo; i++ )
5028 if ( !SDL_strcasecmp(Cargo_names[i], NOX("nothing")) )
5031 if ( i == Num_cargo ) {
5032 SDL_strlcpy(Cargo_names[i], NOX("Nothing"), NAME_LENGTH);
5035 pobj->cargo1 = char(i);
5037 pobj->status_count = 0;
5039 pobj->arrival_location = 0; // ASSUMPTION: this is index to arrival_lcation string array for hyperspace!!!!
5040 pobj->arrival_distance = 0;
5041 pobj->arrival_anchor = -1;
5042 pobj->arrival_cue = Locked_sexp_true;
5043 pobj->arrival_delay = timestamp_rand(WARP_IN_TIME_MIN, WARP_IN_TIME_MAX);
5045 pobj->subsys_count = 0; // number of elements used in subsys_status array
5046 pobj->initial_velocity = 100; // start at 100% velocity
5047 pobj->initial_hull = 100; // start at 100% hull
5048 pobj->initial_shields = 100; // and 100% shields
5050 pobj->departure_location = 0; // ASSUMPTION: this is index to departure_lcation string array for hyperspace!!!!
5051 pobj->departure_anchor = -1;
5052 pobj->departure_cue = Locked_sexp_false;
5053 pobj->departure_delay= 0;
5055 pobj->determination = 10; // ASSUMPTION: mission file always had this number written out
5057 if ( Player_obj->flags & P_OF_NO_SHIELDS )
5058 pobj->flags = P_OF_NO_SHIELDS; // support ships have no shields when player has not shields
5060 pobj->ai_class = Ship_info[pobj->ship_class].ai_class;
5064 pobj->docked_with[0] = '\0';
5066 pobj->persona_index = -1;
5067 pobj->net_signature = multi_assign_network_signature(MULTI_SIG_SHIP);
5068 pobj->wing_status_wing_index = -1;
5069 pobj->wing_status_wing_pos = -1;
5070 pobj->respawn_count = 0;
5071 pobj->alt_type_index = -1;
5075 // returns true if a support ship is currently in the process of warping in.
5076 int mission_is_support_ship_arriving()
5078 if ( Arriving_support_ship )
5084 // returns true if the given ship is scheduled to be repaired by the arriving support ship
5085 int mission_is_repair_scheduled( object *objp )
5090 if ( !Arriving_support_ship )
5093 SDL_assert ( objp->type == OBJ_SHIP );
5094 name = Ships[objp->instance].ship_name;
5095 for (i = 0; i < Num_arriving_repair_targets; i++ ) {
5096 if ( !strcmp( name, Arriving_repair_targets[i]) )
5103 // function which removed the given ship from the list of ships that are to get repair
5104 // by arriving support ship
5105 int mission_remove_scheduled_repair( object *objp )
5110 if ( !Arriving_support_ship )
5113 // itereate through the target list looking for this ship name. If not found, we
5114 // can simply return.
5115 SDL_assert ( objp->type == OBJ_SHIP );
5116 name = Ships[objp->instance].ship_name;
5117 for (index = 0; index < Num_arriving_repair_targets; index++ ) {
5118 if ( !strcmp( name, Arriving_repair_targets[index]) )
5121 if ( index == Num_arriving_repair_targets )
5124 // ship is found -- compress the array
5125 for ( i = index; i < Num_arriving_repair_targets - 1; i++ )
5126 SDL_strlcpy( Arriving_repair_targets[i], Arriving_repair_targets[i+1], NAME_LENGTH );
5128 Num_arriving_repair_targets--;
5130 if ( MULTIPLAYER_MASTER )
5131 multi_maybe_send_repair_info( objp, NULL, REPAIR_INFO_WARP_REMOVE );
5136 // alternate name stuff
5137 int mission_parse_lookup_alt(char *name)
5147 for(idx=0; idx<Mission_alt_type_count; idx++){
5148 if(!strcmp(Mission_alt_types[idx], name)){
5157 static int mission_parse_lookup_alt_index_warn = 1;
5158 void mission_parse_lookup_alt_index(int index, char *out, const int max_outlen)
5164 if((index < 0) || (index > Mission_alt_type_count)){
5165 if (mission_parse_lookup_alt_index_warn) {
5166 Warning(LOCATION, "Ship with invalid alt_name. Get a programmer");
5167 mission_parse_lookup_alt_index_warn = 0;
5173 SDL_strlcpy(out, Mission_alt_types[index], max_outlen);
5176 int mission_parse_add_alt(char *name)
5184 if(Mission_alt_type_count < MAX_ALT_TYPE_NAMES){
5186 SDL_strlcpy(Mission_alt_types[Mission_alt_type_count++], name, NAME_LENGTH);
5189 return Mission_alt_type_count - 1;
5195 void mission_parse_reset_alt()
5197 Mission_alt_type_count = 0;
5200 int is_training_mission()
5202 return (The_mission.game_type & MISSION_TYPE_TRAINING);