1 /*
2 GAME_WAD.C
3
4 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Sunday, July 3, 1994 10:45:17 PM
22
23 Routines for loading an entire game.
24
25 Sunday, September 25, 1994 5:03:54 PM (alain)
26 call recalculate_redundant_endpoint_data() upon restoring saved game since
27 the redundant data isn't saved.
28 Sunday, November 6, 1994 5:35:34 PM
29 added support for the unified platforms/doors, cleaned up some old code of mine...
30 Saturday, August 26, 1995 2:28:56 PM
31 made portable.
32
33 Jan 30, 2000 (Loren Petrich):
34 Added some typecasts
35 Removed some "static" declarations that conflict with "extern"
36
37 Feb 4, 2000 (Loren Petrich):
38 Changed halt() to assert(false) for better debugging
39
40 Feb 6, 2000 (Loren Petrich):
41 Added loading and saving of physics models in savegames and from map files
42
43 Feb 12, 2000 (Loren Petrich):
44 Added MARATHON_INFINITY_DATA_VERSION where appropriate
45
46 Feb 14, 2000 (Loren Petrich):
47 Added more Pfhorte-friendly error checking to reading in of
48 map-info ('Minf') chunk; allowing it to be 2 bytes shorter.
49
50 Feb 17, 2000 (Loren Petrich):
51 Hides cursor after warning user about loading non-Bungie map files
52 (strERRORS, warningExternalMapsFile)
53
54 Feb 19, 2000 (Loren Petrich):
55 Fixed off-by-one asserts in load_***() routines;
56
57 Feb 26, 2000 (Loren Petrich):
58 Added chase-cam initialization
59
60 June 15, 2000 (Loren Petrich):
61 Added supprt for Chris Pruett's Pfhortran
62
63 Aug 12, 2000 (Loren Petrich):
64 Using object-oriented file handler
65
66 Aug 25, 2000 (Loren Petrich):
67 Cleared errors (game_errors.c/h) produced by Pfhortran
68 and by checking on a scenario's image files
69
70 Aug 28, 2000 (Loren Petrich):
71 Started on using new pack/unpack routines
72
73 Nov 26, 2000 (Loren Petrich):
74 Movied a RunLevelScript() before some other stuff, such as entering_map(),
75 so that textures to be loaded can be specified before they actually get loaded.
76
77 Feb 15, 2002 (Br'fin (Jeremy Parsons)):
78 Additional save data is now applied to the Temporary file instead of the original
79 (Old level preview info is now saved under Macintosh again)
80 */
81
82 // This needs to do the right thing on save game, which is storing the precalculated crap.
83
84 #include "cseries.h"
85
86 #include <string.h>
87 #include <stdlib.h>
88
89 #include "map.h"
90 #include "monsters.h"
91 #include "network.h"
92 #include "projectiles.h"
93 #include "effects.h"
94 #include "player.h"
95 #include "platforms.h"
96 #include "flood_map.h"
97 #include "scenery.h"
98 #include "lightsource.h"
99 #include "media.h"
100 #include "weapons.h"
101 #include "shell.h"
102 #include "preferences.h"
103 #include "FileHandler.h"
104
105 #include "editor.h"
106 #include "tags.h"
107 #include "wad.h"
108 #include "game_wad.h"
109 #include "interface.h"
110 #include "game_window.h"
111 #include "game_errors.h"
112 #include "computer_interface.h" // for loading/saving terminal state.
113 #include "images.h"
114 #include "shell.h"
115 #include "preferences.h"
116 #include "SoundManager.h"
117 #include "Plugins.h"
118
119 // LP change: added chase-cam init and render allocation
120 #include "ChaseCam.h"
121 #include "render.h"
122
123 #include "XML_LevelScript.h"
124
125 // For packing and unpacking some of the stuff
126 #include "Packing.h"
127
128 #include "motion_sensor.h" // ZZZ for reset_motion_sensor()
129
130 #include "Music.h"
131
132 // unify the save game code into one structure.
133
134 /* -------- local globals */
135 FileSpecifier MapFileSpec;
136 static bool file_is_set= false;
137
138 // LP addition: was a physics model loaded from the previous level loaded?
139 static bool PhysicsModelLoadedEarlier = false;
140
141 // The following local globals are for handling games that need to be restored.
142 struct revert_game_info
143 {
144 bool game_is_from_disk;
145 struct game_data game_information;
146 struct player_start_data player_start;
147 struct entry_point entry_point;
148 FileSpecifier SavedGame;
149 };
150 static struct revert_game_info revert_game_data;
151
152 /* -------- static functions */
153 static void scan_and_add_scenery(void);
154 static void complete_restoring_level(struct wad_data *wad);
155 static void load_redundant_map_data(short *redundant_data, size_t count);
156 static void allocate_map_structure_for_map(struct wad_data *wad);
157 static wad_data *build_export_wad(wad_header *header, int32 *length);
158 static struct wad_data *build_save_game_wad(struct wad_header *header, int32 *length);
159
160 static void allocate_map_for_counts(size_t polygon_count, size_t side_count,
161 size_t endpoint_count, size_t line_count);
162 static void load_points(uint8 *points, size_t count);
163 static void load_lines(uint8 *lines, size_t count);
164 static void load_sides(uint8 *sides, size_t count, short version);
165 static void load_polygons(uint8 *polys, size_t count, short version);
166 static void load_lights(uint8 *_lights, size_t count, short version);
167 static void load_annotations(uint8 *annotations, size_t count);
168 static void load_objects(uint8 *map_objects, size_t count);
169 static void load_media(uint8 *_medias, size_t count);
170 static void load_map_info(uint8 *map_info);
171 static void load_ambient_sound_images(uint8 *data, size_t count);
172 static void load_random_sound_images(uint8 *data, size_t count);
173 static void load_terminal_data(uint8 *data, size_t length);
174
175 /* Used _ONLY_ by game_wad.c internally and precalculate.c. */
176 // ZZZ: hmm, no longer true, now using when resuming a network saved-game... hope that's ok?...
177 //static bool process_map_wad(struct wad_data *wad, bool restoring_game, short version);
178
179 /* Final three calls, must be in this order! */
180 static void recalculate_redundant_map(void);
181 static void scan_and_add_platforms(uint8 *platform_static_data, size_t count, short version);
182 static void complete_loading_level(short *_map_indexes, size_t map_index_count,
183 uint8 *_platform_data, size_t platform_data_count,
184 uint8 *actual_platform_data, size_t actual_platform_data_count, short version);
185
186 static uint8 *unpack_directory_data(uint8 *Stream, directory_data *Objects, size_t Count);
187 //static uint8 *pack_directory_data(uint8 *Stream, directory_data *Objects, int Count);
188
189 /* ------------------------ Net functions */
get_net_map_data_length(void * data)190 int32 get_net_map_data_length(
191 void *data)
192 {
193 return get_flat_data_length(data);
194 }
195
196 /* Note that this frees it as well */
process_net_map_data(void * data)197 bool process_net_map_data(
198 void *data)
199 {
200 struct wad_header header;
201 struct wad_data *wad;
202 bool success= false;
203
204 wad= inflate_flat_data(data, &header);
205 if(wad)
206 {
207 success= process_map_wad(wad, false, header.data_version);
208 free_wad(wad); /* Note that the flat data points into the wad. */
209 }
210
211 return success;
212 }
213
214 /* This will have to do some interesting voodoo with union wads, methinks */
get_map_for_net_transfer(struct entry_point * entry)215 void *get_map_for_net_transfer(
216 struct entry_point *entry)
217 {
218 assert(file_is_set);
219
220 /* false means don't use union maps.. */
221 return get_flat_data(MapFileSpec, false, entry->level_number);
222 }
223
224 /* ---------------------- End Net Functions ----------- */
225
226 /* This takes a cstring */
set_map_file(FileSpecifier & File)227 void set_map_file(FileSpecifier& File)
228 {
229 // Do whatever parameter restoration is specified before changing the file
230 if (file_is_set) RunRestorationScript();
231
232 MapFileSpec = File;
233 set_scenario_images_file(File);
234 // Only need to do this here
235 LoadLevelScripts(File);
236
237 // Don't care whether there was an error when checking on the file's scenario images
238 clear_game_error();
239
240 file_is_set= true;
241 }
242
243 /* Set to the default map.. (Only if no map doubleclicked upon on startup.. */
set_to_default_map(void)244 void set_to_default_map(
245 void)
246 {
247 FileSpecifier NewMapFile;
248
249 get_default_map_spec(NewMapFile);
250 set_map_file(NewMapFile);
251 }
252
253 /* Return true if it finds the file, and it sets the mapfile to that file. */
254 /* Otherwise it returns false, meaning that we need have the file sent to us. */
use_map_file(uint32 checksum)255 bool use_map_file(
256 uint32 checksum)
257 {
258 FileSpecifier File;
259 bool success= false;
260
261 if(find_wad_file_that_has_checksum(File, _typecode_scenario, strPATHS, checksum))
262 {
263 set_map_file(File);
264 success= true;
265 }
266
267 return success;
268 }
269
load_level_from_map(short level_index)270 bool load_level_from_map(
271 short level_index)
272 {
273 OpenedFile OFile;
274 struct wad_header header;
275 struct wad_data *wad;
276 short index_to_load;
277 bool restoring_game= false;
278
279 if(file_is_set)
280 {
281 /* Determine what we are trying to do.. */
282 if(level_index==NONE)
283 {
284 restoring_game= true;
285 index_to_load= 0; /* Saved games are always index 0 */
286 } else {
287 index_to_load= level_index;
288 }
289
290 OpenedFile MapFile;
291 if (open_wad_file_for_reading(MapFileSpec,MapFile))
292 {
293 /* Read the file */
294 if(read_wad_header(MapFile, &header))
295 {
296 if(index_to_load>=0 && index_to_load<header.wad_count)
297 {
298
299 wad= read_indexed_wad_from_file(MapFile, &header, index_to_load, true);
300 if (wad)
301 {
302 /* Process everything... */
303 process_map_wad(wad, restoring_game, header.data_version);
304
305 /* Nuke our memory... */
306 free_wad(wad);
307 } else {
308 // error code has been set...
309 }
310 } else {
311 set_game_error(gameError, errWadIndexOutOfRange);
312 }
313 } else {
314 // error code has been set...
315 }
316
317 /* Close the file.. */
318 close_wad_file(MapFile);
319 } else {
320 // error code has been set..
321 }
322 } else {
323 set_game_error(gameError, errMapFileNotSet);
324 }
325
326 /* ... and bail */
327 return (!error_pending());
328 }
329
330 // keep these around for level export
331 static std::vector<static_platform_data> static_platforms;
332
333 extern bool ok_to_reset_scenery_solidity;
334
335 /* Hopefully this is in the correct order of initialization... */
336 /* This sucks, beavis. */
complete_loading_level(short * _map_indexes,size_t map_index_count,uint8 * _platform_data,size_t platform_data_count,uint8 * actual_platform_data,size_t actual_platform_data_count,short version)337 void complete_loading_level(
338 short *_map_indexes,
339 size_t map_index_count,
340 uint8 *_platform_data,
341 size_t platform_data_count,
342 uint8 *actual_platform_data,
343 size_t actual_platform_data_count,
344 short version)
345 {
346 /* Scan, add the doors, recalculate, and generally tie up all loose ends */
347 /* Recalculate the redundant data.. */
348 load_redundant_map_data(_map_indexes, map_index_count);
349
350 static_platforms.clear();
351
352 /* Add the platforms. */
353 if(_platform_data || (_platform_data==NULL && actual_platform_data==NULL))
354 {
355 scan_and_add_platforms(_platform_data, platform_data_count, version);
356 } else {
357 assert(actual_platform_data);
358 PlatformList.resize(actual_platform_data_count);
359 unpack_platform_data(actual_platform_data,platforms,actual_platform_data_count);
360 assert(actual_platform_data_count == static_cast<size_t>(static_cast<int16>(actual_platform_data_count)));
361 assert(0 <= static_cast<int16>(actual_platform_data_count));
362 dynamic_world->platform_count= static_cast<int16>(actual_platform_data_count);
363 }
364
365 scan_and_add_scenery();
366 ok_to_reset_scenery_solidity = true;
367
368 /* Gotta do this after recalculate redundant.. */
369 if(version==MARATHON_ONE_DATA_VERSION)
370 {
371 short loop;
372
373 for(loop= 0; loop<dynamic_world->side_count; ++loop)
374 {
375 guess_side_lightsource_indexes(loop);
376 if (static_world->environment_flags&_environment_vacuum)
377 {
378 side_data *side= get_side_data(loop);
379 if (side->flags&_side_is_control_panel)
380 side->flags |= _side_is_lighted_switch;
381 }
382 }
383 }
384 }
385
386 /* Call with location of NULL to get the number of start locations for a */
387 /* given team or player */
get_player_starting_location_and_facing(short team,short index,struct object_location * location)388 short get_player_starting_location_and_facing(
389 short team,
390 short index,
391 struct object_location *location)
392 {
393 short ii;
394 struct map_object *saved_object;
395 short count= 0;
396 bool done= false;
397
398 saved_object= saved_objects;
399 for(ii=0; !done && ii<dynamic_world->initial_objects_count; ++ii)
400 {
401 if(saved_object->type==_saved_player)
402 {
403 /* index=NONE means use any starting location */
404 if(saved_object->index==team || team==NONE)
405 {
406 if(location && count==index)
407 {
408 location->p= saved_object->location;
409 location->polygon_index= saved_object->polygon_index;
410 location->yaw= saved_object->facing;
411 location->pitch= 0;
412 location->flags= saved_object->flags;
413 done= true;
414 }
415 count++;
416 }
417 }
418 ++saved_object;
419 }
420
421 /* If they asked for a valid location, make sure that we gave them one */
422 if(location) vassert(done, csprintf(temporary, "Tried to place: %d only %d starting pts.", index, count));
423
424 return count;
425 }
426
get_current_map_checksum(void)427 uint32 get_current_map_checksum(
428 void)
429 {
430 // fileref file_handle;
431 struct wad_header header;
432
433 assert(file_is_set);
434 OpenedFile MapFile;
435 open_wad_file_for_reading(MapFileSpec, MapFile);
436 assert(MapFile.IsOpen());
437
438 /* Read the file */
439 read_wad_header(MapFile, &header);
440
441 /* Close the file.. */
442 close_wad_file(MapFile);
443
444 return header.checksum;
445 }
446
447 // ZZZ: split this out from new_game for sharing
set_saved_game_name_to_default()448 void set_saved_game_name_to_default()
449 {
450 revert_game_data.SavedGame.SetToSavedGamesDir();
451 revert_game_data.SavedGame += getcstr(temporary, strFILENAMES, filenameDEFAULT_SAVE_GAME);
452 }
453
454 extern void ResetPassedLua();
455
new_game(short number_of_players,bool network,struct game_data * game_information,struct player_start_data * player_start_information,struct entry_point * entry_point)456 bool new_game(
457 short number_of_players,
458 bool network,
459 struct game_data *game_information,
460 struct player_start_data *player_start_information,
461 struct entry_point *entry_point)
462 {
463 assert(!network || number_of_players == NetGetNumberOfPlayers());
464
465 const short intended_local_player_index = network ? NetGetLocalPlayerIndex() : 0;
466
467 short player_index, i;
468 bool success= true;
469
470 ResetPassedLua();
471
472 /* Make sure our code is synchronized.. */
473 assert(MAXIMUM_PLAYER_START_NAME_LENGTH==MAXIMUM_PLAYER_NAME_LENGTH);
474
475 /* Initialize the global network going flag... */
476 game_is_networked= network;
477
478 /* If we want to save it, this is an untitled map.. */
479 set_saved_game_name_to_default();
480
481 /* Set the random seed. */
482 set_random_seed(game_information->initial_random_seed);
483
484 /* Initialize the players to a known state. This must be done before goto_level */
485 /* because it sets dynamic_world->player_count to 0, which is crucial for when */
486 /* I try to recreate the players... */
487 initialize_map_for_new_game(); // memsets dynamic_world to 0
488
489 /* Copy the game data into the dynamic_world */
490 /* ajr-this used to be done only when we successfully loaded the map. however, goto_level
491 * will place the initial monsters on a level, which calls new_monster, which relies
492 * on this information being setup properly, so we do it here instead. */
493 obj_copy(dynamic_world->game_information, *game_information);
494
495 /* Load the level */
496 assert(file_is_set);
497 success= goto_level(entry_point, true, number_of_players);
498 /* If we were able to load the map... */
499 if(success)
500 {
501 /* Initialize the players-> note there may be more than one player in a */
502 /* non-network game, for playback.. */
503 for (i=0;i<number_of_players;++i)
504 {
505 new_player_flags flags = (i == intended_local_player_index ? new_player_make_local_and_current : 0);
506 player_index= new_player(player_start_information[i].team,
507 player_start_information[i].color, player_start_information[i].identifier, flags);
508 assert(player_index==i);
509
510 /* Now copy in the name of the player.. */
511 assert(strlen(player_start_information[i].name)<=MAXIMUM_PLAYER_NAME_LENGTH);
512 strncpy(players[i].name, player_start_information[i].name, MAXIMUM_PLAYER_NAME_LENGTH+1);
513 }
514
515 /* we need to alert the function that reverts the game of the game setup so that
516 * new game can be called if the user wants to revert later.
517 */
518 setup_revert_game_info(game_information, player_start_information, entry_point);
519
520 // Reset the player queues (done here and in load_game)
521 reset_action_queues();
522
523 /* Load the collections */
524 /* entering map might fail if NetSync() fails.. */
525 success= entering_map(false);
526
527 // ZZZ: set motion sensor to sane state - needs to come after entering_map() (which calls load_collections())
528 reset_motion_sensor(current_player_index);
529 }
530
531 // LP change: adding chase-cam initialization
532 ChaseCam_Initialize();
533
534 return success;
535 }
536
get_indexed_entry_point(struct entry_point * entry_point,short * index,int32 type)537 bool get_indexed_entry_point(
538 struct entry_point *entry_point,
539 short *index,
540 int32 type)
541 {
542 short actual_index;
543
544 // Open map file
545 assert(file_is_set);
546 OpenedFile MapFile;
547 if (!open_wad_file_for_reading(MapFileSpec,MapFile))
548 return false;
549
550 // Read header
551 wad_header header;
552 if (!read_wad_header(MapFile, &header)) {
553 close_wad_file(MapFile);
554 return false;
555 }
556
557 bool success = false;
558 if (header.application_specific_directory_data_size == SIZEOF_directory_data)
559 {
560
561 // New style wad
562 void *total_directory_data= read_directory_data(MapFile, &header);
563
564 assert(total_directory_data);
565 for(actual_index= *index; actual_index<header.wad_count; ++actual_index)
566 {
567 uint8 *p = (uint8 *)get_indexed_directory_data(&header, actual_index, total_directory_data);
568 directory_data directory;
569 unpack_directory_data(p, &directory, 1);
570
571 /* Find the flags that match.. */
572 if(directory.entry_point_flags & type)
573 {
574 /* This one is valid! */
575 entry_point->level_number= actual_index;
576 strncpy(entry_point->level_name, directory.level_name, 66);
577
578 *index= actual_index+1;
579 success= true;
580 break; /* Out of the for loop */
581 }
582 }
583 free(total_directory_data);
584
585 } else {
586
587 // Old style wad, find the index
588 for(actual_index= *index; !success && actual_index<header.wad_count; ++actual_index)
589 {
590 struct wad_data *wad;
591
592 /* Read the file */
593 wad= read_indexed_wad_from_file(MapFile, &header, actual_index, true);
594 if (wad)
595 {
596 /* IF this has the proper type.. */
597 size_t length;
598 uint8 *p = (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &length);
599 assert(length == SIZEOF_static_data);
600 static_data map_info;
601 unpack_static_data(p, &map_info, 1);
602
603 // single-player Marathon 1 levels aren't always marked
604 if (header.data_version == MARATHON_ONE_DATA_VERSION &&
605 map_info.entry_point_flags == 0)
606 map_info.entry_point_flags = _single_player_entry_point;
607
608 // Marathon 1 handled (then-unused) coop flag differently
609 if (header.data_version == MARATHON_ONE_DATA_VERSION)
610 {
611 if (map_info.entry_point_flags & _single_player_entry_point)
612 map_info.entry_point_flags |= _multiplayer_cooperative_entry_point;
613 if (map_info.entry_point_flags & _multiplayer_carnage_entry_point)
614 map_info.entry_point_flags &= ~_multiplayer_cooperative_entry_point;
615 }
616
617 if(map_info.entry_point_flags & type)
618 {
619 /* This one is valid! */
620 entry_point->level_number= actual_index;
621 assert(strlen(map_info.level_name)<LEVEL_NAME_LENGTH);
622 strncpy(entry_point->level_name, map_info.level_name, 66);
623
624 *index= actual_index+1;
625 success= true;
626 }
627
628 free_wad(wad);
629 }
630 }
631 }
632
633 return success;
634 }
635
636 // Get vector of map entry points matching given type
get_entry_points(vector<entry_point> & vec,int32 type)637 bool get_entry_points(vector<entry_point> &vec, int32 type)
638 {
639 vec.clear();
640
641 // Open map file
642 assert(file_is_set);
643 OpenedFile MapFile;
644 if (!open_wad_file_for_reading(MapFileSpec,MapFile))
645 return false;
646
647 // Read header
648 wad_header header;
649 if (!read_wad_header(MapFile, &header)) {
650 close_wad_file(MapFile);
651 return false;
652 }
653
654 bool success = false;
655 if (header.application_specific_directory_data_size == SIZEOF_directory_data) {
656
657 // New style wad, read directory data
658 void *total_directory_data = read_directory_data(MapFile, &header);
659 assert(total_directory_data);
660
661 // Push matching directory entries into vector
662 for (int i=0; i<header.wad_count; i++) {
663 uint8 *p = (uint8 *)get_indexed_directory_data(&header, i, total_directory_data);
664 directory_data directory;
665 unpack_directory_data(p, &directory, 1);
666
667 if (directory.entry_point_flags & type) {
668
669 // This one is valid
670 entry_point point;
671 point.level_number = i;
672 strncpy(point.level_name, directory.level_name, 66);
673 vec.push_back(point);
674 success = true;
675 }
676 }
677 free(total_directory_data);
678
679 } else {
680
681 // Old style wad
682 for (int i=0; i<header.wad_count; i++) {
683
684 wad_data *wad = read_indexed_wad_from_file(MapFile, &header, i, true);
685 if (!wad)
686 continue;
687
688 // Read map_info data
689 size_t length;
690 uint8 *p = (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &length);
691 assert(length == SIZEOF_static_data);
692 static_data map_info;
693 unpack_static_data(p, &map_info, 1);
694
695 // single-player Marathon 1 levels aren't always marked
696 if (header.data_version == MARATHON_ONE_DATA_VERSION &&
697 map_info.entry_point_flags == 0)
698 map_info.entry_point_flags = _single_player_entry_point;
699
700 // Marathon 1 handled (then-unused) coop flag differently
701 if (header.data_version == MARATHON_ONE_DATA_VERSION)
702 {
703 if (map_info.entry_point_flags & _single_player_entry_point)
704 map_info.entry_point_flags |= _multiplayer_cooperative_entry_point;
705 if (map_info.entry_point_flags & _multiplayer_carnage_entry_point)
706 map_info.entry_point_flags &= ~_multiplayer_cooperative_entry_point;
707 }
708
709 if (map_info.entry_point_flags & type) {
710
711 // This one is valid
712 entry_point point;
713 point.level_number = i;
714 assert(strlen(map_info.level_name) < LEVEL_NAME_LENGTH);
715 strncpy(point.level_name, map_info.level_name, 66);
716 vec.push_back(point);
717 success = true;
718 }
719
720 free_wad(wad);
721 }
722 }
723
724 return success;
725 }
726
727 extern void LoadSoloLua();
728 extern void LoadReplayNetLua();
729 extern void LoadStatsLua();
730 extern void RunLuaScript();
731
732 /* This is called when the game level is changed somehow */
733 /* The only thing that has to be valid in the entry point is the level_index */
734
735 /* Returns a short that is an OSErr... */
goto_level(struct entry_point * entry,bool new_game,short number_of_players)736 bool goto_level(
737 struct entry_point *entry,
738 bool new_game,
739 short number_of_players)
740 {
741 bool success= true;
742
743 if(!new_game)
744 {
745 /* Clear the current map */
746 leaving_map();
747
748 // ghs: hack to get new MML-specified sounds loaded
749 SoundManager::instance()->UnloadAllSounds();
750 }
751
752 #if !defined(DISABLE_NETWORKING)
753 /* If the game is networked, then I must call the network code to do the right */
754 /* thing with the map.. */
755 if(game_is_networked)
756 {
757 /* This function, if it is a server, calls get_map_for_net_transfer, and */
758 /* then calls process_map_wad on it. Non-server receives the map and then */
759 /* calls process_map_wad on it. */
760 success= NetChangeMap(entry);
761 }
762 else
763 #endif // !defined(DISABLE_NETWORKING)
764 {
765 /* Load it and then rock.. */
766 load_level_from_map(entry->level_number);
767 if(error_pending()) success= false;
768 }
769
770 if (success)
771 {
772 // LP: doing this here because level-specific MML may specify which level-specific
773 // textures to load.
774 // Being careful to carry over errors so that Pfhortran errors can be ignored
775 short SavedType, SavedError = get_game_error(&SavedType);
776 if (!game_is_networked || use_map_file(((game_info *) NetGetGameData())->parent_checksum))
777 {
778 RunLevelScript(entry->level_number);
779 }
780 else
781 {
782 ResetLevelScript();
783 }
784 RunScriptChunks();
785 if (!game_is_networked && number_of_players == 1)
786 {
787 LoadSoloLua();
788 }
789 else if (!game_is_networked)
790 {
791 LoadReplayNetLua();
792 }
793 LoadStatsLua();
794
795 Music::instance()->PreloadLevelMusic();
796 set_game_error(SavedType,SavedError);
797
798 if (!new_game)
799 {
800 recreate_players_for_new_level();
801 }
802
803 /* Load the collections */
804 dynamic_world->current_level_number= entry->level_number;
805
806 // ghs: this runs very early now
807 // we want to be before place_initial_objects, and
808 // before MarkLuaCollections
809 RunLuaScript();
810
811 if (film_profile.early_object_initialization)
812 {
813 place_initial_objects();
814 initialize_control_panels_for_level();
815 }
816
817 if (!new_game)
818 {
819
820 /* entering_map might fail if netsync fails, but we will have already displayed */
821 /* the error.. */
822 success= entering_map(false);
823 }
824
825 if (!film_profile.early_object_initialization && success)
826 {
827 place_initial_objects();
828 initialize_control_panels_for_level();
829 }
830
831 }
832
833 // if(!success) alert_user(fatalError, strERRORS, badReadMap, -1);
834
835 /* We be done.. */
836 return success;
837 }
838
839 /* -------------------- Private or map editor functions */
allocate_map_for_counts(size_t polygon_count,size_t side_count,size_t endpoint_count,size_t line_count)840 void allocate_map_for_counts(
841 size_t polygon_count,
842 size_t side_count,
843 size_t endpoint_count,
844 size_t line_count)
845 {
846 //long cumulative_length= 0;
847 size_t automap_line_count, automap_polygon_count, map_index_count;
848 // long automap_line_length, automap_polygon_length, map_index_length;
849
850 /* Give the map indexes a whole bunch of memory (cause we can't calculate it) */
851 // map_index_length= (polygon_count*32+1024)*sizeof(int16);
852 map_index_count= (polygon_count*32+1024);
853
854 /* Automap lines. */
855 // automap_line_length= (line_count/8+((line_count%8)?1:0))*sizeof(byte);
856 automap_line_count= (line_count/8+((line_count%8)?1:0));
857
858 /* Automap Polygons */
859 // automap_polygon_length= (polygon_count/8+((polygon_count%8)?1:0))*sizeof(byte);
860 automap_polygon_count= (polygon_count/8+((polygon_count%8)?1:0));
861
862 // cumulative_length+= polygon_count*sizeof(struct polygon_data);
863 // cumulative_length+= side_count*sizeof(struct side_data);
864 // cumulative_length+= endpoint_count*sizeof(struct endpoint_data);
865 // cumulative_length+= line_count*sizeof(struct line_data);
866 // cumulative_length+= map_index_length;
867 // cumulative_length+= automap_line_length;
868 // cumulative_length+= automap_polygon_length;
869
870 /* Okay, we now have the length. Allocate our block.. */
871 // reallocate_map_structure_memory(cumulative_length);
872
873 /* Tell the recalculation data how big it is.. */
874 // set_map_index_buffer_size(map_index_length);
875
876 /* Setup our pointers. */
877 // map_polygons= (struct polygon_data *) get_map_structure_chunk(polygon_count*sizeof(struct polygon_data));
878 // map_sides= (struct side_data *) get_map_structure_chunk(side_count*sizeof(struct side_data));
879 // map_endpoints= (struct endpoint_data *) get_map_structure_chunk(endpoint_count*sizeof(struct endpoint_data));
880 // map_lines= (struct line_data *) get_map_structure_chunk(line_count*sizeof(struct line_data));
881 // map_indexes= (short *) get_map_structure_chunk(map_index_length);
882 // automap_lines= (uint8 *) get_map_structure_chunk(automap_line_length);
883 // automap_polygons= (uint8 *) get_map_structure_chunk(automap_polygon_length);
884
885 // Most of the other stuff: reallocate here
886 EndpointList.resize(endpoint_count);
887 LineList.resize(line_count);
888 SideList.resize(side_count);
889 PolygonList.resize(polygon_count);
890 AutomapLineList.resize(automap_line_count);
891 AutomapPolygonList.resize(automap_polygon_count);
892
893 // Map indexes: start off with none of them (of course),
894 // but reserve a size equal to the map index length
895 MapIndexList.clear();
896 MapIndexList.reserve(map_index_count);
897 dynamic_world->map_index_count= 0;
898
899 // Stuff that needs the max number of polygons
900 allocate_render_memory();
901 allocate_flood_map_memory();
902 }
903
load_points(uint8 * points,size_t count)904 void load_points(
905 uint8 *points,
906 size_t count)
907 {
908 size_t loop;
909
910 // OK to modify input-data pointer since it's called by value
911 for(loop=0; loop<count; ++loop)
912 {
913 world_point2d& vertex = map_endpoints[loop].vertex;
914 StreamToValue(points,vertex.x);
915 StreamToValue(points,vertex.y);
916 }
917 assert(count == static_cast<size_t>(static_cast<int16>(count)));
918 assert(0 <= static_cast<int16>(count));
919 dynamic_world->endpoint_count= static_cast<int16>(count);
920 }
921
load_lines(uint8 * lines,size_t count)922 void load_lines(
923 uint8 *lines,
924 size_t count)
925 {
926 // assert(count>=0 && count<=MAXIMUM_LINES_PER_MAP);
927 unpack_line_data(lines,map_lines,count);
928 assert(count == static_cast<size_t>(static_cast<int16>(count)));
929 assert(0 <= static_cast<int16>(count));
930 dynamic_world->line_count= static_cast<int16>(count);
931 }
932
load_sides(uint8 * sides,size_t count,short version)933 void load_sides(
934 uint8 *sides,
935 size_t count,
936 short version)
937 {
938 size_t loop;
939
940 // assert(count>=0 && count<=MAXIMUM_SIDES_PER_MAP);
941
942 unpack_side_data(sides,map_sides,count);
943
944 for(loop=0; loop<count; ++loop)
945 {
946 if(version==MARATHON_ONE_DATA_VERSION)
947 {
948 map_sides[loop].transparent_texture.texture= UNONE;
949 map_sides[loop].ambient_delta= 0;
950 map_sides[loop].flags |= _side_item_is_optional;
951 }
952 ++sides;
953 }
954
955 assert(count == static_cast<size_t>(static_cast<int16>(count)));
956 assert(0 <= static_cast<int16>(count));
957 dynamic_world->side_count= static_cast<int16>(count);
958 }
959
load_polygons(uint8 * polys,size_t count,short version)960 void load_polygons(
961 uint8 *polys,
962 size_t count,
963 short version)
964 {
965 size_t loop;
966
967 // assert(count>=0 && count<=MAXIMUM_POLYGONS_PER_MAP);
968
969 unpack_polygon_data(polys,map_polygons,count);
970 assert(count == static_cast<size_t>(static_cast<int16>(count)));
971 assert(0 <= static_cast<int16>(count));
972 dynamic_world->polygon_count= static_cast<int16>(count);
973
974 /* Allow for backward compatibility! */
975 switch(version)
976 {
977 case MARATHON_ONE_DATA_VERSION:
978 for(loop= 0; loop<count; ++loop)
979 {
980 map_polygons[loop].media_index= NONE;
981 map_polygons[loop].floor_origin.x= map_polygons[loop].floor_origin.y= 0;
982 map_polygons[loop].ceiling_origin.x= map_polygons[loop].ceiling_origin.y= 0;
983
984 switch (map_polygons[loop].type)
985 {
986 case _polygon_is_hill:
987 map_polygons[loop].type = _polygon_is_minor_ouch;
988 break;
989 case _polygon_is_base:
990 map_polygons[loop].type = _polygon_is_major_ouch;
991 break;
992 case _polygon_is_zone_border:
993 map_polygons[loop].type = _polygon_is_glue;
994 break;
995 case _polygon_is_goal:
996 map_polygons[loop].type = _polygon_is_glue_trigger;
997 break;
998 case _polygon_is_visible_monster_trigger:
999 map_polygons[loop].type = _polygon_is_superglue;
1000 break;
1001 case _polygon_is_invisible_monster_trigger:
1002 map_polygons[loop].type = _polygon_must_be_explored;
1003 break;
1004 case _polygon_is_dual_monster_trigger:
1005 map_polygons[loop].type = _polygon_is_automatic_exit;
1006 break;
1007 }
1008 }
1009 break;
1010
1011 case MARATHON_TWO_DATA_VERSION:
1012 // LP addition:
1013 case MARATHON_INFINITY_DATA_VERSION:
1014 break;
1015
1016 default:
1017 assert(false);
1018 break;
1019 }
1020 }
1021
load_lights(uint8 * _lights,size_t count,short version)1022 void load_lights(
1023 uint8 *_lights,
1024 size_t count,
1025 short version)
1026 {
1027 unsigned short loop, new_index;
1028
1029 LightList.resize(count);
1030 objlist_clear(lights,count);
1031 // vassert(count>=0 && count<=MAXIMUM_LIGHTS_PER_MAP, csprintf(temporary, "Light count: %d vers: %d",
1032 // count, version));
1033
1034 old_light_data *OldLights;
1035
1036 switch(version)
1037 {
1038 case MARATHON_ONE_DATA_VERSION: {
1039
1040 // Unpack the old lights into a temporary array
1041 OldLights = new old_light_data[count];
1042 unpack_old_light_data(_lights,OldLights,count);
1043
1044 old_light_data *OldLtPtr = OldLights;
1045 for(loop= 0; loop<count; ++loop, OldLtPtr++)
1046 {
1047 static_light_data TempLight;
1048 convert_old_light_data_to_new(&TempLight, OldLtPtr, 1);
1049
1050 new_index = new_light(&TempLight);
1051 assert(new_index==loop);
1052 }
1053 delete []OldLights;
1054 break;
1055 }
1056
1057 case MARATHON_TWO_DATA_VERSION:
1058 case MARATHON_INFINITY_DATA_VERSION:
1059 // OK to modify the data pointer since it was passed by value
1060 for(loop= 0; loop<count; ++loop)
1061 {
1062 static_light_data TempLight;
1063 _lights = unpack_static_light_data(_lights, &TempLight, 1);
1064
1065 new_index = new_light(&TempLight);
1066 assert(new_index==loop);
1067 }
1068 break;
1069
1070 default:
1071 assert(false);
1072 break;
1073 }
1074 }
1075
load_annotations(uint8 * annotations,size_t count)1076 void load_annotations(
1077 uint8 *annotations,
1078 size_t count)
1079 {
1080 // assert(count>=0 && count<=MAXIMUM_ANNOTATIONS_PER_MAP);
1081 MapAnnotationList.resize(count);
1082 unpack_map_annotation(annotations,map_annotations,count);
1083 assert(count == static_cast<size_t>(static_cast<int16>(count)));
1084 assert(0 <= static_cast<int16>(count));
1085 dynamic_world->default_annotation_count= static_cast<int16>(count);
1086 }
1087
load_objects(uint8 * map_objects,size_t count)1088 void load_objects(uint8 *map_objects, size_t count)
1089 {
1090 // assert(count>=0 && count<=MAXIMUM_SAVED_OBJECTS);
1091 SavedObjectList.resize(count);
1092 unpack_map_object(map_objects,saved_objects,count);
1093 assert(count == static_cast<size_t>(static_cast<int16>(count)));
1094 assert(0 <= static_cast<int16>(count));
1095 dynamic_world->initial_objects_count= static_cast<int16>(count);
1096 }
1097
load_map_info(uint8 * map_info)1098 void load_map_info(
1099 uint8 *map_info)
1100 {
1101 unpack_static_data(map_info,static_world,1);
1102 static_world->ball_in_play = false;
1103 }
1104
load_media(uint8 * _medias,size_t count)1105 void load_media(
1106 uint8 *_medias,
1107 size_t count)
1108 {
1109 // struct media_data *media= _medias;
1110 size_t ii;
1111
1112 MediaList.resize(count);
1113 objlist_clear(medias,count);
1114 // assert(count>=0 && count<=MAXIMUM_MEDIAS_PER_MAP);
1115
1116 for(ii= 0; ii<count; ++ii)
1117 {
1118 media_data TempMedia;
1119 _medias = unpack_media_data(_medias,&TempMedia,1);
1120
1121 size_t new_index = new_media(&TempMedia);
1122 assert(new_index==ii);
1123 }
1124 }
1125
load_ambient_sound_images(uint8 * data,size_t count)1126 void load_ambient_sound_images(
1127 uint8 *data,
1128 size_t count)
1129 {
1130 // assert(count>=0 &&count<=MAXIMUM_AMBIENT_SOUND_IMAGES_PER_MAP);
1131 AmbientSoundImageList.resize(count);
1132 unpack_ambient_sound_image_data(data,ambient_sound_images,count);
1133 assert(count == static_cast<size_t>(static_cast<int16>(count)));
1134 assert(0 <= static_cast<int16>(count));
1135 dynamic_world->ambient_sound_image_count= static_cast<int16>(count);
1136 }
1137
load_random_sound_images(uint8 * data,size_t count)1138 void load_random_sound_images(
1139 uint8 *data,
1140 size_t count)
1141 {
1142 // assert(count>=0 &&count<=MAXIMUM_RANDOM_SOUND_IMAGES_PER_MAP);
1143 RandomSoundImageList.resize(count);
1144 unpack_random_sound_image_data(data,random_sound_images,count);
1145 assert(count == static_cast<size_t>(static_cast<int16>(count)));
1146 assert(0 <= static_cast<int16>(count));
1147 dynamic_world->random_sound_image_count= static_cast<int16>(count);
1148 }
1149
1150 /* Recalculate all the redundant crap- must be done before platforms/doors/etc.. */
recalculate_redundant_map(void)1151 void recalculate_redundant_map(
1152 void)
1153 {
1154 short loop;
1155
1156 for(loop=0;loop<dynamic_world->polygon_count;++loop) recalculate_redundant_polygon_data(loop);
1157 for(loop=0;loop<dynamic_world->line_count;++loop) recalculate_redundant_line_data(loop);
1158 for(loop=0;loop<dynamic_world->endpoint_count;++loop) recalculate_redundant_endpoint_data(loop);
1159 }
1160
load_game_from_file(FileSpecifier & File,bool run_scripts,bool * was_map_found)1161 bool load_game_from_file(FileSpecifier& File, bool run_scripts, bool *was_map_found)
1162 {
1163 bool success= false;
1164
1165 ResetPassedLua();
1166
1167 /* Setup for a revert.. */
1168 revert_game_data.game_is_from_disk = true;
1169 revert_game_data.SavedGame = File;
1170
1171 /* Use the save game file.. */
1172 set_map_file(File);
1173
1174 /* Load the level from the map */
1175 success= load_level_from_map(NONE); /* Save games are ALWAYS index NONE */
1176 if (success)
1177 {
1178 uint32 parent_checksum;
1179
1180 /* Find the original scenario this saved game was a part of.. */
1181 parent_checksum= read_wad_file_parent_checksum(File);
1182 bool found_map = use_map_file(parent_checksum);
1183 if (was_map_found)
1184 {
1185 *was_map_found = found_map;
1186 }
1187 if (!found_map)
1188 {
1189 /* Tell the user theyÕre screwed when they try to leave this level. */
1190 alert_user(infoError, strERRORS, cantFindMap, 0);
1191
1192 // LP addition: makes the game look normal
1193 hide_cursor();
1194
1195 /* Set to the default map. */
1196 set_to_default_map();
1197 }
1198
1199 if (run_scripts)
1200 {
1201 // LP: getting the level scripting off of the map file
1202 // Being careful to carry over errors so that Pfhortran errors can be ignored
1203 short SavedType, SavedError = get_game_error(&SavedType);
1204 if (found_map)
1205 {
1206 RunLevelScript(dynamic_world->current_level_number);
1207 }
1208 else
1209 {
1210 ResetLevelScript();
1211 }
1212 RunScriptChunks();
1213 if (!game_is_networked)
1214 {
1215 LoadSoloLua();
1216 }
1217 LoadStatsLua();
1218 set_game_error(SavedType,SavedError);
1219 }
1220 }
1221
1222 return success;
1223 }
1224
setup_revert_game_info(struct game_data * game_info,struct player_start_data * start,struct entry_point * entry)1225 void setup_revert_game_info(
1226 struct game_data *game_info,
1227 struct player_start_data *start,
1228 struct entry_point *entry)
1229 {
1230 revert_game_data.game_is_from_disk = false;
1231 obj_copy(revert_game_data.game_information, *game_info);
1232 obj_copy(revert_game_data.player_start, *start);
1233 obj_copy(revert_game_data.entry_point, *entry);
1234 }
1235
1236 extern void reset_messages();
1237
revert_game(void)1238 bool revert_game(
1239 void)
1240 {
1241 bool successful;
1242
1243 assert(dynamic_world->player_count==1);
1244
1245 leaving_map();
1246
1247 if (revert_game_data.game_is_from_disk)
1248 {
1249 /* Reload their last saved game.. */
1250 successful= load_game_from_file(revert_game_data.SavedGame, true, NULL);
1251 if (successful)
1252 {
1253 Music::instance()->PreloadLevelMusic();
1254 RunLuaScript();
1255
1256 // LP: added for loading the textures if one had died on another level;
1257 // this gets around WZ's moving of this line into make_restored_game_relevant()
1258 successful = entering_map(true /*restoring game*/);
1259 }
1260
1261 /* And they don't get to continue. */
1262 stop_recording();
1263 }
1264 else
1265 {
1266 /* This was the totally evil line discussed above. */
1267 successful= new_game(1, false, &revert_game_data.game_information, &revert_game_data.player_start,
1268 &revert_game_data.entry_point);
1269
1270 /* And rewind so that the last player is used. */
1271 rewind_recording();
1272 }
1273
1274 if(successful)
1275 {
1276 update_interface(NONE);
1277 ChaseCam_Reset();
1278 ResetFieldOfView();
1279 reset_messages();
1280 ReloadViewContext();
1281 }
1282
1283 return successful;
1284 }
1285
export_level(FileSpecifier & File)1286 bool export_level(FileSpecifier& File)
1287 {
1288 struct wad_header header;
1289 short err = 0;
1290 bool success = false;
1291 int32 offset, wad_length;
1292 struct directory_entry entry;
1293 struct wad_data *wad;
1294
1295 FileSpecifier TempFile;
1296 TempFile.SetTempName(File);
1297
1298 /* Fill in the default wad header (we are using File instead of TempFile to get the name right in the header) */
1299 fill_default_wad_header(File, CURRENT_WADFILE_VERSION, MARATHON_TWO_DATA_VERSION, 1, 0, &header);
1300
1301 if (create_wadfile(TempFile, _typecode_scenario))
1302 {
1303 OpenedFile SaveFile;
1304 if (open_wad_file_for_writing(TempFile, SaveFile))
1305 {
1306 /* Write out the new header */
1307 if (write_wad_header(SaveFile, &header))
1308 {
1309 offset = SIZEOF_wad_header;
1310
1311 wad = build_export_wad(&header, &wad_length);
1312 if (wad)
1313 {
1314 set_indexed_directory_offset_and_length(&header, &entry, 0, offset, wad_length, 0);
1315
1316 if (write_wad(SaveFile, &header, wad, offset))
1317 {
1318 /* Update the new header */
1319 offset+= wad_length;
1320 header.directory_offset= offset;
1321 if (write_wad_header(SaveFile, &header) && write_directorys(SaveFile, &header, &entry))
1322 {
1323 /* We win. */
1324 success= true;
1325 }
1326 }
1327
1328 free_wad(wad);
1329 }
1330 }
1331
1332 err = SaveFile.GetError();
1333 calculate_and_store_wadfile_checksum(SaveFile);
1334 close_wad_file(SaveFile);
1335 }
1336
1337 if (!err)
1338 {
1339 // We can't delete open files on Windows, so close
1340 // the current level before we overwrite it.
1341 bool restore_images = false;
1342 if (File == get_map_file())
1343 {
1344 unset_scenario_images_file();
1345 restore_images = true;
1346 }
1347 if (!TempFile.Rename(File))
1348 {
1349 err = 1;
1350 }
1351 if (restore_images)
1352 {
1353 set_scenario_images_file(File);
1354 clear_game_error();
1355 }
1356 }
1357 }
1358
1359 if (err || error_pending())
1360 {
1361 success = false;
1362 }
1363
1364
1365 return success;
1366
1367 }
1368
get_current_saved_game_name(FileSpecifier & File)1369 void get_current_saved_game_name(FileSpecifier& File)
1370 {
1371 File = revert_game_data.SavedGame;
1372 }
1373
1374 /* The current mapfile should be set to the save game file... */
save_game_file(FileSpecifier & File,const std::string & metadata,const std::string & imagedata)1375 bool save_game_file(FileSpecifier& File, const std::string& metadata, const std::string& imagedata)
1376 {
1377 struct wad_header header;
1378 short err = 0;
1379 bool success= false;
1380 int32 offset, wad_length;
1381 struct directory_entry entries[2];
1382 struct wad_data *wad, *meta_wad;
1383
1384 /* Save off the random seed. */
1385 dynamic_world->random_seed= get_random_seed();
1386
1387 /* Setup to revert the game properly */
1388 revert_game_data.game_is_from_disk= true;
1389 revert_game_data.SavedGame = File;
1390
1391 // LP: add a file here; use temporary file for a safe save.
1392 // Write into the temporary file first
1393 FileSpecifier TempFile;
1394 TempFile.SetTempName(File);
1395
1396 /* Fill in the default wad header (we are using File instead of TempFile to get the name right in the header) */
1397 fill_default_wad_header(File, CURRENT_WADFILE_VERSION, EDITOR_MAP_VERSION, 2, 0, &header);
1398
1399 /* Assume that we confirmed on save as... */
1400 if (create_wadfile(TempFile,_typecode_savegame))
1401 {
1402 OpenedFile SaveFile;
1403 if(open_wad_file_for_writing(TempFile,SaveFile))
1404 {
1405 /* Write out the new header */
1406 if (write_wad_header(SaveFile, &header))
1407 {
1408 offset= SIZEOF_wad_header;
1409
1410 wad= build_save_game_wad(&header, &wad_length);
1411 if (wad)
1412 {
1413 /* Set the entry data.. */
1414 set_indexed_directory_offset_and_length(&header,
1415 entries, 0, offset, wad_length, 0);
1416
1417 /* Save it.. */
1418 if (write_wad(SaveFile, &header, wad, offset))
1419 {
1420 /* Update the new header */
1421 offset+= wad_length;
1422 header.directory_offset= offset;
1423 header.parent_checksum= read_wad_file_checksum(MapFileSpec);
1424
1425 /* Create metadata wad */
1426 meta_wad = build_meta_game_wad(metadata, imagedata, &header, &wad_length);
1427 if (meta_wad)
1428 {
1429 set_indexed_directory_offset_and_length(&header,
1430 entries, 1, offset, wad_length, SAVE_GAME_METADATA_INDEX);
1431
1432 if (write_wad(SaveFile, &header, meta_wad, offset))
1433 {
1434 offset+= wad_length;
1435 header.directory_offset= offset;
1436
1437 if (write_wad_header(SaveFile, &header) && write_directorys(SaveFile, &header, entries))
1438 {
1439 /* We win. */
1440 success= true;
1441 }
1442 }
1443
1444 free_wad(meta_wad);
1445 }
1446 }
1447
1448 free_wad(wad);
1449 }
1450 }
1451
1452 err = SaveFile.GetError();
1453 close_wad_file(SaveFile);
1454 }
1455
1456 if (!err)
1457 {
1458 if (!TempFile.Rename(File))
1459 {
1460 err = 1;
1461 }
1462 }
1463 }
1464
1465 if(err || error_pending())
1466 {
1467 if(!err) err= get_game_error(NULL);
1468 alert_user(infoError, strERRORS, fileError, err);
1469 clear_game_error();
1470 success= false;
1471 }
1472
1473 return success;
1474 }
1475
1476 /* -------- static functions */
scan_and_add_platforms(uint8 * platform_static_data,size_t count,short version)1477 static void scan_and_add_platforms(
1478 uint8 *platform_static_data,
1479 size_t count,
1480 short version)
1481 {
1482 struct polygon_data *polygon;
1483 short loop;
1484
1485 PlatformList.resize(count);
1486 objlist_clear(platforms,count);
1487
1488 static_platforms.resize(count);
1489 unpack_static_platform_data(platform_static_data, static_platforms.data(), count);
1490
1491 polygon= map_polygons;
1492 for(loop=0; loop<dynamic_world->polygon_count; ++loop)
1493 {
1494 if (polygon->type==_polygon_is_platform)
1495 {
1496 /* Search and find the extra data. If it is not there, use the permutation for */
1497 /* backwards compatibility! */
1498
1499 size_t platform_static_data_index;
1500 for(platform_static_data_index = 0; platform_static_data_index<count; ++platform_static_data_index)
1501 {
1502 if (static_platforms[platform_static_data_index].polygon_index == loop)
1503 {
1504 new_platform(&static_platforms[platform_static_data_index], loop, version);
1505 break;
1506 }
1507 }
1508
1509 /* DIdn't find it- use a standard platform */
1510 if(platform_static_data_index==count)
1511 {
1512 polygon->permutation= 1;
1513 new_platform(get_defaults_for_platform_type(polygon->permutation), loop, version);
1514 }
1515 }
1516 ++polygon;
1517 }
1518 }
1519
1520
1521 extern void unpack_lua_states(uint8*, size_t);
1522
1523 /* Load a level from a wad-> mainly used by the net stuff. */
process_map_wad(struct wad_data * wad,bool restoring_game,short version)1524 bool process_map_wad(
1525 struct wad_data *wad,
1526 bool restoring_game,
1527 short version)
1528 {
1529 size_t data_length;
1530 uint8 *data;
1531 size_t count;
1532 bool is_preprocessed_map= false;
1533
1534 assert(version==MARATHON_INFINITY_DATA_VERSION || version==MARATHON_TWO_DATA_VERSION || version==MARATHON_ONE_DATA_VERSION);
1535
1536 /* zero everything so no slots are used */
1537 initialize_map_for_new_level();
1538
1539 /* Calculate the length (for reallocate map) */
1540 allocate_map_structure_for_map(wad);
1541
1542 /* Extract points */
1543 data= (uint8 *)extract_type_from_wad(wad, POINT_TAG, &data_length);
1544 count= data_length/SIZEOF_world_point2d;
1545 assert(data_length == count*SIZEOF_world_point2d);
1546
1547 if(count)
1548 {
1549 load_points(data, count);
1550 } else {
1551
1552 data= (uint8 *)extract_type_from_wad(wad, ENDPOINT_DATA_TAG, &data_length);
1553 count= data_length/SIZEOF_endpoint_data;
1554 assert(data_length == count*SIZEOF_endpoint_data);
1555 // assert(count>=0 && count<MAXIMUM_ENDPOINTS_PER_MAP);
1556
1557 /* Slam! */
1558 unpack_endpoint_data(data,map_endpoints,count);
1559 assert(count == static_cast<size_t>(static_cast<int16>(count)));
1560 assert(0 <= static_cast<int16>(count));
1561 dynamic_world->endpoint_count= static_cast<int16>(count);
1562
1563 if (version > MARATHON_ONE_DATA_VERSION)
1564 is_preprocessed_map= true;
1565 }
1566
1567 /* Extract lines */
1568 data= (uint8 *)extract_type_from_wad(wad, LINE_TAG, &data_length);
1569 count = data_length/SIZEOF_line_data;
1570 assert(data_length == count*SIZEOF_line_data);
1571 load_lines(data, count);
1572
1573 /* Order is important! */
1574 data= (uint8 *)extract_type_from_wad(wad, SIDE_TAG, &data_length);
1575 count = data_length/SIZEOF_side_data;
1576 assert(data_length == count*SIZEOF_side_data);
1577 load_sides(data, count, version);
1578
1579 /* Extract polygons */
1580 data= (uint8 *)extract_type_from_wad(wad, POLYGON_TAG, &data_length);
1581 count = data_length/SIZEOF_polygon_data;
1582 assert(data_length == count*SIZEOF_polygon_data);
1583 load_polygons(data, count, version);
1584
1585 /* Extract the lightsources */
1586 if(restoring_game)
1587 {
1588 // Slurp them in
1589 data= (uint8 *)extract_type_from_wad(wad, LIGHTSOURCE_TAG, &data_length);
1590 count = data_length/SIZEOF_light_data;
1591 assert(data_length == count*SIZEOF_light_data);
1592 LightList.resize(count);
1593 unpack_light_data(data,lights,count);
1594 }
1595 else
1596 {
1597 /* When you are restoring a game, the actual light structure is set. */
1598 data= (uint8 *)extract_type_from_wad(wad, LIGHTSOURCE_TAG, &data_length);
1599 if(version==MARATHON_ONE_DATA_VERSION)
1600 {
1601 /* We have an old style light */
1602 count= data_length/SIZEOF_old_light_data;
1603 assert(count*SIZEOF_old_light_data==data_length);
1604 load_lights(data, count, version);
1605 } else {
1606 count= data_length/SIZEOF_static_light_data;
1607 assert(count*SIZEOF_static_light_data==data_length);
1608 load_lights(data, count, version);
1609 }
1610
1611 // HACK!!!!!!!!!!!!!!! vulcan doesnÕt NONE .first_object field after adding scenery
1612 {
1613 for (count= 0; count<static_cast<size_t>(dynamic_world->polygon_count); ++count)
1614 {
1615 map_polygons[count].first_object= NONE;
1616 }
1617 }
1618 }
1619
1620 /* Extract the annotations */
1621 data= (uint8 *)extract_type_from_wad(wad, ANNOTATION_TAG, &data_length);
1622 count = data_length/SIZEOF_map_annotation;
1623 assert(data_length == count*SIZEOF_map_annotation);
1624 load_annotations(data, count);
1625
1626 /* Extract the objects */
1627 data= (uint8 *)extract_type_from_wad(wad, OBJECT_TAG, &data_length);
1628 count = data_length/SIZEOF_map_object;
1629 assert(data_length == count*static_cast<size_t>(SIZEOF_map_object));
1630 load_objects(data, count);
1631
1632 /* Extract the map info data */
1633 data= (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &data_length);
1634 // LP change: made this more Pfhorte-friendly
1635 assert(static_cast<size_t>(SIZEOF_static_data)==data_length
1636 || static_cast<size_t>(SIZEOF_static_data-2)==data_length);
1637 load_map_info(data);
1638 if (version == MARATHON_ONE_DATA_VERSION)
1639 {
1640 if (static_world->mission_flags & _mission_exploration)
1641 {
1642 static_world->mission_flags &= ~_mission_exploration;
1643 static_world->mission_flags |= _mission_exploration_m1;
1644 }
1645 if (static_world->mission_flags & _mission_rescue)
1646 {
1647 static_world->mission_flags &= ~_mission_rescue;
1648 static_world->mission_flags |= _mission_rescue_m1;
1649 }
1650 if (static_world->mission_flags & _mission_repair)
1651 {
1652 static_world->mission_flags &= ~_mission_repair;
1653 static_world->mission_flags |= _mission_repair_m1;
1654 }
1655 if (static_world->environment_flags & _environment_rebellion)
1656 {
1657 static_world->environment_flags &= ~_environment_rebellion;
1658 static_world->environment_flags |= _environment_rebellion_m1;
1659 }
1660 static_world->environment_flags |= _environment_glue_m1|_environment_ouch_m1|_environment_song_index_m1|_environment_terminals_stop_time|_environment_activation_ranges|_environment_m1_weapons;
1661
1662 }
1663
1664 if (static_world->environment_flags & _environment_song_index_m1) {
1665 Music::instance()->SetClassicLevelMusic(static_world->song_index);
1666 }
1667
1668 /* Extract the game difficulty info.. */
1669 data= (uint8 *)extract_type_from_wad(wad, ITEM_PLACEMENT_STRUCTURE_TAG, &data_length);
1670 // In case of an absent placement chunk...
1671 if (data_length == 0)
1672 {
1673 data = new uint8[2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition];
1674 memset(data,0,2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition);
1675 }
1676 else
1677 assert(data_length == 2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition);
1678 load_placement_data(data + MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition, data);
1679 if (data_length == 0)
1680 delete []data;
1681
1682 /* Extract the terminal data. */
1683 data= (uint8 *)extract_type_from_wad(wad, TERMINAL_DATA_TAG, &data_length);
1684 load_terminal_data(data, data_length);
1685
1686 /* Extract the media definitions */
1687 if(restoring_game)
1688 {
1689 // Slurp it in
1690 data= (uint8 *)extract_type_from_wad(wad, MEDIA_TAG, &data_length);
1691 count= data_length/SIZEOF_media_data;
1692 assert(count*SIZEOF_media_data==data_length);
1693 MediaList.resize(count);
1694 unpack_media_data(data,medias,count);
1695 }
1696 else
1697 {
1698 data= (uint8 *)extract_type_from_wad(wad, MEDIA_TAG, &data_length);
1699 count= data_length/SIZEOF_media_data;
1700 assert(count*SIZEOF_media_data==data_length);
1701 load_media(data, count);
1702 }
1703
1704 /* Extract the ambient sound images */
1705 data= (uint8 *)extract_type_from_wad(wad, AMBIENT_SOUND_TAG, &data_length);
1706 count = data_length/SIZEOF_ambient_sound_image_data;
1707 assert(data_length == count*SIZEOF_ambient_sound_image_data);
1708 load_ambient_sound_images(data, count);
1709 load_ambient_sound_images(data, data_length/SIZEOF_ambient_sound_image_data);
1710
1711 /* Extract the random sound images */
1712 data= (uint8 *)extract_type_from_wad(wad, RANDOM_SOUND_TAG, &data_length);
1713 count = data_length/SIZEOF_random_sound_image_data;
1714 assert(data_length == count*SIZEOF_random_sound_image_data);
1715 load_random_sound_images(data, count);
1716
1717 /* Extract embedded shapes */
1718 data= (uint8 *)extract_type_from_wad(wad, SHAPE_PATCH_TAG, &data_length);
1719 set_shapes_patch_data(data, data_length);
1720
1721 /* Extract MMLS */
1722 data= (uint8 *)extract_type_from_wad(wad, MMLS_TAG, &data_length);
1723 SetMMLS(data, data_length);
1724
1725 /* Extract LUAS */
1726 data= (uint8 *)extract_type_from_wad(wad, LUAS_TAG, &data_length);
1727 SetLUAS(data, data_length);
1728
1729 /* Extract saved Lua state */
1730 data =(uint8 *)extract_type_from_wad(wad, LUA_STATE_TAG, &data_length);
1731 unpack_lua_states(data, data_length);
1732
1733 // LP addition: load the physics-model chunks (all fixed-size)
1734 bool PhysicsModelLoaded = false;
1735
1736 data= (uint8 *)extract_type_from_wad(wad, MONSTER_PHYSICS_TAG, &data_length);
1737 count = data_length/SIZEOF_monster_definition;
1738 assert(count*SIZEOF_monster_definition == data_length);
1739 assert(count <= NUMBER_OF_MONSTER_TYPES);
1740 if (data_length > 0)
1741 {
1742 if (!PhysicsModelLoaded) init_physics_wad_data();
1743 PhysicsModelLoaded = true;
1744 unpack_monster_definition(data,count);
1745 }
1746
1747 data= (uint8 *)extract_type_from_wad(wad, EFFECTS_PHYSICS_TAG, &data_length);
1748 count = data_length/SIZEOF_effect_definition;
1749 assert(count*SIZEOF_effect_definition == data_length);
1750 assert(count <= NUMBER_OF_EFFECT_TYPES);
1751 if (data_length > 0)
1752 {
1753 if (!PhysicsModelLoaded) init_physics_wad_data();
1754 PhysicsModelLoaded = true;
1755 unpack_effect_definition(data,count);
1756 }
1757
1758 data= (uint8 *)extract_type_from_wad(wad, PROJECTILE_PHYSICS_TAG, &data_length);
1759 count = data_length/SIZEOF_projectile_definition;
1760 assert(count*SIZEOF_projectile_definition == data_length);
1761 assert(count <= NUMBER_OF_PROJECTILE_TYPES);
1762 if (data_length > 0)
1763 {
1764 if (!PhysicsModelLoaded) init_physics_wad_data();
1765 PhysicsModelLoaded = true;
1766 unpack_projectile_definition(data,count);
1767 }
1768
1769 data= (uint8 *)extract_type_from_wad(wad, PHYSICS_PHYSICS_TAG, &data_length);
1770 count = data_length/SIZEOF_physics_constants;
1771 assert(count*SIZEOF_physics_constants == data_length);
1772 assert(count <= get_number_of_physics_models());
1773 if (data_length > 0)
1774 {
1775 if (!PhysicsModelLoaded) init_physics_wad_data();
1776 PhysicsModelLoaded = true;
1777 unpack_physics_constants(data,count);
1778 }
1779
1780 data= (uint8 *)extract_type_from_wad(wad, WEAPONS_PHYSICS_TAG, &data_length);
1781 count = data_length/SIZEOF_weapon_definition;
1782 assert(count*SIZEOF_weapon_definition == data_length);
1783 assert(count <= get_number_of_weapon_types());
1784 if (data_length > 0)
1785 {
1786 if (!PhysicsModelLoaded) init_physics_wad_data();
1787 PhysicsModelLoaded = true;
1788 unpack_weapon_definition(data,count);
1789 }
1790
1791 // LP addition: Reload the physics model if it had been loaded in the previous level,
1792 // but not in the current level. This avoids the persistent-physics bug.
1793 // ghs: always reload the physics model if there isn't one merged
1794 if (PhysicsModelLoadedEarlier && !PhysicsModelLoaded && !game_is_networked)
1795 import_definition_structures();
1796 PhysicsModelLoadedEarlier = PhysicsModelLoaded;
1797
1798 /* If we are restoring the game, then we need to add the dynamic data */
1799 if(restoring_game)
1800 {
1801 // Slurp it all in...
1802 data= (uint8 *)extract_type_from_wad(wad, MAP_INDEXES_TAG, &data_length);
1803 count= data_length/sizeof(short);
1804 assert(count*int32(sizeof(short))==data_length);
1805 MapIndexList.resize(count);
1806 StreamToList(data,map_indexes,count);
1807
1808 data= (uint8 *)extract_type_from_wad(wad, PLAYER_STRUCTURE_TAG, &data_length);
1809 count= data_length/SIZEOF_player_data;
1810 assert(count*SIZEOF_player_data==data_length);
1811 unpack_player_data(data,players,count);
1812 team_damage_from_player_data();
1813
1814 data= (uint8 *)extract_type_from_wad(wad, DYNAMIC_STRUCTURE_TAG, &data_length);
1815 assert(data_length == SIZEOF_dynamic_data);
1816 unpack_dynamic_data(data,dynamic_world,1);
1817
1818 data= (uint8 *)extract_type_from_wad(wad, OBJECT_STRUCTURE_TAG, &data_length);
1819 count= data_length/SIZEOF_object_data;
1820 assert(count*SIZEOF_object_data==data_length);
1821 vassert(count <= MAXIMUM_OBJECTS_PER_MAP,
1822 csprintf(temporary,"Number of map objects %zu > limit %u",count,MAXIMUM_OBJECTS_PER_MAP));
1823 unpack_object_data(data,objects,count);
1824
1825 // Unpacking is E-Z here...
1826 data= (uint8 *)extract_type_from_wad(wad, AUTOMAP_LINES, &data_length);
1827 memcpy(automap_lines,data,data_length);
1828 data= (uint8 *)extract_type_from_wad(wad, AUTOMAP_POLYGONS, &data_length);
1829 memcpy(automap_polygons,data,data_length);
1830
1831 data= (uint8 *)extract_type_from_wad(wad, MONSTERS_STRUCTURE_TAG, &data_length);
1832 count= data_length/SIZEOF_monster_data;
1833 assert(count*SIZEOF_monster_data==data_length);
1834 vassert(count <= MAXIMUM_MONSTERS_PER_MAP,
1835 csprintf(temporary,"Number of monsters %zu > limit %u",count,MAXIMUM_MONSTERS_PER_MAP));
1836 unpack_monster_data(data,monsters,count);
1837
1838 data= (uint8 *)extract_type_from_wad(wad, EFFECTS_STRUCTURE_TAG, &data_length);
1839 count= data_length/SIZEOF_effect_data;
1840 assert(count*SIZEOF_effect_data==data_length);
1841 vassert(count <= MAXIMUM_EFFECTS_PER_MAP,
1842 csprintf(temporary,"Number of effects %zu > limit %u",count,MAXIMUM_EFFECTS_PER_MAP));
1843 unpack_effect_data(data,effects,count);
1844
1845 data= (uint8 *)extract_type_from_wad(wad, PROJECTILES_STRUCTURE_TAG, &data_length);
1846 count= data_length/SIZEOF_projectile_data;
1847 assert(count*SIZEOF_projectile_data==data_length);
1848 vassert(count <= MAXIMUM_PROJECTILES_PER_MAP,
1849 csprintf(temporary,"Number of projectiles %zu > limit %u",count,MAXIMUM_PROJECTILES_PER_MAP));
1850 unpack_projectile_data(data,projectiles,count);
1851
1852 data= (uint8 *)extract_type_from_wad(wad, PLATFORM_STRUCTURE_TAG, &data_length);
1853 count= data_length/SIZEOF_platform_data;
1854 assert(count*SIZEOF_platform_data==data_length);
1855 PlatformList.resize(count);
1856 unpack_platform_data(data,platforms,count);
1857
1858 data= (uint8 *)extract_type_from_wad(wad, WEAPON_STATE_TAG, &data_length);
1859 count= data_length/SIZEOF_player_weapon_data;
1860 assert(count*SIZEOF_player_weapon_data==data_length);
1861 unpack_player_weapon_data(data,count);
1862
1863 data= (uint8 *)extract_type_from_wad(wad, TERMINAL_STATE_TAG, &data_length);
1864 count= data_length/SIZEOF_player_terminal_data;
1865 assert(count*SIZEOF_player_terminal_data==data_length);
1866 unpack_player_terminal_data(data,count);
1867
1868 complete_restoring_level(wad);
1869 } else {
1870 uint8 *map_index_data;
1871 size_t map_index_count;
1872 uint8 *platform_structures;
1873 size_t platform_structure_count;
1874
1875 if(version==MARATHON_ONE_DATA_VERSION)
1876 {
1877 /* Force precalculation */
1878 map_index_data= NULL;
1879 map_index_count= 0;
1880 } else {
1881 map_index_data= (uint8 *)extract_type_from_wad(wad, MAP_INDEXES_TAG, &data_length);
1882 map_index_count= data_length/sizeof(short);
1883 assert(map_index_count*sizeof(short)==data_length);
1884 }
1885
1886 assert((is_preprocessed_map && map_index_count) || (!is_preprocessed_map && !map_index_count));
1887
1888 data= (uint8 *)extract_type_from_wad(wad, PLATFORM_STATIC_DATA_TAG, &data_length);
1889 count= data_length/SIZEOF_static_platform_data;
1890 assert(count*SIZEOF_static_platform_data==data_length);
1891
1892 platform_structures= (uint8 *)extract_type_from_wad(wad, PLATFORM_STRUCTURE_TAG, &data_length);
1893 platform_structure_count= data_length/SIZEOF_platform_data;
1894 assert(platform_structure_count*SIZEOF_platform_data==data_length);
1895
1896 complete_loading_level((short *) map_index_data, map_index_count,
1897 data, count, platform_structures,
1898 platform_structure_count, version);
1899
1900 }
1901
1902 /* ... and bail */
1903 return true;
1904 }
1905
allocate_map_structure_for_map(struct wad_data * wad)1906 static void allocate_map_structure_for_map(
1907 struct wad_data *wad)
1908 {
1909 size_t data_length;
1910 size_t line_count, polygon_count, side_count, endpoint_count;
1911
1912 /* Extract points */
1913 extract_type_from_wad(wad, POINT_TAG, &data_length);
1914 endpoint_count= data_length/SIZEOF_world_point2d;
1915 if(endpoint_count*SIZEOF_world_point2d!=data_length) alert_corrupted_map(0x7074); // 'pt'
1916
1917 if(!endpoint_count)
1918 {
1919 extract_type_from_wad(wad, ENDPOINT_DATA_TAG, &data_length);
1920 endpoint_count= data_length/SIZEOF_endpoint_data;
1921 if(endpoint_count*SIZEOF_endpoint_data!=data_length) alert_corrupted_map(0x6570); // 'ep'
1922 }
1923
1924 /* Extract lines */
1925 extract_type_from_wad(wad, LINE_TAG, &data_length);
1926 line_count= data_length/SIZEOF_line_data;
1927 if(line_count*SIZEOF_line_data!=data_length) alert_corrupted_map(0x6c69); // 'li'
1928
1929 /* Sides.. */
1930 extract_type_from_wad(wad, SIDE_TAG, &data_length);
1931 side_count= data_length/SIZEOF_side_data;
1932 if(side_count*SIZEOF_side_data!=data_length) alert_corrupted_map(0x7369); // 'si'
1933
1934 /* Extract polygons */
1935 extract_type_from_wad(wad, POLYGON_TAG, &data_length);
1936 polygon_count= data_length/SIZEOF_polygon_data;
1937 if(polygon_count*SIZEOF_polygon_data!=data_length) alert_corrupted_map(0x7369); // 'si'
1938
1939 allocate_map_for_counts(polygon_count, side_count, endpoint_count, line_count);
1940 }
1941
1942 /* Note that we assume the redundant data has already been recalculated... */
load_redundant_map_data(short * redundant_data,size_t count)1943 static void load_redundant_map_data(
1944 short *redundant_data,
1945 size_t count)
1946 {
1947 if (redundant_data)
1948 {
1949 // assert(redundant_data && map_indexes);
1950 uint8 *Stream = (uint8 *)redundant_data;
1951 MapIndexList.resize(count);
1952 StreamToList(Stream,map_indexes,count);
1953 assert(count == static_cast<size_t>(static_cast<int16>(count)));
1954 assert(0 <= static_cast<int16>(count));
1955 dynamic_world->map_index_count= static_cast<int16>(count);
1956 }
1957 else
1958 {
1959 recalculate_redundant_map();
1960 precalculate_map_indexes();
1961 }
1962 }
1963
load_terminal_data(uint8 * data,size_t length)1964 void load_terminal_data(
1965 uint8 *data,
1966 size_t length)
1967 {
1968 /* I would really like it if I could get these into computer_interface.c statically */
1969 unpack_map_terminal_data(data,length);
1970 }
1971
scan_and_add_scenery(void)1972 static void scan_and_add_scenery(
1973 void)
1974 {
1975 short ii;
1976 struct map_object *saved_object;
1977
1978 saved_object= saved_objects;
1979 for(ii=0; ii<dynamic_world->initial_objects_count; ++ii)
1980 {
1981 if (saved_object->type==_saved_object)
1982 {
1983 struct object_location location;
1984
1985 location.p= saved_object->location;
1986 location.flags= saved_object->flags;
1987 location.yaw= saved_object->facing;
1988 location.polygon_index= saved_object->polygon_index;
1989 new_scenery(&location, saved_object->index);
1990 }
1991
1992 ++saved_object;
1993 }
1994 }
1995
1996 struct save_game_data
1997 {
1998 uint32 tag;
1999 short unit_size;
2000 bool loaded_by_level;
2001 };
2002
2003 #define NUMBER_OF_EXPORT_ARRAYS (sizeof(export_data)/sizeof(struct save_game_data))
2004 save_game_data export_data[]=
2005 {
2006 { POINT_TAG, SIZEOF_world_point2d, true },
2007 { LINE_TAG, SIZEOF_line_data, true },
2008 { POLYGON_TAG, SIZEOF_polygon_data, true },
2009 { SIDE_TAG, SIZEOF_side_data, true },
2010 { LIGHTSOURCE_TAG, SIZEOF_static_light_data, true, },
2011 { ANNOTATION_TAG, SIZEOF_map_annotation, true },
2012 { OBJECT_TAG, SIZEOF_map_object, true },
2013 { MAP_INFO_TAG, SIZEOF_static_data, true },
2014 { ITEM_PLACEMENT_STRUCTURE_TAG, SIZEOF_object_frequency_definition, true },
2015 { PLATFORM_STATIC_DATA_TAG, SIZEOF_static_platform_data, true },
2016 { TERMINAL_DATA_TAG, sizeof(byte), true },
2017 { MEDIA_TAG, SIZEOF_media_data, true }, // false },
2018 { AMBIENT_SOUND_TAG, SIZEOF_ambient_sound_image_data, true },
2019 { RANDOM_SOUND_TAG, SIZEOF_random_sound_image_data, true },
2020 { SHAPE_PATCH_TAG, sizeof(byte), true },
2021 // { PLATFORM_STRUCTURE_TAG, SIZEOF_platform_data, true },
2022 };
2023
2024 #define NUMBER_OF_SAVE_ARRAYS (sizeof(save_data)/sizeof(struct save_game_data))
2025 struct save_game_data save_data[]=
2026 {
2027 { ENDPOINT_DATA_TAG, SIZEOF_endpoint_data, true },
2028 { LINE_TAG, SIZEOF_line_data, true },
2029 { SIDE_TAG, SIZEOF_side_data, true },
2030 { POLYGON_TAG, SIZEOF_polygon_data, true },
2031 { LIGHTSOURCE_TAG, SIZEOF_light_data, true }, // false },
2032 { ANNOTATION_TAG, SIZEOF_map_annotation, true },
2033 { OBJECT_TAG, SIZEOF_map_object, true },
2034 { MAP_INFO_TAG, SIZEOF_static_data, true },
2035 { ITEM_PLACEMENT_STRUCTURE_TAG, SIZEOF_object_frequency_definition, true },
2036 { MEDIA_TAG, SIZEOF_media_data, true }, // false },
2037 { AMBIENT_SOUND_TAG, SIZEOF_ambient_sound_image_data, true },
2038 { RANDOM_SOUND_TAG, SIZEOF_random_sound_image_data, true },
2039 { TERMINAL_DATA_TAG, sizeof(byte), true },
2040
2041 // LP addition: handling of physics models
2042 { MONSTER_PHYSICS_TAG, SIZEOF_monster_definition, true},
2043 { EFFECTS_PHYSICS_TAG, SIZEOF_effect_definition, true},
2044 { PROJECTILE_PHYSICS_TAG, SIZEOF_projectile_definition, true},
2045 { PHYSICS_PHYSICS_TAG, SIZEOF_physics_constants, true},
2046 { WEAPONS_PHYSICS_TAG, SIZEOF_weapon_definition, true},
2047
2048 // GHS: save the new embedded shapes
2049 { SHAPE_PATCH_TAG, sizeof(byte), true },
2050
2051 { MMLS_TAG, sizeof(byte), true },
2052 { LUAS_TAG, sizeof(byte), true },
2053
2054 { MAP_INDEXES_TAG, sizeof(short), true }, // false },
2055 { PLAYER_STRUCTURE_TAG, SIZEOF_player_data, true }, // false },
2056 { DYNAMIC_STRUCTURE_TAG, SIZEOF_dynamic_data, true }, // false },
2057 { OBJECT_STRUCTURE_TAG, SIZEOF_object_data, true }, // false },
2058 { AUTOMAP_LINES, sizeof(byte), true }, // false },
2059 { AUTOMAP_POLYGONS, sizeof(byte), true }, // false },
2060 { MONSTERS_STRUCTURE_TAG, SIZEOF_monster_data, true }, // false },
2061 { EFFECTS_STRUCTURE_TAG, SIZEOF_effect_data, true }, // false },
2062 { PROJECTILES_STRUCTURE_TAG, SIZEOF_projectile_data, true }, // false },
2063 { PLATFORM_STRUCTURE_TAG, SIZEOF_platform_data, true }, // false },
2064 { WEAPON_STATE_TAG, SIZEOF_player_weapon_data, true }, // false },
2065 { TERMINAL_STATE_TAG, SIZEOF_player_terminal_data, true }, // false }
2066
2067 { LUA_STATE_TAG, sizeof(byte), true },
2068 };
2069
export_tag_to_global_array_and_size(uint32 tag,size_t * size)2070 static uint8 *export_tag_to_global_array_and_size(
2071 uint32 tag,
2072 size_t *size
2073 )
2074 {
2075 uint8 *array = NULL;
2076 size_t unit_size = 0;
2077 size_t count = 0;
2078 unsigned index;
2079
2080 for (index=0; index<NUMBER_OF_EXPORT_ARRAYS; ++index)
2081 {
2082 if(export_data[index].tag==tag)
2083 {
2084 unit_size= export_data[index].unit_size;
2085 break;
2086 }
2087 }
2088 assert(index != NUMBER_OF_EXPORT_ARRAYS);
2089
2090 switch (tag)
2091 {
2092 case POINT_TAG:
2093 count = dynamic_world->endpoint_count;
2094 break;
2095
2096 case LIGHTSOURCE_TAG:
2097 count = dynamic_world->light_count;
2098 break;
2099
2100 case PLATFORM_STATIC_DATA_TAG:
2101 count = dynamic_world->platform_count;
2102 break;
2103
2104 case POLYGON_TAG:
2105 count = dynamic_world->polygon_count;
2106 break;
2107
2108 default:
2109 assert(false);
2110 break;
2111 }
2112
2113 // Allocate a temporary packed-data chunk;
2114 // indicate if there is nothing to be written
2115 *size= count*unit_size;
2116 if (*size > 0)
2117 array = new byte[*size];
2118 else
2119 return NULL;
2120
2121 objlist_clear(array, *size);
2122
2123 // An OK-to-alter version of that array pointer
2124 uint8 *temp_array = array;
2125
2126 switch (tag)
2127 {
2128 case POINT_TAG:
2129 for (size_t loop = 0; loop < count; ++loop)
2130 {
2131 world_point2d& vertex = map_endpoints[loop].vertex;
2132 ValueToStream(temp_array, vertex.x);
2133 ValueToStream(temp_array, vertex.y);
2134 }
2135 break;
2136
2137 case LIGHTSOURCE_TAG:
2138 for (size_t loop = 0; loop < count; ++loop)
2139 {
2140 temp_array = pack_static_light_data(temp_array, &lights[loop].static_data, 1);
2141 }
2142 break;
2143
2144 case PLATFORM_STATIC_DATA_TAG:
2145 if (static_platforms.size() == count)
2146 {
2147 // export them directly as they came in
2148 pack_static_platform_data(array, &static_platforms[0], count);
2149 }
2150 else
2151 {
2152 for (size_t loop = 0; loop < count; ++loop)
2153 {
2154 // ghs: this belongs somewhere else
2155 static_platform_data platform;
2156 obj_clear(platform);
2157 platform.type = platforms[loop].type;
2158 platform.speed = platforms[loop].speed;
2159 platform.delay = platforms[loop].delay;
2160 if (PLATFORM_GOES_BOTH_WAYS(&platforms[loop]))
2161 {
2162 platform.maximum_height = platforms[loop].maximum_ceiling_height;
2163 platform.minimum_height = platforms[loop].minimum_floor_height;
2164 }
2165 else if (PLATFORM_COMES_FROM_FLOOR(&platforms[loop]))
2166 {
2167 platform.maximum_height = platforms[loop].maximum_floor_height;
2168 platform.minimum_height = platforms[loop].minimum_floor_height;
2169 }
2170 else
2171 {
2172 platform.maximum_height = platforms[loop].maximum_ceiling_height;
2173 platform.minimum_height = platforms[loop].minimum_floor_height;
2174 }
2175 platform.static_flags = platforms[loop].static_flags;
2176 platform.polygon_index = platforms[loop].polygon_index;
2177 platform.tag = platforms[loop].tag;
2178
2179 temp_array = pack_static_platform_data(temp_array, &platform, 1);
2180 }
2181 }
2182 break;
2183
2184 case POLYGON_TAG:
2185 for (size_t loop = 0; loop < count; ++loop)
2186 {
2187 // Forge visual mode crashes if we don't do this
2188 polygon_data polygon = PolygonList[loop];
2189 polygon.first_object = NONE;
2190 temp_array = pack_polygon_data(temp_array, &polygon, 1);
2191 }
2192 break;
2193
2194 default:
2195 assert(false);
2196 break;
2197 }
2198
2199 return array;
2200 }
2201
2202 extern size_t save_lua_states();
2203 extern void pack_lua_states(uint8*, size_t);
2204
2205
2206 /* the sizes are the sizes to save in the file, be aware! */
tag_to_global_array_and_size(uint32 tag,size_t * size)2207 static uint8 *tag_to_global_array_and_size(
2208 uint32 tag,
2209 size_t *size
2210 )
2211 {
2212 uint8 *array= NULL;
2213 size_t unit_size = 0;
2214 size_t count = 0;
2215 unsigned index;
2216
2217 for (index=0; index<NUMBER_OF_SAVE_ARRAYS; ++index)
2218 {
2219 if(save_data[index].tag==tag)
2220 {
2221 unit_size= save_data[index].unit_size;
2222 break;
2223 }
2224 }
2225 assert(index != NUMBER_OF_SAVE_ARRAYS);
2226
2227 // LP: had fixed off-by-one error in medias saving,
2228 // and had added physics-model saving
2229
2230 switch (tag)
2231 {
2232 case ENDPOINT_DATA_TAG:
2233 count= dynamic_world->endpoint_count;
2234 break;
2235 case LINE_TAG:
2236 count= dynamic_world->line_count;
2237 break;
2238 case SIDE_TAG:
2239 count= dynamic_world->side_count;
2240 break;
2241 case POLYGON_TAG:
2242 count= dynamic_world->polygon_count;
2243 break;
2244 case LIGHTSOURCE_TAG:
2245 count= dynamic_world->light_count;
2246 break;
2247 case ANNOTATION_TAG:
2248 count= dynamic_world->default_annotation_count;
2249 break;
2250 case OBJECT_TAG:
2251 count= dynamic_world->initial_objects_count;
2252 break;
2253 case MAP_INFO_TAG:
2254 count= 1;
2255 break;
2256 case PLAYER_STRUCTURE_TAG:
2257 count= dynamic_world->player_count;
2258 break;
2259 case DYNAMIC_STRUCTURE_TAG:
2260 count= 1;
2261 break;
2262 case OBJECT_STRUCTURE_TAG:
2263 count= dynamic_world->object_count;
2264 break;
2265 case MAP_INDEXES_TAG:
2266 count= static_cast<unsigned short>(dynamic_world->map_index_count);
2267 break;
2268 case AUTOMAP_LINES:
2269 count= (dynamic_world->line_count/8+((dynamic_world->line_count%8)?1:0));
2270 break;
2271 case AUTOMAP_POLYGONS:
2272 count= (dynamic_world->polygon_count/8+((dynamic_world->polygon_count%8)?1:0));
2273 break;
2274 case MONSTERS_STRUCTURE_TAG:
2275 count= dynamic_world->monster_count;
2276 break;
2277 case EFFECTS_STRUCTURE_TAG:
2278 count= dynamic_world->effect_count;
2279 break;
2280 case PROJECTILES_STRUCTURE_TAG:
2281 count= dynamic_world->projectile_count;
2282 break;
2283 case MEDIA_TAG:
2284 count= count_number_of_medias_used();
2285 break;
2286 case ITEM_PLACEMENT_STRUCTURE_TAG:
2287 count= 2*MAXIMUM_OBJECT_TYPES;
2288 break;
2289 case PLATFORM_STRUCTURE_TAG:
2290 count= dynamic_world->platform_count;
2291 break;
2292 case AMBIENT_SOUND_TAG:
2293 count= dynamic_world->ambient_sound_image_count;
2294 break;
2295 case RANDOM_SOUND_TAG:
2296 count= dynamic_world->random_sound_image_count;
2297 break;
2298 case TERMINAL_DATA_TAG:
2299 count= calculate_packed_terminal_data_length();
2300 break;
2301 case WEAPON_STATE_TAG:
2302 count= dynamic_world->player_count;
2303 break;
2304 case TERMINAL_STATE_TAG:
2305 count= dynamic_world->player_count;
2306 break;
2307 case MONSTER_PHYSICS_TAG:
2308 count= NUMBER_OF_MONSTER_TYPES;
2309 break;
2310 case EFFECTS_PHYSICS_TAG:
2311 count= NUMBER_OF_EFFECT_TYPES;
2312 break;
2313 case PROJECTILE_PHYSICS_TAG:
2314 count= NUMBER_OF_PROJECTILE_TYPES;
2315 break;
2316 case PHYSICS_PHYSICS_TAG:
2317 count= get_number_of_physics_models();
2318 break;
2319 case WEAPONS_PHYSICS_TAG:
2320 count= get_number_of_weapon_types();
2321 break;
2322 case SHAPE_PATCH_TAG:
2323 get_shapes_patch_data(count);
2324 break;
2325 case MMLS_TAG:
2326 GetMMLS(count);
2327 break;
2328 case LUAS_TAG:
2329 GetLUAS(count);
2330 break;
2331 case LUA_STATE_TAG:
2332 count= save_lua_states();
2333 break;
2334 default:
2335 assert(false);
2336 break;
2337 }
2338
2339 // Allocate a temporary packed-data chunk;
2340 // indicate if there is nothing to be written
2341 *size= count*unit_size;
2342 if (*size > 0)
2343 array = new byte[*size];
2344 else
2345 return NULL;
2346
2347 objlist_clear(array, *size);
2348
2349 // An OK-to-alter version of that array pointer
2350 uint8 *temp_array = array;
2351
2352 switch (tag)
2353 {
2354 case ENDPOINT_DATA_TAG:
2355 pack_endpoint_data(array,map_endpoints,count);
2356 break;
2357 case LINE_TAG:
2358 pack_line_data(array,map_lines,count);
2359 break;
2360 case SIDE_TAG:
2361 pack_side_data(array,map_sides,count);
2362 break;
2363 case POLYGON_TAG:
2364 pack_polygon_data(array,map_polygons,count);
2365 break;
2366 case LIGHTSOURCE_TAG:
2367 pack_light_data(array,lights,count);
2368 break;
2369 case ANNOTATION_TAG:
2370 pack_map_annotation(array,map_annotations,count);
2371 break;
2372 case OBJECT_TAG:
2373 pack_map_object(array,saved_objects,count);
2374 break;
2375 case MAP_INFO_TAG:
2376 pack_static_data(array,static_world,count);
2377 break;
2378 case PLAYER_STRUCTURE_TAG:
2379 pack_player_data(array,players,count);
2380 break;
2381 case DYNAMIC_STRUCTURE_TAG:
2382 pack_dynamic_data(array,dynamic_world,count);
2383 break;
2384 case OBJECT_STRUCTURE_TAG:
2385 pack_object_data(array,objects,count);
2386 break;
2387 case MAP_INDEXES_TAG:
2388 ListToStream(temp_array,map_indexes,count); // E-Z packing here...
2389 break;
2390 case AUTOMAP_LINES:
2391 memcpy(array,automap_lines,*size);
2392 break;
2393 case AUTOMAP_POLYGONS:
2394 memcpy(array,automap_polygons,*size);
2395 break;
2396 case MONSTERS_STRUCTURE_TAG:
2397 pack_monster_data(array,monsters,count);
2398 break;
2399 case EFFECTS_STRUCTURE_TAG:
2400 pack_effect_data(array,effects,count);
2401 break;
2402 case PROJECTILES_STRUCTURE_TAG:
2403 pack_projectile_data(array,projectiles,count);
2404 break;
2405 case MEDIA_TAG:
2406 pack_media_data(array,medias,count);
2407 break;
2408 case ITEM_PLACEMENT_STRUCTURE_TAG:
2409 pack_object_frequency_definition(array,get_placement_info(),count);
2410 break;
2411 case PLATFORM_STRUCTURE_TAG:
2412 pack_platform_data(array,platforms,count);
2413 break;
2414 case AMBIENT_SOUND_TAG:
2415 pack_ambient_sound_image_data(array,ambient_sound_images,count);
2416 break;
2417 case RANDOM_SOUND_TAG:
2418 pack_random_sound_image_data(array,random_sound_images,count);
2419 break;
2420 case TERMINAL_DATA_TAG:
2421 pack_map_terminal_data(array,count);
2422 break;
2423 case WEAPON_STATE_TAG:
2424 pack_player_weapon_data(array,count);
2425 break;
2426 case TERMINAL_STATE_TAG:
2427 pack_player_terminal_data(array,count);
2428 break;
2429 case MONSTER_PHYSICS_TAG:
2430 pack_monster_definition(array,count);
2431 break;
2432 case EFFECTS_PHYSICS_TAG:
2433 pack_effect_definition(array,count);
2434 break;
2435 case PROJECTILE_PHYSICS_TAG:
2436 pack_projectile_definition(array,count);
2437 break;
2438 case PHYSICS_PHYSICS_TAG:
2439 pack_physics_constants(array,count);
2440 break;
2441 case WEAPONS_PHYSICS_TAG:
2442 pack_weapon_definition(array,count);
2443 break;
2444 case SHAPE_PATCH_TAG:
2445 memcpy(array, get_shapes_patch_data(count), count);
2446 break;
2447 case MMLS_TAG:
2448 memcpy(array, GetMMLS(count), count);
2449 break;
2450 case LUAS_TAG:
2451 memcpy(array, GetLUAS(count), count);
2452 break;
2453 case LUA_STATE_TAG:
2454 pack_lua_states(array, count);
2455 break;
2456 default:
2457 assert(false);
2458 break;
2459 }
2460
2461 return array;
2462 }
2463
build_export_wad(wad_header * header,int32 * length)2464 static wad_data *build_export_wad(wad_header *header, int32 *length)
2465 {
2466 struct wad_data *wad= NULL;
2467 uint8 *array_to_slam;
2468 size_t size;
2469
2470 wad= create_empty_wad();
2471 if(wad)
2472 {
2473 recalculate_map_counts();
2474
2475 // try to divine initial platform/polygon states
2476 vector<platform_data> SavedPlatforms = PlatformList;
2477 vector<polygon_data> SavedPolygons = PolygonList;
2478 vector<line_data> SavedLines = LineList;
2479
2480 for (size_t loop = 0; loop < PlatformList.size(); ++loop)
2481 {
2482 platform_data *platform = &PlatformList[loop];
2483 // reset the polygon heights
2484 if (PLATFORM_COMES_FROM_FLOOR(platform))
2485 {
2486 platform->floor_height = platform->minimum_floor_height;
2487 PolygonList[platform->polygon_index].floor_height = platform->floor_height;
2488 }
2489 if (PLATFORM_COMES_FROM_CEILING(platform))
2490 {
2491 platform->ceiling_height = platform->maximum_ceiling_height;
2492 PolygonList[platform->polygon_index].ceiling_height = platform->ceiling_height;
2493 }
2494 }
2495
2496 for (size_t loop = 0; loop < LineList.size(); ++loop)
2497 {
2498 line_data *line = &LineList[loop];
2499 if (LINE_IS_VARIABLE_ELEVATION(line))
2500 {
2501 SET_LINE_VARIABLE_ELEVATION(line, false);
2502 SET_LINE_SOLIDITY(line, false);
2503 SET_LINE_TRANSPARENCY(line, true);
2504 }
2505 }
2506
2507 for(unsigned loop= 0; loop<NUMBER_OF_EXPORT_ARRAYS; ++loop)
2508 {
2509 /* If there is a conversion function, let it handle it */
2510 switch (export_data[loop].tag)
2511 {
2512 case POINT_TAG:
2513 case LIGHTSOURCE_TAG:
2514 case PLATFORM_STATIC_DATA_TAG:
2515 case POLYGON_TAG:
2516 array_to_slam= export_tag_to_global_array_and_size(export_data[loop].tag, &size);
2517 break;
2518 default:
2519 array_to_slam= tag_to_global_array_and_size(export_data[loop].tag, &size);
2520 }
2521
2522 /* Add it to the wad.. */
2523 if(size)
2524 {
2525 wad= append_data_to_wad(wad, export_data[loop].tag, array_to_slam, size, 0);
2526 delete []array_to_slam;
2527 }
2528 }
2529
2530 PlatformList = SavedPlatforms;
2531 PolygonList = SavedPolygons;
2532 LineList = SavedLines;
2533
2534 if(wad) *length= calculate_wad_length(header, wad);
2535 }
2536
2537 return wad;
2538 }
2539
2540 /* Build the wad, with all the crap */
build_save_game_wad(struct wad_header * header,int32 * length)2541 static struct wad_data *build_save_game_wad(
2542 struct wad_header *header,
2543 int32 *length)
2544 {
2545 struct wad_data *wad= NULL;
2546 uint8 *array_to_slam;
2547 size_t size;
2548
2549 wad= create_empty_wad();
2550 if(wad)
2551 {
2552 recalculate_map_counts();
2553 for(unsigned loop= 0; loop<NUMBER_OF_SAVE_ARRAYS; ++loop)
2554 {
2555 /* If there is a conversion function, let it handle it */
2556 array_to_slam= tag_to_global_array_and_size(save_data[loop].tag, &size);
2557
2558 /* Add it to the wad.. */
2559 if(size)
2560 {
2561 wad= append_data_to_wad(wad, save_data[loop].tag, array_to_slam, size, 0);
2562 delete []array_to_slam;
2563 }
2564 }
2565 if(wad) *length= calculate_wad_length(header, wad);
2566 }
2567
2568 return wad;
2569 }
2570
2571 /* Build save game wad holding metadata and preview image */
build_meta_game_wad(const std::string & metadata,const std::string & imagedata,struct wad_header * header,int32 * length)2572 struct wad_data *build_meta_game_wad(
2573 const std::string& metadata,
2574 const std::string& imagedata,
2575 struct wad_header *header,
2576 int32 *length)
2577 {
2578 struct wad_data *wad= NULL;
2579
2580 wad= create_empty_wad();
2581 if(wad)
2582 {
2583 size_t size = metadata.length();
2584 if (size)
2585 {
2586 wad= append_data_to_wad(wad, SAVE_META_TAG, metadata.c_str(), size, 0);
2587 }
2588
2589 size_t imgsize = imagedata.length();
2590 if (imgsize)
2591 {
2592 wad= append_data_to_wad(wad, SAVE_IMG_TAG, imagedata.c_str(), imgsize, 0);
2593 }
2594 if(wad) *length= calculate_wad_length(header, wad);
2595 }
2596
2597 return wad;
2598 }
2599
2600 /* Load and slam all of the arrays */
complete_restoring_level(struct wad_data * wad)2601 static void complete_restoring_level(
2602 struct wad_data *wad)
2603 {
2604 ok_to_reset_scenery_solidity = false;
2605 /* Loading games needs this done. */
2606 reset_action_queues();
2607 }
2608
2609
2610 /* CP Addition: get_map_file returns a pointer to the current map file */
get_map_file()2611 FileSpecifier& get_map_file()
2612 {
2613 return MapFileSpec;
2614 }
2615
level_has_embedded_physics_lua(int Level,bool & HasPhysics,bool & HasLua)2616 void level_has_embedded_physics_lua(int Level, bool& HasPhysics, bool& HasLua)
2617 {
2618 // load the wad file and look for chunks !!??
2619 wad_header header;
2620 wad_data* wad;
2621 OpenedFile MapFile;
2622 if (open_wad_file_for_reading(get_map_file(), MapFile))
2623 {
2624 if (read_wad_header(MapFile, &header))
2625 {
2626 wad = read_indexed_wad_from_file(MapFile, &header, Level, true);
2627 if (wad)
2628 {
2629 size_t data_length;
2630 extract_type_from_wad(wad, PHYSICS_PHYSICS_TAG, &data_length);
2631 HasPhysics = data_length > 0;
2632
2633 extract_type_from_wad(wad, LUAS_TAG, &data_length);
2634 HasLua = data_length > 0;
2635 free_wad(wad);
2636 }
2637 }
2638 close_wad_file(MapFile);
2639 }
2640 }
2641
2642
2643 /*
2644 * Unpacking/packing functions
2645 */
2646
unpack_directory_data(uint8 * Stream,directory_data * Objects,size_t Count)2647 static uint8 *unpack_directory_data(uint8 *Stream, directory_data *Objects, size_t Count)
2648 {
2649 uint8* S = Stream;
2650 directory_data* ObjPtr = Objects;
2651
2652 for (size_t k = 0; k < Count; k++, ObjPtr++)
2653 {
2654 StreamToValue(S,ObjPtr->mission_flags);
2655 StreamToValue(S,ObjPtr->environment_flags);
2656 StreamToValue(S,ObjPtr->entry_point_flags);
2657 StreamToBytes(S,ObjPtr->level_name,LEVEL_NAME_LENGTH);
2658 }
2659
2660 assert((S - Stream) == SIZEOF_directory_data);
2661 return S;
2662 }
2663
2664 // ZZZ: gnu cc swears this is currently unused, and I don't see any sneaky #includes that might need it...
2665 /*
2666 static uint8 *pack_directory_data(uint8 *Stream, directory_data *Objects, int Count)
2667 {
2668 uint8* S = Stream;
2669 directory_data* ObjPtr = Objects;
2670
2671 for (int k = 0; k < Count; k++, ObjPtr++)
2672 {
2673 ValueToStream(S,ObjPtr->mission_flags);
2674 ValueToStream(S,ObjPtr->environment_flags);
2675 ValueToStream(S,ObjPtr->entry_point_flags);
2676 BytesToStream(S,ObjPtr->level_name,LEVEL_NAME_LENGTH);
2677 }
2678
2679 assert((S - Stream) == SIZEOF_directory_data);
2680 return S;
2681 }
2682 */
2683