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