• R/O
  • SSH
  • HTTPS

marathon: コミット


コミットメタ情報

リビジョン509 (tree)
日時2011-12-19 20:17:12
作者logue

ログメッセージ

・公式版r4662とマージ。複数のレベルにまたがるフィルムの再生の互換性を改善。
・フォントをOSのシステムフォントからも呼び出す試み。
・MMLで指定したフォント設定が反映されないバグを修正。

変更サマリ

差分

--- marathon/trunk/Source_Files/GameWorld/marathon2.cpp (revision 508)
+++ marathon/trunk/Source_Files/GameWorld/marathon2.cpp (revision 509)
@@ -1,902 +1,902 @@
1-/*
2-MARATHON.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-Friday, December 3, 1993 10:00:32 AM
22-
23-Monday, September 5, 1994 2:42:28 PM (ajr)
24- fixed kill_limit.
25-Saturday, September 17, 1994 6:04:59 PM (alain)
26- fixed autotriggering of platforms
27-Thursday, December 8, 1994 3:58:12 PM (Jason)
28- only players trigger platforms.
29-
30-Feb 6, 2000 (Loren Petrich):
31- Added typecode initialization
32-
33-Feb 10, 2000 (Loren Petrich):
34- Added dynamic-limits initialization
35-
36-Feb 15, 2000 (Loren Petrich):
37- Added item-initialization and item-animation stuff
38-
39-Mar 12, 2000 (Loren Petrich):
40- Added OpenGL initializer
41-
42-May 11, 2000 (Loren Petrich):
43- Rewrote to get rid of dynamic-limit and animated-texture initializers;
44- also used new animated-texture update function.
45-
46-June 15, 2000 (Loren Petrich):
47- Added support for Chris Pruett's Pfhortran
48-
49-Aug 10, 2000 (Loren Petrich):
50- Added Chris Pruett's Pfhortran changes
51-
52-Feb 4, 2002 (Br'fin (Jeremy Parsons)):
53- Moved Macintosh call to OGL_Initialize to shell_macintosh.cpp
54-
55-Feb 20, 2002 (Woody Zenfell):
56- Changed action queues operations to ActionQueues operations on GetRealActionQueues()
57-
58-Mar 13, 2002 (Br'fin (Jeremy Parsons)):
59- Altered enter_game to stop and reset fades after script_init
60-
61-Jan 12, 2003 (Woody Zenfell):
62- Added ability to reset intermediate action queues (GameQueue)
63- Fixed potential out-of-sync bug
64-
65-Feb 8, 2003 (Woody Zenfell):
66- Reformulated main update loop and multiple ActionFlags queue handling.
67- PLAYER_IS_PFHORTRAN_CONTROLLED is now no longer used - if a player has
68- entries in the PfhortranActionQueues, they'll be used; if not, his
69- entries from the RealActionQueues will be.
70-
71- June 14, 2003 (Woody Zenfell):
72- Player movement prediction support:
73- + Support for retaining a partial game-state (this could be moved out to another file)
74- + Changes to update_world() to take advantage of partial game-state saving/restoring.
75-*/
76-
77-#include "cseries.h"
78-#include "map.h"
79-#include "render.h"
80-#include "interface.h"
81-#include "FilmProfile.h"
82-#include "flood_map.h"
83-#include "effects.h"
84-#include "monsters.h"
85-#include "projectiles.h"
86-#include "player.h"
87-#include "network.h"
88-#include "scenery.h"
89-#include "platforms.h"
90-#include "lightsource.h"
91-#include "media.h"
92-#include "Music.h"
93-#include "fades.h"
94-#include "items.h"
95-#include "weapons.h"
96-#include "game_window.h"
97-#include "SoundManager.h"
98-#include "network_games.h"
99-// LP additions:
100-#include "tags.h"
101-#include "AnimatedTextures.h"
102-#include "ChaseCam.h"
103-#include "OGL_Setup.h"
104-
105-// MH additions:
106-#include "lua_script.h"
107-#include "lua_hud_script.h"
108-#include <string>
109-
110-// ZZZ additions:
111-#include "ActionQueues.h"
112-#include "Logging.h"
113-
114-// for screen_mode :(
115-#include "screen.h"
116-#include "shell.h"
117-
118-#include "Console.h"
119-
120-#include <limits.h>
121-
122-#ifdef env68k
123-#pragma segment marathon
124-#endif
125-
126-/* ---------- constants */
127-
128-/* ---------- globals */
129-
130-// This is an intermediate action-flags queue for transferring action flags
131-// from whichever source to the engine's event handling
132-// ghs: making this externally available for Lua's trigger modifications
133-static ModifiableActionQueues* GameQueue = NULL;
134-ModifiableActionQueues* GetGameQueue() { return GameQueue; }
135-
136-// ZZZ: We keep this around for use in prediction (we assume a player keeps on doin' what he's been doin')
137-static uint32 sMostRecentFlagsForPlayer[MAXIMUM_NUMBER_OF_PLAYERS];
138-
139-/* ---------- private prototypes */
140-
141-static void game_timed_out(void);
142-
143-static void load_all_game_sounds(short environment_code);
144-
145-/* ---------- code */
146-
147-void initialize_marathon(
148- void)
149-{
150-#ifndef DEMO /* no external physics models for demo */
151-// import_definition_structures();
152-#endif
153-
154- build_trig_tables();
155- allocate_map_memory();
156- // Rendering and flood-map done when starting a level,
157- // since they require map-geometry sizes
158- // allocate_render_memory();
159- allocate_pathfinding_memory();
160- // allocate_flood_map_memory();
161- allocate_texture_tables();
162- initialize_weapon_manager();
163- initialize_game_window();
164- initialize_scenery();
165- // LP additions:
166- initialize_items();
167-#if defined(HAVE_OPENGL) && !defined(mac)
168- OGL_Initialize();
169-#endif
170- GameQueue = new ModifiableActionQueues(MAXIMUM_NUMBER_OF_PLAYERS, ACTION_QUEUE_BUFFER_DIAMETER, true);
171-}
172-
173-static size_t sPredictedTicks = 0;
174-
175-void
176-reset_intermediate_action_queues() {
177- GameQueue->reset();
178-
179- // ZZZ: I don't know that this is strictly the best place (or the best function name)
180- // to do this stuff, but it works, anyway.
181- for(size_t i = 0; i < MAXIMUM_NUMBER_OF_PLAYERS; i++)
182- sMostRecentFlagsForPlayer[i] = 0;
183-
184- sPredictedTicks = 0;
185-}
186-
187-
188-// ZZZ: For prediction...
189-static bool sPredictionWanted= false;
190-
191-void
192-set_prediction_wanted(bool inPrediction)
193-{
194- sPredictionWanted= inPrediction;
195-}
196-
197-static player_data sSavedPlayerData[MAXIMUM_NUMBER_OF_PLAYERS];
198-static monster_data sSavedPlayerMonsterData[MAXIMUM_NUMBER_OF_PLAYERS];
199-static object_data sSavedPlayerObjectData[MAXIMUM_NUMBER_OF_PLAYERS];
200-static object_data sSavedPlayerParasiticObjectData[MAXIMUM_NUMBER_OF_PLAYERS];
201-static short sSavedPlayerObjectNextObject[MAXIMUM_NUMBER_OF_PLAYERS];
202-
203-// For sanity-checking...
204-static int32 sSavedTickCount;
205-static uint16 sSavedRandomSeed;
206-
207-
208-// ZZZ: If not already in predictive mode, save off partial game-state for later restoration.
209-static void
210-enter_predictive_mode()
211-{
212- if(sPredictedTicks == 0)
213- {
214- for(short i = 0; i < dynamic_world->player_count; i++)
215- {
216- sSavedPlayerData[i] = *get_player_data(i);
217- if(sSavedPlayerData[i].monster_index != NONE)
218- {
219- sSavedPlayerMonsterData[i] = *get_monster_data(sSavedPlayerData[i].monster_index);
220- if(sSavedPlayerMonsterData[i].object_index != NONE)
221- {
222- sSavedPlayerObjectData[i] = *get_object_data(sSavedPlayerMonsterData[i].object_index);
223- sSavedPlayerObjectNextObject[i] = sSavedPlayerObjectData[i].next_object;
224- if(sSavedPlayerObjectData[i].parasitic_object != NONE)
225- sSavedPlayerParasiticObjectData[i] = *get_object_data(sSavedPlayerObjectData[i].parasitic_object);
226- }
227- }
228- }
229-
230- // Sanity checking
231- sSavedTickCount = dynamic_world->tick_count;
232- sSavedRandomSeed = get_random_seed();
233- }
234-}
235-
236-
237-#if COMPARE_MEMORY
238-// ZZZ: I wrote this function to help catch incomplete state save/restore operations on entering and exiting predictive mode
239-// It's not currently in use anywhere, but may prove useful sometime? so I'm including it in my submission.
240-static void
241-compare_memory(const char* inChunk1, const char* inChunk2, size_t inSize, size_t inIgnoreStart, size_t inIgnoreEnd, const char* inDescription, int inDescriptionNumber)
242-{
243- bool trackingDifferences = false;
244- size_t theDifferenceStart;
245-
246- for(size_t i = 0; i < inSize; i++)
247- {
248- if(inChunk1[i] != inChunk2[i])
249- {
250- if(!trackingDifferences)
251- {
252- theDifferenceStart = i;
253- trackingDifferences = true;
254- }
255- }
256- else
257- {
258- if(trackingDifferences)
259- {
260- if(theDifferenceStart < inIgnoreStart || i >= inIgnoreEnd)
261- logWarning4("%s %d: differences in bytes [%d,%d)", inDescription, inDescriptionNumber, theDifferenceStart, i);
262- trackingDifferences = false;
263- }
264- }
265- }
266-
267- if(trackingDifferences)
268- {
269- if(theDifferenceStart < inIgnoreStart || inSize >= inIgnoreEnd)
270- logWarning4("%s %d: differences in bytes [%d,%d)", inDescription, inDescriptionNumber, theDifferenceStart, inSize);
271- }
272-}
273-#endif
274-
275-// ZZZ: if in predictive mode, restore the saved partial game-state (it'd better take us back
276-// to _exactly_ the same full game-state we saved earlier, else problems.)
277-static void
278-exit_predictive_mode()
279-{
280- if(sPredictedTicks > 0)
281- {
282- for(short i = 0; i < dynamic_world->player_count; i++)
283- {
284- player_data* player = get_player_data(i);
285-
286- assert(player->monster_index == sSavedPlayerData[i].monster_index);
287-
288- {
289- // We *don't* restore this tiny part of the game-state back because
290- // otherwise the player can't use [] to scroll the inventory panel.
291- // [] scrolling happens outside the normal input/update system, so that's
292- // enough to persuade me that not restoring this won't OOS any more often
293- // than []-scrolling did before prediction. :)
294- int16 saved_interface_flags = player->interface_flags;
295- int16 saved_interface_decay = player->interface_decay;
296-
297- *player = sSavedPlayerData[i];
298-
299- player->interface_flags = saved_interface_flags;
300- player->interface_decay = saved_interface_decay;
301- }
302-
303- if(sSavedPlayerData[i].monster_index != NONE)
304- {
305- assert(get_monster_data(sSavedPlayerData[i].monster_index)->object_index == sSavedPlayerMonsterData[i].object_index);
306-
307- *get_monster_data(sSavedPlayerData[i].monster_index) = sSavedPlayerMonsterData[i];
308-
309- if(sSavedPlayerMonsterData[i].object_index != NONE)
310- {
311- assert(get_object_data(sSavedPlayerMonsterData[i].object_index)->parasitic_object == sSavedPlayerObjectData[i].parasitic_object);
312-
313- remove_object_from_polygon_object_list(sSavedPlayerMonsterData[i].object_index);
314-
315- *get_object_data(sSavedPlayerMonsterData[i].object_index) = sSavedPlayerObjectData[i];
316-
317- // We have to defer this insertion since the object lists could still have other players
318- // in their predictive locations etc. - we need to reconstruct everything exactly as it
319- // was when we entered predictive mode.
320- deferred_add_object_to_polygon_object_list(sSavedPlayerMonsterData[i].object_index, sSavedPlayerObjectNextObject[i]);
321-
322- if(sSavedPlayerObjectData[i].parasitic_object != NONE)
323- *get_object_data(sSavedPlayerObjectData[i].parasitic_object) = sSavedPlayerParasiticObjectData[i];
324- }
325- }
326- }
327-
328- perform_deferred_polygon_object_list_manipulations();
329-
330- sPredictedTicks = 0;
331-
332- // Sanity checking
333- if(sSavedTickCount != dynamic_world->tick_count)
334- logWarning2("saved tick count %d != dynamic_world->tick_count %d", sSavedTickCount, dynamic_world->tick_count);
335-
336- if(sSavedRandomSeed != get_random_seed())
337- logWarning2("saved random seed %d != get_random_seed() %d", sSavedRandomSeed, get_random_seed());
338- }
339-}
340-
341-
342-// ZZZ: move a single tick's flags (if there's one present for each player in the Base Queues)
343-// from the Base Queues into the Output Queues, overriding each with the corresponding player's
344-// flags from the Overlay Queues, if non-empty.
345-static bool
346-overlay_queue_with_queue_into_queue(ActionQueues* inBaseQueues, ActionQueues* inOverlayQueues, ActionQueues* inOutputQueues)
347-{
348- bool haveFlagsForAllPlayers = true;
349- for(int p = 0; p < dynamic_world->player_count; p++)
350- {
351- if(inBaseQueues->countActionFlags(p) <= 0)
352- {
353- haveFlagsForAllPlayers = false;
354- break;
355- }
356- }
357-
358- if(!haveFlagsForAllPlayers)
359- {
360- return false;
361- }
362-
363- for(int p = 0; p < dynamic_world->player_count; p++)
364- {
365- // Trust me, this is right - we dequeue from the Base Queues whether or not they get overridden.
366- uint32 action_flags = inBaseQueues->dequeueActionFlags(p);
367-
368- if(inOverlayQueues != NULL && inOverlayQueues->countActionFlags(p) > 0)
369- {
370- action_flags = inOverlayQueues->dequeueActionFlags(p);
371- }
372-
373- inOutputQueues->enqueueActionFlags(p, &action_flags, 1);
374- }
375-
376- return true;
377-}
378-
379-
380-// Return values for update_world_elements_one_tick()
381-enum {
382- kUpdateNormalCompletion,
383- kUpdateGameOver,
384- kUpdateChangeLevel
385-};
386-
387-// ZZZ: split out from update_world()'s loop.
388-static int
389-update_world_elements_one_tick()
390-{
391- L_Call_Idle();
392-
393- update_lights();
394- update_medias();
395- update_platforms();
396-
397- update_control_panels(); // don't put after update_players
398- update_players(GameQueue, false);
399- move_projectiles();
400- move_monsters();
401- update_effects();
402- recreate_objects();
403-
404- handle_random_sound_image();
405- animate_scenery();
406-
407- // LP additions:
408- if (film_profile.animate_items)
409- {
410- animate_items();
411- }
412-
413- AnimTxtr_Update();
414- ChaseCam_Update();
415-
416-#if !defined(DISABLE_NETWORKING)
417- update_net_game();
418-#endif // !defined(DISABLE_NETWORKING)
419-
420- if(check_level_change())
421- {
422- return kUpdateChangeLevel;
423- }
424-
425-#if !defined(DISABLE_NETWORKING)
426- if(game_is_over())
427- {
428- return kUpdateGameOver;
429- }
430-#endif // !defined(DISABLE_NETWORKING)
431-
432- dynamic_world->tick_count+= 1;
433- dynamic_world->game_information.game_time_remaining-= 1;
434-
435- return kUpdateNormalCompletion;
436-}
437-
438-// ZZZ: new formulation of update_world(), should be simpler and clearer I hope.
439-// Now returns (whether something changed, number of real ticks elapsed) since, with
440-// prediction, something can change even if no real ticks have elapsed.
441-
442-std::pair<bool, int16>
443-update_world()
444-{
445- short theElapsedTime = 0;
446- bool canUpdate = true;
447- int theUpdateResult = kUpdateNormalCompletion;
448-
449-#ifndef DISABLE_NETWORKING
450- if (game_is_networked)
451- NetProcessMessagesInGame();
452-#endif
453-
454- while(canUpdate)
455- {
456- // If we have flags in the GameQueue, or can put a tick's-worth there, we're ok.
457- // Note that GameQueue should be stocked evenly (i.e. every player has the same # of flags)
458- if(GameQueue->countActionFlags(0) == 0)
459- {
460- canUpdate = overlay_queue_with_queue_into_queue(GetRealActionQueues(), GetLuaActionQueues(), GameQueue);
461- }
462-
463- if(!sPredictionWanted)
464- {
465- // See if the speed-limiter (net time or heartbeat count) will let us advance a tick
466-#if !defined(DISABLE_NETWORKING)
467- int theMostRecentAllowedTick = game_is_networked ? NetGetNetTime() : get_heartbeat_count();
468-#else
469- int theMostRecentAllowedTick = get_heartbeat_count();
470-#endif
471-
472- if(dynamic_world->tick_count >= theMostRecentAllowedTick)
473- {
474- canUpdate = false;
475- }
476- }
477-
478- // If we can't update, we can't update. We're done for now.
479- if(!canUpdate)
480- {
481- break;
482- }
483-
484- // Transition from predictive -> real update mode, if necessary.
485- exit_predictive_mode();
486-
487- // Capture the flags for each player for use in prediction
488- for(short i = 0; i < dynamic_world->player_count; i++)
489- sMostRecentFlagsForPlayer[i] = GameQueue->peekActionFlags(i, 0);
490-
491- theUpdateResult = update_world_elements_one_tick();
492-
493- theElapsedTime++;
494-
495-
496- L_Call_PostIdle();
497- if(theUpdateResult != kUpdateNormalCompletion)
498- {
499- canUpdate = false;
500- }
501- }
502-
503- // This and the following voodoo comes, effectively, from Bungie's code.
504- if(theUpdateResult == kUpdateChangeLevel)
505- {
506- theElapsedTime = 0;
507- }
508-
509- /* Game is over. */
510- if(theUpdateResult == kUpdateGameOver)
511- {
512- game_timed_out();
513- theElapsedTime = 0;
514- }
515- else if (theElapsedTime)
516- {
517- update_interface(theElapsedTime);
518- update_fades();
519- }
520-
521- check_recording_replaying();
522-
523- // ZZZ: Prediction!
524- bool didPredict = false;
525-
526- if(theUpdateResult == kUpdateNormalCompletion && sPredictionWanted)
527- {
528- NetUpdateUnconfirmedActionFlags();
529-
530- // We use "2" to make sure there's always room for our one set of elements.
531- // (thePredictiveQueues should always hold only 0 or 1 element for each player.)
532- ActionQueues thePredictiveQueues(dynamic_world->player_count, 2, true);
533-
534- // Observe, since we don't use a speed-limiter in predictive mode, that there cannot be flags
535- // stranded in the GameQueue. Unfortunately this approach will mispredict if a script is
536- // controlling the local player. We could be smarter about it if that eventually becomes an issue.
537- for ( ; sPredictedTicks < NetGetUnconfirmedActionFlagsCount(); sPredictedTicks++)
538- {
539- // Real -> predictive transition, if necessary
540- enter_predictive_mode();
541-
542- // Enqueue stuff into thePredictiveQueues
543- for(short thePlayerIndex = 0; thePlayerIndex < dynamic_world->player_count; thePlayerIndex++)
544- {
545- uint32 theFlags = (thePlayerIndex == local_player_index) ? NetGetUnconfirmedActionFlag(sPredictedTicks) : sMostRecentFlagsForPlayer[thePlayerIndex];
546- thePredictiveQueues.enqueueActionFlags(thePlayerIndex, &theFlags, 1);
547- }
548-
549- // update_players() will dequeue the elements we just put in there
550- update_players(&thePredictiveQueues, true);
551-
552- didPredict = true;
553-
554- } // loop while local player has flags we haven't used for prediction
555-
556- } // if we should predict
557-
558- // we return separately 1. "whether to redraw" and 2. "how many game-ticks elapsed"
559- return std::pair<bool, int16>(didPredict || theElapsedTime != 0, theElapsedTime);
560-}
561-
562-/* call this function before leaving the old level, but DO NOT call it when saving the player.
563- it should be called when you're leaving the game (i.e., quitting or reverting, etc.) */
564-void leaving_map(
565- void)
566-{
567-
568- remove_all_projectiles();
569- remove_all_nonpersistent_effects();
570-
571- /* mark our shape collections for unloading */
572- mark_environment_collections(static_world->environment_code, false);
573- mark_all_monster_collections(false);
574- mark_player_collections(false);
575- mark_map_collections(false);
576- MarkLuaCollections(false);
577- MarkLuaHUDCollections(false);
578- L_Call_Cleanup ();
579- //Close and unload the Lua state
580- CloseLuaScript();
581-#if !defined(DISABLE_NETWORKING)
582- NetSetChatCallbacks(NULL);
583-#endif // !defined(DISABLE_NETWORKING)
584- Console::instance()->deactivate_input();
585-
586- /* all we do is mark them for unloading, we don't explicitly dispose of them; whenever the
587- next level is loaded someone (probably entering_map, below) will call load_collections()
588- and the stuff we marked as needed to be ditched will be */
589-
590- /* stop counting world ticks */
591-// set_keyboard_controller_status(false);
592-
593- // Hackish. Should probably be in stop_all_sounds(), but that just
594- // doesn't work out.
595- Music::instance()->StopLevelMusic();
596- SoundManager::instance()->StopAllSounds();
597-
598- SoundManager::instance()->UnloadCustomSounds();
599-}
600-
601-/* call this function after the new level has been completely read into memory, after
602- player->location and player->facing have been updated, and as close to the end of
603- the loading process in general as possible. */
604-// LP: added whether a savegame is being restored (skip Pfhortran init if that's the case)
605-bool entering_map(bool restoring_saved)
606-{
607- bool success= true;
608-
609- /* if any active monsters think they have paths, we'll make them reconsider */
610- initialize_monsters_for_new_level();
611-
612- /* and since no monsters have paths, we should make sure no paths think they have monsters */
613- reset_paths();
614-
615- /* mark our shape collections for loading and load them */
616- mark_environment_collections(static_world->environment_code, true);
617- mark_all_monster_collections(true);
618- mark_player_collections(true);
619- mark_map_collections(true);
620-
621- MarkLuaCollections(true);
622- MarkLuaHUDCollections(true);
623-
624-#ifdef SDL
625- load_collections(true, get_screen_mode()->acceleration != _no_acceleration);
626-#else
627- load_collections(true, true);
628-#endif
629-
630- load_all_monster_sounds();
631- load_all_game_sounds(static_world->environment_code);
632-
633-#if !defined(DISABLE_NETWORKING)
634- /* tell the keyboard controller to start recording keyboard flags */
635- if (game_is_networked) success= NetSync(); /* make sure everybody is ready */
636-#endif // !defined(DISABLE_NETWORKING)
637-
638- /* make sure nobodyユs holding a weapon illegal in the new environment */
639- check_player_weapons_for_environment_change();
640-
641-#if !defined(DISABLE_NETWORKING)
642- if (dynamic_world->player_count>1 && !restoring_saved) initialize_net_game();
643-#endif // !defined(DISABLE_NETWORKING)
644- randomize_scenery_shapes();
645-
646- reset_action_queues(); //ヲヲ
647-// sync_heartbeat_count();
648-// set_keyboard_controller_status(true);
649-
650- L_Call_Init(restoring_saved);
651-
652-#if !defined(DISABLE_NETWORKING)
653- NetSetChatCallbacks(InGameChatCallbacks::instance());
654-#endif // !defined(DISABLE_NETWORKING)
655-
656- // Zero out fades *AND* any inadvertant fades from script start...
657- stop_fade();
658- set_fade_effect(NONE);
659-
660- if (!success) leaving_map();
661-
662- return success;
663-}
664-
665-/* This is called when an object of some mass enters a polygon from another */
666-/* polygon. It handles triggering lightsources, platforms, and whatever */
667-/* else it is that we can think of. */
668-void changed_polygon(
669- short original_polygon_index,
670- short new_polygon_index,
671- short player_index)
672-{
673- struct polygon_data *new_polygon= get_polygon_data(new_polygon_index);
674- struct player_data *player= player_index!=NONE ? get_player_data(player_index) : (struct player_data *) NULL;
675-
676- (void) (original_polygon_index);
677-
678- /* Entering this polygon.. */
679- switch (new_polygon->type)
680- {
681- case _polygon_is_visible_monster_trigger:
682- if (player)
683- {
684- activate_nearby_monsters(player->monster_index, player->monster_index,
685- _pass_solid_lines|_activate_deaf_monsters|_use_activation_biases|_activation_cannot_be_avoided);
686- }
687- break;
688- case _polygon_is_invisible_monster_trigger:
689- case _polygon_is_dual_monster_trigger:
690- if (player)
691- {
692- activate_nearby_monsters(player->monster_index, player->monster_index,
693- _pass_solid_lines|_activate_deaf_monsters|_activate_invisible_monsters|_use_activation_biases|_activation_cannot_be_avoided);
694- }
695- break;
696-
697- case _polygon_is_item_trigger:
698- if (player)
699- {
700- trigger_nearby_items(new_polygon_index);
701- }
702- break;
703-
704- case _polygon_is_light_on_trigger:
705- case _polygon_is_light_off_trigger:
706- set_light_status(new_polygon->permutation,
707- new_polygon->type==_polygon_is_light_off_trigger ? false : true);
708- break;
709-
710- case _polygon_is_platform:
711- platform_was_entered(new_polygon->permutation, player ? true : false);
712- break;
713- case _polygon_is_platform_on_trigger:
714- case _polygon_is_platform_off_trigger:
715- if (player)
716- {
717- try_and_change_platform_state(get_polygon_data(new_polygon->permutation)->permutation,
718- new_polygon->type==_polygon_is_platform_off_trigger ? false : true);
719- }
720- break;
721-
722- case _polygon_must_be_explored:
723- /* When a player enters a must be explored, it now becomes a normal polygon, to allow */
724- /* for must be explored flags to work across cooperative net games */
725- if(player)
726- {
727- new_polygon->type= _polygon_is_normal;
728- }
729- break;
730-
731- default:
732- break;
733- }
734-}
735-
736-/* _level_failed is the same as _level_finished but indicates a non-fatal failure condition (e.g.,
737- too many civilians died during _mission_rescue) */
738-short calculate_level_completion_state(
739- void)
740-{
741- short completion_state= _level_finished;
742-
743- /* if there are any monsters left on an extermination map, we havenユt finished yet */
744- if (static_world->mission_flags&_mission_extermination)
745- {
746- if (live_aliens_on_map()) completion_state= _level_unfinished;
747- }
748-
749- /* if there are any polygons which must be explored and have not been entered, weユre not done */
750- if (static_world->mission_flags&_mission_exploration)
751- {
752- short polygon_index;
753- struct polygon_data *polygon;
754-
755- for (polygon_index= 0, polygon= map_polygons; polygon_index<dynamic_world->polygon_count; ++polygon_index, ++polygon)
756- {
757- if (polygon->type==_polygon_must_be_explored)
758- {
759- completion_state= _level_unfinished;
760- break;
761- }
762- }
763- }
764-
765- /* if there are any items left on this map, weユre not done */
766- if (static_world->mission_flags&_mission_retrieval)
767- {
768- if (unretrieved_items_on_map()) completion_state= _level_unfinished;
769- }
770-
771- /* if there are any untoggled repair switches on this level then weユre not there */
772- if (static_world->mission_flags&_mission_repair)
773- {
774- if (untoggled_repair_switches_on_level()) completion_state= _level_unfinished;
775- }
776-
777- /* if weユve finished the level, check failure conditions */
778- if (completion_state==_level_finished)
779- {
780- /* if this is a rescue mission and more than half of the civilians died, the mission failed */
781- if (static_world->mission_flags&_mission_rescue &&
782- dynamic_world->current_civilian_causalties>dynamic_world->current_civilian_count/2)
783- {
784- completion_state= _level_failed;
785- }
786- }
787-
788- return completion_state;
789-}
790-
791-short calculate_damage(
792- struct damage_definition *damage)
793-{
794- short total_damage= damage->base + (damage->random ? global_random()%damage->random : 0);
795-
796- total_damage= FIXED_INTEGERAL_PART(total_damage*damage->scale);
797-
798- /* if this damage was caused by an alien modify it for the current difficulty level */
799- if (damage->flags&_alien_damage)
800- {
801- switch (dynamic_world->game_information.difficulty_level)
802- {
803- case _wuss_level: total_damage-= total_damage>>1; break;
804- case _easy_level: total_damage-= total_damage>>2; break;
805- /* harder levels do not cause more damage */
806- }
807- }
808-
809- return total_damage;
810-}
811-
812-#define MINOR_OUCH_FREQUENCY 0xf
813-#define MAJOR_OUCH_FREQUENCY 0x7
814-#define MINOR_OUCH_DAMAGE 15
815-#define MAJOR_OUCH_DAMAGE 7
816-
817-// LP temp fix: assignments are intended to approximate Marathon 1 (minor = lava, major = PfhorSlime)
818-#define _damage_polygon _damage_lava
819-#define _damage_major_polygon _damage_goo
820-
821-void cause_polygon_damage(
822- short polygon_index,
823- short monster_index)
824-{
825- struct polygon_data *polygon= get_polygon_data(polygon_index);
826- struct monster_data *monster= get_monster_data(monster_index);
827- struct object_data *object= get_object_data(monster->object_index);
828-
829-// #if 0
830- if ((polygon->type==_polygon_is_minor_ouch && !(dynamic_world->tick_count&MINOR_OUCH_FREQUENCY) && object->location.z==polygon->floor_height) ||
831- (polygon->type==_polygon_is_major_ouch && !(dynamic_world->tick_count&MAJOR_OUCH_FREQUENCY)))
832- {
833- struct damage_definition damage;
834-
835- damage.flags= _alien_damage;
836- damage.type= polygon->type==_polygon_is_minor_ouch ? _damage_polygon : _damage_major_polygon;
837- damage.base= polygon->type==_polygon_is_minor_ouch ? MINOR_OUCH_DAMAGE : MAJOR_OUCH_DAMAGE;
838- damage.random= 0;
839- damage.scale= FIXED_ONE;
840-
841- damage_monster(monster_index, NONE, NONE, (world_point3d *) NULL, &damage, NONE);
842- }
843-// #endif
844-}
845-
846-/* ---------- private code */
847-
848-/* They ran out of time. This means different things depending on the */
849-/* type of game.. */
850-static void game_timed_out(
851- void)
852-{
853- if(player_controlling_game())
854- {
855- set_game_state(_close_game);
856- } else {
857- set_game_state(_switch_demo);
858- }
859-}
860-
861-
862-// LP: suppressed this as superfluous; won't try to reassign these sounds for M1 compatibility
863-static void load_all_game_sounds(
864- short environment_code)
865-{
866-}
867-
868-/*
869-#define NUMBER_OF_PRELOAD_SOUNDS (sizeof(preload_sounds)/sizeof(short))
870-static short preload_sounds[]=
871-{
872- _snd_teleport_in,
873- _snd_teleport_out,
874- _snd_bullet_ricochet,
875- _snd_magnum_firing,
876- _snd_assault_rifle_firing,
877- _snd_body_falling,
878- _snd_body_exploding,
879- _snd_bullet_hitting_flesh
880-};
881-
882-#define NUMBER_OF_PRELOAD_SOUNDS0 (sizeof(preload_sounds0)/sizeof(short))
883-static short preload_sounds0[]= {_snd_water, _snd_wind};
884-
885-#define NUMBER_OF_PRELOAD_SOUNDS1 (sizeof(preload_sounds1)/sizeof(short))
886-static short preload_sounds1[]= {_snd_lava, _snd_wind};
887-
888-static void load_all_game_sounds(
889- short environment_code)
890-{
891- load_sounds(preload_sounds, NUMBER_OF_PRELOAD_SOUNDS);
892-
893- switch (environment_code)
894- {
895- case 0: load_sounds(preload_sounds0, NUMBER_OF_PRELOAD_SOUNDS0); break;
896- case 1: load_sounds(preload_sounds1, NUMBER_OF_PRELOAD_SOUNDS1); break;
897- case 2: break;
898- case 3: break;
899- case 4: break;
900- }
901-}
902-*/
1+/*
2+MARATHON.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+Friday, December 3, 1993 10:00:32 AM
22+
23+Monday, September 5, 1994 2:42:28 PM (ajr)
24+ fixed kill_limit.
25+Saturday, September 17, 1994 6:04:59 PM (alain)
26+ fixed autotriggering of platforms
27+Thursday, December 8, 1994 3:58:12 PM (Jason)
28+ only players trigger platforms.
29+
30+Feb 6, 2000 (Loren Petrich):
31+ Added typecode initialization
32+
33+Feb 10, 2000 (Loren Petrich):
34+ Added dynamic-limits initialization
35+
36+Feb 15, 2000 (Loren Petrich):
37+ Added item-initialization and item-animation stuff
38+
39+Mar 12, 2000 (Loren Petrich):
40+ Added OpenGL initializer
41+
42+May 11, 2000 (Loren Petrich):
43+ Rewrote to get rid of dynamic-limit and animated-texture initializers;
44+ also used new animated-texture update function.
45+
46+June 15, 2000 (Loren Petrich):
47+ Added support for Chris Pruett's Pfhortran
48+
49+Aug 10, 2000 (Loren Petrich):
50+ Added Chris Pruett's Pfhortran changes
51+
52+Feb 4, 2002 (Br'fin (Jeremy Parsons)):
53+ Moved Macintosh call to OGL_Initialize to shell_macintosh.cpp
54+
55+Feb 20, 2002 (Woody Zenfell):
56+ Changed action queues operations to ActionQueues operations on GetRealActionQueues()
57+
58+Mar 13, 2002 (Br'fin (Jeremy Parsons)):
59+ Altered enter_game to stop and reset fades after script_init
60+
61+Jan 12, 2003 (Woody Zenfell):
62+ Added ability to reset intermediate action queues (GameQueue)
63+ Fixed potential out-of-sync bug
64+
65+Feb 8, 2003 (Woody Zenfell):
66+ Reformulated main update loop and multiple ActionFlags queue handling.
67+ PLAYER_IS_PFHORTRAN_CONTROLLED is now no longer used - if a player has
68+ entries in the PfhortranActionQueues, they'll be used; if not, his
69+ entries from the RealActionQueues will be.
70+
71+ June 14, 2003 (Woody Zenfell):
72+ Player movement prediction support:
73+ + Support for retaining a partial game-state (this could be moved out to another file)
74+ + Changes to update_world() to take advantage of partial game-state saving/restoring.
75+*/
76+
77+#include "cseries.h"
78+#include "map.h"
79+#include "render.h"
80+#include "interface.h"
81+#include "FilmProfile.h"
82+#include "flood_map.h"
83+#include "effects.h"
84+#include "monsters.h"
85+#include "projectiles.h"
86+#include "player.h"
87+#include "network.h"
88+#include "scenery.h"
89+#include "platforms.h"
90+#include "lightsource.h"
91+#include "media.h"
92+#include "Music.h"
93+#include "fades.h"
94+#include "items.h"
95+#include "weapons.h"
96+#include "game_window.h"
97+#include "SoundManager.h"
98+#include "network_games.h"
99+// LP additions:
100+#include "tags.h"
101+#include "AnimatedTextures.h"
102+#include "ChaseCam.h"
103+#include "OGL_Setup.h"
104+
105+// MH additions:
106+#include "lua_script.h"
107+#include "lua_hud_script.h"
108+#include <string>
109+
110+// ZZZ additions:
111+#include "ActionQueues.h"
112+#include "Logging.h"
113+
114+// for screen_mode :(
115+#include "screen.h"
116+#include "shell.h"
117+
118+#include "Console.h"
119+
120+#include <limits.h>
121+
122+#ifdef env68k
123+#pragma segment marathon
124+#endif
125+
126+/* ---------- constants */
127+
128+/* ---------- globals */
129+
130+// This is an intermediate action-flags queue for transferring action flags
131+// from whichever source to the engine's event handling
132+// ghs: making this externally available for Lua's trigger modifications
133+static ModifiableActionQueues* GameQueue = NULL;
134+ModifiableActionQueues* GetGameQueue() { return GameQueue; }
135+
136+// ZZZ: We keep this around for use in prediction (we assume a player keeps on doin' what he's been doin')
137+static uint32 sMostRecentFlagsForPlayer[MAXIMUM_NUMBER_OF_PLAYERS];
138+
139+/* ---------- private prototypes */
140+
141+static void game_timed_out(void);
142+
143+static void load_all_game_sounds(short environment_code);
144+
145+/* ---------- code */
146+
147+void initialize_marathon(
148+ void)
149+{
150+#ifndef DEMO /* no external physics models for demo */
151+// import_definition_structures();
152+#endif
153+
154+ build_trig_tables();
155+ allocate_map_memory();
156+ // Rendering and flood-map done when starting a level,
157+ // since they require map-geometry sizes
158+ // allocate_render_memory();
159+ allocate_pathfinding_memory();
160+ // allocate_flood_map_memory();
161+ allocate_texture_tables();
162+ initialize_weapon_manager();
163+ initialize_game_window();
164+ initialize_scenery();
165+ // LP additions:
166+ initialize_items();
167+#if defined(HAVE_OPENGL) && !defined(mac)
168+ OGL_Initialize();
169+#endif
170+ GameQueue = new ModifiableActionQueues(MAXIMUM_NUMBER_OF_PLAYERS, ACTION_QUEUE_BUFFER_DIAMETER, true);
171+}
172+
173+static size_t sPredictedTicks = 0;
174+
175+void
176+reset_intermediate_action_queues() {
177+ GameQueue->reset();
178+
179+ // ZZZ: I don't know that this is strictly the best place (or the best function name)
180+ // to do this stuff, but it works, anyway.
181+ for(size_t i = 0; i < MAXIMUM_NUMBER_OF_PLAYERS; i++)
182+ sMostRecentFlagsForPlayer[i] = 0;
183+
184+ sPredictedTicks = 0;
185+}
186+
187+
188+// ZZZ: For prediction...
189+static bool sPredictionWanted= false;
190+
191+void
192+set_prediction_wanted(bool inPrediction)
193+{
194+ sPredictionWanted= inPrediction;
195+}
196+
197+static player_data sSavedPlayerData[MAXIMUM_NUMBER_OF_PLAYERS];
198+static monster_data sSavedPlayerMonsterData[MAXIMUM_NUMBER_OF_PLAYERS];
199+static object_data sSavedPlayerObjectData[MAXIMUM_NUMBER_OF_PLAYERS];
200+static object_data sSavedPlayerParasiticObjectData[MAXIMUM_NUMBER_OF_PLAYERS];
201+static short sSavedPlayerObjectNextObject[MAXIMUM_NUMBER_OF_PLAYERS];
202+
203+// For sanity-checking...
204+static int32 sSavedTickCount;
205+static uint16 sSavedRandomSeed;
206+
207+
208+// ZZZ: If not already in predictive mode, save off partial game-state for later restoration.
209+static void
210+enter_predictive_mode()
211+{
212+ if(sPredictedTicks == 0)
213+ {
214+ for(short i = 0; i < dynamic_world->player_count; i++)
215+ {
216+ sSavedPlayerData[i] = *get_player_data(i);
217+ if(sSavedPlayerData[i].monster_index != NONE)
218+ {
219+ sSavedPlayerMonsterData[i] = *get_monster_data(sSavedPlayerData[i].monster_index);
220+ if(sSavedPlayerMonsterData[i].object_index != NONE)
221+ {
222+ sSavedPlayerObjectData[i] = *get_object_data(sSavedPlayerMonsterData[i].object_index);
223+ sSavedPlayerObjectNextObject[i] = sSavedPlayerObjectData[i].next_object;
224+ if(sSavedPlayerObjectData[i].parasitic_object != NONE)
225+ sSavedPlayerParasiticObjectData[i] = *get_object_data(sSavedPlayerObjectData[i].parasitic_object);
226+ }
227+ }
228+ }
229+
230+ // Sanity checking
231+ sSavedTickCount = dynamic_world->tick_count;
232+ sSavedRandomSeed = get_random_seed();
233+ }
234+}
235+
236+
237+#if COMPARE_MEMORY
238+// ZZZ: I wrote this function to help catch incomplete state save/restore operations on entering and exiting predictive mode
239+// It's not currently in use anywhere, but may prove useful sometime? so I'm including it in my submission.
240+static void
241+compare_memory(const char* inChunk1, const char* inChunk2, size_t inSize, size_t inIgnoreStart, size_t inIgnoreEnd, const char* inDescription, int inDescriptionNumber)
242+{
243+ bool trackingDifferences = false;
244+ size_t theDifferenceStart;
245+
246+ for(size_t i = 0; i < inSize; i++)
247+ {
248+ if(inChunk1[i] != inChunk2[i])
249+ {
250+ if(!trackingDifferences)
251+ {
252+ theDifferenceStart = i;
253+ trackingDifferences = true;
254+ }
255+ }
256+ else
257+ {
258+ if(trackingDifferences)
259+ {
260+ if(theDifferenceStart < inIgnoreStart || i >= inIgnoreEnd)
261+ logWarning4("%s %d: differences in bytes [%d,%d)", inDescription, inDescriptionNumber, theDifferenceStart, i);
262+ trackingDifferences = false;
263+ }
264+ }
265+ }
266+
267+ if(trackingDifferences)
268+ {
269+ if(theDifferenceStart < inIgnoreStart || inSize >= inIgnoreEnd)
270+ logWarning4("%s %d: differences in bytes [%d,%d)", inDescription, inDescriptionNumber, theDifferenceStart, inSize);
271+ }
272+}
273+#endif
274+
275+// ZZZ: if in predictive mode, restore the saved partial game-state (it'd better take us back
276+// to _exactly_ the same full game-state we saved earlier, else problems.)
277+static void
278+exit_predictive_mode()
279+{
280+ if(sPredictedTicks > 0)
281+ {
282+ for(short i = 0; i < dynamic_world->player_count; i++)
283+ {
284+ player_data* player = get_player_data(i);
285+
286+ assert(player->monster_index == sSavedPlayerData[i].monster_index);
287+
288+ {
289+ // We *don't* restore this tiny part of the game-state back because
290+ // otherwise the player can't use [] to scroll the inventory panel.
291+ // [] scrolling happens outside the normal input/update system, so that's
292+ // enough to persuade me that not restoring this won't OOS any more often
293+ // than []-scrolling did before prediction. :)
294+ int16 saved_interface_flags = player->interface_flags;
295+ int16 saved_interface_decay = player->interface_decay;
296+
297+ *player = sSavedPlayerData[i];
298+
299+ player->interface_flags = saved_interface_flags;
300+ player->interface_decay = saved_interface_decay;
301+ }
302+
303+ if(sSavedPlayerData[i].monster_index != NONE)
304+ {
305+ assert(get_monster_data(sSavedPlayerData[i].monster_index)->object_index == sSavedPlayerMonsterData[i].object_index);
306+
307+ *get_monster_data(sSavedPlayerData[i].monster_index) = sSavedPlayerMonsterData[i];
308+
309+ if(sSavedPlayerMonsterData[i].object_index != NONE)
310+ {
311+ assert(get_object_data(sSavedPlayerMonsterData[i].object_index)->parasitic_object == sSavedPlayerObjectData[i].parasitic_object);
312+
313+ remove_object_from_polygon_object_list(sSavedPlayerMonsterData[i].object_index);
314+
315+ *get_object_data(sSavedPlayerMonsterData[i].object_index) = sSavedPlayerObjectData[i];
316+
317+ // We have to defer this insertion since the object lists could still have other players
318+ // in their predictive locations etc. - we need to reconstruct everything exactly as it
319+ // was when we entered predictive mode.
320+ deferred_add_object_to_polygon_object_list(sSavedPlayerMonsterData[i].object_index, sSavedPlayerObjectNextObject[i]);
321+
322+ if(sSavedPlayerObjectData[i].parasitic_object != NONE)
323+ *get_object_data(sSavedPlayerObjectData[i].parasitic_object) = sSavedPlayerParasiticObjectData[i];
324+ }
325+ }
326+ }
327+
328+ perform_deferred_polygon_object_list_manipulations();
329+
330+ sPredictedTicks = 0;
331+
332+ // Sanity checking
333+ if(sSavedTickCount != dynamic_world->tick_count)
334+ logWarning2("saved tick count %d != dynamic_world->tick_count %d", sSavedTickCount, dynamic_world->tick_count);
335+
336+ if(sSavedRandomSeed != get_random_seed())
337+ logWarning2("saved random seed %d != get_random_seed() %d", sSavedRandomSeed, get_random_seed());
338+ }
339+}
340+
341+
342+// ZZZ: move a single tick's flags (if there's one present for each player in the Base Queues)
343+// from the Base Queues into the Output Queues, overriding each with the corresponding player's
344+// flags from the Overlay Queues, if non-empty.
345+static bool
346+overlay_queue_with_queue_into_queue(ActionQueues* inBaseQueues, ActionQueues* inOverlayQueues, ActionQueues* inOutputQueues)
347+{
348+ bool haveFlagsForAllPlayers = true;
349+ for(int p = 0; p < dynamic_world->player_count; p++)
350+ {
351+ if(inBaseQueues->countActionFlags(p) <= 0)
352+ {
353+ haveFlagsForAllPlayers = false;
354+ break;
355+ }
356+ }
357+
358+ if(!haveFlagsForAllPlayers)
359+ {
360+ return false;
361+ }
362+
363+ for(int p = 0; p < dynamic_world->player_count; p++)
364+ {
365+ // Trust me, this is right - we dequeue from the Base Queues whether or not they get overridden.
366+ uint32 action_flags = inBaseQueues->dequeueActionFlags(p);
367+
368+ if(inOverlayQueues != NULL && inOverlayQueues->countActionFlags(p) > 0)
369+ {
370+ action_flags = inOverlayQueues->dequeueActionFlags(p);
371+ }
372+
373+ inOutputQueues->enqueueActionFlags(p, &action_flags, 1);
374+ }
375+
376+ return true;
377+}
378+
379+
380+// Return values for update_world_elements_one_tick()
381+enum {
382+ kUpdateNormalCompletion,
383+ kUpdateGameOver,
384+ kUpdateChangeLevel
385+};
386+
387+// ZZZ: split out from update_world()'s loop.
388+static int
389+update_world_elements_one_tick()
390+{
391+ L_Call_Idle();
392+
393+ update_lights();
394+ update_medias();
395+ update_platforms();
396+
397+ update_control_panels(); // don't put after update_players
398+ update_players(GameQueue, false);
399+ move_projectiles();
400+ move_monsters();
401+ update_effects();
402+ recreate_objects();
403+
404+ handle_random_sound_image();
405+ animate_scenery();
406+
407+ // LP additions:
408+ if (film_profile.animate_items)
409+ {
410+ animate_items();
411+ }
412+
413+ AnimTxtr_Update();
414+ ChaseCam_Update();
415+
416+#if !defined(DISABLE_NETWORKING)
417+ update_net_game();
418+#endif // !defined(DISABLE_NETWORKING)
419+
420+ if(check_level_change())
421+ {
422+ return kUpdateChangeLevel;
423+ }
424+
425+#if !defined(DISABLE_NETWORKING)
426+ if(game_is_over())
427+ {
428+ return kUpdateGameOver;
429+ }
430+#endif // !defined(DISABLE_NETWORKING)
431+
432+ dynamic_world->tick_count+= 1;
433+ dynamic_world->game_information.game_time_remaining-= 1;
434+
435+ return kUpdateNormalCompletion;
436+}
437+
438+// ZZZ: new formulation of update_world(), should be simpler and clearer I hope.
439+// Now returns (whether something changed, number of real ticks elapsed) since, with
440+// prediction, something can change even if no real ticks have elapsed.
441+
442+std::pair<bool, int16>
443+update_world()
444+{
445+ short theElapsedTime = 0;
446+ bool canUpdate = true;
447+ int theUpdateResult = kUpdateNormalCompletion;
448+
449+#ifndef DISABLE_NETWORKING
450+ if (game_is_networked)
451+ NetProcessMessagesInGame();
452+#endif
453+
454+ while(canUpdate)
455+ {
456+ // If we have flags in the GameQueue, or can put a tick's-worth there, we're ok.
457+ // Note that GameQueue should be stocked evenly (i.e. every player has the same # of flags)
458+ if(GameQueue->countActionFlags(0) == 0)
459+ {
460+ canUpdate = overlay_queue_with_queue_into_queue(GetRealActionQueues(), GetLuaActionQueues(), GameQueue);
461+ }
462+
463+ if(!sPredictionWanted)
464+ {
465+ // See if the speed-limiter (net time or heartbeat count) will let us advance a tick
466+#if !defined(DISABLE_NETWORKING)
467+ int theMostRecentAllowedTick = game_is_networked ? NetGetNetTime() : get_heartbeat_count();
468+#else
469+ int theMostRecentAllowedTick = get_heartbeat_count();
470+#endif
471+
472+ if(dynamic_world->tick_count >= theMostRecentAllowedTick)
473+ {
474+ canUpdate = false;
475+ }
476+ }
477+
478+ // If we can't update, we can't update. We're done for now.
479+ if(!canUpdate)
480+ {
481+ break;
482+ }
483+
484+ // Transition from predictive -> real update mode, if necessary.
485+ exit_predictive_mode();
486+
487+ // Capture the flags for each player for use in prediction
488+ for(short i = 0; i < dynamic_world->player_count; i++)
489+ sMostRecentFlagsForPlayer[i] = GameQueue->peekActionFlags(i, 0);
490+
491+ theUpdateResult = update_world_elements_one_tick();
492+
493+ theElapsedTime++;
494+
495+
496+ L_Call_PostIdle();
497+ if(theUpdateResult != kUpdateNormalCompletion)
498+ {
499+ canUpdate = false;
500+ }
501+ }
502+
503+ // This and the following voodoo comes, effectively, from Bungie's code.
504+ if(theUpdateResult == kUpdateChangeLevel)
505+ {
506+ theElapsedTime = 0;
507+ }
508+
509+ /* Game is over. */
510+ if(theUpdateResult == kUpdateGameOver)
511+ {
512+ game_timed_out();
513+ theElapsedTime = 0;
514+ }
515+ else if (theElapsedTime)
516+ {
517+ update_interface(theElapsedTime);
518+ update_fades();
519+ }
520+
521+ check_recording_replaying();
522+
523+ // ZZZ: Prediction!
524+ bool didPredict = false;
525+
526+ if(theUpdateResult == kUpdateNormalCompletion && sPredictionWanted)
527+ {
528+ NetUpdateUnconfirmedActionFlags();
529+
530+ // We use "2" to make sure there's always room for our one set of elements.
531+ // (thePredictiveQueues should always hold only 0 or 1 element for each player.)
532+ ActionQueues thePredictiveQueues(dynamic_world->player_count, 2, true);
533+
534+ // Observe, since we don't use a speed-limiter in predictive mode, that there cannot be flags
535+ // stranded in the GameQueue. Unfortunately this approach will mispredict if a script is
536+ // controlling the local player. We could be smarter about it if that eventually becomes an issue.
537+ for ( ; sPredictedTicks < NetGetUnconfirmedActionFlagsCount(); sPredictedTicks++)
538+ {
539+ // Real -> predictive transition, if necessary
540+ enter_predictive_mode();
541+
542+ // Enqueue stuff into thePredictiveQueues
543+ for(short thePlayerIndex = 0; thePlayerIndex < dynamic_world->player_count; thePlayerIndex++)
544+ {
545+ uint32 theFlags = (thePlayerIndex == local_player_index) ? NetGetUnconfirmedActionFlag(sPredictedTicks) : sMostRecentFlagsForPlayer[thePlayerIndex];
546+ thePredictiveQueues.enqueueActionFlags(thePlayerIndex, &theFlags, 1);
547+ }
548+
549+ // update_players() will dequeue the elements we just put in there
550+ update_players(&thePredictiveQueues, true);
551+
552+ didPredict = true;
553+
554+ } // loop while local player has flags we haven't used for prediction
555+
556+ } // if we should predict
557+
558+ // we return separately 1. "whether to redraw" and 2. "how many game-ticks elapsed"
559+ return std::pair<bool, int16>(didPredict || theElapsedTime != 0, theElapsedTime);
560+}
561+
562+/* call this function before leaving the old level, but DO NOT call it when saving the player.
563+ it should be called when you're leaving the game (i.e., quitting or reverting, etc.) */
564+void leaving_map(
565+ void)
566+{
567+
568+ remove_all_projectiles();
569+ remove_all_nonpersistent_effects();
570+
571+ /* mark our shape collections for unloading */
572+ mark_environment_collections(static_world->environment_code, false);
573+ mark_all_monster_collections(false);
574+ mark_player_collections(false);
575+ mark_map_collections(false);
576+ MarkLuaCollections(false);
577+ MarkLuaHUDCollections(false);
578+ L_Call_Cleanup ();
579+ //Close and unload the Lua state
580+ CloseLuaScript();
581+#if !defined(DISABLE_NETWORKING)
582+ NetSetChatCallbacks(NULL);
583+#endif // !defined(DISABLE_NETWORKING)
584+ Console::instance()->deactivate_input();
585+
586+ /* all we do is mark them for unloading, we don't explicitly dispose of them; whenever the
587+ next level is loaded someone (probably entering_map, below) will call load_collections()
588+ and the stuff we marked as needed to be ditched will be */
589+
590+ /* stop counting world ticks */
591+// set_keyboard_controller_status(false);
592+
593+ // Hackish. Should probably be in stop_all_sounds(), but that just
594+ // doesn't work out.
595+ Music::instance()->StopLevelMusic();
596+ SoundManager::instance()->StopAllSounds();
597+
598+ SoundManager::instance()->UnloadCustomSounds();
599+}
600+
601+/* call this function after the new level has been completely read into memory, after
602+ player->location and player->facing have been updated, and as close to the end of
603+ the loading process in general as possible. */
604+// LP: added whether a savegame is being restored (skip Pfhortran init if that's the case)
605+bool entering_map(bool restoring_saved)
606+{
607+ bool success= true;
608+
609+ /* if any active monsters think they have paths, we'll make them reconsider */
610+ initialize_monsters_for_new_level();
611+
612+ /* and since no monsters have paths, we should make sure no paths think they have monsters */
613+ reset_paths();
614+
615+ /* mark our shape collections for loading and load them */
616+ mark_environment_collections(static_world->environment_code, true);
617+ mark_all_monster_collections(true);
618+ mark_player_collections(true);
619+ mark_map_collections(true);
620+
621+ MarkLuaCollections(true);
622+ MarkLuaHUDCollections(true);
623+
624+#ifdef SDL
625+ load_collections(true, get_screen_mode()->acceleration != _no_acceleration);
626+#else
627+ load_collections(true, true);
628+#endif
629+
630+ load_all_monster_sounds();
631+ load_all_game_sounds(static_world->environment_code);
632+
633+#if !defined(DISABLE_NETWORKING)
634+ /* tell the keyboard controller to start recording keyboard flags */
635+ if (game_is_networked) success= NetSync(); /* make sure everybody is ready */
636+#endif // !defined(DISABLE_NETWORKING)
637+
638+ /* make sure nobodyユs holding a weapon illegal in the new environment */
639+ check_player_weapons_for_environment_change();
640+
641+#if !defined(DISABLE_NETWORKING)
642+ if (dynamic_world->player_count>1 && !restoring_saved) initialize_net_game();
643+#endif // !defined(DISABLE_NETWORKING)
644+ randomize_scenery_shapes();
645+
646+// reset_action_queues(); //ヲヲ
647+// sync_heartbeat_count();
648+// set_keyboard_controller_status(true);
649+
650+ L_Call_Init(restoring_saved);
651+
652+#if !defined(DISABLE_NETWORKING)
653+ NetSetChatCallbacks(InGameChatCallbacks::instance());
654+#endif // !defined(DISABLE_NETWORKING)
655+
656+ // Zero out fades *AND* any inadvertant fades from script start...
657+ stop_fade();
658+ set_fade_effect(NONE);
659+
660+ if (!success) leaving_map();
661+
662+ return success;
663+}
664+
665+/* This is called when an object of some mass enters a polygon from another */
666+/* polygon. It handles triggering lightsources, platforms, and whatever */
667+/* else it is that we can think of. */
668+void changed_polygon(
669+ short original_polygon_index,
670+ short new_polygon_index,
671+ short player_index)
672+{
673+ struct polygon_data *new_polygon= get_polygon_data(new_polygon_index);
674+ struct player_data *player= player_index!=NONE ? get_player_data(player_index) : (struct player_data *) NULL;
675+
676+ (void) (original_polygon_index);
677+
678+ /* Entering this polygon.. */
679+ switch (new_polygon->type)
680+ {
681+ case _polygon_is_visible_monster_trigger:
682+ if (player)
683+ {
684+ activate_nearby_monsters(player->monster_index, player->monster_index,
685+ _pass_solid_lines|_activate_deaf_monsters|_use_activation_biases|_activation_cannot_be_avoided);
686+ }
687+ break;
688+ case _polygon_is_invisible_monster_trigger:
689+ case _polygon_is_dual_monster_trigger:
690+ if (player)
691+ {
692+ activate_nearby_monsters(player->monster_index, player->monster_index,
693+ _pass_solid_lines|_activate_deaf_monsters|_activate_invisible_monsters|_use_activation_biases|_activation_cannot_be_avoided);
694+ }
695+ break;
696+
697+ case _polygon_is_item_trigger:
698+ if (player)
699+ {
700+ trigger_nearby_items(new_polygon_index);
701+ }
702+ break;
703+
704+ case _polygon_is_light_on_trigger:
705+ case _polygon_is_light_off_trigger:
706+ set_light_status(new_polygon->permutation,
707+ new_polygon->type==_polygon_is_light_off_trigger ? false : true);
708+ break;
709+
710+ case _polygon_is_platform:
711+ platform_was_entered(new_polygon->permutation, player ? true : false);
712+ break;
713+ case _polygon_is_platform_on_trigger:
714+ case _polygon_is_platform_off_trigger:
715+ if (player)
716+ {
717+ try_and_change_platform_state(get_polygon_data(new_polygon->permutation)->permutation,
718+ new_polygon->type==_polygon_is_platform_off_trigger ? false : true);
719+ }
720+ break;
721+
722+ case _polygon_must_be_explored:
723+ /* When a player enters a must be explored, it now becomes a normal polygon, to allow */
724+ /* for must be explored flags to work across cooperative net games */
725+ if(player)
726+ {
727+ new_polygon->type= _polygon_is_normal;
728+ }
729+ break;
730+
731+ default:
732+ break;
733+ }
734+}
735+
736+/* _level_failed is the same as _level_finished but indicates a non-fatal failure condition (e.g.,
737+ too many civilians died during _mission_rescue) */
738+short calculate_level_completion_state(
739+ void)
740+{
741+ short completion_state= _level_finished;
742+
743+ /* if there are any monsters left on an extermination map, we havenユt finished yet */
744+ if (static_world->mission_flags&_mission_extermination)
745+ {
746+ if (live_aliens_on_map()) completion_state= _level_unfinished;
747+ }
748+
749+ /* if there are any polygons which must be explored and have not been entered, weユre not done */
750+ if (static_world->mission_flags&_mission_exploration)
751+ {
752+ short polygon_index;
753+ struct polygon_data *polygon;
754+
755+ for (polygon_index= 0, polygon= map_polygons; polygon_index<dynamic_world->polygon_count; ++polygon_index, ++polygon)
756+ {
757+ if (polygon->type==_polygon_must_be_explored)
758+ {
759+ completion_state= _level_unfinished;
760+ break;
761+ }
762+ }
763+ }
764+
765+ /* if there are any items left on this map, weユre not done */
766+ if (static_world->mission_flags&_mission_retrieval)
767+ {
768+ if (unretrieved_items_on_map()) completion_state= _level_unfinished;
769+ }
770+
771+ /* if there are any untoggled repair switches on this level then weユre not there */
772+ if (static_world->mission_flags&_mission_repair)
773+ {
774+ if (untoggled_repair_switches_on_level()) completion_state= _level_unfinished;
775+ }
776+
777+ /* if weユve finished the level, check failure conditions */
778+ if (completion_state==_level_finished)
779+ {
780+ /* if this is a rescue mission and more than half of the civilians died, the mission failed */
781+ if (static_world->mission_flags&_mission_rescue &&
782+ dynamic_world->current_civilian_causalties>dynamic_world->current_civilian_count/2)
783+ {
784+ completion_state= _level_failed;
785+ }
786+ }
787+
788+ return completion_state;
789+}
790+
791+short calculate_damage(
792+ struct damage_definition *damage)
793+{
794+ short total_damage= damage->base + (damage->random ? global_random()%damage->random : 0);
795+
796+ total_damage= FIXED_INTEGERAL_PART(total_damage*damage->scale);
797+
798+ /* if this damage was caused by an alien modify it for the current difficulty level */
799+ if (damage->flags&_alien_damage)
800+ {
801+ switch (dynamic_world->game_information.difficulty_level)
802+ {
803+ case _wuss_level: total_damage-= total_damage>>1; break;
804+ case _easy_level: total_damage-= total_damage>>2; break;
805+ /* harder levels do not cause more damage */
806+ }
807+ }
808+
809+ return total_damage;
810+}
811+
812+#define MINOR_OUCH_FREQUENCY 0xf
813+#define MAJOR_OUCH_FREQUENCY 0x7
814+#define MINOR_OUCH_DAMAGE 15
815+#define MAJOR_OUCH_DAMAGE 7
816+
817+// LP temp fix: assignments are intended to approximate Marathon 1 (minor = lava, major = PfhorSlime)
818+#define _damage_polygon _damage_lava
819+#define _damage_major_polygon _damage_goo
820+
821+void cause_polygon_damage(
822+ short polygon_index,
823+ short monster_index)
824+{
825+ struct polygon_data *polygon= get_polygon_data(polygon_index);
826+ struct monster_data *monster= get_monster_data(monster_index);
827+ struct object_data *object= get_object_data(monster->object_index);
828+
829+// #if 0
830+ if ((polygon->type==_polygon_is_minor_ouch && !(dynamic_world->tick_count&MINOR_OUCH_FREQUENCY) && object->location.z==polygon->floor_height) ||
831+ (polygon->type==_polygon_is_major_ouch && !(dynamic_world->tick_count&MAJOR_OUCH_FREQUENCY)))
832+ {
833+ struct damage_definition damage;
834+
835+ damage.flags= _alien_damage;
836+ damage.type= polygon->type==_polygon_is_minor_ouch ? _damage_polygon : _damage_major_polygon;
837+ damage.base= polygon->type==_polygon_is_minor_ouch ? MINOR_OUCH_DAMAGE : MAJOR_OUCH_DAMAGE;
838+ damage.random= 0;
839+ damage.scale= FIXED_ONE;
840+
841+ damage_monster(monster_index, NONE, NONE, (world_point3d *) NULL, &damage, NONE);
842+ }
843+// #endif
844+}
845+
846+/* ---------- private code */
847+
848+/* They ran out of time. This means different things depending on the */
849+/* type of game.. */
850+static void game_timed_out(
851+ void)
852+{
853+ if(player_controlling_game())
854+ {
855+ set_game_state(_close_game);
856+ } else {
857+ set_game_state(_switch_demo);
858+ }
859+}
860+
861+
862+// LP: suppressed this as superfluous; won't try to reassign these sounds for M1 compatibility
863+static void load_all_game_sounds(
864+ short environment_code)
865+{
866+}
867+
868+/*
869+#define NUMBER_OF_PRELOAD_SOUNDS (sizeof(preload_sounds)/sizeof(short))
870+static short preload_sounds[]=
871+{
872+ _snd_teleport_in,
873+ _snd_teleport_out,
874+ _snd_bullet_ricochet,
875+ _snd_magnum_firing,
876+ _snd_assault_rifle_firing,
877+ _snd_body_falling,
878+ _snd_body_exploding,
879+ _snd_bullet_hitting_flesh
880+};
881+
882+#define NUMBER_OF_PRELOAD_SOUNDS0 (sizeof(preload_sounds0)/sizeof(short))
883+static short preload_sounds0[]= {_snd_water, _snd_wind};
884+
885+#define NUMBER_OF_PRELOAD_SOUNDS1 (sizeof(preload_sounds1)/sizeof(short))
886+static short preload_sounds1[]= {_snd_lava, _snd_wind};
887+
888+static void load_all_game_sounds(
889+ short environment_code)
890+{
891+ load_sounds(preload_sounds, NUMBER_OF_PRELOAD_SOUNDS);
892+
893+ switch (environment_code)
894+ {
895+ case 0: load_sounds(preload_sounds0, NUMBER_OF_PRELOAD_SOUNDS0); break;
896+ case 1: load_sounds(preload_sounds1, NUMBER_OF_PRELOAD_SOUNDS1); break;
897+ case 2: break;
898+ case 3: break;
899+ case 4: break;
900+ }
901+}
902+*/
--- marathon/trunk/Source_Files/RenderOther/sdl_fonts.cpp (revision 508)
+++ marathon/trunk/Source_Files/RenderOther/sdl_fonts.cpp (revision 509)
@@ -237,6 +237,8 @@
237237 return info;
238238 }
239239 */
240+#include <iostream> // std::cout を使うのに必要
241+#include <boost/format.hpp> // boost::format を使うのに必要
240242 #ifdef HAVE_SDL_TTF
241243 static TTF_Font *load_ttf_font(const std::string& path, uint16 style, int16 size)
242244 {
@@ -253,17 +255,77 @@
253255
254256 TTF_Font *font = 0;
255257
256- // Japanese Font cannot render as embeded font.
257- // then, if Fonts.ttf exsists, read external font forcely.
258- FILE* fp = fopen( FONT_PATH, "r" );
259- if( !fp ){
260- fprintf(stderr, "TTF Font %s is not found. Load internal font. Japanese strings will be garbled.\n", FONT_PATH);
261- font = TTF_OpenFontRW(SDL_RWFromConstMem(aleph_sans_mono_bold, sizeof(aleph_sans_mono_bold)), 0, size);
262- }else{
263- font = TTF_OpenFont(FONT_PATH, size);
264- fclose( fp );
258+ // Load AlephOne Default Font. path is "mono"
259+ if (path == "mono")
260+ {
261+ // Japanese Font cannot render as embeded font.
262+ FILE* fp = fopen( FONT_PATH, "r" );
263+ if( fp ){
264+ // Fonts.ttf is exists, Load this Font.
265+ font = TTF_OpenFont(FONT_PATH, size);
266+ fclose( fp );
267+ }else{
268+ // If Fonts.ttf is missing, Load from System Font
269+ const string fontPath[] = {
270+#if defined(__WIN32__)
271+ // for Windows 7 (Meiryo Bold)
272+ "c:/Windows/winsxs/x86_microsoft-windows-f..truetype-meiryobold_31bf3856ad364e35_6.1.7600.16385_none_cd23f5e0d8f9c6fa/meiryob.ttc",
273+ "c:/Windows/winsxs/amd64_microsoft-windows-f..truetype-meiryobold_31bf3856ad364e35_6.1.7600.16385_none_2942916491573830/meiryob.ttc",
274+ // for Windows Vista
275+ "c:/Windows/Fonts/meiryob.ttc",
276+ // for less than Windows XP (MS Gothic)
277+ "c:/windows/fonts/msgothic.ttc",
278+ "c:/winnt/fonts/msgothic.ttc",
279+#elif defined(__MACOS__)
280+ // for MacOS (Hiragino Kaku Gothic Pro W6)
281+ "/System/Library/Fonts/Hiragino Kaku Gothic Pro W6.otf",
282+ "/System/Library/Fonts/Cache/HiraginoKakuGothicProNW6.otf"
283+#else
284+ // for Linux
285+ "/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf",
286+ "/usr/X11R6/lib/X11/fonts/TrueType/VL-Gothic-Regular.ttf",
287+ "/usr/X11/lib/X11/fonts/truetype/VL-Gothic-Regular.ttf",
288+ "/usr/share/fonts/ja-ipafonts/ipag.ttc",
289+
290+ "/usr/share/fonts/TrueType/mika.ttf",
291+ "/usr/X11R6/lib/X11/fonts/TrueType/mika.ttf",
292+ "/usr/X11R6/lib/X11/fonts/truetype/sazanami-gothic.ttf",
293+ "/usr/X11/lib/X11/fonts/truetype/sazanami-gothic.ttf",
294+ "/usr/share/fonts/TrueType/sazanami-gothic.ttf",
295+ "/usr/X11R6/lib/X11/fonts/TrueType/sazanami-gothic.ttf",
296+ "/usr/share/fonts/truetype/sazanami-gothic.ttf",
297+ "/usr/share/fonts/TrueType/FS-Gothic-gs.ttf",
298+ "/usr/X11R6/lib/X11/fonts/TrueType/FS-Gothic.ttf",
299+ "/usr/share/fonts/TrueType/gt200001.ttf",
300+ "/usr/X11R6/lib/X11/fonts/TrueType/gt200001.ttf",
301+#endif
302+ };
303+
304+ for ( int i=0; !fontPath[i].empty(); i++ ) {
305+ font = TTF_OpenFont(fontPath[i].c_str(), size);
306+ if ( !font ) { continue; }
307+ else { break; }
308+ }
309+ }
310+ if( !font ){
311+ font = TTF_OpenFontRW(SDL_RWFromConstMem(aleph_sans_mono_bold, sizeof(aleph_sans_mono_bold)), 0, size);
312+ }
265313 }
314+ else
315+ {
316+ // Load from Font specified in MML.
317+ short SavedType, SavedError = get_game_error(&SavedType);
266318
319+ FileSpecifier fileSpec(path);
320+ OpenedFile file;
321+ if (fileSpec.Open(file))
322+ {
323+ font = TTF_OpenFontRW(file.TakeRWops(), 1, size);
324+ }
325+
326+ set_game_error(SavedType, SavedError);
327+ }
328+
267329 if (font)
268330 {
269331 int ttf_style = TTF_STYLE_NORMAL;
@@ -307,7 +369,10 @@
307369 #endif
308370
309371 font_info *load_font(const TextSpec &spec) {
372+// return static_cast<font_info*>(load_font(spec));
373+
310374 #ifdef HAVE_SDL_TTF
375+ if (spec.normal != "")
311376 {
312377 std::string file;
313378 file = locate_font(spec.normal);
@@ -391,11 +456,27 @@
391456 }
392457 }
393458 }
459+
460+
394461 return info;
395462 }
396- return 0;
463+/* else if (spec.font != -1)
464+ {
465+ return static_cast<font_info *>(load_sdl_font(spec));
466+ }
467+*/
468+ else
469+ return 0;
397470 }
471+ else
398472 #endif
473+/* if (spec.font != -1)
474+ {
475+ return static_cast<font_info *>(load_sdl_font(spec));
476+ }
477+ else
478+*/
479+ return 0;
399480 }
400481
401482 /*
--- marathon/trunk/Source_Files/CSeries/FilmProfile.cpp (revision 508)
+++ marathon/trunk/Source_Files/CSeries/FilmProfile.cpp (revision 509)
@@ -17,6 +17,7 @@
1717 false, // use_vertical_kick_threshold
1818 false, // infinity_tag_fix
1919 false, // adjacent_polygons_always_intersect
20+ true, // early_object_initialization
2021 };
2122
2223 static FilmProfile marathon2 = {
@@ -34,6 +35,7 @@
3435 true, // use_vertical_kick_threshold
3536 false, // infinity_tag_fix
3637 false, // adjacent_polygons_always_intersect
38+ false, // early_object_initialization
3739 };
3840
3941 static FilmProfile marathon_infinity = {
@@ -51,6 +53,7 @@
5153 true, // use_vertical_kick_threshold
5254 true, // infinity_tag_fix
5355 true, // adjacent_polygons_always_intersect
56+ false, // early_object_initialization
5457 };
5558
5659 FilmProfile film_profile = alephone1_0;
--- marathon/trunk/Source_Files/CSeries/FilmProfile.h (revision 508)
+++ marathon/trunk/Source_Files/CSeries/FilmProfile.h (revision 509)
@@ -72,6 +72,9 @@
7272 // Marathon Infinity always adds adjacent polygons to the
7373 // intersecting indexes (unmerged maps only)
7474 bool adjacent_polygons_always_intersect;
75+
76+ // Aleph One moved object initialization to improve Lua access
77+ bool early_object_initialization;
7578 };
7679
7780 extern FilmProfile film_profile;
--- marathon/trunk/Source_Files/Files/game_wad.cpp (revision 508)
+++ marathon/trunk/Source_Files/Files/game_wad.cpp (revision 509)
@@ -1,2592 +1,2601 @@
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-#ifdef env68k
133-#pragma segment file_io
134-#endif
135-
136-// unify the save game code into one structure.
137-
138-/* -------- local globals */
139-FileSpecifier MapFileSpec;
140-static bool file_is_set= false;
141-
142-// LP addition: was a physics model loaded from the previous level loaded?
143-static bool PhysicsModelLoadedEarlier = false;
144-
145-// The following local globals are for handling games that need to be restored.
146-struct revert_game_info
147-{
148- bool game_is_from_disk;
149- struct game_data game_information;
150- struct player_start_data player_start;
151- struct entry_point entry_point;
152- FileSpecifier SavedGame;
153-};
154-static struct revert_game_info revert_game_data;
155-
156-#if 0
157-/* Borrowed from the old lightsource.h, to allow Marathon II to open/use Marathon I maps */
158-struct old_light_data {
159- uint16 flags;
160-
161- int16 type;
162- int16 mode; /* on, off, etc. */
163- int16 phase;
164-
165- fixed minimum_intensity, maximum_intensity;
166- int16 period; /* on, in ticks (turning on and off periods are always the same for a given light type,
167- or else are some function of this period) */
168-
169- fixed intensity; /* current intensity */
170-
171- int16 unused[5];
172-};
173-
174-enum /* old light types */
175-{
176- _light_is_normal,
177- _light_is_rheostat,
178- _light_is_flourescent,
179- _light_is_strobe,
180- _light_flickers,
181- _light_pulsates,
182- _light_is_annoying,
183- _light_is_energy_efficient
184-};
185-#endif
186-
187-/* -------- static functions */
188-static void scan_and_add_scenery(void);
189-static void complete_restoring_level(struct wad_data *wad);
190-static void load_redundant_map_data(short *redundant_data, size_t count);
191-static void allocate_map_structure_for_map(struct wad_data *wad);
192-static wad_data *build_export_wad(wad_header *header, int32 *length);
193-static struct wad_data *build_save_game_wad(struct wad_header *header, int32 *length);
194-
195-static void allocate_map_for_counts(size_t polygon_count, size_t side_count,
196- size_t endpoint_count, size_t line_count);
197-static void load_points(uint8 *points, size_t count);
198-static void load_lines(uint8 *lines, size_t count);
199-static void load_sides(uint8 *sides, size_t count, short version);
200-static void load_polygons(uint8 *polys, size_t count, short version);
201-static void load_lights(uint8 *_lights, size_t count, short version);
202-static void load_annotations(uint8 *annotations, size_t count);
203-static void load_objects(uint8 *map_objects, size_t count);
204-static void load_media(uint8 *_medias, size_t count);
205-static void load_map_info(uint8 *map_info);
206-static void load_ambient_sound_images(uint8 *data, size_t count);
207-static void load_random_sound_images(uint8 *data, size_t count);
208-static void load_terminal_data(uint8 *data, size_t length);
209-
210-/* Used _ONLY_ by game_wad.c internally and precalculate.c. */
211-// ZZZ: hmm, no longer true, now using when resuming a network saved-game... hope that's ok?...
212-//static bool process_map_wad(struct wad_data *wad, bool restoring_game, short version);
213-
214-/* Final three calls, must be in this order! */
215-static void recalculate_redundant_map(void);
216-static void scan_and_add_platforms(uint8 *platform_static_data, size_t count, short version);
217-static void complete_loading_level(short *_map_indexes, size_t map_index_count,
218- uint8 *_platform_data, size_t platform_data_count,
219- uint8 *actual_platform_data, size_t actual_platform_data_count, short version);
220-
221-static uint8 *unpack_directory_data(uint8 *Stream, directory_data *Objects, size_t Count);
222-//static uint8 *pack_directory_data(uint8 *Stream, directory_data *Objects, int Count);
223-
224-/* ------------------------ Net functions */
225-int32 get_net_map_data_length(
226- void *data)
227-{
228- return get_flat_data_length(data);
229-}
230-
231-/* Note that this frees it as well */
232-bool process_net_map_data(
233- void *data)
234-{
235- struct wad_header header;
236- struct wad_data *wad;
237- bool success= false;
238-
239- wad= inflate_flat_data(data, &header);
240- if(wad)
241- {
242- success= process_map_wad(wad, false, header.data_version);
243- free_wad(wad); /* Note that the flat data points into the wad. */
244- }
245-
246- return success;
247-}
248-
249-/* This will have to do some interesting voodoo with union wads, methinks */
250-void *get_map_for_net_transfer(
251- struct entry_point *entry)
252-{
253- assert(file_is_set);
254-
255- /* false means don't use union maps.. */
256- return get_flat_data(MapFileSpec, false, entry->level_number);
257-}
258-
259-/* ---------------------- End Net Functions ----------- */
260-
261-/* This takes a cstring */
262-void set_map_file(FileSpecifier& File)
263-{
264- // Do whatever parameter restoration is specified before changing the file
265- if (file_is_set) RunRestorationScript();
266-
267- MapFileSpec = File;
268- set_scenario_images_file(File);
269- // Only need to do this here
270- LoadLevelScripts(File);
271-
272- // Don't care whether there was an error when checking on the file's scenario images
273- clear_game_error();
274-
275- file_is_set= true;
276-}
277-
278-/* Set to the default map.. (Only if no map doubleclicked upon on startup.. */
279-void set_to_default_map(
280- void)
281-{
282- FileSpecifier NewMapFile;
283-
284- get_default_map_spec(NewMapFile);
285- set_map_file(NewMapFile);
286-}
287-
288-/* Return true if it finds the file, and it sets the mapfile to that file. */
289-/* Otherwise it returns false, meaning that we need have the file sent to us. */
290-bool use_map_file(
291- uint32 checksum)
292-{
293- FileSpecifier File;
294- bool success= false;
295-
296- if(find_wad_file_that_has_checksum(File, _typecode_scenario, strPATHS, checksum))
297- {
298- set_map_file(File);
299- success= true;
300- }
301-
302- return success;
303-}
304-
305-bool load_level_from_map(
306- short level_index)
307-{
308- OpenedFile OFile;
309- struct wad_header header;
310- struct wad_data *wad;
311- short index_to_load;
312- bool restoring_game= false;
313-
314- if(file_is_set)
315- {
316- /* Determine what we are trying to do.. */
317- if(level_index==NONE)
318- {
319- restoring_game= true;
320- index_to_load= 0; /* Saved games are always index 0 */
321- } else {
322- index_to_load= level_index;
323- }
324-
325- OpenedFile MapFile;
326- if (open_wad_file_for_reading(MapFileSpec,MapFile))
327- {
328- /* Read the file */
329- if(read_wad_header(MapFile, &header))
330- {
331- if(index_to_load>=0 && index_to_load<header.wad_count)
332- {
333-
334- wad= read_indexed_wad_from_file(MapFile, &header, index_to_load, true);
335- if (wad)
336- {
337- /* Process everything... */
338- process_map_wad(wad, restoring_game, header.data_version);
339-
340- /* Nuke our memory... */
341- free_wad(wad);
342- } else {
343- // error code has been set...
344- }
345- } else {
346- set_game_error(gameError, errWadIndexOutOfRange);
347- }
348- } else {
349- // error code has been set...
350- }
351-
352- /* Close the file.. */
353- close_wad_file(MapFile);
354- } else {
355- // error code has been set..
356- }
357- } else {
358- set_game_error(gameError, errMapFileNotSet);
359- }
360-
361- /* ... and bail */
362- return (!error_pending());
363-}
364-
365-// keep these around for level export
366-static std::vector<static_platform_data> static_platforms;
367-
368-extern bool ok_to_reset_scenery_solidity;
369-
370-/* Hopefully this is in the correct order of initialization... */
371-/* This sucks, beavis. */
372-void complete_loading_level(
373- short *_map_indexes,
374- size_t map_index_count,
375- uint8 *_platform_data,
376- size_t platform_data_count,
377- uint8 *actual_platform_data,
378- size_t actual_platform_data_count,
379- short version)
380-{
381- /* Scan, add the doors, recalculate, and generally tie up all loose ends */
382- /* Recalculate the redundant data.. */
383- load_redundant_map_data(_map_indexes, map_index_count);
384-
385- static_platforms.clear();
386-
387- /* Add the platforms. */
388- if(_platform_data || (_platform_data==NULL && actual_platform_data==NULL))
389- {
390- scan_and_add_platforms(_platform_data, platform_data_count, version);
391- } else {
392- assert(actual_platform_data);
393- PlatformList.resize(actual_platform_data_count);
394- unpack_platform_data(actual_platform_data,platforms,actual_platform_data_count);
395- assert(actual_platform_data_count == static_cast<size_t>(static_cast<int16>(actual_platform_data_count)));
396- assert(0 <= static_cast<int16>(actual_platform_data_count));
397- dynamic_world->platform_count= static_cast<int16>(actual_platform_data_count);
398- }
399-
400- scan_and_add_scenery();
401- ok_to_reset_scenery_solidity = true;
402-
403- /* Gotta do this after recalculate redundant.. */
404- if(version==MARATHON_ONE_DATA_VERSION)
405- {
406- short loop;
407-
408- for(loop= 0; loop<dynamic_world->side_count; ++loop)
409- {
410- guess_side_lightsource_indexes(loop);
411- }
412- }
413-}
414-
415-/* Call with location of NULL to get the number of start locations for a */
416-/* given team or player */
417-short get_player_starting_location_and_facing(
418- short team,
419- short index,
420- struct object_location *location)
421-{
422-#if 1
423- short ii;
424- struct map_object *saved_object;
425- short count= 0;
426- bool done= false;
427-
428- saved_object= saved_objects;
429- for(ii=0; !done && ii<dynamic_world->initial_objects_count; ++ii)
430- {
431- if(saved_object->type==_saved_player)
432- {
433- /* index=NONE means use any starting location */
434- if(saved_object->index==team || team==NONE)
435- {
436- if(location && count==index)
437- {
438- location->p= saved_object->location;
439- location->polygon_index= saved_object->polygon_index;
440- location->yaw= saved_object->facing;
441- location->pitch= 0;
442- location->flags= saved_object->flags;
443- done= true;
444- }
445- count++;
446- }
447- }
448- ++saved_object;
449- }
450-
451- /* If they asked for a valid location, make sure that we gave them one */
452- if(location) vassert(done, csprintf(temporary, "Tried to place: %d only %d starting pts.", index, count));
453-
454- return count;
455-#else
456- location->x= 0x14e9;
457- location->y= 0x1ba0;
458- *facing= 0x00;
459- *polygon_index= 0x6f;
460-
461- return 1;
462-#endif
463-}
464-
465-uint32 get_current_map_checksum(
466- void)
467-{
468- // fileref file_handle;
469- struct wad_header header;
470-
471- assert(file_is_set);
472- OpenedFile MapFile;
473- open_wad_file_for_reading(MapFileSpec, MapFile);
474- assert(MapFile.IsOpen());
475-
476- /* Read the file */
477- read_wad_header(MapFile, &header);
478-
479- /* Close the file.. */
480- close_wad_file(MapFile);
481-
482- return header.checksum;
483-}
484-
485-// ZZZ: split this out from new_game for sharing
486-void set_saved_game_name_to_default()
487-{
488-#if defined(mac) || defined(SDL_RFORK_HACK)
489- revert_game_data.SavedGame.SetToApp();
490- revert_game_data.SavedGame.SetName(getcstr(temporary, strFILENAMES, filenameDEFAULT_SAVE_GAME),_typecode_savegame);
491-#endif
492-#if defined(SDL) && !defined(SDL_RFORK_HACK)
493- revert_game_data.SavedGame.SetToSavedGamesDir();
494- revert_game_data.SavedGame += getcstr(temporary, strFILENAMES, filenameDEFAULT_SAVE_GAME);
495-#endif
496-}
497-
498-extern void ResetPassedLua();
499-
500-bool new_game(
501- short number_of_players,
502- bool network,
503- struct game_data *game_information,
504- struct player_start_data *player_start_information,
505- struct entry_point *entry_point)
506-{
507- short player_index, i;
508- bool success= true;
509-
510- ResetPassedLua();
511-
512- /* Make sure our code is synchronized.. */
513- assert(MAXIMUM_PLAYER_START_NAME_LENGTH==MAXIMUM_PLAYER_NAME_LENGTH);
514-
515- /* Initialize the global network going flag... */
516- game_is_networked= network;
517-
518- /* If we want to save it, this is an untitled map.. */
519- set_saved_game_name_to_default();
520-
521- /* Set the random seed. */
522- set_random_seed(game_information->initial_random_seed);
523-
524- /* Initialize the players to a known state. This must be done before goto_level */
525- /* because it sets dynamic_world->player_count to 0, which is crucial for when */
526- /* I try to recreate the players... */
527- initialize_map_for_new_game(); // memsets dynamic_world to 0
528-
529- /* Copy the game data into the dynamic_world */
530- /* ajr-this used to be done only when we successfully loaded the map. however, goto_level
531- * will place the initial monsters on a level, which calls new_monster, which relies
532- * on this information being setup properly, so we do it here instead. */
533- obj_copy(dynamic_world->game_information, *game_information);
534-
535- /* Load the level */
536- assert(file_is_set);
537- success= goto_level(entry_point, true);
538- /* If we were able to load the map... */
539- if(success)
540- {
541- /* Initialize the players-> note there may be more than one player in a */
542- /* non-network game, for playback.. */
543- for (i=0;i<number_of_players;++i)
544- {
545- player_index= new_player(player_start_information[i].team,
546- player_start_information[i].color, player_start_information[i].identifier);
547- assert(player_index==i);
548-
549- /* Now copy in the name of the player.. */
550- assert(strlen(player_start_information[i].name)<=MAXIMUM_PLAYER_NAME_LENGTH);
551- strcpy(players[i].name, player_start_information[i].name);
552- }
553-
554-#if !defined(DISABLE_NETWORKING)
555- if(game_is_networked)
556- {
557- /* Make sure we can count. */
558- assert(number_of_players==NetGetNumberOfPlayers());
559-
560- set_local_player_index(NetGetLocalPlayerIndex());
561- set_current_player_index(NetGetLocalPlayerIndex());
562- }
563- else
564-#endif // !defined(DISABLE_NETWORKING)
565- {
566- set_local_player_index(0);
567- set_current_player_index(0);
568- }
569-
570- /* we need to alert the function that reverts the game of the game setup so that
571- * new game can be called if the user wants to revert later.
572- */
573- setup_revert_game_info(game_information, player_start_information, entry_point);
574-
575- // Reset the player queues (done here and in load_game)
576- reset_action_queues();
577-
578- /* Load the collections */
579- /* entering map might fail if NetSync() fails.. */
580- success= entering_map(false);
581-
582- // ZZZ: set motion sensor to sane state - needs to come after entering_map() (which calls load_collections())
583- reset_motion_sensor(current_player_index);
584- }
585-
586- // LP change: adding chase-cam initialization
587- ChaseCam_Initialize();
588-
589- return success;
590-}
591-
592-bool get_indexed_entry_point(
593- struct entry_point *entry_point,
594- short *index,
595- int32 type)
596-{
597- short actual_index;
598-
599- // Open map file
600- assert(file_is_set);
601- OpenedFile MapFile;
602- if (!open_wad_file_for_reading(MapFileSpec,MapFile))
603- return false;
604-
605- // Read header
606- wad_header header;
607- if (!read_wad_header(MapFile, &header)) {
608- close_wad_file(MapFile);
609- return false;
610- }
611-
612- bool success = false;
613- if (header.application_specific_directory_data_size == SIZEOF_directory_data)
614- {
615-
616- // New style wad
617- void *total_directory_data= read_directory_data(MapFile, &header);
618-
619- assert(total_directory_data);
620- for(actual_index= *index; actual_index<header.wad_count; ++actual_index)
621- {
622- uint8 *p = (uint8 *)get_indexed_directory_data(&header, actual_index, total_directory_data);
623- directory_data directory;
624- unpack_directory_data(p, &directory, 1);
625-
626- /* Find the flags that match.. */
627- if(directory.entry_point_flags & type)
628- {
629- /* This one is valid! */
630- entry_point->level_number= actual_index;
631- strcpy(entry_point->level_name, directory.level_name);
632-
633- *index= actual_index+1;
634- success= true;
635- break; /* Out of the for loop */
636- }
637- }
638- free(total_directory_data);
639-
640- } else {
641-
642- // Old style wad, find the index
643- for(actual_index= *index; !success && actual_index<header.wad_count; ++actual_index)
644- {
645- struct wad_data *wad;
646-
647- /* Read the file */
648- wad= read_indexed_wad_from_file(MapFile, &header, actual_index, true);
649- if (wad)
650- {
651- /* IF this has the proper type.. */
652- size_t length;
653- uint8 *p = (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &length);
654- assert(length == SIZEOF_static_data);
655- static_data map_info;
656- unpack_static_data(p, &map_info, 1);
657-
658- if(map_info.entry_point_flags & type)
659- {
660- /* This one is valid! */
661- entry_point->level_number= actual_index;
662- assert(strlen(map_info.level_name)<LEVEL_NAME_LENGTH);
663- strcpy(entry_point->level_name, map_info.level_name);
664-
665- *index= actual_index+1;
666- success= true;
667- }
668-
669- free_wad(wad);
670- }
671- }
672- }
673-
674- return success;
675-}
676-
677-// Get vector of map entry points matching given type
678-bool get_entry_points(vector<entry_point> &vec, int32 type)
679-{
680- vec.clear();
681-
682- // Open map file
683- assert(file_is_set);
684- OpenedFile MapFile;
685- if (!open_wad_file_for_reading(MapFileSpec,MapFile))
686- return false;
687-
688- // Read header
689- wad_header header;
690- if (!read_wad_header(MapFile, &header)) {
691- close_wad_file(MapFile);
692- return false;
693- }
694-
695- bool success = false;
696- if (header.application_specific_directory_data_size == SIZEOF_directory_data) {
697-
698- // New style wad, read directory data
699- void *total_directory_data = read_directory_data(MapFile, &header);
700- assert(total_directory_data);
701-
702- // Push matching directory entries into vector
703- for (int i=0; i<header.wad_count; i++) {
704- uint8 *p = (uint8 *)get_indexed_directory_data(&header, i, total_directory_data);
705- directory_data directory;
706- unpack_directory_data(p, &directory, 1);
707-
708- if (directory.entry_point_flags & type) {
709-
710- // This one is valid
711- entry_point point;
712- point.level_number = i;
713- strcpy(point.level_name, directory.level_name);
714- vec.push_back(point);
715- success = true;
716- }
717- }
718- free(total_directory_data);
719-
720- } else {
721-
722- // Old style wad
723- for (int i=0; i<header.wad_count; i++) {
724-
725- wad_data *wad = read_indexed_wad_from_file(MapFile, &header, i, true);
726- if (!wad)
727- continue;
728-
729- // Read map_info data
730- size_t length;
731- uint8 *p = (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &length);
732- assert(length == SIZEOF_static_data);
733- static_data map_info;
734- unpack_static_data(p, &map_info, 1);
735-
736- if (map_info.entry_point_flags & type) {
737-
738- // This one is valid
739- entry_point point;
740- point.level_number = i;
741- assert(strlen(map_info.level_name) < LEVEL_NAME_LENGTH);
742- strcpy(point.level_name, map_info.level_name);
743- vec.push_back(point);
744- success = true;
745- }
746-
747- free_wad(wad);
748- }
749- }
750-
751- return success;
752-}
753-
754-extern void LoadSoloLua();
755-extern void RunLuaScript();
756-
757-/* This is called when the game level is changed somehow */
758-/* The only thing that has to be valid in the entry point is the level_index */
759-
760-/* Returns a short that is an OSErr... */
761-bool goto_level(
762- struct entry_point *entry,
763- bool new_game)
764-{
765- bool success= true;
766-
767- if(!new_game)
768- {
769- /* Clear the current map */
770- leaving_map();
771-
772- // ghs: hack to get new MML-specified sounds loaded
773- SoundManager::instance()->UnloadAllSounds();
774- }
775-
776-#if !defined(DISABLE_NETWORKING)
777- /* If the game is networked, then I must call the network code to do the right */
778- /* thing with the map.. */
779- if(game_is_networked)
780- {
781- /* This function, if it is a server, calls get_map_for_net_transfer, and */
782- /* then calls process_map_wad on it. Non-server receives the map and then */
783- /* calls process_map_wad on it. */
784- success= NetChangeMap(entry);
785- }
786- else
787-#endif // !defined(DISABLE_NETWORKING)
788- {
789- /* Load it and then rock.. */
790- load_level_from_map(entry->level_number);
791- if(error_pending()) success= false;
792- }
793-
794- if (success)
795- {
796- // LP: doing this here because level-specific MML may specify which level-specific
797- // textures to load.
798- // Being careful to carry over errors so that Pfhortran errors can be ignored
799- short SavedType, SavedError = get_game_error(&SavedType);
800- if (!game_is_networked || use_map_file(((game_info *) NetGetGameData())->parent_checksum))
801- {
802- RunLevelScript(entry->level_number);
803- }
804- else
805- {
806- ResetLevelScript();
807- }
808- RunScriptChunks();
809- if (!game_is_networked)
810- {
811- Plugins::instance()->load_solo_mml();
812- LoadSoloLua();
813- }
814- Music::instance()->PreloadLevelMusic();
815- set_game_error(SavedType,SavedError);
816-
817- if (!new_game)
818- {
819- recreate_players_for_new_level();
820- }
821-
822- /* Load the collections */
823- dynamic_world->current_level_number= entry->level_number;
824-
825- // ghs: this runs very early now
826- // we want to be before place_initial_objects, and
827- // before MarkLuaCollections
828- RunLuaScript();
829-
830- place_initial_objects();
831- initialize_control_panels_for_level();
832-
833- if (!new_game)
834- {
835-
836- /* entering_map might fail if netsync fails, but we will have already displayed */
837- /* the error.. */
838- success= entering_map(false);
839- }
840-
841- }
842-
843-// if(!success) alert_user(fatalError, strERRORS, badReadMap, -1);
844-
845- /* We be done.. */
846- return success;
847-}
848-
849-/* -------------------- Private or map editor functions */
850-void allocate_map_for_counts(
851- size_t polygon_count,
852- size_t side_count,
853- size_t endpoint_count,
854- size_t line_count)
855-{
856- //long cumulative_length= 0;
857- size_t automap_line_count, automap_polygon_count, map_index_count;
858- // long automap_line_length, automap_polygon_length, map_index_length;
859-
860- /* Give the map indexes a whole bunch of memory (cause we can't calculate it) */
861- // map_index_length= (polygon_count*32+1024)*sizeof(int16);
862- map_index_count= (polygon_count*32+1024);
863-
864- /* Automap lines. */
865- // automap_line_length= (line_count/8+((line_count%8)?1:0))*sizeof(byte);
866- automap_line_count= (line_count/8+((line_count%8)?1:0));
867-
868- /* Automap Polygons */
869- // automap_polygon_length= (polygon_count/8+((polygon_count%8)?1:0))*sizeof(byte);
870- automap_polygon_count= (polygon_count/8+((polygon_count%8)?1:0));
871-
872- // cumulative_length+= polygon_count*sizeof(struct polygon_data);
873- // cumulative_length+= side_count*sizeof(struct side_data);
874- // cumulative_length+= endpoint_count*sizeof(struct endpoint_data);
875- // cumulative_length+= line_count*sizeof(struct line_data);
876- // cumulative_length+= map_index_length;
877- // cumulative_length+= automap_line_length;
878- // cumulative_length+= automap_polygon_length;
879-
880- /* Okay, we now have the length. Allocate our block.. */
881- // reallocate_map_structure_memory(cumulative_length);
882-
883- /* Tell the recalculation data how big it is.. */
884- // set_map_index_buffer_size(map_index_length);
885-
886- /* Setup our pointers. */
887- // map_polygons= (struct polygon_data *) get_map_structure_chunk(polygon_count*sizeof(struct polygon_data));
888- // map_sides= (struct side_data *) get_map_structure_chunk(side_count*sizeof(struct side_data));
889- // map_endpoints= (struct endpoint_data *) get_map_structure_chunk(endpoint_count*sizeof(struct endpoint_data));
890- // map_lines= (struct line_data *) get_map_structure_chunk(line_count*sizeof(struct line_data));
891- // map_indexes= (short *) get_map_structure_chunk(map_index_length);
892- // automap_lines= (uint8 *) get_map_structure_chunk(automap_line_length);
893- // automap_polygons= (uint8 *) get_map_structure_chunk(automap_polygon_length);
894-
895- // Most of the other stuff: reallocate here
896- EndpointList.resize(endpoint_count);
897- LineList.resize(line_count);
898- SideList.resize(side_count);
899- PolygonList.resize(polygon_count);
900- AutomapLineList.resize(automap_line_count);
901- AutomapPolygonList.resize(automap_polygon_count);
902-
903- // Map indexes: start off with none of them (of course),
904- // but reserve a size equal to the map index length
905- MapIndexList.clear();
906- MapIndexList.reserve(map_index_count);
907- dynamic_world->map_index_count= 0;
908-
909- // Stuff that needs the max number of polygons
910- allocate_render_memory();
911- allocate_flood_map_memory();
912-}
913-
914-void load_points(
915- uint8 *points,
916- size_t count)
917-{
918- size_t loop;
919-
920- // OK to modify input-data pointer since it's called by value
921- for(loop=0; loop<count; ++loop)
922- {
923- world_point2d& vertex = map_endpoints[loop].vertex;
924- StreamToValue(points,vertex.x);
925- StreamToValue(points,vertex.y);
926- }
927- assert(count == static_cast<size_t>(static_cast<int16>(count)));
928- assert(0 <= static_cast<int16>(count));
929- dynamic_world->endpoint_count= static_cast<int16>(count);
930-}
931-
932-void load_lines(
933- uint8 *lines,
934- size_t count)
935-{
936- // assert(count>=0 && count<=MAXIMUM_LINES_PER_MAP);
937- unpack_line_data(lines,map_lines,count);
938- assert(count == static_cast<size_t>(static_cast<int16>(count)));
939- assert(0 <= static_cast<int16>(count));
940- dynamic_world->line_count= static_cast<int16>(count);
941-}
942-
943-void load_sides(
944- uint8 *sides,
945- size_t count,
946- short version)
947-{
948- size_t loop;
949-
950- // assert(count>=0 && count<=MAXIMUM_SIDES_PER_MAP);
951-
952- unpack_side_data(sides,map_sides,count);
953-
954- for(loop=0; loop<count; ++loop)
955- {
956- if(version==MARATHON_ONE_DATA_VERSION)
957- {
958- map_sides[loop].transparent_texture.texture= UNONE;
959- map_sides[loop].ambient_delta= 0;
960- }
961- ++sides;
962- }
963-
964- assert(count == static_cast<size_t>(static_cast<int16>(count)));
965- assert(0 <= static_cast<int16>(count));
966- dynamic_world->side_count= static_cast<int16>(count);
967-}
968-
969-void load_polygons(
970- uint8 *polys,
971- size_t count,
972- short version)
973-{
974- size_t loop;
975-
976- // assert(count>=0 && count<=MAXIMUM_POLYGONS_PER_MAP);
977-
978- unpack_polygon_data(polys,map_polygons,count);
979- assert(count == static_cast<size_t>(static_cast<int16>(count)));
980- assert(0 <= static_cast<int16>(count));
981- dynamic_world->polygon_count= static_cast<int16>(count);
982-
983- /* Allow for backward compatibility! */
984- switch(version)
985- {
986- case MARATHON_ONE_DATA_VERSION:
987- for(loop= 0; loop<count; ++loop)
988- {
989- map_polygons[loop].media_index= NONE;
990- map_polygons[loop].floor_origin.x= map_polygons[loop].floor_origin.y= 0;
991- map_polygons[loop].ceiling_origin.x= map_polygons[loop].ceiling_origin.y= 0;
992- }
993- break;
994-
995- case MARATHON_TWO_DATA_VERSION:
996- // LP addition:
997- case MARATHON_INFINITY_DATA_VERSION:
998- break;
999-
1000- default:
1001- assert(false);
1002- break;
1003- }
1004-}
1005-
1006-void load_lights(
1007- uint8 *_lights,
1008- size_t count,
1009- short version)
1010-{
1011- unsigned short loop, new_index;
1012-
1013- LightList.resize(count);
1014- objlist_clear(lights,count);
1015- // vassert(count>=0 && count<=MAXIMUM_LIGHTS_PER_MAP, csprintf(temporary, "Light count: %d vers: %d",
1016- // count, version));
1017-
1018- old_light_data *OldLights;
1019-
1020- switch(version)
1021- {
1022- case MARATHON_ONE_DATA_VERSION: {
1023-
1024- // Unpack the old lights into a temporary array
1025- OldLights = new old_light_data[count];
1026- unpack_old_light_data(_lights,OldLights,count);
1027-
1028- old_light_data *OldLtPtr = OldLights;
1029- for(loop= 0; loop<count; ++loop, OldLtPtr++)
1030- {
1031- static_light_data TempLight;
1032- convert_old_light_data_to_new(&TempLight, OldLtPtr, 1);
1033-
1034- new_index = new_light(&TempLight);
1035- assert(new_index==loop);
1036- }
1037- delete []OldLights;
1038- break;
1039- }
1040-
1041- case MARATHON_TWO_DATA_VERSION:
1042- case MARATHON_INFINITY_DATA_VERSION:
1043- // OK to modify the data pointer since it was passed by value
1044- for(loop= 0; loop<count; ++loop)
1045- {
1046- static_light_data TempLight;
1047- _lights = unpack_static_light_data(_lights, &TempLight, 1);
1048-
1049- new_index = new_light(&TempLight);
1050- assert(new_index==loop);
1051- }
1052- break;
1053-
1054- default:
1055- assert(false);
1056- break;
1057- }
1058-}
1059-
1060-void load_annotations(
1061- uint8 *annotations,
1062- size_t count)
1063-{
1064- // assert(count>=0 && count<=MAXIMUM_ANNOTATIONS_PER_MAP);
1065- MapAnnotationList.resize(count);
1066- unpack_map_annotation(annotations,map_annotations,count);
1067- assert(count == static_cast<size_t>(static_cast<int16>(count)));
1068- assert(0 <= static_cast<int16>(count));
1069- dynamic_world->default_annotation_count= static_cast<int16>(count);
1070-}
1071-
1072-void load_objects(uint8 *map_objects, size_t count)
1073-{
1074- // assert(count>=0 && count<=MAXIMUM_SAVED_OBJECTS);
1075- SavedObjectList.resize(count);
1076- unpack_map_object(map_objects,saved_objects,count);
1077- assert(count == static_cast<size_t>(static_cast<int16>(count)));
1078- assert(0 <= static_cast<int16>(count));
1079- dynamic_world->initial_objects_count= static_cast<int16>(count);
1080-}
1081-
1082-void load_map_info(
1083- uint8 *map_info)
1084-{
1085- unpack_static_data(map_info,static_world,1);
1086- static_world->ball_in_play = false;
1087-}
1088-
1089-void load_media(
1090- uint8 *_medias,
1091- size_t count)
1092-{
1093- // struct media_data *media= _medias;
1094- size_t ii;
1095-
1096- MediaList.resize(count);
1097- objlist_clear(medias,count);
1098- // assert(count>=0 && count<=MAXIMUM_MEDIAS_PER_MAP);
1099-
1100- for(ii= 0; ii<count; ++ii)
1101- {
1102- media_data TempMedia;
1103- _medias = unpack_media_data(_medias,&TempMedia,1);
1104-
1105- size_t new_index = new_media(&TempMedia);
1106- assert(new_index==ii);
1107- }
1108-}
1109-
1110-void load_ambient_sound_images(
1111- uint8 *data,
1112- size_t count)
1113-{
1114- // assert(count>=0 &&count<=MAXIMUM_AMBIENT_SOUND_IMAGES_PER_MAP);
1115- AmbientSoundImageList.resize(count);
1116- unpack_ambient_sound_image_data(data,ambient_sound_images,count);
1117- assert(count == static_cast<size_t>(static_cast<int16>(count)));
1118- assert(0 <= static_cast<int16>(count));
1119- dynamic_world->ambient_sound_image_count= static_cast<int16>(count);
1120-}
1121-
1122-void load_random_sound_images(
1123- uint8 *data,
1124- size_t count)
1125-{
1126- // assert(count>=0 &&count<=MAXIMUM_RANDOM_SOUND_IMAGES_PER_MAP);
1127- RandomSoundImageList.resize(count);
1128- unpack_random_sound_image_data(data,random_sound_images,count);
1129- assert(count == static_cast<size_t>(static_cast<int16>(count)));
1130- assert(0 <= static_cast<int16>(count));
1131- dynamic_world->random_sound_image_count= static_cast<int16>(count);
1132-}
1133-
1134-/* Recalculate all the redundant crap- must be done before platforms/doors/etc.. */
1135-void recalculate_redundant_map(
1136- void)
1137-{
1138- short loop;
1139-
1140- for(loop=0;loop<dynamic_world->polygon_count;++loop) recalculate_redundant_polygon_data(loop);
1141- for(loop=0;loop<dynamic_world->line_count;++loop) recalculate_redundant_line_data(loop);
1142- for(loop=0;loop<dynamic_world->endpoint_count;++loop) recalculate_redundant_endpoint_data(loop);
1143-}
1144-
1145-extern bool load_game_from_file(FileSpecifier& File);
1146-
1147-bool load_game_from_file(FileSpecifier& File)
1148-{
1149- bool success= false;
1150-
1151- ResetPassedLua();
1152-
1153- /* Setup for a revert.. */
1154- revert_game_data.game_is_from_disk = true;
1155- revert_game_data.SavedGame = File;
1156-
1157- /* Use the save game file.. */
1158- set_map_file(File);
1159-
1160- /* Load the level from the map */
1161- success= load_level_from_map(NONE); /* Save games are ALWAYS index NONE */
1162- if (success)
1163- {
1164- uint32 parent_checksum;
1165-
1166- /* Find the original scenario this saved game was a part of.. */
1167- parent_checksum= read_wad_file_parent_checksum(File);
1168- if(use_map_file(parent_checksum))
1169- {
1170- // LP: getting the level scripting off of the map file
1171- // Being careful to carry over errors so that Pfhortran errors can be ignored
1172- short SavedType, SavedError = get_game_error(&SavedType);
1173- RunLevelScript(dynamic_world->current_level_number);
1174- RunScriptChunks();
1175- if (!game_is_networked)
1176- {
1177- Plugins::instance()->load_solo_mml();
1178- LoadSoloLua();
1179- }
1180- set_game_error(SavedType,SavedError);
1181- }
1182- else
1183- {
1184- /* Tell the user theyÕre screwed when they try to leave this level. */
1185- alert_user(infoError, strERRORS, cantFindMap, 0);
1186-
1187- // LP addition: makes the game look normal
1188- hide_cursor();
1189-
1190- /* Set to the default map. */
1191- set_to_default_map();
1192-
1193- ResetLevelScript();
1194- RunScriptChunks();
1195- }
1196- }
1197-
1198- return success;
1199-}
1200-
1201-void setup_revert_game_info(
1202- struct game_data *game_info,
1203- struct player_start_data *start,
1204- struct entry_point *entry)
1205-{
1206- revert_game_data.game_is_from_disk = false;
1207- obj_copy(revert_game_data.game_information, *game_info);
1208- obj_copy(revert_game_data.player_start, *start);
1209- obj_copy(revert_game_data.entry_point, *entry);
1210-}
1211-
1212-extern void reset_messages();
1213-
1214-bool revert_game(
1215- void)
1216-{
1217- bool successful;
1218-
1219- assert(dynamic_world->player_count==1);
1220-
1221- leaving_map();
1222-
1223- if (revert_game_data.game_is_from_disk)
1224- {
1225- /* Reload their last saved game.. */
1226- successful= load_game_from_file(revert_game_data.SavedGame);
1227- if (successful)
1228- {
1229- Music::instance()->PreloadLevelMusic();
1230- RunLuaScript();
1231-
1232- // LP: added for loading the textures if one had died on another level;
1233- // this gets around WZ's moving of this line into make_restored_game_relevant()
1234- successful = entering_map(true /*restoring game*/);
1235- }
1236-
1237- /* And they don't get to continue. */
1238- stop_recording();
1239- }
1240- else
1241- {
1242- /* This was the totally evil line discussed above. */
1243- successful= new_game(1, false, &revert_game_data.game_information, &revert_game_data.player_start,
1244- &revert_game_data.entry_point);
1245-
1246- /* And rewind so that the last player is used. */
1247- rewind_recording();
1248- }
1249-
1250- if(successful)
1251- {
1252- update_interface(NONE);
1253- ChaseCam_Reset();
1254- ResetFieldOfView();
1255- reset_messages();
1256- ReloadViewContext();
1257- }
1258-
1259- return successful;
1260-}
1261-
1262-bool export_level(FileSpecifier& File)
1263-{
1264- struct wad_header header;
1265- short err = 0;
1266- bool success = false;
1267- int32 offset, wad_length;
1268- struct directory_entry entry;
1269- struct wad_data *wad;
1270-
1271- FileSpecifier TempFile;
1272- DirectorySpecifier TempFileDir;
1273- File.ToDirectory(TempFileDir);
1274- TempFile.FromDirectory(TempFileDir);
1275- TempFile.AddPart("savetemp.dat");
1276-
1277- /* Fill in the default wad header (we are using File instead of TempFile to get the name right in the header) */
1278- fill_default_wad_header(File, CURRENT_WADFILE_VERSION, MARATHON_TWO_DATA_VERSION, 1, 0, &header);
1279-
1280- if (create_wadfile(TempFile, _typecode_scenario))
1281- {
1282- OpenedFile SaveFile;
1283- if (open_wad_file_for_writing(TempFile, SaveFile))
1284- {
1285- /* Write out the new header */
1286- if (write_wad_header(SaveFile, &header))
1287- {
1288- offset = SIZEOF_wad_header;
1289-
1290- wad = build_export_wad(&header, &wad_length);
1291- if (wad)
1292- {
1293- set_indexed_directory_offset_and_length(&header, &entry, 0, offset, wad_length, 0);
1294-
1295- if (write_wad(SaveFile, &header, wad, offset))
1296- {
1297- /* Update the new header */
1298- offset+= wad_length;
1299- header.directory_offset= offset;
1300- if (write_wad_header(SaveFile, &header) && write_directorys(SaveFile, &header, &entry))
1301- {
1302- /* We win. */
1303- success= true;
1304- }
1305- }
1306-
1307- free_wad(wad);
1308- }
1309- }
1310-
1311- err = SaveFile.GetError();
1312- calculate_and_store_wadfile_checksum(SaveFile);
1313- close_wad_file(SaveFile);
1314- }
1315-
1316- if (!err)
1317- {
1318- if (!File.Exists())
1319- create_wadfile(File,_typecode_savegame);
1320-
1321- TempFile.Exchange(File);
1322- err = TempFile.GetError();
1323- TempFile.Delete(); // it's not an error if this fails
1324- }
1325- }
1326-
1327- if (err || error_pending())
1328- {
1329- success = false;
1330- }
1331-
1332-
1333- return success;
1334-
1335-}
1336-
1337-void get_current_saved_game_name(FileSpecifier& File)
1338-{
1339- File = revert_game_data.SavedGame;
1340-}
1341-
1342-/* The current mapfile should be set to the save game file... */
1343-bool save_game_file(FileSpecifier& File)
1344-{
1345- struct wad_header header;
1346- short err = 0;
1347- bool success= false;
1348- int32 offset, wad_length;
1349- struct directory_entry entry;
1350- struct wad_data *wad;
1351-
1352- /* Save off the random seed. */
1353- dynamic_world->random_seed= get_random_seed();
1354-
1355- /* Setup to revert the game properly */
1356- revert_game_data.game_is_from_disk= true;
1357- revert_game_data.SavedGame = File;
1358-
1359- // LP: add a file here; use temporary file for a safe save.
1360- // Write into the temporary file first
1361- FileSpecifier TempFile;
1362- DirectorySpecifier TempFileDir;
1363- File.ToDirectory(TempFileDir);
1364- TempFile.FromDirectory(TempFileDir);
1365-#if defined(mac) || defined(SDL_RFORK_HACK)
1366- TempFile.SetName("savetemp.dat",NONE);
1367-#else
1368- TempFile.AddPart("savetemp.dat");
1369-#endif
1370-
1371- /* Fill in the default wad header (we are using File instead of TempFile to get the name right in the header) */
1372- fill_default_wad_header(File, CURRENT_WADFILE_VERSION, EDITOR_MAP_VERSION, 1, 0, &header);
1373-
1374- /* Assume that we confirmed on save as... */
1375- if (create_wadfile(TempFile,_typecode_savegame))
1376- {
1377- OpenedFile SaveFile;
1378- if(open_wad_file_for_writing(TempFile,SaveFile))
1379- {
1380- /* Write out the new header */
1381- if (write_wad_header(SaveFile, &header))
1382- {
1383- offset= SIZEOF_wad_header;
1384-
1385- wad= build_save_game_wad(&header, &wad_length);
1386- if (wad)
1387- {
1388- /* Set the entry data.. */
1389- set_indexed_directory_offset_and_length(&header,
1390- &entry, 0, offset, wad_length, 0);
1391-
1392- /* Save it.. */
1393- if (write_wad(SaveFile, &header, wad, offset))
1394- {
1395- /* Update the new header */
1396- offset+= wad_length;
1397- header.directory_offset= offset;
1398- header.parent_checksum= read_wad_file_checksum(MapFileSpec);
1399- if (write_wad_header(SaveFile, &header) && write_directorys(SaveFile, &header, &entry))
1400- {
1401- /* This function saves the overhead map as a thumbnail, as well */
1402- /* as adding the string resource that tells you what it is when */
1403- /* it is clicked on & Marathon2 isn't installed. Obviously, both */
1404- /* of these are superfluous for a dos environment. */
1405- add_finishing_touches_to_save_file(TempFile);
1406-
1407- /* We win. */
1408- success= true;
1409- }
1410- }
1411-
1412- free_wad(wad);
1413- }
1414- }
1415-
1416- err = SaveFile.GetError();
1417- close_wad_file(SaveFile);
1418- }
1419-
1420- // LP addition: exchange with temporary file;
1421- // create target file if necessary
1422- if (!err)
1423- {
1424- if (!File.Exists())
1425- create_wadfile(File,_typecode_savegame);
1426-
1427- TempFile.Exchange(File);
1428- err = TempFile.GetError();
1429- TempFile.Delete(); // it's not an error if this fails
1430- }
1431- }
1432-
1433- if(err || error_pending())
1434- {
1435- if(!err) err= get_game_error(NULL);
1436- alert_user(infoError, strERRORS, fileError, err);
1437- clear_game_error();
1438- success= false;
1439- }
1440-
1441- return success;
1442-}
1443-
1444-/* -------- static functions */
1445-static void scan_and_add_platforms(
1446- uint8 *platform_static_data,
1447- size_t count,
1448- short version)
1449-{
1450- struct polygon_data *polygon;
1451- short loop;
1452-
1453- PlatformList.resize(count);
1454- objlist_clear(platforms,count);
1455-
1456- static_platforms.resize(count);
1457- unpack_static_platform_data(platform_static_data, &static_platforms[0], count);
1458-
1459- polygon= map_polygons;
1460- for(loop=0; loop<dynamic_world->polygon_count; ++loop)
1461- {
1462- if (polygon->type==_polygon_is_platform)
1463- {
1464- /* Search and find the extra data. If it is not there, use the permutation for */
1465- /* backwards compatibility! */
1466-
1467- size_t platform_static_data_index;
1468- for(platform_static_data_index = 0; platform_static_data_index<count; ++platform_static_data_index)
1469- {
1470- if (static_platforms[platform_static_data_index].polygon_index == loop)
1471- {
1472- new_platform(&static_platforms[platform_static_data_index], loop, version);
1473- break;
1474- }
1475- }
1476-
1477- /* DIdn't find it- use a standard platform */
1478- if(platform_static_data_index==count)
1479- {
1480- polygon->permutation= 1;
1481- new_platform(get_defaults_for_platform_type(polygon->permutation), loop, version);
1482- }
1483- }
1484- ++polygon;
1485- }
1486-}
1487-
1488-
1489-extern void unpack_lua_states(uint8*, size_t);
1490-
1491-/* Load a level from a wad-> mainly used by the net stuff. */
1492-bool process_map_wad(
1493- struct wad_data *wad,
1494- bool restoring_game,
1495- short version)
1496-{
1497- size_t data_length;
1498- uint8 *data;
1499- size_t count;
1500- bool is_preprocessed_map= false;
1501-
1502- assert(version==MARATHON_INFINITY_DATA_VERSION || version==MARATHON_TWO_DATA_VERSION || version==MARATHON_ONE_DATA_VERSION);
1503-
1504- /* zero everything so no slots are used */
1505- initialize_map_for_new_level();
1506-
1507- /* Calculate the length (for reallocate map) */
1508- allocate_map_structure_for_map(wad);
1509-
1510- /* Extract points */
1511- data= (uint8 *)extract_type_from_wad(wad, POINT_TAG, &data_length);
1512- count= data_length/SIZEOF_world_point2d;
1513- assert(data_length == count*SIZEOF_world_point2d);
1514-
1515- if(count)
1516- {
1517- load_points(data, count);
1518- } else {
1519-
1520- data= (uint8 *)extract_type_from_wad(wad, ENDPOINT_DATA_TAG, &data_length);
1521- count= data_length/SIZEOF_endpoint_data;
1522- assert(data_length == count*SIZEOF_endpoint_data);
1523- // assert(count>=0 && count<MAXIMUM_ENDPOINTS_PER_MAP);
1524-
1525- /* Slam! */
1526- unpack_endpoint_data(data,map_endpoints,count);
1527- assert(count == static_cast<size_t>(static_cast<int16>(count)));
1528- assert(0 <= static_cast<int16>(count));
1529- dynamic_world->endpoint_count= static_cast<int16>(count);
1530-
1531- if (version > MARATHON_ONE_DATA_VERSION)
1532- is_preprocessed_map= true;
1533- }
1534-
1535- /* Extract lines */
1536- data= (uint8 *)extract_type_from_wad(wad, LINE_TAG, &data_length);
1537- count = data_length/SIZEOF_line_data;
1538- assert(data_length == count*SIZEOF_line_data);
1539- load_lines(data, count);
1540-
1541- /* Order is important! */
1542- data= (uint8 *)extract_type_from_wad(wad, SIDE_TAG, &data_length);
1543- count = data_length/SIZEOF_side_data;
1544- assert(data_length == count*SIZEOF_side_data);
1545- load_sides(data, count, version);
1546-
1547- /* Extract polygons */
1548- data= (uint8 *)extract_type_from_wad(wad, POLYGON_TAG, &data_length);
1549- count = data_length/SIZEOF_polygon_data;
1550- assert(data_length == count*SIZEOF_polygon_data);
1551- load_polygons(data, count, version);
1552-
1553- /* Extract the lightsources */
1554- if(restoring_game)
1555- {
1556- // Slurp them in
1557- data= (uint8 *)extract_type_from_wad(wad, LIGHTSOURCE_TAG, &data_length);
1558- count = data_length/SIZEOF_light_data;
1559- assert(data_length == count*SIZEOF_light_data);
1560- LightList.resize(count);
1561- unpack_light_data(data,lights,count);
1562- }
1563- else
1564- {
1565- /* When you are restoring a game, the actual light structure is set. */
1566- data= (uint8 *)extract_type_from_wad(wad, LIGHTSOURCE_TAG, &data_length);
1567- if(version==MARATHON_ONE_DATA_VERSION)
1568- {
1569- /* We have an old style light */
1570- count= data_length/SIZEOF_old_light_data;
1571- assert(count*SIZEOF_old_light_data==data_length);
1572- load_lights(data, count, version);
1573- } else {
1574- count= data_length/SIZEOF_static_light_data;
1575- assert(count*SIZEOF_static_light_data==data_length);
1576- load_lights(data, count, version);
1577- }
1578-
1579- // HACK!!!!!!!!!!!!!!! vulcan doesnÕt NONE .first_object field after adding scenery
1580- {
1581- for (count= 0; count<static_cast<size_t>(dynamic_world->polygon_count); ++count)
1582- {
1583- map_polygons[count].first_object= NONE;
1584- }
1585- }
1586- }
1587-
1588- /* Extract the annotations */
1589- data= (uint8 *)extract_type_from_wad(wad, ANNOTATION_TAG, &data_length);
1590- count = data_length/SIZEOF_map_annotation;
1591- assert(data_length == count*SIZEOF_map_annotation);
1592- load_annotations(data, count);
1593-
1594- /* Extract the objects */
1595- data= (uint8 *)extract_type_from_wad(wad, OBJECT_TAG, &data_length);
1596- count = data_length/SIZEOF_map_object;
1597- assert(data_length == count*static_cast<size_t>(SIZEOF_map_object));
1598- load_objects(data, count);
1599-
1600- /* Extract the map info data */
1601- data= (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &data_length);
1602- // LP change: made this more Pfhorte-friendly
1603- assert(static_cast<size_t>(SIZEOF_static_data)==data_length
1604- || static_cast<size_t>(SIZEOF_static_data-2)==data_length);
1605- load_map_info(data);
1606-
1607- /* Extract the game difficulty info.. */
1608- data= (uint8 *)extract_type_from_wad(wad, ITEM_PLACEMENT_STRUCTURE_TAG, &data_length);
1609- // In case of an absent placement chunk...
1610- if (data_length == 0)
1611- {
1612- data = new uint8[2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition];
1613- memset(data,0,2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition);
1614- }
1615- else
1616- assert(data_length == 2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition);
1617- load_placement_data(data + MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition, data);
1618- if (data_length == 0)
1619- delete []data;
1620-
1621- /* Extract the terminal data. */
1622- data= (uint8 *)extract_type_from_wad(wad, TERMINAL_DATA_TAG, &data_length);
1623- load_terminal_data(data, data_length);
1624-
1625- /* Extract the media definitions */
1626- if(restoring_game)
1627- {
1628- // Slurp it in
1629- data= (uint8 *)extract_type_from_wad(wad, MEDIA_TAG, &data_length);
1630- count= data_length/SIZEOF_media_data;
1631- assert(count*SIZEOF_media_data==data_length);
1632- MediaList.resize(count);
1633- unpack_media_data(data,medias,count);
1634- }
1635- else
1636- {
1637- data= (uint8 *)extract_type_from_wad(wad, MEDIA_TAG, &data_length);
1638- count= data_length/SIZEOF_media_data;
1639- assert(count*SIZEOF_media_data==data_length);
1640- load_media(data, count);
1641- }
1642-
1643- /* Extract the ambient sound images */
1644- data= (uint8 *)extract_type_from_wad(wad, AMBIENT_SOUND_TAG, &data_length);
1645- count = data_length/SIZEOF_ambient_sound_image_data;
1646- assert(data_length == count*SIZEOF_ambient_sound_image_data);
1647- load_ambient_sound_images(data, count);
1648- load_ambient_sound_images(data, data_length/SIZEOF_ambient_sound_image_data);
1649-
1650- /* Extract the random sound images */
1651- data= (uint8 *)extract_type_from_wad(wad, RANDOM_SOUND_TAG, &data_length);
1652- count = data_length/SIZEOF_random_sound_image_data;
1653- assert(data_length == count*SIZEOF_random_sound_image_data);
1654- load_random_sound_images(data, count);
1655-
1656- /* Extract embedded shapes */
1657- data= (uint8 *)extract_type_from_wad(wad, SHAPE_PATCH_TAG, &data_length);
1658- set_shapes_patch_data(data, data_length);
1659-
1660- /* Extract MMLS */
1661- data= (uint8 *)extract_type_from_wad(wad, MMLS_TAG, &data_length);
1662- SetMMLS(data, data_length);
1663-
1664- /* Extract LUAS */
1665- data= (uint8 *)extract_type_from_wad(wad, LUAS_TAG, &data_length);
1666- SetLUAS(data, data_length);
1667-
1668- /* Extract saved Lua state */
1669- data =(uint8 *)extract_type_from_wad(wad, LUA_STATE_TAG, &data_length);
1670- unpack_lua_states(data, data_length);
1671-
1672- // LP addition: load the physics-model chunks (all fixed-size)
1673- bool PhysicsModelLoaded = false;
1674-
1675- data= (uint8 *)extract_type_from_wad(wad, MONSTER_PHYSICS_TAG, &data_length);
1676- count = data_length/SIZEOF_monster_definition;
1677- assert(count*SIZEOF_monster_definition == data_length);
1678- assert(count <= NUMBER_OF_MONSTER_TYPES);
1679- if (data_length > 0)
1680- {
1681- if (!PhysicsModelLoaded) init_physics_wad_data();
1682- PhysicsModelLoaded = true;
1683- unpack_monster_definition(data,count);
1684- }
1685-
1686- data= (uint8 *)extract_type_from_wad(wad, EFFECTS_PHYSICS_TAG, &data_length);
1687- count = data_length/SIZEOF_effect_definition;
1688- assert(count*SIZEOF_effect_definition == data_length);
1689- assert(count <= NUMBER_OF_EFFECT_TYPES);
1690- if (data_length > 0)
1691- {
1692- if (!PhysicsModelLoaded) init_physics_wad_data();
1693- PhysicsModelLoaded = true;
1694- unpack_effect_definition(data,count);
1695- }
1696-
1697- data= (uint8 *)extract_type_from_wad(wad, PROJECTILE_PHYSICS_TAG, &data_length);
1698- count = data_length/SIZEOF_projectile_definition;
1699- assert(count*SIZEOF_projectile_definition == data_length);
1700- assert(count <= NUMBER_OF_PROJECTILE_TYPES);
1701- if (data_length > 0)
1702- {
1703- if (!PhysicsModelLoaded) init_physics_wad_data();
1704- PhysicsModelLoaded = true;
1705- unpack_projectile_definition(data,count);
1706- }
1707-
1708- data= (uint8 *)extract_type_from_wad(wad, PHYSICS_PHYSICS_TAG, &data_length);
1709- count = data_length/SIZEOF_physics_constants;
1710- assert(count*SIZEOF_physics_constants == data_length);
1711- assert(count <= get_number_of_physics_models());
1712- if (data_length > 0)
1713- {
1714- if (!PhysicsModelLoaded) init_physics_wad_data();
1715- PhysicsModelLoaded = true;
1716- unpack_physics_constants(data,count);
1717- }
1718-
1719- data= (uint8 *)extract_type_from_wad(wad, WEAPONS_PHYSICS_TAG, &data_length);
1720- count = data_length/SIZEOF_weapon_definition;
1721- assert(count*SIZEOF_weapon_definition == data_length);
1722- assert(count <= get_number_of_weapon_types());
1723- if (data_length > 0)
1724- {
1725- if (!PhysicsModelLoaded) init_physics_wad_data();
1726- PhysicsModelLoaded = true;
1727- unpack_weapon_definition(data,count);
1728- }
1729-
1730- // LP addition: Reload the physics model if it had been loaded in the previous level,
1731- // but not in the current level. This avoids the persistent-physics bug.
1732- // ghs: always reload the physics model if there isn't one merged
1733- if (PhysicsModelLoadedEarlier && !PhysicsModelLoaded && !game_is_networked)
1734- import_definition_structures();
1735- PhysicsModelLoadedEarlier = PhysicsModelLoaded;
1736-
1737- /* If we are restoring the game, then we need to add the dynamic data */
1738- if(restoring_game)
1739- {
1740- // Slurp it all in...
1741- data= (uint8 *)extract_type_from_wad(wad, MAP_INDEXES_TAG, &data_length);
1742- count= data_length/sizeof(short);
1743- assert(count*int32(sizeof(short))==data_length);
1744- MapIndexList.resize(count);
1745- StreamToList(data,map_indexes,count);
1746-
1747- data= (uint8 *)extract_type_from_wad(wad, PLAYER_STRUCTURE_TAG, &data_length);
1748- count= data_length/SIZEOF_player_data;
1749- assert(count*SIZEOF_player_data==data_length);
1750- unpack_player_data(data,players,count);
1751- team_damage_from_player_data();
1752-
1753- data= (uint8 *)extract_type_from_wad(wad, DYNAMIC_STRUCTURE_TAG, &data_length);
1754- assert(data_length == SIZEOF_dynamic_data);
1755- unpack_dynamic_data(data,dynamic_world,1);
1756-
1757- data= (uint8 *)extract_type_from_wad(wad, OBJECT_STRUCTURE_TAG, &data_length);
1758- count= data_length/SIZEOF_object_data;
1759- assert(count*SIZEOF_object_data==data_length);
1760- vassert(count <= MAXIMUM_OBJECTS_PER_MAP,
1761- csprintf(temporary,"Number of map objects %lu > limit %u",count,MAXIMUM_OBJECTS_PER_MAP));
1762- unpack_object_data(data,objects,count);
1763-
1764- // Unpacking is E-Z here...
1765- data= (uint8 *)extract_type_from_wad(wad, AUTOMAP_LINES, &data_length);
1766- memcpy(automap_lines,data,data_length);
1767- data= (uint8 *)extract_type_from_wad(wad, AUTOMAP_POLYGONS, &data_length);
1768- memcpy(automap_polygons,data,data_length);
1769-
1770- data= (uint8 *)extract_type_from_wad(wad, MONSTERS_STRUCTURE_TAG, &data_length);
1771- count= data_length/SIZEOF_monster_data;
1772- assert(count*SIZEOF_monster_data==data_length);
1773- vassert(count <= MAXIMUM_MONSTERS_PER_MAP,
1774- csprintf(temporary,"Number of monsters %lu > limit %u",count,MAXIMUM_MONSTERS_PER_MAP));
1775- unpack_monster_data(data,monsters,count);
1776-
1777- data= (uint8 *)extract_type_from_wad(wad, EFFECTS_STRUCTURE_TAG, &data_length);
1778- count= data_length/SIZEOF_effect_data;
1779- assert(count*SIZEOF_effect_data==data_length);
1780- vassert(count <= MAXIMUM_EFFECTS_PER_MAP,
1781- csprintf(temporary,"Number of effects %lu > limit %u",count,MAXIMUM_EFFECTS_PER_MAP));
1782- unpack_effect_data(data,effects,count);
1783-
1784- data= (uint8 *)extract_type_from_wad(wad, PROJECTILES_STRUCTURE_TAG, &data_length);
1785- count= data_length/SIZEOF_projectile_data;
1786- assert(count*SIZEOF_projectile_data==data_length);
1787- vassert(count <= MAXIMUM_PROJECTILES_PER_MAP,
1788- csprintf(temporary,"Number of projectiles %lu > limit %u",count,MAXIMUM_PROJECTILES_PER_MAP));
1789- unpack_projectile_data(data,projectiles,count);
1790-
1791- data= (uint8 *)extract_type_from_wad(wad, PLATFORM_STRUCTURE_TAG, &data_length);
1792- count= data_length/SIZEOF_platform_data;
1793- assert(count*SIZEOF_platform_data==data_length);
1794- PlatformList.resize(count);
1795- unpack_platform_data(data,platforms,count);
1796-
1797- data= (uint8 *)extract_type_from_wad(wad, WEAPON_STATE_TAG, &data_length);
1798- count= data_length/SIZEOF_player_weapon_data;
1799- assert(count*SIZEOF_player_weapon_data==data_length);
1800- unpack_player_weapon_data(data,count);
1801-
1802- data= (uint8 *)extract_type_from_wad(wad, TERMINAL_STATE_TAG, &data_length);
1803- count= data_length/SIZEOF_player_terminal_data;
1804- assert(count*SIZEOF_player_terminal_data==data_length);
1805- unpack_player_terminal_data(data,count);
1806-
1807- complete_restoring_level(wad);
1808- } else {
1809- uint8 *map_index_data;
1810- size_t map_index_count;
1811- uint8 *platform_structures;
1812- size_t platform_structure_count;
1813-
1814- if(version==MARATHON_ONE_DATA_VERSION)
1815- {
1816- /* Force precalculation */
1817- map_index_data= NULL;
1818- map_index_count= 0;
1819- } else {
1820- map_index_data= (uint8 *)extract_type_from_wad(wad, MAP_INDEXES_TAG, &data_length);
1821- map_index_count= data_length/sizeof(short);
1822- assert(map_index_count*sizeof(short)==data_length);
1823- }
1824-
1825- assert(is_preprocessed_map&&map_index_count || !is_preprocessed_map&&!map_index_count);
1826-
1827- data= (uint8 *)extract_type_from_wad(wad, PLATFORM_STATIC_DATA_TAG, &data_length);
1828- count= data_length/SIZEOF_static_platform_data;
1829- assert(count*SIZEOF_static_platform_data==data_length);
1830-
1831- platform_structures= (uint8 *)extract_type_from_wad(wad, PLATFORM_STRUCTURE_TAG, &data_length);
1832- platform_structure_count= data_length/SIZEOF_platform_data;
1833- assert(platform_structure_count*SIZEOF_platform_data==data_length);
1834-
1835- complete_loading_level((short *) map_index_data, map_index_count,
1836- data, count, platform_structures,
1837- platform_structure_count, version);
1838-
1839- }
1840-
1841- /* ... and bail */
1842- return true;
1843-}
1844-
1845-static void allocate_map_structure_for_map(
1846- struct wad_data *wad)
1847-{
1848- size_t data_length;
1849- size_t line_count, polygon_count, side_count, endpoint_count;
1850-
1851- /* Extract points */
1852- extract_type_from_wad(wad, POINT_TAG, &data_length);
1853- endpoint_count= data_length/SIZEOF_world_point2d;
1854- if(endpoint_count*SIZEOF_world_point2d!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x7074); // 'pt'
1855-
1856- if(!endpoint_count)
1857- {
1858- extract_type_from_wad(wad, ENDPOINT_DATA_TAG, &data_length);
1859- endpoint_count= data_length/SIZEOF_endpoint_data;
1860- if(endpoint_count*SIZEOF_endpoint_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x6570); // 'ep'
1861- }
1862-
1863- /* Extract lines */
1864- extract_type_from_wad(wad, LINE_TAG, &data_length);
1865- line_count= data_length/SIZEOF_line_data;
1866- if(line_count*SIZEOF_line_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x6c69); // 'li'
1867-
1868- /* Sides.. */
1869- extract_type_from_wad(wad, SIDE_TAG, &data_length);
1870- side_count= data_length/SIZEOF_side_data;
1871- if(side_count*SIZEOF_side_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x7369); // 'si'
1872-
1873- /* Extract polygons */
1874- extract_type_from_wad(wad, POLYGON_TAG, &data_length);
1875- polygon_count= data_length/SIZEOF_polygon_data;
1876- if(polygon_count*SIZEOF_polygon_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x7369); // 'si'
1877-
1878- allocate_map_for_counts(polygon_count, side_count, endpoint_count, line_count);
1879-}
1880-
1881-/* Note that we assume the redundant data has already been recalculated... */
1882-static void load_redundant_map_data(
1883- short *redundant_data,
1884- size_t count)
1885-{
1886- if (redundant_data)
1887- {
1888- // assert(redundant_data && map_indexes);
1889- uint8 *Stream = (uint8 *)redundant_data;
1890- MapIndexList.resize(count);
1891- StreamToList(Stream,map_indexes,count);
1892- assert(count == static_cast<size_t>(static_cast<int16>(count)));
1893- assert(0 <= static_cast<int16>(count));
1894- dynamic_world->map_index_count= static_cast<int16>(count);
1895- }
1896- else
1897- {
1898- recalculate_redundant_map();
1899- precalculate_map_indexes();
1900- }
1901-}
1902-
1903-void load_terminal_data(
1904- uint8 *data,
1905- size_t length)
1906-{
1907- /* I would really like it if I could get these into computer_interface.c statically */
1908- unpack_map_terminal_data(data,length);
1909-}
1910-
1911-static void scan_and_add_scenery(
1912- void)
1913-{
1914- short ii;
1915- struct map_object *saved_object;
1916-
1917- saved_object= saved_objects;
1918- for(ii=0; ii<dynamic_world->initial_objects_count; ++ii)
1919- {
1920- if (saved_object->type==_saved_object)
1921- {
1922- struct object_location location;
1923-
1924- location.p= saved_object->location;
1925- location.flags= saved_object->flags;
1926- location.yaw= saved_object->facing;
1927- location.polygon_index= saved_object->polygon_index;
1928- new_scenery(&location, saved_object->index);
1929- }
1930-
1931- ++saved_object;
1932- }
1933-}
1934-
1935-struct save_game_data
1936-{
1937- uint32 tag;
1938- short unit_size;
1939- bool loaded_by_level;
1940-};
1941-
1942-#define NUMBER_OF_EXPORT_ARRAYS (sizeof(export_data)/sizeof(struct save_game_data))
1943-save_game_data export_data[]=
1944-{
1945- { POINT_TAG, SIZEOF_world_point2d, true },
1946- { LINE_TAG, SIZEOF_line_data, true },
1947- { POLYGON_TAG, SIZEOF_polygon_data, true },
1948- { SIDE_TAG, SIZEOF_side_data, true },
1949- { LIGHTSOURCE_TAG, SIZEOF_static_light_data, true, },
1950- { ANNOTATION_TAG, SIZEOF_map_annotation, true },
1951- { OBJECT_TAG, SIZEOF_map_object, true },
1952- { MAP_INFO_TAG, SIZEOF_static_data, true },
1953- { ITEM_PLACEMENT_STRUCTURE_TAG, SIZEOF_object_frequency_definition, true },
1954- { PLATFORM_STATIC_DATA_TAG, SIZEOF_static_platform_data, true },
1955- { TERMINAL_DATA_TAG, sizeof(byte), true },
1956- { MEDIA_TAG, SIZEOF_media_data, true }, // false },
1957- { AMBIENT_SOUND_TAG, SIZEOF_ambient_sound_image_data, true },
1958- { RANDOM_SOUND_TAG, SIZEOF_random_sound_image_data, true },
1959- { SHAPE_PATCH_TAG, sizeof(byte), true },
1960-// { PLATFORM_STRUCTURE_TAG, SIZEOF_platform_data, true },
1961-};
1962-
1963-#define NUMBER_OF_SAVE_ARRAYS (sizeof(save_data)/sizeof(struct save_game_data))
1964-struct save_game_data save_data[]=
1965-{
1966- { ENDPOINT_DATA_TAG, SIZEOF_endpoint_data, true },
1967- { LINE_TAG, SIZEOF_line_data, true },
1968- { SIDE_TAG, SIZEOF_side_data, true },
1969- { POLYGON_TAG, SIZEOF_polygon_data, true },
1970- { LIGHTSOURCE_TAG, SIZEOF_light_data, true }, // false },
1971- { ANNOTATION_TAG, SIZEOF_map_annotation, true },
1972- { OBJECT_TAG, SIZEOF_map_object, true },
1973- { MAP_INFO_TAG, SIZEOF_static_data, true },
1974- { ITEM_PLACEMENT_STRUCTURE_TAG, SIZEOF_object_frequency_definition, true },
1975- { MEDIA_TAG, SIZEOF_media_data, true }, // false },
1976- { AMBIENT_SOUND_TAG, SIZEOF_ambient_sound_image_data, true },
1977- { RANDOM_SOUND_TAG, SIZEOF_random_sound_image_data, true },
1978- { TERMINAL_DATA_TAG, sizeof(byte), true },
1979-
1980- // LP addition: handling of physics models
1981- { MONSTER_PHYSICS_TAG, SIZEOF_monster_definition, true},
1982- { EFFECTS_PHYSICS_TAG, SIZEOF_effect_definition, true},
1983- { PROJECTILE_PHYSICS_TAG, SIZEOF_projectile_definition, true},
1984- { PHYSICS_PHYSICS_TAG, SIZEOF_physics_constants, true},
1985- { WEAPONS_PHYSICS_TAG, SIZEOF_weapon_definition, true},
1986-
1987- // GHS: save the new embedded shapes
1988- { SHAPE_PATCH_TAG, sizeof(byte), true },
1989-
1990- { MMLS_TAG, sizeof(byte), true },
1991- { LUAS_TAG, sizeof(byte), true },
1992-
1993- { MAP_INDEXES_TAG, sizeof(short), true }, // false },
1994- { PLAYER_STRUCTURE_TAG, SIZEOF_player_data, true }, // false },
1995- { DYNAMIC_STRUCTURE_TAG, SIZEOF_dynamic_data, true }, // false },
1996- { OBJECT_STRUCTURE_TAG, SIZEOF_object_data, true }, // false },
1997- { AUTOMAP_LINES, sizeof(byte), true }, // false },
1998- { AUTOMAP_POLYGONS, sizeof(byte), true }, // false },
1999- { MONSTERS_STRUCTURE_TAG, SIZEOF_monster_data, true }, // false },
2000- { EFFECTS_STRUCTURE_TAG, SIZEOF_effect_data, true }, // false },
2001- { PROJECTILES_STRUCTURE_TAG, SIZEOF_projectile_data, true }, // false },
2002- { PLATFORM_STRUCTURE_TAG, SIZEOF_platform_data, true }, // false },
2003- { WEAPON_STATE_TAG, SIZEOF_player_weapon_data, true }, // false },
2004- { TERMINAL_STATE_TAG, SIZEOF_player_terminal_data, true }, // false }
2005-
2006- { LUA_STATE_TAG, sizeof(byte), true },
2007-};
2008-
2009-static uint8 *export_tag_to_global_array_and_size(
2010- uint32 tag,
2011- size_t *size
2012- )
2013-{
2014- uint8 *array = NULL;
2015- size_t unit_size = 0;
2016- size_t count = 0;
2017- unsigned index;
2018-
2019- for (index=0; index<NUMBER_OF_EXPORT_ARRAYS; ++index)
2020- {
2021- if(export_data[index].tag==tag)
2022- {
2023- unit_size= export_data[index].unit_size;
2024- break;
2025- }
2026- }
2027- assert(index != NUMBER_OF_EXPORT_ARRAYS);
2028-
2029- switch (tag)
2030- {
2031- case POINT_TAG:
2032- count = dynamic_world->endpoint_count;
2033- break;
2034-
2035- case LIGHTSOURCE_TAG:
2036- count = dynamic_world->light_count;
2037- break;
2038-
2039- case PLATFORM_STATIC_DATA_TAG:
2040- count = dynamic_world->platform_count;
2041- break;
2042-
2043- case POLYGON_TAG:
2044- count = dynamic_world->polygon_count;
2045- break;
2046-
2047- default:
2048- assert(false);
2049- break;
2050- }
2051-
2052- // Allocate a temporary packed-data chunk;
2053- // indicate if there is nothing to be written
2054- *size= count*unit_size;
2055- if (*size > 0)
2056- array = new byte[*size];
2057- else
2058- return NULL;
2059-
2060- objlist_clear(array, *size);
2061-
2062- // An OK-to-alter version of that array pointer
2063- uint8 *temp_array = array;
2064-
2065- switch (tag)
2066- {
2067- case POINT_TAG:
2068- for (size_t loop = 0; loop < count; ++loop)
2069- {
2070- world_point2d& vertex = map_endpoints[loop].vertex;
2071- ValueToStream(temp_array, vertex.x);
2072- ValueToStream(temp_array, vertex.y);
2073- }
2074- break;
2075-
2076- case LIGHTSOURCE_TAG:
2077- for (size_t loop = 0; loop < count; ++loop)
2078- {
2079- temp_array = pack_static_light_data(temp_array, &lights[loop].static_data, 1);
2080- }
2081- break;
2082-
2083- case PLATFORM_STATIC_DATA_TAG:
2084- if (static_platforms.size() == count)
2085- {
2086- // export them directly as they came in
2087- pack_static_platform_data(array, &static_platforms[0], count);
2088- }
2089- else
2090- {
2091- for (size_t loop = 0; loop < count; ++loop)
2092- {
2093- // ghs: this belongs somewhere else
2094- static_platform_data platform;
2095- obj_clear(platform);
2096- platform.type = platforms[loop].type;
2097- platform.speed = platforms[loop].speed;
2098- platform.delay = platforms[loop].delay;
2099- if (PLATFORM_GOES_BOTH_WAYS(&platforms[loop]))
2100- {
2101- platform.maximum_height = platforms[loop].maximum_ceiling_height;
2102- platform.minimum_height = platforms[loop].minimum_floor_height;
2103- }
2104- else if (PLATFORM_COMES_FROM_FLOOR(&platforms[loop]))
2105- {
2106- platform.maximum_height = platforms[loop].maximum_floor_height;
2107- platform.minimum_height = platforms[loop].minimum_floor_height;
2108- }
2109- else
2110- {
2111- platform.maximum_height = platforms[loop].maximum_ceiling_height;
2112- platform.minimum_height = platforms[loop].minimum_floor_height;
2113- }
2114- platform.static_flags = platforms[loop].static_flags;
2115- platform.polygon_index = platforms[loop].polygon_index;
2116- platform.tag = platforms[loop].tag;
2117-
2118- temp_array = pack_static_platform_data(temp_array, &platform, 1);
2119- }
2120- }
2121- break;
2122-
2123- case POLYGON_TAG:
2124- for (size_t loop = 0; loop < count; ++loop)
2125- {
2126- // Forge visual mode crashes if we don't do this
2127- polygon_data polygon = PolygonList[loop];
2128- polygon.first_object = NONE;
2129- temp_array = pack_polygon_data(temp_array, &polygon, 1);
2130- }
2131- break;
2132-
2133- default:
2134- assert(false);
2135- break;
2136- }
2137-
2138- return array;
2139-}
2140-
2141-extern size_t save_lua_states();
2142-extern void pack_lua_states(uint8*, size_t);
2143-
2144-
2145-/* the sizes are the sizes to save in the file, be aware! */
2146-static uint8 *tag_to_global_array_and_size(
2147- uint32 tag,
2148- size_t *size
2149- )
2150-{
2151- uint8 *array= NULL;
2152- size_t unit_size = 0;
2153- size_t count = 0;
2154- unsigned index;
2155-
2156- for (index=0; index<NUMBER_OF_SAVE_ARRAYS; ++index)
2157- {
2158- if(save_data[index].tag==tag)
2159- {
2160- unit_size= save_data[index].unit_size;
2161- break;
2162- }
2163- }
2164- assert(index != NUMBER_OF_SAVE_ARRAYS);
2165-
2166- // LP: had fixed off-by-one error in medias saving,
2167- // and had added physics-model saving
2168-
2169- switch (tag)
2170- {
2171- case ENDPOINT_DATA_TAG:
2172- count= dynamic_world->endpoint_count;
2173- break;
2174- case LINE_TAG:
2175- count= dynamic_world->line_count;
2176- break;
2177- case SIDE_TAG:
2178- count= dynamic_world->side_count;
2179- break;
2180- case POLYGON_TAG:
2181- count= dynamic_world->polygon_count;
2182- break;
2183- case LIGHTSOURCE_TAG:
2184- count= dynamic_world->light_count;
2185- break;
2186- case ANNOTATION_TAG:
2187- count= dynamic_world->default_annotation_count;
2188- break;
2189- case OBJECT_TAG:
2190- count= dynamic_world->initial_objects_count;
2191- break;
2192- case MAP_INFO_TAG:
2193- count= 1;
2194- break;
2195- case PLAYER_STRUCTURE_TAG:
2196- count= dynamic_world->player_count;
2197- break;
2198- case DYNAMIC_STRUCTURE_TAG:
2199- count= 1;
2200- break;
2201- case OBJECT_STRUCTURE_TAG:
2202- count= dynamic_world->object_count;
2203- break;
2204- case MAP_INDEXES_TAG:
2205- count= static_cast<unsigned short>(dynamic_world->map_index_count);
2206- break;
2207- case AUTOMAP_LINES:
2208- count= (dynamic_world->line_count/8+((dynamic_world->line_count%8)?1:0));
2209- break;
2210- case AUTOMAP_POLYGONS:
2211- count= (dynamic_world->polygon_count/8+((dynamic_world->polygon_count%8)?1:0));
2212- break;
2213- case MONSTERS_STRUCTURE_TAG:
2214- count= dynamic_world->monster_count;
2215- break;
2216- case EFFECTS_STRUCTURE_TAG:
2217- count= dynamic_world->effect_count;
2218- break;
2219- case PROJECTILES_STRUCTURE_TAG:
2220- count= dynamic_world->projectile_count;
2221- break;
2222- case MEDIA_TAG:
2223- count= count_number_of_medias_used();
2224- break;
2225- case ITEM_PLACEMENT_STRUCTURE_TAG:
2226- count= 2*MAXIMUM_OBJECT_TYPES;
2227- break;
2228- case PLATFORM_STRUCTURE_TAG:
2229- count= dynamic_world->platform_count;
2230- break;
2231- case AMBIENT_SOUND_TAG:
2232- count= dynamic_world->ambient_sound_image_count;
2233- break;
2234- case RANDOM_SOUND_TAG:
2235- count= dynamic_world->random_sound_image_count;
2236- break;
2237- case TERMINAL_DATA_TAG:
2238- count= calculate_packed_terminal_data_length();
2239- break;
2240- case WEAPON_STATE_TAG:
2241- count= dynamic_world->player_count;
2242- break;
2243- case TERMINAL_STATE_TAG:
2244- count= dynamic_world->player_count;
2245- break;
2246- case MONSTER_PHYSICS_TAG:
2247- count= NUMBER_OF_MONSTER_TYPES;
2248- break;
2249- case EFFECTS_PHYSICS_TAG:
2250- count= NUMBER_OF_EFFECT_TYPES;
2251- break;
2252- case PROJECTILE_PHYSICS_TAG:
2253- count= NUMBER_OF_PROJECTILE_TYPES;
2254- break;
2255- case PHYSICS_PHYSICS_TAG:
2256- count= get_number_of_physics_models();
2257- break;
2258- case WEAPONS_PHYSICS_TAG:
2259- count= get_number_of_weapon_types();
2260- break;
2261- case SHAPE_PATCH_TAG:
2262- get_shapes_patch_data(count);
2263- break;
2264- case MMLS_TAG:
2265- GetMMLS(count);
2266- break;
2267- case LUAS_TAG:
2268- GetLUAS(count);
2269- break;
2270- case LUA_STATE_TAG:
2271- count= save_lua_states();
2272- break;
2273- default:
2274- assert(false);
2275- break;
2276- }
2277-
2278- // Allocate a temporary packed-data chunk;
2279- // indicate if there is nothing to be written
2280- *size= count*unit_size;
2281- if (*size > 0)
2282- array = new byte[*size];
2283- else
2284- return NULL;
2285-
2286- objlist_clear(array, *size);
2287-
2288- // An OK-to-alter version of that array pointer
2289- uint8 *temp_array = array;
2290-
2291- switch (tag)
2292- {
2293- case ENDPOINT_DATA_TAG:
2294- pack_endpoint_data(array,map_endpoints,count);
2295- break;
2296- case LINE_TAG:
2297- pack_line_data(array,map_lines,count);
2298- break;
2299- case SIDE_TAG:
2300- pack_side_data(array,map_sides,count);
2301- break;
2302- case POLYGON_TAG:
2303- pack_polygon_data(array,map_polygons,count);
2304- break;
2305- case LIGHTSOURCE_TAG:
2306- pack_light_data(array,lights,count);
2307- break;
2308- case ANNOTATION_TAG:
2309- pack_map_annotation(array,map_annotations,count);
2310- break;
2311- case OBJECT_TAG:
2312- pack_map_object(array,saved_objects,count);
2313- break;
2314- case MAP_INFO_TAG:
2315- pack_static_data(array,static_world,count);
2316- break;
2317- case PLAYER_STRUCTURE_TAG:
2318- pack_player_data(array,players,count);
2319- break;
2320- case DYNAMIC_STRUCTURE_TAG:
2321- pack_dynamic_data(array,dynamic_world,count);
2322- break;
2323- case OBJECT_STRUCTURE_TAG:
2324- pack_object_data(array,objects,count);
2325- break;
2326- case MAP_INDEXES_TAG:
2327- ListToStream(temp_array,map_indexes,count); // E-Z packing here...
2328- break;
2329- case AUTOMAP_LINES:
2330- memcpy(array,automap_lines,*size);
2331- break;
2332- case AUTOMAP_POLYGONS:
2333- memcpy(array,automap_polygons,*size);
2334- break;
2335- case MONSTERS_STRUCTURE_TAG:
2336- pack_monster_data(array,monsters,count);
2337- break;
2338- case EFFECTS_STRUCTURE_TAG:
2339- pack_effect_data(array,effects,count);
2340- break;
2341- case PROJECTILES_STRUCTURE_TAG:
2342- pack_projectile_data(array,projectiles,count);
2343- break;
2344- case MEDIA_TAG:
2345- pack_media_data(array,medias,count);
2346- break;
2347- case ITEM_PLACEMENT_STRUCTURE_TAG:
2348- pack_object_frequency_definition(array,get_placement_info(),count);
2349- break;
2350- case PLATFORM_STRUCTURE_TAG:
2351- pack_platform_data(array,platforms,count);
2352- break;
2353- case AMBIENT_SOUND_TAG:
2354- pack_ambient_sound_image_data(array,ambient_sound_images,count);
2355- break;
2356- case RANDOM_SOUND_TAG:
2357- pack_random_sound_image_data(array,random_sound_images,count);
2358- break;
2359- case TERMINAL_DATA_TAG:
2360- pack_map_terminal_data(array,count);
2361- break;
2362- case WEAPON_STATE_TAG:
2363- pack_player_weapon_data(array,count);
2364- break;
2365- case TERMINAL_STATE_TAG:
2366- pack_player_terminal_data(array,count);
2367- break;
2368- case MONSTER_PHYSICS_TAG:
2369- pack_monster_definition(array,count);
2370- break;
2371- case EFFECTS_PHYSICS_TAG:
2372- pack_effect_definition(array,count);
2373- break;
2374- case PROJECTILE_PHYSICS_TAG:
2375- pack_projectile_definition(array,count);
2376- break;
2377- case PHYSICS_PHYSICS_TAG:
2378- pack_physics_constants(array,count);
2379- break;
2380- case WEAPONS_PHYSICS_TAG:
2381- pack_weapon_definition(array,count);
2382- break;
2383- case SHAPE_PATCH_TAG:
2384- memcpy(array, get_shapes_patch_data(count), count);
2385- break;
2386- case MMLS_TAG:
2387- memcpy(array, GetMMLS(count), count);
2388- break;
2389- case LUAS_TAG:
2390- memcpy(array, GetLUAS(count), count);
2391- break;
2392- case LUA_STATE_TAG:
2393- pack_lua_states(array, count);
2394- break;
2395- default:
2396- assert(false);
2397- break;
2398- }
2399-
2400- return array;
2401-}
2402-
2403-static wad_data *build_export_wad(wad_header *header, int32 *length)
2404-{
2405- struct wad_data *wad= NULL;
2406- uint8 *array_to_slam;
2407- size_t size;
2408-
2409- wad= create_empty_wad();
2410- if(wad)
2411- {
2412- recalculate_map_counts();
2413-
2414- // try to divine initial platform/polygon states
2415- vector<platform_data> SavedPlatforms = PlatformList;
2416- vector<polygon_data> SavedPolygons = PolygonList;
2417- vector<line_data> SavedLines = LineList;
2418-
2419- for (size_t loop = 0; loop < PlatformList.size(); ++loop)
2420- {
2421- platform_data *platform = &PlatformList[loop];
2422- // reset the polygon heights
2423- if (PLATFORM_COMES_FROM_FLOOR(platform))
2424- {
2425- platform->floor_height = platform->minimum_floor_height;
2426- PolygonList[platform->polygon_index].floor_height = platform->floor_height;
2427- }
2428- if (PLATFORM_COMES_FROM_CEILING(platform))
2429- {
2430- platform->ceiling_height = platform->maximum_ceiling_height;
2431- PolygonList[platform->polygon_index].ceiling_height = platform->ceiling_height;
2432- }
2433- }
2434-
2435- for (size_t loop = 0; loop < LineList.size(); ++loop)
2436- {
2437- line_data *line = &LineList[loop];
2438- if (LINE_IS_VARIABLE_ELEVATION(line))
2439- {
2440- SET_LINE_VARIABLE_ELEVATION(line, false);
2441- SET_LINE_SOLIDITY(line, false);
2442- SET_LINE_TRANSPARENCY(line, true);
2443- }
2444- }
2445-
2446- for(unsigned loop= 0; loop<NUMBER_OF_EXPORT_ARRAYS; ++loop)
2447- {
2448- /* If there is a conversion function, let it handle it */
2449- switch (export_data[loop].tag)
2450- {
2451- case POINT_TAG:
2452- case LIGHTSOURCE_TAG:
2453- case PLATFORM_STATIC_DATA_TAG:
2454- case POLYGON_TAG:
2455- array_to_slam= export_tag_to_global_array_and_size(export_data[loop].tag, &size);
2456- break;
2457- default:
2458- array_to_slam= tag_to_global_array_and_size(export_data[loop].tag, &size);
2459- }
2460-
2461- /* Add it to the wad.. */
2462- if(size)
2463- {
2464- wad= append_data_to_wad(wad, export_data[loop].tag, array_to_slam, size, 0);
2465- delete []array_to_slam;
2466- }
2467- }
2468-
2469- PlatformList = SavedPlatforms;
2470- PolygonList = SavedPolygons;
2471- LineList = SavedLines;
2472-
2473- if(wad) *length= calculate_wad_length(header, wad);
2474- }
2475-
2476- return wad;
2477-}
2478-
2479-/* Build the wad, with all the crap */
2480-static struct wad_data *build_save_game_wad(
2481- struct wad_header *header,
2482- int32 *length)
2483-{
2484- struct wad_data *wad= NULL;
2485- uint8 *array_to_slam;
2486- size_t size;
2487-
2488- wad= create_empty_wad();
2489- if(wad)
2490- {
2491- recalculate_map_counts();
2492- for(unsigned loop= 0; loop<NUMBER_OF_SAVE_ARRAYS; ++loop)
2493- {
2494- /* If there is a conversion function, let it handle it */
2495- array_to_slam= tag_to_global_array_and_size(save_data[loop].tag, &size);
2496-
2497- /* Add it to the wad.. */
2498- if(size)
2499- {
2500- wad= append_data_to_wad(wad, save_data[loop].tag, array_to_slam, size, 0);
2501- delete []array_to_slam;
2502- }
2503- }
2504- if(wad) *length= calculate_wad_length(header, wad);
2505- }
2506-
2507- return wad;
2508-}
2509-
2510-/* Load and slam all of the arrays */
2511-static void complete_restoring_level(
2512- struct wad_data *wad)
2513-{
2514- ok_to_reset_scenery_solidity = false;
2515- /* Loading games needs this done. */
2516- reset_action_queues();
2517-}
2518-
2519-
2520-/* CP Addition: get_map_file returns a pointer to the current map file */
2521-FileSpecifier& get_map_file()
2522-{
2523- return MapFileSpec;
2524-}
2525-
2526-void level_has_embedded_physics_lua(int Level, bool& HasPhysics, bool& HasLua)
2527-{
2528- // load the wad file and look for chunks !!??
2529- wad_header header;
2530- wad_data* wad;
2531- OpenedFile MapFile;
2532- if (open_wad_file_for_reading(get_map_file(), MapFile))
2533- {
2534- if (read_wad_header(MapFile, &header))
2535- {
2536- wad = read_indexed_wad_from_file(MapFile, &header, Level, true);
2537- if (wad)
2538- {
2539- size_t data_length;
2540- extract_type_from_wad(wad, PHYSICS_PHYSICS_TAG, &data_length);
2541- HasPhysics = data_length > 0;
2542-
2543- extract_type_from_wad(wad, LUAS_TAG, &data_length);
2544- HasLua = data_length > 0;
2545- free_wad(wad);
2546- }
2547- }
2548- close_wad_file(MapFile);
2549- }
2550-}
2551-
2552-
2553-/*
2554- * Unpacking/packing functions
2555- */
2556-
2557-static uint8 *unpack_directory_data(uint8 *Stream, directory_data *Objects, size_t Count)
2558-{
2559- uint8* S = Stream;
2560- directory_data* ObjPtr = Objects;
2561-
2562- for (size_t k = 0; k < Count; k++, ObjPtr++)
2563- {
2564- StreamToValue(S,ObjPtr->mission_flags);
2565- StreamToValue(S,ObjPtr->environment_flags);
2566- StreamToValue(S,ObjPtr->entry_point_flags);
2567- StreamToBytes(S,ObjPtr->level_name,LEVEL_NAME_LENGTH);
2568- }
2569-
2570- assert((S - Stream) == SIZEOF_directory_data);
2571- return S;
2572-}
2573-
2574-// ZZZ: gnu cc swears this is currently unused, and I don't see any sneaky #includes that might need it...
2575-/*
2576-static uint8 *pack_directory_data(uint8 *Stream, directory_data *Objects, int Count)
2577-{
2578- uint8* S = Stream;
2579- directory_data* ObjPtr = Objects;
2580-
2581- for (int k = 0; k < Count; k++, ObjPtr++)
2582- {
2583- ValueToStream(S,ObjPtr->mission_flags);
2584- ValueToStream(S,ObjPtr->environment_flags);
2585- ValueToStream(S,ObjPtr->entry_point_flags);
2586- BytesToStream(S,ObjPtr->level_name,LEVEL_NAME_LENGTH);
2587- }
2588-
2589- assert((S - Stream) == SIZEOF_directory_data);
2590- return S;
2591-}
2592-*/
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+#ifdef env68k
133+#pragma segment file_io
134+#endif
135+
136+// unify the save game code into one structure.
137+
138+/* -------- local globals */
139+FileSpecifier MapFileSpec;
140+static bool file_is_set= false;
141+
142+// LP addition: was a physics model loaded from the previous level loaded?
143+static bool PhysicsModelLoadedEarlier = false;
144+
145+// The following local globals are for handling games that need to be restored.
146+struct revert_game_info
147+{
148+ bool game_is_from_disk;
149+ struct game_data game_information;
150+ struct player_start_data player_start;
151+ struct entry_point entry_point;
152+ FileSpecifier SavedGame;
153+};
154+static struct revert_game_info revert_game_data;
155+
156+#if 0
157+/* Borrowed from the old lightsource.h, to allow Marathon II to open/use Marathon I maps */
158+struct old_light_data {
159+ uint16 flags;
160+
161+ int16 type;
162+ int16 mode; /* on, off, etc. */
163+ int16 phase;
164+
165+ fixed minimum_intensity, maximum_intensity;
166+ int16 period; /* on, in ticks (turning on and off periods are always the same for a given light type,
167+ or else are some function of this period) */
168+
169+ fixed intensity; /* current intensity */
170+
171+ int16 unused[5];
172+};
173+
174+enum /* old light types */
175+{
176+ _light_is_normal,
177+ _light_is_rheostat,
178+ _light_is_flourescent,
179+ _light_is_strobe,
180+ _light_flickers,
181+ _light_pulsates,
182+ _light_is_annoying,
183+ _light_is_energy_efficient
184+};
185+#endif
186+
187+/* -------- static functions */
188+static void scan_and_add_scenery(void);
189+static void complete_restoring_level(struct wad_data *wad);
190+static void load_redundant_map_data(short *redundant_data, size_t count);
191+static void allocate_map_structure_for_map(struct wad_data *wad);
192+static wad_data *build_export_wad(wad_header *header, int32 *length);
193+static struct wad_data *build_save_game_wad(struct wad_header *header, int32 *length);
194+
195+static void allocate_map_for_counts(size_t polygon_count, size_t side_count,
196+ size_t endpoint_count, size_t line_count);
197+static void load_points(uint8 *points, size_t count);
198+static void load_lines(uint8 *lines, size_t count);
199+static void load_sides(uint8 *sides, size_t count, short version);
200+static void load_polygons(uint8 *polys, size_t count, short version);
201+static void load_lights(uint8 *_lights, size_t count, short version);
202+static void load_annotations(uint8 *annotations, size_t count);
203+static void load_objects(uint8 *map_objects, size_t count);
204+static void load_media(uint8 *_medias, size_t count);
205+static void load_map_info(uint8 *map_info);
206+static void load_ambient_sound_images(uint8 *data, size_t count);
207+static void load_random_sound_images(uint8 *data, size_t count);
208+static void load_terminal_data(uint8 *data, size_t length);
209+
210+/* Used _ONLY_ by game_wad.c internally and precalculate.c. */
211+// ZZZ: hmm, no longer true, now using when resuming a network saved-game... hope that's ok?...
212+//static bool process_map_wad(struct wad_data *wad, bool restoring_game, short version);
213+
214+/* Final three calls, must be in this order! */
215+static void recalculate_redundant_map(void);
216+static void scan_and_add_platforms(uint8 *platform_static_data, size_t count, short version);
217+static void complete_loading_level(short *_map_indexes, size_t map_index_count,
218+ uint8 *_platform_data, size_t platform_data_count,
219+ uint8 *actual_platform_data, size_t actual_platform_data_count, short version);
220+
221+static uint8 *unpack_directory_data(uint8 *Stream, directory_data *Objects, size_t Count);
222+//static uint8 *pack_directory_data(uint8 *Stream, directory_data *Objects, int Count);
223+
224+/* ------------------------ Net functions */
225+int32 get_net_map_data_length(
226+ void *data)
227+{
228+ return get_flat_data_length(data);
229+}
230+
231+/* Note that this frees it as well */
232+bool process_net_map_data(
233+ void *data)
234+{
235+ struct wad_header header;
236+ struct wad_data *wad;
237+ bool success= false;
238+
239+ wad= inflate_flat_data(data, &header);
240+ if(wad)
241+ {
242+ success= process_map_wad(wad, false, header.data_version);
243+ free_wad(wad); /* Note that the flat data points into the wad. */
244+ }
245+
246+ return success;
247+}
248+
249+/* This will have to do some interesting voodoo with union wads, methinks */
250+void *get_map_for_net_transfer(
251+ struct entry_point *entry)
252+{
253+ assert(file_is_set);
254+
255+ /* false means don't use union maps.. */
256+ return get_flat_data(MapFileSpec, false, entry->level_number);
257+}
258+
259+/* ---------------------- End Net Functions ----------- */
260+
261+/* This takes a cstring */
262+void set_map_file(FileSpecifier& File)
263+{
264+ // Do whatever parameter restoration is specified before changing the file
265+ if (file_is_set) RunRestorationScript();
266+
267+ MapFileSpec = File;
268+ set_scenario_images_file(File);
269+ // Only need to do this here
270+ LoadLevelScripts(File);
271+
272+ // Don't care whether there was an error when checking on the file's scenario images
273+ clear_game_error();
274+
275+ file_is_set= true;
276+}
277+
278+/* Set to the default map.. (Only if no map doubleclicked upon on startup.. */
279+void set_to_default_map(
280+ void)
281+{
282+ FileSpecifier NewMapFile;
283+
284+ get_default_map_spec(NewMapFile);
285+ set_map_file(NewMapFile);
286+}
287+
288+/* Return true if it finds the file, and it sets the mapfile to that file. */
289+/* Otherwise it returns false, meaning that we need have the file sent to us. */
290+bool use_map_file(
291+ uint32 checksum)
292+{
293+ FileSpecifier File;
294+ bool success= false;
295+
296+ if(find_wad_file_that_has_checksum(File, _typecode_scenario, strPATHS, checksum))
297+ {
298+ set_map_file(File);
299+ success= true;
300+ }
301+
302+ return success;
303+}
304+
305+bool load_level_from_map(
306+ short level_index)
307+{
308+ OpenedFile OFile;
309+ struct wad_header header;
310+ struct wad_data *wad;
311+ short index_to_load;
312+ bool restoring_game= false;
313+
314+ if(file_is_set)
315+ {
316+ /* Determine what we are trying to do.. */
317+ if(level_index==NONE)
318+ {
319+ restoring_game= true;
320+ index_to_load= 0; /* Saved games are always index 0 */
321+ } else {
322+ index_to_load= level_index;
323+ }
324+
325+ OpenedFile MapFile;
326+ if (open_wad_file_for_reading(MapFileSpec,MapFile))
327+ {
328+ /* Read the file */
329+ if(read_wad_header(MapFile, &header))
330+ {
331+ if(index_to_load>=0 && index_to_load<header.wad_count)
332+ {
333+
334+ wad= read_indexed_wad_from_file(MapFile, &header, index_to_load, true);
335+ if (wad)
336+ {
337+ /* Process everything... */
338+ process_map_wad(wad, restoring_game, header.data_version);
339+
340+ /* Nuke our memory... */
341+ free_wad(wad);
342+ } else {
343+ // error code has been set...
344+ }
345+ } else {
346+ set_game_error(gameError, errWadIndexOutOfRange);
347+ }
348+ } else {
349+ // error code has been set...
350+ }
351+
352+ /* Close the file.. */
353+ close_wad_file(MapFile);
354+ } else {
355+ // error code has been set..
356+ }
357+ } else {
358+ set_game_error(gameError, errMapFileNotSet);
359+ }
360+
361+ /* ... and bail */
362+ return (!error_pending());
363+}
364+
365+// keep these around for level export
366+static std::vector<static_platform_data> static_platforms;
367+
368+extern bool ok_to_reset_scenery_solidity;
369+
370+/* Hopefully this is in the correct order of initialization... */
371+/* This sucks, beavis. */
372+void complete_loading_level(
373+ short *_map_indexes,
374+ size_t map_index_count,
375+ uint8 *_platform_data,
376+ size_t platform_data_count,
377+ uint8 *actual_platform_data,
378+ size_t actual_platform_data_count,
379+ short version)
380+{
381+ /* Scan, add the doors, recalculate, and generally tie up all loose ends */
382+ /* Recalculate the redundant data.. */
383+ load_redundant_map_data(_map_indexes, map_index_count);
384+
385+ static_platforms.clear();
386+
387+ /* Add the platforms. */
388+ if(_platform_data || (_platform_data==NULL && actual_platform_data==NULL))
389+ {
390+ scan_and_add_platforms(_platform_data, platform_data_count, version);
391+ } else {
392+ assert(actual_platform_data);
393+ PlatformList.resize(actual_platform_data_count);
394+ unpack_platform_data(actual_platform_data,platforms,actual_platform_data_count);
395+ assert(actual_platform_data_count == static_cast<size_t>(static_cast<int16>(actual_platform_data_count)));
396+ assert(0 <= static_cast<int16>(actual_platform_data_count));
397+ dynamic_world->platform_count= static_cast<int16>(actual_platform_data_count);
398+ }
399+
400+ scan_and_add_scenery();
401+ ok_to_reset_scenery_solidity = true;
402+
403+ /* Gotta do this after recalculate redundant.. */
404+ if(version==MARATHON_ONE_DATA_VERSION)
405+ {
406+ short loop;
407+
408+ for(loop= 0; loop<dynamic_world->side_count; ++loop)
409+ {
410+ guess_side_lightsource_indexes(loop);
411+ }
412+ }
413+}
414+
415+/* Call with location of NULL to get the number of start locations for a */
416+/* given team or player */
417+short get_player_starting_location_and_facing(
418+ short team,
419+ short index,
420+ struct object_location *location)
421+{
422+#if 1
423+ short ii;
424+ struct map_object *saved_object;
425+ short count= 0;
426+ bool done= false;
427+
428+ saved_object= saved_objects;
429+ for(ii=0; !done && ii<dynamic_world->initial_objects_count; ++ii)
430+ {
431+ if(saved_object->type==_saved_player)
432+ {
433+ /* index=NONE means use any starting location */
434+ if(saved_object->index==team || team==NONE)
435+ {
436+ if(location && count==index)
437+ {
438+ location->p= saved_object->location;
439+ location->polygon_index= saved_object->polygon_index;
440+ location->yaw= saved_object->facing;
441+ location->pitch= 0;
442+ location->flags= saved_object->flags;
443+ done= true;
444+ }
445+ count++;
446+ }
447+ }
448+ ++saved_object;
449+ }
450+
451+ /* If they asked for a valid location, make sure that we gave them one */
452+ if(location) vassert(done, csprintf(temporary, "Tried to place: %d only %d starting pts.", index, count));
453+
454+ return count;
455+#else
456+ location->x= 0x14e9;
457+ location->y= 0x1ba0;
458+ *facing= 0x00;
459+ *polygon_index= 0x6f;
460+
461+ return 1;
462+#endif
463+}
464+
465+uint32 get_current_map_checksum(
466+ void)
467+{
468+ // fileref file_handle;
469+ struct wad_header header;
470+
471+ assert(file_is_set);
472+ OpenedFile MapFile;
473+ open_wad_file_for_reading(MapFileSpec, MapFile);
474+ assert(MapFile.IsOpen());
475+
476+ /* Read the file */
477+ read_wad_header(MapFile, &header);
478+
479+ /* Close the file.. */
480+ close_wad_file(MapFile);
481+
482+ return header.checksum;
483+}
484+
485+// ZZZ: split this out from new_game for sharing
486+void set_saved_game_name_to_default()
487+{
488+#if defined(mac) || defined(SDL_RFORK_HACK)
489+ revert_game_data.SavedGame.SetToApp();
490+ revert_game_data.SavedGame.SetName(getcstr(temporary, strFILENAMES, filenameDEFAULT_SAVE_GAME),_typecode_savegame);
491+#endif
492+#if defined(SDL) && !defined(SDL_RFORK_HACK)
493+ revert_game_data.SavedGame.SetToSavedGamesDir();
494+ revert_game_data.SavedGame += getcstr(temporary, strFILENAMES, filenameDEFAULT_SAVE_GAME);
495+#endif
496+}
497+
498+extern void ResetPassedLua();
499+
500+bool new_game(
501+ short number_of_players,
502+ bool network,
503+ struct game_data *game_information,
504+ struct player_start_data *player_start_information,
505+ struct entry_point *entry_point)
506+{
507+ short player_index, i;
508+ bool success= true;
509+
510+ ResetPassedLua();
511+
512+ /* Make sure our code is synchronized.. */
513+ assert(MAXIMUM_PLAYER_START_NAME_LENGTH==MAXIMUM_PLAYER_NAME_LENGTH);
514+
515+ /* Initialize the global network going flag... */
516+ game_is_networked= network;
517+
518+ /* If we want to save it, this is an untitled map.. */
519+ set_saved_game_name_to_default();
520+
521+ /* Set the random seed. */
522+ set_random_seed(game_information->initial_random_seed);
523+
524+ /* Initialize the players to a known state. This must be done before goto_level */
525+ /* because it sets dynamic_world->player_count to 0, which is crucial for when */
526+ /* I try to recreate the players... */
527+ initialize_map_for_new_game(); // memsets dynamic_world to 0
528+
529+ /* Copy the game data into the dynamic_world */
530+ /* ajr-this used to be done only when we successfully loaded the map. however, goto_level
531+ * will place the initial monsters on a level, which calls new_monster, which relies
532+ * on this information being setup properly, so we do it here instead. */
533+ obj_copy(dynamic_world->game_information, *game_information);
534+
535+ /* Load the level */
536+ assert(file_is_set);
537+ success= goto_level(entry_point, true);
538+ /* If we were able to load the map... */
539+ if(success)
540+ {
541+ /* Initialize the players-> note there may be more than one player in a */
542+ /* non-network game, for playback.. */
543+ for (i=0;i<number_of_players;++i)
544+ {
545+ player_index= new_player(player_start_information[i].team,
546+ player_start_information[i].color, player_start_information[i].identifier);
547+ assert(player_index==i);
548+
549+ /* Now copy in the name of the player.. */
550+ assert(strlen(player_start_information[i].name)<=MAXIMUM_PLAYER_NAME_LENGTH);
551+ strcpy(players[i].name, player_start_information[i].name);
552+ }
553+
554+#if !defined(DISABLE_NETWORKING)
555+ if(game_is_networked)
556+ {
557+ /* Make sure we can count. */
558+ assert(number_of_players==NetGetNumberOfPlayers());
559+
560+ set_local_player_index(NetGetLocalPlayerIndex());
561+ set_current_player_index(NetGetLocalPlayerIndex());
562+ }
563+ else
564+#endif // !defined(DISABLE_NETWORKING)
565+ {
566+ set_local_player_index(0);
567+ set_current_player_index(0);
568+ }
569+
570+ /* we need to alert the function that reverts the game of the game setup so that
571+ * new game can be called if the user wants to revert later.
572+ */
573+ setup_revert_game_info(game_information, player_start_information, entry_point);
574+
575+ // Reset the player queues (done here and in load_game)
576+ reset_action_queues();
577+
578+ /* Load the collections */
579+ /* entering map might fail if NetSync() fails.. */
580+ success= entering_map(false);
581+
582+ // ZZZ: set motion sensor to sane state - needs to come after entering_map() (which calls load_collections())
583+ reset_motion_sensor(current_player_index);
584+ }
585+
586+ // LP change: adding chase-cam initialization
587+ ChaseCam_Initialize();
588+
589+ return success;
590+}
591+
592+bool get_indexed_entry_point(
593+ struct entry_point *entry_point,
594+ short *index,
595+ int32 type)
596+{
597+ short actual_index;
598+
599+ // Open map file
600+ assert(file_is_set);
601+ OpenedFile MapFile;
602+ if (!open_wad_file_for_reading(MapFileSpec,MapFile))
603+ return false;
604+
605+ // Read header
606+ wad_header header;
607+ if (!read_wad_header(MapFile, &header)) {
608+ close_wad_file(MapFile);
609+ return false;
610+ }
611+
612+ bool success = false;
613+ if (header.application_specific_directory_data_size == SIZEOF_directory_data)
614+ {
615+
616+ // New style wad
617+ void *total_directory_data= read_directory_data(MapFile, &header);
618+
619+ assert(total_directory_data);
620+ for(actual_index= *index; actual_index<header.wad_count; ++actual_index)
621+ {
622+ uint8 *p = (uint8 *)get_indexed_directory_data(&header, actual_index, total_directory_data);
623+ directory_data directory;
624+ unpack_directory_data(p, &directory, 1);
625+
626+ /* Find the flags that match.. */
627+ if(directory.entry_point_flags & type)
628+ {
629+ /* This one is valid! */
630+ entry_point->level_number= actual_index;
631+ strcpy(entry_point->level_name, directory.level_name);
632+
633+ *index= actual_index+1;
634+ success= true;
635+ break; /* Out of the for loop */
636+ }
637+ }
638+ free(total_directory_data);
639+
640+ } else {
641+
642+ // Old style wad, find the index
643+ for(actual_index= *index; !success && actual_index<header.wad_count; ++actual_index)
644+ {
645+ struct wad_data *wad;
646+
647+ /* Read the file */
648+ wad= read_indexed_wad_from_file(MapFile, &header, actual_index, true);
649+ if (wad)
650+ {
651+ /* IF this has the proper type.. */
652+ size_t length;
653+ uint8 *p = (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &length);
654+ assert(length == SIZEOF_static_data);
655+ static_data map_info;
656+ unpack_static_data(p, &map_info, 1);
657+
658+ if(map_info.entry_point_flags & type)
659+ {
660+ /* This one is valid! */
661+ entry_point->level_number= actual_index;
662+ assert(strlen(map_info.level_name)<LEVEL_NAME_LENGTH);
663+ strcpy(entry_point->level_name, map_info.level_name);
664+
665+ *index= actual_index+1;
666+ success= true;
667+ }
668+
669+ free_wad(wad);
670+ }
671+ }
672+ }
673+
674+ return success;
675+}
676+
677+// Get vector of map entry points matching given type
678+bool get_entry_points(vector<entry_point> &vec, int32 type)
679+{
680+ vec.clear();
681+
682+ // Open map file
683+ assert(file_is_set);
684+ OpenedFile MapFile;
685+ if (!open_wad_file_for_reading(MapFileSpec,MapFile))
686+ return false;
687+
688+ // Read header
689+ wad_header header;
690+ if (!read_wad_header(MapFile, &header)) {
691+ close_wad_file(MapFile);
692+ return false;
693+ }
694+
695+ bool success = false;
696+ if (header.application_specific_directory_data_size == SIZEOF_directory_data) {
697+
698+ // New style wad, read directory data
699+ void *total_directory_data = read_directory_data(MapFile, &header);
700+ assert(total_directory_data);
701+
702+ // Push matching directory entries into vector
703+ for (int i=0; i<header.wad_count; i++) {
704+ uint8 *p = (uint8 *)get_indexed_directory_data(&header, i, total_directory_data);
705+ directory_data directory;
706+ unpack_directory_data(p, &directory, 1);
707+
708+ if (directory.entry_point_flags & type) {
709+
710+ // This one is valid
711+ entry_point point;
712+ point.level_number = i;
713+ strcpy(point.level_name, directory.level_name);
714+ vec.push_back(point);
715+ success = true;
716+ }
717+ }
718+ free(total_directory_data);
719+
720+ } else {
721+
722+ // Old style wad
723+ for (int i=0; i<header.wad_count; i++) {
724+
725+ wad_data *wad = read_indexed_wad_from_file(MapFile, &header, i, true);
726+ if (!wad)
727+ continue;
728+
729+ // Read map_info data
730+ size_t length;
731+ uint8 *p = (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &length);
732+ assert(length == SIZEOF_static_data);
733+ static_data map_info;
734+ unpack_static_data(p, &map_info, 1);
735+
736+ if (map_info.entry_point_flags & type) {
737+
738+ // This one is valid
739+ entry_point point;
740+ point.level_number = i;
741+ assert(strlen(map_info.level_name) < LEVEL_NAME_LENGTH);
742+ strcpy(point.level_name, map_info.level_name);
743+ vec.push_back(point);
744+ success = true;
745+ }
746+
747+ free_wad(wad);
748+ }
749+ }
750+
751+ return success;
752+}
753+
754+extern void LoadSoloLua();
755+extern void RunLuaScript();
756+
757+/* This is called when the game level is changed somehow */
758+/* The only thing that has to be valid in the entry point is the level_index */
759+
760+/* Returns a short that is an OSErr... */
761+bool goto_level(
762+ struct entry_point *entry,
763+ bool new_game)
764+{
765+ bool success= true;
766+
767+ if(!new_game)
768+ {
769+ /* Clear the current map */
770+ leaving_map();
771+
772+ // ghs: hack to get new MML-specified sounds loaded
773+ SoundManager::instance()->UnloadAllSounds();
774+ }
775+
776+#if !defined(DISABLE_NETWORKING)
777+ /* If the game is networked, then I must call the network code to do the right */
778+ /* thing with the map.. */
779+ if(game_is_networked)
780+ {
781+ /* This function, if it is a server, calls get_map_for_net_transfer, and */
782+ /* then calls process_map_wad on it. Non-server receives the map and then */
783+ /* calls process_map_wad on it. */
784+ success= NetChangeMap(entry);
785+ }
786+ else
787+#endif // !defined(DISABLE_NETWORKING)
788+ {
789+ /* Load it and then rock.. */
790+ load_level_from_map(entry->level_number);
791+ if(error_pending()) success= false;
792+ }
793+
794+ if (success)
795+ {
796+ // LP: doing this here because level-specific MML may specify which level-specific
797+ // textures to load.
798+ // Being careful to carry over errors so that Pfhortran errors can be ignored
799+ short SavedType, SavedError = get_game_error(&SavedType);
800+ if (!game_is_networked || use_map_file(((game_info *) NetGetGameData())->parent_checksum))
801+ {
802+ RunLevelScript(entry->level_number);
803+ }
804+ else
805+ {
806+ ResetLevelScript();
807+ }
808+ RunScriptChunks();
809+ if (!game_is_networked)
810+ {
811+ Plugins::instance()->load_solo_mml();
812+ LoadSoloLua();
813+ }
814+ Music::instance()->PreloadLevelMusic();
815+ set_game_error(SavedType,SavedError);
816+
817+ if (!new_game)
818+ {
819+ recreate_players_for_new_level();
820+ }
821+
822+ /* Load the collections */
823+ dynamic_world->current_level_number= entry->level_number;
824+
825+ // ghs: this runs very early now
826+ // we want to be before place_initial_objects, and
827+ // before MarkLuaCollections
828+ RunLuaScript();
829+
830+ if (film_profile.early_object_initialization)
831+ {
832+ place_initial_objects();
833+ initialize_control_panels_for_level();
834+ }
835+
836+ if (!new_game)
837+ {
838+
839+ /* entering_map might fail if netsync fails, but we will have already displayed */
840+ /* the error.. */
841+ success= entering_map(false);
842+ }
843+
844+ if (!film_profile.early_object_initialization && success)
845+ {
846+ place_initial_objects();
847+ initialize_control_panels_for_level();
848+ }
849+
850+ }
851+
852+// if(!success) alert_user(fatalError, strERRORS, badReadMap, -1);
853+
854+ /* We be done.. */
855+ return success;
856+}
857+
858+/* -------------------- Private or map editor functions */
859+void allocate_map_for_counts(
860+ size_t polygon_count,
861+ size_t side_count,
862+ size_t endpoint_count,
863+ size_t line_count)
864+{
865+ //long cumulative_length= 0;
866+ size_t automap_line_count, automap_polygon_count, map_index_count;
867+ // long automap_line_length, automap_polygon_length, map_index_length;
868+
869+ /* Give the map indexes a whole bunch of memory (cause we can't calculate it) */
870+ // map_index_length= (polygon_count*32+1024)*sizeof(int16);
871+ map_index_count= (polygon_count*32+1024);
872+
873+ /* Automap lines. */
874+ // automap_line_length= (line_count/8+((line_count%8)?1:0))*sizeof(byte);
875+ automap_line_count= (line_count/8+((line_count%8)?1:0));
876+
877+ /* Automap Polygons */
878+ // automap_polygon_length= (polygon_count/8+((polygon_count%8)?1:0))*sizeof(byte);
879+ automap_polygon_count= (polygon_count/8+((polygon_count%8)?1:0));
880+
881+ // cumulative_length+= polygon_count*sizeof(struct polygon_data);
882+ // cumulative_length+= side_count*sizeof(struct side_data);
883+ // cumulative_length+= endpoint_count*sizeof(struct endpoint_data);
884+ // cumulative_length+= line_count*sizeof(struct line_data);
885+ // cumulative_length+= map_index_length;
886+ // cumulative_length+= automap_line_length;
887+ // cumulative_length+= automap_polygon_length;
888+
889+ /* Okay, we now have the length. Allocate our block.. */
890+ // reallocate_map_structure_memory(cumulative_length);
891+
892+ /* Tell the recalculation data how big it is.. */
893+ // set_map_index_buffer_size(map_index_length);
894+
895+ /* Setup our pointers. */
896+ // map_polygons= (struct polygon_data *) get_map_structure_chunk(polygon_count*sizeof(struct polygon_data));
897+ // map_sides= (struct side_data *) get_map_structure_chunk(side_count*sizeof(struct side_data));
898+ // map_endpoints= (struct endpoint_data *) get_map_structure_chunk(endpoint_count*sizeof(struct endpoint_data));
899+ // map_lines= (struct line_data *) get_map_structure_chunk(line_count*sizeof(struct line_data));
900+ // map_indexes= (short *) get_map_structure_chunk(map_index_length);
901+ // automap_lines= (uint8 *) get_map_structure_chunk(automap_line_length);
902+ // automap_polygons= (uint8 *) get_map_structure_chunk(automap_polygon_length);
903+
904+ // Most of the other stuff: reallocate here
905+ EndpointList.resize(endpoint_count);
906+ LineList.resize(line_count);
907+ SideList.resize(side_count);
908+ PolygonList.resize(polygon_count);
909+ AutomapLineList.resize(automap_line_count);
910+ AutomapPolygonList.resize(automap_polygon_count);
911+
912+ // Map indexes: start off with none of them (of course),
913+ // but reserve a size equal to the map index length
914+ MapIndexList.clear();
915+ MapIndexList.reserve(map_index_count);
916+ dynamic_world->map_index_count= 0;
917+
918+ // Stuff that needs the max number of polygons
919+ allocate_render_memory();
920+ allocate_flood_map_memory();
921+}
922+
923+void load_points(
924+ uint8 *points,
925+ size_t count)
926+{
927+ size_t loop;
928+
929+ // OK to modify input-data pointer since it's called by value
930+ for(loop=0; loop<count; ++loop)
931+ {
932+ world_point2d& vertex = map_endpoints[loop].vertex;
933+ StreamToValue(points,vertex.x);
934+ StreamToValue(points,vertex.y);
935+ }
936+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
937+ assert(0 <= static_cast<int16>(count));
938+ dynamic_world->endpoint_count= static_cast<int16>(count);
939+}
940+
941+void load_lines(
942+ uint8 *lines,
943+ size_t count)
944+{
945+ // assert(count>=0 && count<=MAXIMUM_LINES_PER_MAP);
946+ unpack_line_data(lines,map_lines,count);
947+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
948+ assert(0 <= static_cast<int16>(count));
949+ dynamic_world->line_count= static_cast<int16>(count);
950+}
951+
952+void load_sides(
953+ uint8 *sides,
954+ size_t count,
955+ short version)
956+{
957+ size_t loop;
958+
959+ // assert(count>=0 && count<=MAXIMUM_SIDES_PER_MAP);
960+
961+ unpack_side_data(sides,map_sides,count);
962+
963+ for(loop=0; loop<count; ++loop)
964+ {
965+ if(version==MARATHON_ONE_DATA_VERSION)
966+ {
967+ map_sides[loop].transparent_texture.texture= UNONE;
968+ map_sides[loop].ambient_delta= 0;
969+ }
970+ ++sides;
971+ }
972+
973+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
974+ assert(0 <= static_cast<int16>(count));
975+ dynamic_world->side_count= static_cast<int16>(count);
976+}
977+
978+void load_polygons(
979+ uint8 *polys,
980+ size_t count,
981+ short version)
982+{
983+ size_t loop;
984+
985+ // assert(count>=0 && count<=MAXIMUM_POLYGONS_PER_MAP);
986+
987+ unpack_polygon_data(polys,map_polygons,count);
988+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
989+ assert(0 <= static_cast<int16>(count));
990+ dynamic_world->polygon_count= static_cast<int16>(count);
991+
992+ /* Allow for backward compatibility! */
993+ switch(version)
994+ {
995+ case MARATHON_ONE_DATA_VERSION:
996+ for(loop= 0; loop<count; ++loop)
997+ {
998+ map_polygons[loop].media_index= NONE;
999+ map_polygons[loop].floor_origin.x= map_polygons[loop].floor_origin.y= 0;
1000+ map_polygons[loop].ceiling_origin.x= map_polygons[loop].ceiling_origin.y= 0;
1001+ }
1002+ break;
1003+
1004+ case MARATHON_TWO_DATA_VERSION:
1005+ // LP addition:
1006+ case MARATHON_INFINITY_DATA_VERSION:
1007+ break;
1008+
1009+ default:
1010+ assert(false);
1011+ break;
1012+ }
1013+}
1014+
1015+void load_lights(
1016+ uint8 *_lights,
1017+ size_t count,
1018+ short version)
1019+{
1020+ unsigned short loop, new_index;
1021+
1022+ LightList.resize(count);
1023+ objlist_clear(lights,count);
1024+ // vassert(count>=0 && count<=MAXIMUM_LIGHTS_PER_MAP, csprintf(temporary, "Light count: %d vers: %d",
1025+ // count, version));
1026+
1027+ old_light_data *OldLights;
1028+
1029+ switch(version)
1030+ {
1031+ case MARATHON_ONE_DATA_VERSION: {
1032+
1033+ // Unpack the old lights into a temporary array
1034+ OldLights = new old_light_data[count];
1035+ unpack_old_light_data(_lights,OldLights,count);
1036+
1037+ old_light_data *OldLtPtr = OldLights;
1038+ for(loop= 0; loop<count; ++loop, OldLtPtr++)
1039+ {
1040+ static_light_data TempLight;
1041+ convert_old_light_data_to_new(&TempLight, OldLtPtr, 1);
1042+
1043+ new_index = new_light(&TempLight);
1044+ assert(new_index==loop);
1045+ }
1046+ delete []OldLights;
1047+ break;
1048+ }
1049+
1050+ case MARATHON_TWO_DATA_VERSION:
1051+ case MARATHON_INFINITY_DATA_VERSION:
1052+ // OK to modify the data pointer since it was passed by value
1053+ for(loop= 0; loop<count; ++loop)
1054+ {
1055+ static_light_data TempLight;
1056+ _lights = unpack_static_light_data(_lights, &TempLight, 1);
1057+
1058+ new_index = new_light(&TempLight);
1059+ assert(new_index==loop);
1060+ }
1061+ break;
1062+
1063+ default:
1064+ assert(false);
1065+ break;
1066+ }
1067+}
1068+
1069+void load_annotations(
1070+ uint8 *annotations,
1071+ size_t count)
1072+{
1073+ // assert(count>=0 && count<=MAXIMUM_ANNOTATIONS_PER_MAP);
1074+ MapAnnotationList.resize(count);
1075+ unpack_map_annotation(annotations,map_annotations,count);
1076+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
1077+ assert(0 <= static_cast<int16>(count));
1078+ dynamic_world->default_annotation_count= static_cast<int16>(count);
1079+}
1080+
1081+void load_objects(uint8 *map_objects, size_t count)
1082+{
1083+ // assert(count>=0 && count<=MAXIMUM_SAVED_OBJECTS);
1084+ SavedObjectList.resize(count);
1085+ unpack_map_object(map_objects,saved_objects,count);
1086+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
1087+ assert(0 <= static_cast<int16>(count));
1088+ dynamic_world->initial_objects_count= static_cast<int16>(count);
1089+}
1090+
1091+void load_map_info(
1092+ uint8 *map_info)
1093+{
1094+ unpack_static_data(map_info,static_world,1);
1095+ static_world->ball_in_play = false;
1096+}
1097+
1098+void load_media(
1099+ uint8 *_medias,
1100+ size_t count)
1101+{
1102+ // struct media_data *media= _medias;
1103+ size_t ii;
1104+
1105+ MediaList.resize(count);
1106+ objlist_clear(medias,count);
1107+ // assert(count>=0 && count<=MAXIMUM_MEDIAS_PER_MAP);
1108+
1109+ for(ii= 0; ii<count; ++ii)
1110+ {
1111+ media_data TempMedia;
1112+ _medias = unpack_media_data(_medias,&TempMedia,1);
1113+
1114+ size_t new_index = new_media(&TempMedia);
1115+ assert(new_index==ii);
1116+ }
1117+}
1118+
1119+void load_ambient_sound_images(
1120+ uint8 *data,
1121+ size_t count)
1122+{
1123+ // assert(count>=0 &&count<=MAXIMUM_AMBIENT_SOUND_IMAGES_PER_MAP);
1124+ AmbientSoundImageList.resize(count);
1125+ unpack_ambient_sound_image_data(data,ambient_sound_images,count);
1126+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
1127+ assert(0 <= static_cast<int16>(count));
1128+ dynamic_world->ambient_sound_image_count= static_cast<int16>(count);
1129+}
1130+
1131+void load_random_sound_images(
1132+ uint8 *data,
1133+ size_t count)
1134+{
1135+ // assert(count>=0 &&count<=MAXIMUM_RANDOM_SOUND_IMAGES_PER_MAP);
1136+ RandomSoundImageList.resize(count);
1137+ unpack_random_sound_image_data(data,random_sound_images,count);
1138+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
1139+ assert(0 <= static_cast<int16>(count));
1140+ dynamic_world->random_sound_image_count= static_cast<int16>(count);
1141+}
1142+
1143+/* Recalculate all the redundant crap- must be done before platforms/doors/etc.. */
1144+void recalculate_redundant_map(
1145+ void)
1146+{
1147+ short loop;
1148+
1149+ for(loop=0;loop<dynamic_world->polygon_count;++loop) recalculate_redundant_polygon_data(loop);
1150+ for(loop=0;loop<dynamic_world->line_count;++loop) recalculate_redundant_line_data(loop);
1151+ for(loop=0;loop<dynamic_world->endpoint_count;++loop) recalculate_redundant_endpoint_data(loop);
1152+}
1153+
1154+extern bool load_game_from_file(FileSpecifier& File);
1155+
1156+bool load_game_from_file(FileSpecifier& File)
1157+{
1158+ bool success= false;
1159+
1160+ ResetPassedLua();
1161+
1162+ /* Setup for a revert.. */
1163+ revert_game_data.game_is_from_disk = true;
1164+ revert_game_data.SavedGame = File;
1165+
1166+ /* Use the save game file.. */
1167+ set_map_file(File);
1168+
1169+ /* Load the level from the map */
1170+ success= load_level_from_map(NONE); /* Save games are ALWAYS index NONE */
1171+ if (success)
1172+ {
1173+ uint32 parent_checksum;
1174+
1175+ /* Find the original scenario this saved game was a part of.. */
1176+ parent_checksum= read_wad_file_parent_checksum(File);
1177+ if(use_map_file(parent_checksum))
1178+ {
1179+ // LP: getting the level scripting off of the map file
1180+ // Being careful to carry over errors so that Pfhortran errors can be ignored
1181+ short SavedType, SavedError = get_game_error(&SavedType);
1182+ RunLevelScript(dynamic_world->current_level_number);
1183+ RunScriptChunks();
1184+ if (!game_is_networked)
1185+ {
1186+ Plugins::instance()->load_solo_mml();
1187+ LoadSoloLua();
1188+ }
1189+ set_game_error(SavedType,SavedError);
1190+ }
1191+ else
1192+ {
1193+ /* Tell the user theyÕre screwed when they try to leave this level. */
1194+ alert_user(infoError, strERRORS, cantFindMap, 0);
1195+
1196+ // LP addition: makes the game look normal
1197+ hide_cursor();
1198+
1199+ /* Set to the default map. */
1200+ set_to_default_map();
1201+
1202+ ResetLevelScript();
1203+ RunScriptChunks();
1204+ }
1205+ }
1206+
1207+ return success;
1208+}
1209+
1210+void setup_revert_game_info(
1211+ struct game_data *game_info,
1212+ struct player_start_data *start,
1213+ struct entry_point *entry)
1214+{
1215+ revert_game_data.game_is_from_disk = false;
1216+ obj_copy(revert_game_data.game_information, *game_info);
1217+ obj_copy(revert_game_data.player_start, *start);
1218+ obj_copy(revert_game_data.entry_point, *entry);
1219+}
1220+
1221+extern void reset_messages();
1222+
1223+bool revert_game(
1224+ void)
1225+{
1226+ bool successful;
1227+
1228+ assert(dynamic_world->player_count==1);
1229+
1230+ leaving_map();
1231+
1232+ if (revert_game_data.game_is_from_disk)
1233+ {
1234+ /* Reload their last saved game.. */
1235+ successful= load_game_from_file(revert_game_data.SavedGame);
1236+ if (successful)
1237+ {
1238+ Music::instance()->PreloadLevelMusic();
1239+ RunLuaScript();
1240+
1241+ // LP: added for loading the textures if one had died on another level;
1242+ // this gets around WZ's moving of this line into make_restored_game_relevant()
1243+ successful = entering_map(true /*restoring game*/);
1244+ }
1245+
1246+ /* And they don't get to continue. */
1247+ stop_recording();
1248+ }
1249+ else
1250+ {
1251+ /* This was the totally evil line discussed above. */
1252+ successful= new_game(1, false, &revert_game_data.game_information, &revert_game_data.player_start,
1253+ &revert_game_data.entry_point);
1254+
1255+ /* And rewind so that the last player is used. */
1256+ rewind_recording();
1257+ }
1258+
1259+ if(successful)
1260+ {
1261+ update_interface(NONE);
1262+ ChaseCam_Reset();
1263+ ResetFieldOfView();
1264+ reset_messages();
1265+ ReloadViewContext();
1266+ }
1267+
1268+ return successful;
1269+}
1270+
1271+bool export_level(FileSpecifier& File)
1272+{
1273+ struct wad_header header;
1274+ short err = 0;
1275+ bool success = false;
1276+ int32 offset, wad_length;
1277+ struct directory_entry entry;
1278+ struct wad_data *wad;
1279+
1280+ FileSpecifier TempFile;
1281+ DirectorySpecifier TempFileDir;
1282+ File.ToDirectory(TempFileDir);
1283+ TempFile.FromDirectory(TempFileDir);
1284+ TempFile.AddPart("savetemp.dat");
1285+
1286+ /* Fill in the default wad header (we are using File instead of TempFile to get the name right in the header) */
1287+ fill_default_wad_header(File, CURRENT_WADFILE_VERSION, MARATHON_TWO_DATA_VERSION, 1, 0, &header);
1288+
1289+ if (create_wadfile(TempFile, _typecode_scenario))
1290+ {
1291+ OpenedFile SaveFile;
1292+ if (open_wad_file_for_writing(TempFile, SaveFile))
1293+ {
1294+ /* Write out the new header */
1295+ if (write_wad_header(SaveFile, &header))
1296+ {
1297+ offset = SIZEOF_wad_header;
1298+
1299+ wad = build_export_wad(&header, &wad_length);
1300+ if (wad)
1301+ {
1302+ set_indexed_directory_offset_and_length(&header, &entry, 0, offset, wad_length, 0);
1303+
1304+ if (write_wad(SaveFile, &header, wad, offset))
1305+ {
1306+ /* Update the new header */
1307+ offset+= wad_length;
1308+ header.directory_offset= offset;
1309+ if (write_wad_header(SaveFile, &header) && write_directorys(SaveFile, &header, &entry))
1310+ {
1311+ /* We win. */
1312+ success= true;
1313+ }
1314+ }
1315+
1316+ free_wad(wad);
1317+ }
1318+ }
1319+
1320+ err = SaveFile.GetError();
1321+ calculate_and_store_wadfile_checksum(SaveFile);
1322+ close_wad_file(SaveFile);
1323+ }
1324+
1325+ if (!err)
1326+ {
1327+ if (!File.Exists())
1328+ create_wadfile(File,_typecode_savegame);
1329+
1330+ TempFile.Exchange(File);
1331+ err = TempFile.GetError();
1332+ TempFile.Delete(); // it's not an error if this fails
1333+ }
1334+ }
1335+
1336+ if (err || error_pending())
1337+ {
1338+ success = false;
1339+ }
1340+
1341+
1342+ return success;
1343+
1344+}
1345+
1346+void get_current_saved_game_name(FileSpecifier& File)
1347+{
1348+ File = revert_game_data.SavedGame;
1349+}
1350+
1351+/* The current mapfile should be set to the save game file... */
1352+bool save_game_file(FileSpecifier& File)
1353+{
1354+ struct wad_header header;
1355+ short err = 0;
1356+ bool success= false;
1357+ int32 offset, wad_length;
1358+ struct directory_entry entry;
1359+ struct wad_data *wad;
1360+
1361+ /* Save off the random seed. */
1362+ dynamic_world->random_seed= get_random_seed();
1363+
1364+ /* Setup to revert the game properly */
1365+ revert_game_data.game_is_from_disk= true;
1366+ revert_game_data.SavedGame = File;
1367+
1368+ // LP: add a file here; use temporary file for a safe save.
1369+ // Write into the temporary file first
1370+ FileSpecifier TempFile;
1371+ DirectorySpecifier TempFileDir;
1372+ File.ToDirectory(TempFileDir);
1373+ TempFile.FromDirectory(TempFileDir);
1374+#if defined(mac) || defined(SDL_RFORK_HACK)
1375+ TempFile.SetName("savetemp.dat",NONE);
1376+#else
1377+ TempFile.AddPart("savetemp.dat");
1378+#endif
1379+
1380+ /* Fill in the default wad header (we are using File instead of TempFile to get the name right in the header) */
1381+ fill_default_wad_header(File, CURRENT_WADFILE_VERSION, EDITOR_MAP_VERSION, 1, 0, &header);
1382+
1383+ /* Assume that we confirmed on save as... */
1384+ if (create_wadfile(TempFile,_typecode_savegame))
1385+ {
1386+ OpenedFile SaveFile;
1387+ if(open_wad_file_for_writing(TempFile,SaveFile))
1388+ {
1389+ /* Write out the new header */
1390+ if (write_wad_header(SaveFile, &header))
1391+ {
1392+ offset= SIZEOF_wad_header;
1393+
1394+ wad= build_save_game_wad(&header, &wad_length);
1395+ if (wad)
1396+ {
1397+ /* Set the entry data.. */
1398+ set_indexed_directory_offset_and_length(&header,
1399+ &entry, 0, offset, wad_length, 0);
1400+
1401+ /* Save it.. */
1402+ if (write_wad(SaveFile, &header, wad, offset))
1403+ {
1404+ /* Update the new header */
1405+ offset+= wad_length;
1406+ header.directory_offset= offset;
1407+ header.parent_checksum= read_wad_file_checksum(MapFileSpec);
1408+ if (write_wad_header(SaveFile, &header) && write_directorys(SaveFile, &header, &entry))
1409+ {
1410+ /* This function saves the overhead map as a thumbnail, as well */
1411+ /* as adding the string resource that tells you what it is when */
1412+ /* it is clicked on & Marathon2 isn't installed. Obviously, both */
1413+ /* of these are superfluous for a dos environment. */
1414+ add_finishing_touches_to_save_file(TempFile);
1415+
1416+ /* We win. */
1417+ success= true;
1418+ }
1419+ }
1420+
1421+ free_wad(wad);
1422+ }
1423+ }
1424+
1425+ err = SaveFile.GetError();
1426+ close_wad_file(SaveFile);
1427+ }
1428+
1429+ // LP addition: exchange with temporary file;
1430+ // create target file if necessary
1431+ if (!err)
1432+ {
1433+ if (!File.Exists())
1434+ create_wadfile(File,_typecode_savegame);
1435+
1436+ TempFile.Exchange(File);
1437+ err = TempFile.GetError();
1438+ TempFile.Delete(); // it's not an error if this fails
1439+ }
1440+ }
1441+
1442+ if(err || error_pending())
1443+ {
1444+ if(!err) err= get_game_error(NULL);
1445+ alert_user(infoError, strERRORS, fileError, err);
1446+ clear_game_error();
1447+ success= false;
1448+ }
1449+
1450+ return success;
1451+}
1452+
1453+/* -------- static functions */
1454+static void scan_and_add_platforms(
1455+ uint8 *platform_static_data,
1456+ size_t count,
1457+ short version)
1458+{
1459+ struct polygon_data *polygon;
1460+ short loop;
1461+
1462+ PlatformList.resize(count);
1463+ objlist_clear(platforms,count);
1464+
1465+ static_platforms.resize(count);
1466+ unpack_static_platform_data(platform_static_data, &static_platforms[0], count);
1467+
1468+ polygon= map_polygons;
1469+ for(loop=0; loop<dynamic_world->polygon_count; ++loop)
1470+ {
1471+ if (polygon->type==_polygon_is_platform)
1472+ {
1473+ /* Search and find the extra data. If it is not there, use the permutation for */
1474+ /* backwards compatibility! */
1475+
1476+ size_t platform_static_data_index;
1477+ for(platform_static_data_index = 0; platform_static_data_index<count; ++platform_static_data_index)
1478+ {
1479+ if (static_platforms[platform_static_data_index].polygon_index == loop)
1480+ {
1481+ new_platform(&static_platforms[platform_static_data_index], loop, version);
1482+ break;
1483+ }
1484+ }
1485+
1486+ /* DIdn't find it- use a standard platform */
1487+ if(platform_static_data_index==count)
1488+ {
1489+ polygon->permutation= 1;
1490+ new_platform(get_defaults_for_platform_type(polygon->permutation), loop, version);
1491+ }
1492+ }
1493+ ++polygon;
1494+ }
1495+}
1496+
1497+
1498+extern void unpack_lua_states(uint8*, size_t);
1499+
1500+/* Load a level from a wad-> mainly used by the net stuff. */
1501+bool process_map_wad(
1502+ struct wad_data *wad,
1503+ bool restoring_game,
1504+ short version)
1505+{
1506+ size_t data_length;
1507+ uint8 *data;
1508+ size_t count;
1509+ bool is_preprocessed_map= false;
1510+
1511+ assert(version==MARATHON_INFINITY_DATA_VERSION || version==MARATHON_TWO_DATA_VERSION || version==MARATHON_ONE_DATA_VERSION);
1512+
1513+ /* zero everything so no slots are used */
1514+ initialize_map_for_new_level();
1515+
1516+ /* Calculate the length (for reallocate map) */
1517+ allocate_map_structure_for_map(wad);
1518+
1519+ /* Extract points */
1520+ data= (uint8 *)extract_type_from_wad(wad, POINT_TAG, &data_length);
1521+ count= data_length/SIZEOF_world_point2d;
1522+ assert(data_length == count*SIZEOF_world_point2d);
1523+
1524+ if(count)
1525+ {
1526+ load_points(data, count);
1527+ } else {
1528+
1529+ data= (uint8 *)extract_type_from_wad(wad, ENDPOINT_DATA_TAG, &data_length);
1530+ count= data_length/SIZEOF_endpoint_data;
1531+ assert(data_length == count*SIZEOF_endpoint_data);
1532+ // assert(count>=0 && count<MAXIMUM_ENDPOINTS_PER_MAP);
1533+
1534+ /* Slam! */
1535+ unpack_endpoint_data(data,map_endpoints,count);
1536+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
1537+ assert(0 <= static_cast<int16>(count));
1538+ dynamic_world->endpoint_count= static_cast<int16>(count);
1539+
1540+ if (version > MARATHON_ONE_DATA_VERSION)
1541+ is_preprocessed_map= true;
1542+ }
1543+
1544+ /* Extract lines */
1545+ data= (uint8 *)extract_type_from_wad(wad, LINE_TAG, &data_length);
1546+ count = data_length/SIZEOF_line_data;
1547+ assert(data_length == count*SIZEOF_line_data);
1548+ load_lines(data, count);
1549+
1550+ /* Order is important! */
1551+ data= (uint8 *)extract_type_from_wad(wad, SIDE_TAG, &data_length);
1552+ count = data_length/SIZEOF_side_data;
1553+ assert(data_length == count*SIZEOF_side_data);
1554+ load_sides(data, count, version);
1555+
1556+ /* Extract polygons */
1557+ data= (uint8 *)extract_type_from_wad(wad, POLYGON_TAG, &data_length);
1558+ count = data_length/SIZEOF_polygon_data;
1559+ assert(data_length == count*SIZEOF_polygon_data);
1560+ load_polygons(data, count, version);
1561+
1562+ /* Extract the lightsources */
1563+ if(restoring_game)
1564+ {
1565+ // Slurp them in
1566+ data= (uint8 *)extract_type_from_wad(wad, LIGHTSOURCE_TAG, &data_length);
1567+ count = data_length/SIZEOF_light_data;
1568+ assert(data_length == count*SIZEOF_light_data);
1569+ LightList.resize(count);
1570+ unpack_light_data(data,lights,count);
1571+ }
1572+ else
1573+ {
1574+ /* When you are restoring a game, the actual light structure is set. */
1575+ data= (uint8 *)extract_type_from_wad(wad, LIGHTSOURCE_TAG, &data_length);
1576+ if(version==MARATHON_ONE_DATA_VERSION)
1577+ {
1578+ /* We have an old style light */
1579+ count= data_length/SIZEOF_old_light_data;
1580+ assert(count*SIZEOF_old_light_data==data_length);
1581+ load_lights(data, count, version);
1582+ } else {
1583+ count= data_length/SIZEOF_static_light_data;
1584+ assert(count*SIZEOF_static_light_data==data_length);
1585+ load_lights(data, count, version);
1586+ }
1587+
1588+ // HACK!!!!!!!!!!!!!!! vulcan doesnÕt NONE .first_object field after adding scenery
1589+ {
1590+ for (count= 0; count<static_cast<size_t>(dynamic_world->polygon_count); ++count)
1591+ {
1592+ map_polygons[count].first_object= NONE;
1593+ }
1594+ }
1595+ }
1596+
1597+ /* Extract the annotations */
1598+ data= (uint8 *)extract_type_from_wad(wad, ANNOTATION_TAG, &data_length);
1599+ count = data_length/SIZEOF_map_annotation;
1600+ assert(data_length == count*SIZEOF_map_annotation);
1601+ load_annotations(data, count);
1602+
1603+ /* Extract the objects */
1604+ data= (uint8 *)extract_type_from_wad(wad, OBJECT_TAG, &data_length);
1605+ count = data_length/SIZEOF_map_object;
1606+ assert(data_length == count*static_cast<size_t>(SIZEOF_map_object));
1607+ load_objects(data, count);
1608+
1609+ /* Extract the map info data */
1610+ data= (uint8 *)extract_type_from_wad(wad, MAP_INFO_TAG, &data_length);
1611+ // LP change: made this more Pfhorte-friendly
1612+ assert(static_cast<size_t>(SIZEOF_static_data)==data_length
1613+ || static_cast<size_t>(SIZEOF_static_data-2)==data_length);
1614+ load_map_info(data);
1615+
1616+ /* Extract the game difficulty info.. */
1617+ data= (uint8 *)extract_type_from_wad(wad, ITEM_PLACEMENT_STRUCTURE_TAG, &data_length);
1618+ // In case of an absent placement chunk...
1619+ if (data_length == 0)
1620+ {
1621+ data = new uint8[2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition];
1622+ memset(data,0,2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition);
1623+ }
1624+ else
1625+ assert(data_length == 2*MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition);
1626+ load_placement_data(data + MAXIMUM_OBJECT_TYPES*SIZEOF_object_frequency_definition, data);
1627+ if (data_length == 0)
1628+ delete []data;
1629+
1630+ /* Extract the terminal data. */
1631+ data= (uint8 *)extract_type_from_wad(wad, TERMINAL_DATA_TAG, &data_length);
1632+ load_terminal_data(data, data_length);
1633+
1634+ /* Extract the media definitions */
1635+ if(restoring_game)
1636+ {
1637+ // Slurp it in
1638+ data= (uint8 *)extract_type_from_wad(wad, MEDIA_TAG, &data_length);
1639+ count= data_length/SIZEOF_media_data;
1640+ assert(count*SIZEOF_media_data==data_length);
1641+ MediaList.resize(count);
1642+ unpack_media_data(data,medias,count);
1643+ }
1644+ else
1645+ {
1646+ data= (uint8 *)extract_type_from_wad(wad, MEDIA_TAG, &data_length);
1647+ count= data_length/SIZEOF_media_data;
1648+ assert(count*SIZEOF_media_data==data_length);
1649+ load_media(data, count);
1650+ }
1651+
1652+ /* Extract the ambient sound images */
1653+ data= (uint8 *)extract_type_from_wad(wad, AMBIENT_SOUND_TAG, &data_length);
1654+ count = data_length/SIZEOF_ambient_sound_image_data;
1655+ assert(data_length == count*SIZEOF_ambient_sound_image_data);
1656+ load_ambient_sound_images(data, count);
1657+ load_ambient_sound_images(data, data_length/SIZEOF_ambient_sound_image_data);
1658+
1659+ /* Extract the random sound images */
1660+ data= (uint8 *)extract_type_from_wad(wad, RANDOM_SOUND_TAG, &data_length);
1661+ count = data_length/SIZEOF_random_sound_image_data;
1662+ assert(data_length == count*SIZEOF_random_sound_image_data);
1663+ load_random_sound_images(data, count);
1664+
1665+ /* Extract embedded shapes */
1666+ data= (uint8 *)extract_type_from_wad(wad, SHAPE_PATCH_TAG, &data_length);
1667+ set_shapes_patch_data(data, data_length);
1668+
1669+ /* Extract MMLS */
1670+ data= (uint8 *)extract_type_from_wad(wad, MMLS_TAG, &data_length);
1671+ SetMMLS(data, data_length);
1672+
1673+ /* Extract LUAS */
1674+ data= (uint8 *)extract_type_from_wad(wad, LUAS_TAG, &data_length);
1675+ SetLUAS(data, data_length);
1676+
1677+ /* Extract saved Lua state */
1678+ data =(uint8 *)extract_type_from_wad(wad, LUA_STATE_TAG, &data_length);
1679+ unpack_lua_states(data, data_length);
1680+
1681+ // LP addition: load the physics-model chunks (all fixed-size)
1682+ bool PhysicsModelLoaded = false;
1683+
1684+ data= (uint8 *)extract_type_from_wad(wad, MONSTER_PHYSICS_TAG, &data_length);
1685+ count = data_length/SIZEOF_monster_definition;
1686+ assert(count*SIZEOF_monster_definition == data_length);
1687+ assert(count <= NUMBER_OF_MONSTER_TYPES);
1688+ if (data_length > 0)
1689+ {
1690+ if (!PhysicsModelLoaded) init_physics_wad_data();
1691+ PhysicsModelLoaded = true;
1692+ unpack_monster_definition(data,count);
1693+ }
1694+
1695+ data= (uint8 *)extract_type_from_wad(wad, EFFECTS_PHYSICS_TAG, &data_length);
1696+ count = data_length/SIZEOF_effect_definition;
1697+ assert(count*SIZEOF_effect_definition == data_length);
1698+ assert(count <= NUMBER_OF_EFFECT_TYPES);
1699+ if (data_length > 0)
1700+ {
1701+ if (!PhysicsModelLoaded) init_physics_wad_data();
1702+ PhysicsModelLoaded = true;
1703+ unpack_effect_definition(data,count);
1704+ }
1705+
1706+ data= (uint8 *)extract_type_from_wad(wad, PROJECTILE_PHYSICS_TAG, &data_length);
1707+ count = data_length/SIZEOF_projectile_definition;
1708+ assert(count*SIZEOF_projectile_definition == data_length);
1709+ assert(count <= NUMBER_OF_PROJECTILE_TYPES);
1710+ if (data_length > 0)
1711+ {
1712+ if (!PhysicsModelLoaded) init_physics_wad_data();
1713+ PhysicsModelLoaded = true;
1714+ unpack_projectile_definition(data,count);
1715+ }
1716+
1717+ data= (uint8 *)extract_type_from_wad(wad, PHYSICS_PHYSICS_TAG, &data_length);
1718+ count = data_length/SIZEOF_physics_constants;
1719+ assert(count*SIZEOF_physics_constants == data_length);
1720+ assert(count <= get_number_of_physics_models());
1721+ if (data_length > 0)
1722+ {
1723+ if (!PhysicsModelLoaded) init_physics_wad_data();
1724+ PhysicsModelLoaded = true;
1725+ unpack_physics_constants(data,count);
1726+ }
1727+
1728+ data= (uint8 *)extract_type_from_wad(wad, WEAPONS_PHYSICS_TAG, &data_length);
1729+ count = data_length/SIZEOF_weapon_definition;
1730+ assert(count*SIZEOF_weapon_definition == data_length);
1731+ assert(count <= get_number_of_weapon_types());
1732+ if (data_length > 0)
1733+ {
1734+ if (!PhysicsModelLoaded) init_physics_wad_data();
1735+ PhysicsModelLoaded = true;
1736+ unpack_weapon_definition(data,count);
1737+ }
1738+
1739+ // LP addition: Reload the physics model if it had been loaded in the previous level,
1740+ // but not in the current level. This avoids the persistent-physics bug.
1741+ // ghs: always reload the physics model if there isn't one merged
1742+ if (PhysicsModelLoadedEarlier && !PhysicsModelLoaded && !game_is_networked)
1743+ import_definition_structures();
1744+ PhysicsModelLoadedEarlier = PhysicsModelLoaded;
1745+
1746+ /* If we are restoring the game, then we need to add the dynamic data */
1747+ if(restoring_game)
1748+ {
1749+ // Slurp it all in...
1750+ data= (uint8 *)extract_type_from_wad(wad, MAP_INDEXES_TAG, &data_length);
1751+ count= data_length/sizeof(short);
1752+ assert(count*int32(sizeof(short))==data_length);
1753+ MapIndexList.resize(count);
1754+ StreamToList(data,map_indexes,count);
1755+
1756+ data= (uint8 *)extract_type_from_wad(wad, PLAYER_STRUCTURE_TAG, &data_length);
1757+ count= data_length/SIZEOF_player_data;
1758+ assert(count*SIZEOF_player_data==data_length);
1759+ unpack_player_data(data,players,count);
1760+ team_damage_from_player_data();
1761+
1762+ data= (uint8 *)extract_type_from_wad(wad, DYNAMIC_STRUCTURE_TAG, &data_length);
1763+ assert(data_length == SIZEOF_dynamic_data);
1764+ unpack_dynamic_data(data,dynamic_world,1);
1765+
1766+ data= (uint8 *)extract_type_from_wad(wad, OBJECT_STRUCTURE_TAG, &data_length);
1767+ count= data_length/SIZEOF_object_data;
1768+ assert(count*SIZEOF_object_data==data_length);
1769+ vassert(count <= MAXIMUM_OBJECTS_PER_MAP,
1770+ csprintf(temporary,"Number of map objects %lu > limit %u",count,MAXIMUM_OBJECTS_PER_MAP));
1771+ unpack_object_data(data,objects,count);
1772+
1773+ // Unpacking is E-Z here...
1774+ data= (uint8 *)extract_type_from_wad(wad, AUTOMAP_LINES, &data_length);
1775+ memcpy(automap_lines,data,data_length);
1776+ data= (uint8 *)extract_type_from_wad(wad, AUTOMAP_POLYGONS, &data_length);
1777+ memcpy(automap_polygons,data,data_length);
1778+
1779+ data= (uint8 *)extract_type_from_wad(wad, MONSTERS_STRUCTURE_TAG, &data_length);
1780+ count= data_length/SIZEOF_monster_data;
1781+ assert(count*SIZEOF_monster_data==data_length);
1782+ vassert(count <= MAXIMUM_MONSTERS_PER_MAP,
1783+ csprintf(temporary,"Number of monsters %lu > limit %u",count,MAXIMUM_MONSTERS_PER_MAP));
1784+ unpack_monster_data(data,monsters,count);
1785+
1786+ data= (uint8 *)extract_type_from_wad(wad, EFFECTS_STRUCTURE_TAG, &data_length);
1787+ count= data_length/SIZEOF_effect_data;
1788+ assert(count*SIZEOF_effect_data==data_length);
1789+ vassert(count <= MAXIMUM_EFFECTS_PER_MAP,
1790+ csprintf(temporary,"Number of effects %lu > limit %u",count,MAXIMUM_EFFECTS_PER_MAP));
1791+ unpack_effect_data(data,effects,count);
1792+
1793+ data= (uint8 *)extract_type_from_wad(wad, PROJECTILES_STRUCTURE_TAG, &data_length);
1794+ count= data_length/SIZEOF_projectile_data;
1795+ assert(count*SIZEOF_projectile_data==data_length);
1796+ vassert(count <= MAXIMUM_PROJECTILES_PER_MAP,
1797+ csprintf(temporary,"Number of projectiles %lu > limit %u",count,MAXIMUM_PROJECTILES_PER_MAP));
1798+ unpack_projectile_data(data,projectiles,count);
1799+
1800+ data= (uint8 *)extract_type_from_wad(wad, PLATFORM_STRUCTURE_TAG, &data_length);
1801+ count= data_length/SIZEOF_platform_data;
1802+ assert(count*SIZEOF_platform_data==data_length);
1803+ PlatformList.resize(count);
1804+ unpack_platform_data(data,platforms,count);
1805+
1806+ data= (uint8 *)extract_type_from_wad(wad, WEAPON_STATE_TAG, &data_length);
1807+ count= data_length/SIZEOF_player_weapon_data;
1808+ assert(count*SIZEOF_player_weapon_data==data_length);
1809+ unpack_player_weapon_data(data,count);
1810+
1811+ data= (uint8 *)extract_type_from_wad(wad, TERMINAL_STATE_TAG, &data_length);
1812+ count= data_length/SIZEOF_player_terminal_data;
1813+ assert(count*SIZEOF_player_terminal_data==data_length);
1814+ unpack_player_terminal_data(data,count);
1815+
1816+ complete_restoring_level(wad);
1817+ } else {
1818+ uint8 *map_index_data;
1819+ size_t map_index_count;
1820+ uint8 *platform_structures;
1821+ size_t platform_structure_count;
1822+
1823+ if(version==MARATHON_ONE_DATA_VERSION)
1824+ {
1825+ /* Force precalculation */
1826+ map_index_data= NULL;
1827+ map_index_count= 0;
1828+ } else {
1829+ map_index_data= (uint8 *)extract_type_from_wad(wad, MAP_INDEXES_TAG, &data_length);
1830+ map_index_count= data_length/sizeof(short);
1831+ assert(map_index_count*sizeof(short)==data_length);
1832+ }
1833+
1834+ assert(is_preprocessed_map&&map_index_count || !is_preprocessed_map&&!map_index_count);
1835+
1836+ data= (uint8 *)extract_type_from_wad(wad, PLATFORM_STATIC_DATA_TAG, &data_length);
1837+ count= data_length/SIZEOF_static_platform_data;
1838+ assert(count*SIZEOF_static_platform_data==data_length);
1839+
1840+ platform_structures= (uint8 *)extract_type_from_wad(wad, PLATFORM_STRUCTURE_TAG, &data_length);
1841+ platform_structure_count= data_length/SIZEOF_platform_data;
1842+ assert(platform_structure_count*SIZEOF_platform_data==data_length);
1843+
1844+ complete_loading_level((short *) map_index_data, map_index_count,
1845+ data, count, platform_structures,
1846+ platform_structure_count, version);
1847+
1848+ }
1849+
1850+ /* ... and bail */
1851+ return true;
1852+}
1853+
1854+static void allocate_map_structure_for_map(
1855+ struct wad_data *wad)
1856+{
1857+ size_t data_length;
1858+ size_t line_count, polygon_count, side_count, endpoint_count;
1859+
1860+ /* Extract points */
1861+ extract_type_from_wad(wad, POINT_TAG, &data_length);
1862+ endpoint_count= data_length/SIZEOF_world_point2d;
1863+ if(endpoint_count*SIZEOF_world_point2d!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x7074); // 'pt'
1864+
1865+ if(!endpoint_count)
1866+ {
1867+ extract_type_from_wad(wad, ENDPOINT_DATA_TAG, &data_length);
1868+ endpoint_count= data_length/SIZEOF_endpoint_data;
1869+ if(endpoint_count*SIZEOF_endpoint_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x6570); // 'ep'
1870+ }
1871+
1872+ /* Extract lines */
1873+ extract_type_from_wad(wad, LINE_TAG, &data_length);
1874+ line_count= data_length/SIZEOF_line_data;
1875+ if(line_count*SIZEOF_line_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x6c69); // 'li'
1876+
1877+ /* Sides.. */
1878+ extract_type_from_wad(wad, SIDE_TAG, &data_length);
1879+ side_count= data_length/SIZEOF_side_data;
1880+ if(side_count*SIZEOF_side_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x7369); // 'si'
1881+
1882+ /* Extract polygons */
1883+ extract_type_from_wad(wad, POLYGON_TAG, &data_length);
1884+ polygon_count= data_length/SIZEOF_polygon_data;
1885+ if(polygon_count*SIZEOF_polygon_data!=data_length) alert_user(fatalError, strERRORS, corruptedMap, 0x7369); // 'si'
1886+
1887+ allocate_map_for_counts(polygon_count, side_count, endpoint_count, line_count);
1888+}
1889+
1890+/* Note that we assume the redundant data has already been recalculated... */
1891+static void load_redundant_map_data(
1892+ short *redundant_data,
1893+ size_t count)
1894+{
1895+ if (redundant_data)
1896+ {
1897+ // assert(redundant_data && map_indexes);
1898+ uint8 *Stream = (uint8 *)redundant_data;
1899+ MapIndexList.resize(count);
1900+ StreamToList(Stream,map_indexes,count);
1901+ assert(count == static_cast<size_t>(static_cast<int16>(count)));
1902+ assert(0 <= static_cast<int16>(count));
1903+ dynamic_world->map_index_count= static_cast<int16>(count);
1904+ }
1905+ else
1906+ {
1907+ recalculate_redundant_map();
1908+ precalculate_map_indexes();
1909+ }
1910+}
1911+
1912+void load_terminal_data(
1913+ uint8 *data,
1914+ size_t length)
1915+{
1916+ /* I would really like it if I could get these into computer_interface.c statically */
1917+ unpack_map_terminal_data(data,length);
1918+}
1919+
1920+static void scan_and_add_scenery(
1921+ void)
1922+{
1923+ short ii;
1924+ struct map_object *saved_object;
1925+
1926+ saved_object= saved_objects;
1927+ for(ii=0; ii<dynamic_world->initial_objects_count; ++ii)
1928+ {
1929+ if (saved_object->type==_saved_object)
1930+ {
1931+ struct object_location location;
1932+
1933+ location.p= saved_object->location;
1934+ location.flags= saved_object->flags;
1935+ location.yaw= saved_object->facing;
1936+ location.polygon_index= saved_object->polygon_index;
1937+ new_scenery(&location, saved_object->index);
1938+ }
1939+
1940+ ++saved_object;
1941+ }
1942+}
1943+
1944+struct save_game_data
1945+{
1946+ uint32 tag;
1947+ short unit_size;
1948+ bool loaded_by_level;
1949+};
1950+
1951+#define NUMBER_OF_EXPORT_ARRAYS (sizeof(export_data)/sizeof(struct save_game_data))
1952+save_game_data export_data[]=
1953+{
1954+ { POINT_TAG, SIZEOF_world_point2d, true },
1955+ { LINE_TAG, SIZEOF_line_data, true },
1956+ { POLYGON_TAG, SIZEOF_polygon_data, true },
1957+ { SIDE_TAG, SIZEOF_side_data, true },
1958+ { LIGHTSOURCE_TAG, SIZEOF_static_light_data, true, },
1959+ { ANNOTATION_TAG, SIZEOF_map_annotation, true },
1960+ { OBJECT_TAG, SIZEOF_map_object, true },
1961+ { MAP_INFO_TAG, SIZEOF_static_data, true },
1962+ { ITEM_PLACEMENT_STRUCTURE_TAG, SIZEOF_object_frequency_definition, true },
1963+ { PLATFORM_STATIC_DATA_TAG, SIZEOF_static_platform_data, true },
1964+ { TERMINAL_DATA_TAG, sizeof(byte), true },
1965+ { MEDIA_TAG, SIZEOF_media_data, true }, // false },
1966+ { AMBIENT_SOUND_TAG, SIZEOF_ambient_sound_image_data, true },
1967+ { RANDOM_SOUND_TAG, SIZEOF_random_sound_image_data, true },
1968+ { SHAPE_PATCH_TAG, sizeof(byte), true },
1969+// { PLATFORM_STRUCTURE_TAG, SIZEOF_platform_data, true },
1970+};
1971+
1972+#define NUMBER_OF_SAVE_ARRAYS (sizeof(save_data)/sizeof(struct save_game_data))
1973+struct save_game_data save_data[]=
1974+{
1975+ { ENDPOINT_DATA_TAG, SIZEOF_endpoint_data, true },
1976+ { LINE_TAG, SIZEOF_line_data, true },
1977+ { SIDE_TAG, SIZEOF_side_data, true },
1978+ { POLYGON_TAG, SIZEOF_polygon_data, true },
1979+ { LIGHTSOURCE_TAG, SIZEOF_light_data, true }, // false },
1980+ { ANNOTATION_TAG, SIZEOF_map_annotation, true },
1981+ { OBJECT_TAG, SIZEOF_map_object, true },
1982+ { MAP_INFO_TAG, SIZEOF_static_data, true },
1983+ { ITEM_PLACEMENT_STRUCTURE_TAG, SIZEOF_object_frequency_definition, true },
1984+ { MEDIA_TAG, SIZEOF_media_data, true }, // false },
1985+ { AMBIENT_SOUND_TAG, SIZEOF_ambient_sound_image_data, true },
1986+ { RANDOM_SOUND_TAG, SIZEOF_random_sound_image_data, true },
1987+ { TERMINAL_DATA_TAG, sizeof(byte), true },
1988+
1989+ // LP addition: handling of physics models
1990+ { MONSTER_PHYSICS_TAG, SIZEOF_monster_definition, true},
1991+ { EFFECTS_PHYSICS_TAG, SIZEOF_effect_definition, true},
1992+ { PROJECTILE_PHYSICS_TAG, SIZEOF_projectile_definition, true},
1993+ { PHYSICS_PHYSICS_TAG, SIZEOF_physics_constants, true},
1994+ { WEAPONS_PHYSICS_TAG, SIZEOF_weapon_definition, true},
1995+
1996+ // GHS: save the new embedded shapes
1997+ { SHAPE_PATCH_TAG, sizeof(byte), true },
1998+
1999+ { MMLS_TAG, sizeof(byte), true },
2000+ { LUAS_TAG, sizeof(byte), true },
2001+
2002+ { MAP_INDEXES_TAG, sizeof(short), true }, // false },
2003+ { PLAYER_STRUCTURE_TAG, SIZEOF_player_data, true }, // false },
2004+ { DYNAMIC_STRUCTURE_TAG, SIZEOF_dynamic_data, true }, // false },
2005+ { OBJECT_STRUCTURE_TAG, SIZEOF_object_data, true }, // false },
2006+ { AUTOMAP_LINES, sizeof(byte), true }, // false },
2007+ { AUTOMAP_POLYGONS, sizeof(byte), true }, // false },
2008+ { MONSTERS_STRUCTURE_TAG, SIZEOF_monster_data, true }, // false },
2009+ { EFFECTS_STRUCTURE_TAG, SIZEOF_effect_data, true }, // false },
2010+ { PROJECTILES_STRUCTURE_TAG, SIZEOF_projectile_data, true }, // false },
2011+ { PLATFORM_STRUCTURE_TAG, SIZEOF_platform_data, true }, // false },
2012+ { WEAPON_STATE_TAG, SIZEOF_player_weapon_data, true }, // false },
2013+ { TERMINAL_STATE_TAG, SIZEOF_player_terminal_data, true }, // false }
2014+
2015+ { LUA_STATE_TAG, sizeof(byte), true },
2016+};
2017+
2018+static uint8 *export_tag_to_global_array_and_size(
2019+ uint32 tag,
2020+ size_t *size
2021+ )
2022+{
2023+ uint8 *array = NULL;
2024+ size_t unit_size = 0;
2025+ size_t count = 0;
2026+ unsigned index;
2027+
2028+ for (index=0; index<NUMBER_OF_EXPORT_ARRAYS; ++index)
2029+ {
2030+ if(export_data[index].tag==tag)
2031+ {
2032+ unit_size= export_data[index].unit_size;
2033+ break;
2034+ }
2035+ }
2036+ assert(index != NUMBER_OF_EXPORT_ARRAYS);
2037+
2038+ switch (tag)
2039+ {
2040+ case POINT_TAG:
2041+ count = dynamic_world->endpoint_count;
2042+ break;
2043+
2044+ case LIGHTSOURCE_TAG:
2045+ count = dynamic_world->light_count;
2046+ break;
2047+
2048+ case PLATFORM_STATIC_DATA_TAG:
2049+ count = dynamic_world->platform_count;
2050+ break;
2051+
2052+ case POLYGON_TAG:
2053+ count = dynamic_world->polygon_count;
2054+ break;
2055+
2056+ default:
2057+ assert(false);
2058+ break;
2059+ }
2060+
2061+ // Allocate a temporary packed-data chunk;
2062+ // indicate if there is nothing to be written
2063+ *size= count*unit_size;
2064+ if (*size > 0)
2065+ array = new byte[*size];
2066+ else
2067+ return NULL;
2068+
2069+ objlist_clear(array, *size);
2070+
2071+ // An OK-to-alter version of that array pointer
2072+ uint8 *temp_array = array;
2073+
2074+ switch (tag)
2075+ {
2076+ case POINT_TAG:
2077+ for (size_t loop = 0; loop < count; ++loop)
2078+ {
2079+ world_point2d& vertex = map_endpoints[loop].vertex;
2080+ ValueToStream(temp_array, vertex.x);
2081+ ValueToStream(temp_array, vertex.y);
2082+ }
2083+ break;
2084+
2085+ case LIGHTSOURCE_TAG:
2086+ for (size_t loop = 0; loop < count; ++loop)
2087+ {
2088+ temp_array = pack_static_light_data(temp_array, &lights[loop].static_data, 1);
2089+ }
2090+ break;
2091+
2092+ case PLATFORM_STATIC_DATA_TAG:
2093+ if (static_platforms.size() == count)
2094+ {
2095+ // export them directly as they came in
2096+ pack_static_platform_data(array, &static_platforms[0], count);
2097+ }
2098+ else
2099+ {
2100+ for (size_t loop = 0; loop < count; ++loop)
2101+ {
2102+ // ghs: this belongs somewhere else
2103+ static_platform_data platform;
2104+ obj_clear(platform);
2105+ platform.type = platforms[loop].type;
2106+ platform.speed = platforms[loop].speed;
2107+ platform.delay = platforms[loop].delay;
2108+ if (PLATFORM_GOES_BOTH_WAYS(&platforms[loop]))
2109+ {
2110+ platform.maximum_height = platforms[loop].maximum_ceiling_height;
2111+ platform.minimum_height = platforms[loop].minimum_floor_height;
2112+ }
2113+ else if (PLATFORM_COMES_FROM_FLOOR(&platforms[loop]))
2114+ {
2115+ platform.maximum_height = platforms[loop].maximum_floor_height;
2116+ platform.minimum_height = platforms[loop].minimum_floor_height;
2117+ }
2118+ else
2119+ {
2120+ platform.maximum_height = platforms[loop].maximum_ceiling_height;
2121+ platform.minimum_height = platforms[loop].minimum_floor_height;
2122+ }
2123+ platform.static_flags = platforms[loop].static_flags;
2124+ platform.polygon_index = platforms[loop].polygon_index;
2125+ platform.tag = platforms[loop].tag;
2126+
2127+ temp_array = pack_static_platform_data(temp_array, &platform, 1);
2128+ }
2129+ }
2130+ break;
2131+
2132+ case POLYGON_TAG:
2133+ for (size_t loop = 0; loop < count; ++loop)
2134+ {
2135+ // Forge visual mode crashes if we don't do this
2136+ polygon_data polygon = PolygonList[loop];
2137+ polygon.first_object = NONE;
2138+ temp_array = pack_polygon_data(temp_array, &polygon, 1);
2139+ }
2140+ break;
2141+
2142+ default:
2143+ assert(false);
2144+ break;
2145+ }
2146+
2147+ return array;
2148+}
2149+
2150+extern size_t save_lua_states();
2151+extern void pack_lua_states(uint8*, size_t);
2152+
2153+
2154+/* the sizes are the sizes to save in the file, be aware! */
2155+static uint8 *tag_to_global_array_and_size(
2156+ uint32 tag,
2157+ size_t *size
2158+ )
2159+{
2160+ uint8 *array= NULL;
2161+ size_t unit_size = 0;
2162+ size_t count = 0;
2163+ unsigned index;
2164+
2165+ for (index=0; index<NUMBER_OF_SAVE_ARRAYS; ++index)
2166+ {
2167+ if(save_data[index].tag==tag)
2168+ {
2169+ unit_size= save_data[index].unit_size;
2170+ break;
2171+ }
2172+ }
2173+ assert(index != NUMBER_OF_SAVE_ARRAYS);
2174+
2175+ // LP: had fixed off-by-one error in medias saving,
2176+ // and had added physics-model saving
2177+
2178+ switch (tag)
2179+ {
2180+ case ENDPOINT_DATA_TAG:
2181+ count= dynamic_world->endpoint_count;
2182+ break;
2183+ case LINE_TAG:
2184+ count= dynamic_world->line_count;
2185+ break;
2186+ case SIDE_TAG:
2187+ count= dynamic_world->side_count;
2188+ break;
2189+ case POLYGON_TAG:
2190+ count= dynamic_world->polygon_count;
2191+ break;
2192+ case LIGHTSOURCE_TAG:
2193+ count= dynamic_world->light_count;
2194+ break;
2195+ case ANNOTATION_TAG:
2196+ count= dynamic_world->default_annotation_count;
2197+ break;
2198+ case OBJECT_TAG:
2199+ count= dynamic_world->initial_objects_count;
2200+ break;
2201+ case MAP_INFO_TAG:
2202+ count= 1;
2203+ break;
2204+ case PLAYER_STRUCTURE_TAG:
2205+ count= dynamic_world->player_count;
2206+ break;
2207+ case DYNAMIC_STRUCTURE_TAG:
2208+ count= 1;
2209+ break;
2210+ case OBJECT_STRUCTURE_TAG:
2211+ count= dynamic_world->object_count;
2212+ break;
2213+ case MAP_INDEXES_TAG:
2214+ count= static_cast<unsigned short>(dynamic_world->map_index_count);
2215+ break;
2216+ case AUTOMAP_LINES:
2217+ count= (dynamic_world->line_count/8+((dynamic_world->line_count%8)?1:0));
2218+ break;
2219+ case AUTOMAP_POLYGONS:
2220+ count= (dynamic_world->polygon_count/8+((dynamic_world->polygon_count%8)?1:0));
2221+ break;
2222+ case MONSTERS_STRUCTURE_TAG:
2223+ count= dynamic_world->monster_count;
2224+ break;
2225+ case EFFECTS_STRUCTURE_TAG:
2226+ count= dynamic_world->effect_count;
2227+ break;
2228+ case PROJECTILES_STRUCTURE_TAG:
2229+ count= dynamic_world->projectile_count;
2230+ break;
2231+ case MEDIA_TAG:
2232+ count= count_number_of_medias_used();
2233+ break;
2234+ case ITEM_PLACEMENT_STRUCTURE_TAG:
2235+ count= 2*MAXIMUM_OBJECT_TYPES;
2236+ break;
2237+ case PLATFORM_STRUCTURE_TAG:
2238+ count= dynamic_world->platform_count;
2239+ break;
2240+ case AMBIENT_SOUND_TAG:
2241+ count= dynamic_world->ambient_sound_image_count;
2242+ break;
2243+ case RANDOM_SOUND_TAG:
2244+ count= dynamic_world->random_sound_image_count;
2245+ break;
2246+ case TERMINAL_DATA_TAG:
2247+ count= calculate_packed_terminal_data_length();
2248+ break;
2249+ case WEAPON_STATE_TAG:
2250+ count= dynamic_world->player_count;
2251+ break;
2252+ case TERMINAL_STATE_TAG:
2253+ count= dynamic_world->player_count;
2254+ break;
2255+ case MONSTER_PHYSICS_TAG:
2256+ count= NUMBER_OF_MONSTER_TYPES;
2257+ break;
2258+ case EFFECTS_PHYSICS_TAG:
2259+ count= NUMBER_OF_EFFECT_TYPES;
2260+ break;
2261+ case PROJECTILE_PHYSICS_TAG:
2262+ count= NUMBER_OF_PROJECTILE_TYPES;
2263+ break;
2264+ case PHYSICS_PHYSICS_TAG:
2265+ count= get_number_of_physics_models();
2266+ break;
2267+ case WEAPONS_PHYSICS_TAG:
2268+ count= get_number_of_weapon_types();
2269+ break;
2270+ case SHAPE_PATCH_TAG:
2271+ get_shapes_patch_data(count);
2272+ break;
2273+ case MMLS_TAG:
2274+ GetMMLS(count);
2275+ break;
2276+ case LUAS_TAG:
2277+ GetLUAS(count);
2278+ break;
2279+ case LUA_STATE_TAG:
2280+ count= save_lua_states();
2281+ break;
2282+ default:
2283+ assert(false);
2284+ break;
2285+ }
2286+
2287+ // Allocate a temporary packed-data chunk;
2288+ // indicate if there is nothing to be written
2289+ *size= count*unit_size;
2290+ if (*size > 0)
2291+ array = new byte[*size];
2292+ else
2293+ return NULL;
2294+
2295+ objlist_clear(array, *size);
2296+
2297+ // An OK-to-alter version of that array pointer
2298+ uint8 *temp_array = array;
2299+
2300+ switch (tag)
2301+ {
2302+ case ENDPOINT_DATA_TAG:
2303+ pack_endpoint_data(array,map_endpoints,count);
2304+ break;
2305+ case LINE_TAG:
2306+ pack_line_data(array,map_lines,count);
2307+ break;
2308+ case SIDE_TAG:
2309+ pack_side_data(array,map_sides,count);
2310+ break;
2311+ case POLYGON_TAG:
2312+ pack_polygon_data(array,map_polygons,count);
2313+ break;
2314+ case LIGHTSOURCE_TAG:
2315+ pack_light_data(array,lights,count);
2316+ break;
2317+ case ANNOTATION_TAG:
2318+ pack_map_annotation(array,map_annotations,count);
2319+ break;
2320+ case OBJECT_TAG:
2321+ pack_map_object(array,saved_objects,count);
2322+ break;
2323+ case MAP_INFO_TAG:
2324+ pack_static_data(array,static_world,count);
2325+ break;
2326+ case PLAYER_STRUCTURE_TAG:
2327+ pack_player_data(array,players,count);
2328+ break;
2329+ case DYNAMIC_STRUCTURE_TAG:
2330+ pack_dynamic_data(array,dynamic_world,count);
2331+ break;
2332+ case OBJECT_STRUCTURE_TAG:
2333+ pack_object_data(array,objects,count);
2334+ break;
2335+ case MAP_INDEXES_TAG:
2336+ ListToStream(temp_array,map_indexes,count); // E-Z packing here...
2337+ break;
2338+ case AUTOMAP_LINES:
2339+ memcpy(array,automap_lines,*size);
2340+ break;
2341+ case AUTOMAP_POLYGONS:
2342+ memcpy(array,automap_polygons,*size);
2343+ break;
2344+ case MONSTERS_STRUCTURE_TAG:
2345+ pack_monster_data(array,monsters,count);
2346+ break;
2347+ case EFFECTS_STRUCTURE_TAG:
2348+ pack_effect_data(array,effects,count);
2349+ break;
2350+ case PROJECTILES_STRUCTURE_TAG:
2351+ pack_projectile_data(array,projectiles,count);
2352+ break;
2353+ case MEDIA_TAG:
2354+ pack_media_data(array,medias,count);
2355+ break;
2356+ case ITEM_PLACEMENT_STRUCTURE_TAG:
2357+ pack_object_frequency_definition(array,get_placement_info(),count);
2358+ break;
2359+ case PLATFORM_STRUCTURE_TAG:
2360+ pack_platform_data(array,platforms,count);
2361+ break;
2362+ case AMBIENT_SOUND_TAG:
2363+ pack_ambient_sound_image_data(array,ambient_sound_images,count);
2364+ break;
2365+ case RANDOM_SOUND_TAG:
2366+ pack_random_sound_image_data(array,random_sound_images,count);
2367+ break;
2368+ case TERMINAL_DATA_TAG:
2369+ pack_map_terminal_data(array,count);
2370+ break;
2371+ case WEAPON_STATE_TAG:
2372+ pack_player_weapon_data(array,count);
2373+ break;
2374+ case TERMINAL_STATE_TAG:
2375+ pack_player_terminal_data(array,count);
2376+ break;
2377+ case MONSTER_PHYSICS_TAG:
2378+ pack_monster_definition(array,count);
2379+ break;
2380+ case EFFECTS_PHYSICS_TAG:
2381+ pack_effect_definition(array,count);
2382+ break;
2383+ case PROJECTILE_PHYSICS_TAG:
2384+ pack_projectile_definition(array,count);
2385+ break;
2386+ case PHYSICS_PHYSICS_TAG:
2387+ pack_physics_constants(array,count);
2388+ break;
2389+ case WEAPONS_PHYSICS_TAG:
2390+ pack_weapon_definition(array,count);
2391+ break;
2392+ case SHAPE_PATCH_TAG:
2393+ memcpy(array, get_shapes_patch_data(count), count);
2394+ break;
2395+ case MMLS_TAG:
2396+ memcpy(array, GetMMLS(count), count);
2397+ break;
2398+ case LUAS_TAG:
2399+ memcpy(array, GetLUAS(count), count);
2400+ break;
2401+ case LUA_STATE_TAG:
2402+ pack_lua_states(array, count);
2403+ break;
2404+ default:
2405+ assert(false);
2406+ break;
2407+ }
2408+
2409+ return array;
2410+}
2411+
2412+static wad_data *build_export_wad(wad_header *header, int32 *length)
2413+{
2414+ struct wad_data *wad= NULL;
2415+ uint8 *array_to_slam;
2416+ size_t size;
2417+
2418+ wad= create_empty_wad();
2419+ if(wad)
2420+ {
2421+ recalculate_map_counts();
2422+
2423+ // try to divine initial platform/polygon states
2424+ vector<platform_data> SavedPlatforms = PlatformList;
2425+ vector<polygon_data> SavedPolygons = PolygonList;
2426+ vector<line_data> SavedLines = LineList;
2427+
2428+ for (size_t loop = 0; loop < PlatformList.size(); ++loop)
2429+ {
2430+ platform_data *platform = &PlatformList[loop];
2431+ // reset the polygon heights
2432+ if (PLATFORM_COMES_FROM_FLOOR(platform))
2433+ {
2434+ platform->floor_height = platform->minimum_floor_height;
2435+ PolygonList[platform->polygon_index].floor_height = platform->floor_height;
2436+ }
2437+ if (PLATFORM_COMES_FROM_CEILING(platform))
2438+ {
2439+ platform->ceiling_height = platform->maximum_ceiling_height;
2440+ PolygonList[platform->polygon_index].ceiling_height = platform->ceiling_height;
2441+ }
2442+ }
2443+
2444+ for (size_t loop = 0; loop < LineList.size(); ++loop)
2445+ {
2446+ line_data *line = &LineList[loop];
2447+ if (LINE_IS_VARIABLE_ELEVATION(line))
2448+ {
2449+ SET_LINE_VARIABLE_ELEVATION(line, false);
2450+ SET_LINE_SOLIDITY(line, false);
2451+ SET_LINE_TRANSPARENCY(line, true);
2452+ }
2453+ }
2454+
2455+ for(unsigned loop= 0; loop<NUMBER_OF_EXPORT_ARRAYS; ++loop)
2456+ {
2457+ /* If there is a conversion function, let it handle it */
2458+ switch (export_data[loop].tag)
2459+ {
2460+ case POINT_TAG:
2461+ case LIGHTSOURCE_TAG:
2462+ case PLATFORM_STATIC_DATA_TAG:
2463+ case POLYGON_TAG:
2464+ array_to_slam= export_tag_to_global_array_and_size(export_data[loop].tag, &size);
2465+ break;
2466+ default:
2467+ array_to_slam= tag_to_global_array_and_size(export_data[loop].tag, &size);
2468+ }
2469+
2470+ /* Add it to the wad.. */
2471+ if(size)
2472+ {
2473+ wad= append_data_to_wad(wad, export_data[loop].tag, array_to_slam, size, 0);
2474+ delete []array_to_slam;
2475+ }
2476+ }
2477+
2478+ PlatformList = SavedPlatforms;
2479+ PolygonList = SavedPolygons;
2480+ LineList = SavedLines;
2481+
2482+ if(wad) *length= calculate_wad_length(header, wad);
2483+ }
2484+
2485+ return wad;
2486+}
2487+
2488+/* Build the wad, with all the crap */
2489+static struct wad_data *build_save_game_wad(
2490+ struct wad_header *header,
2491+ int32 *length)
2492+{
2493+ struct wad_data *wad= NULL;
2494+ uint8 *array_to_slam;
2495+ size_t size;
2496+
2497+ wad= create_empty_wad();
2498+ if(wad)
2499+ {
2500+ recalculate_map_counts();
2501+ for(unsigned loop= 0; loop<NUMBER_OF_SAVE_ARRAYS; ++loop)
2502+ {
2503+ /* If there is a conversion function, let it handle it */
2504+ array_to_slam= tag_to_global_array_and_size(save_data[loop].tag, &size);
2505+
2506+ /* Add it to the wad.. */
2507+ if(size)
2508+ {
2509+ wad= append_data_to_wad(wad, save_data[loop].tag, array_to_slam, size, 0);
2510+ delete []array_to_slam;
2511+ }
2512+ }
2513+ if(wad) *length= calculate_wad_length(header, wad);
2514+ }
2515+
2516+ return wad;
2517+}
2518+
2519+/* Load and slam all of the arrays */
2520+static void complete_restoring_level(
2521+ struct wad_data *wad)
2522+{
2523+ ok_to_reset_scenery_solidity = false;
2524+ /* Loading games needs this done. */
2525+ reset_action_queues();
2526+}
2527+
2528+
2529+/* CP Addition: get_map_file returns a pointer to the current map file */
2530+FileSpecifier& get_map_file()
2531+{
2532+ return MapFileSpec;
2533+}
2534+
2535+void level_has_embedded_physics_lua(int Level, bool& HasPhysics, bool& HasLua)
2536+{
2537+ // load the wad file and look for chunks !!??
2538+ wad_header header;
2539+ wad_data* wad;
2540+ OpenedFile MapFile;
2541+ if (open_wad_file_for_reading(get_map_file(), MapFile))
2542+ {
2543+ if (read_wad_header(MapFile, &header))
2544+ {
2545+ wad = read_indexed_wad_from_file(MapFile, &header, Level, true);
2546+ if (wad)
2547+ {
2548+ size_t data_length;
2549+ extract_type_from_wad(wad, PHYSICS_PHYSICS_TAG, &data_length);
2550+ HasPhysics = data_length > 0;
2551+
2552+ extract_type_from_wad(wad, LUAS_TAG, &data_length);
2553+ HasLua = data_length > 0;
2554+ free_wad(wad);
2555+ }
2556+ }
2557+ close_wad_file(MapFile);
2558+ }
2559+}
2560+
2561+
2562+/*
2563+ * Unpacking/packing functions
2564+ */
2565+
2566+static uint8 *unpack_directory_data(uint8 *Stream, directory_data *Objects, size_t Count)
2567+{
2568+ uint8* S = Stream;
2569+ directory_data* ObjPtr = Objects;
2570+
2571+ for (size_t k = 0; k < Count; k++, ObjPtr++)
2572+ {
2573+ StreamToValue(S,ObjPtr->mission_flags);
2574+ StreamToValue(S,ObjPtr->environment_flags);
2575+ StreamToValue(S,ObjPtr->entry_point_flags);
2576+ StreamToBytes(S,ObjPtr->level_name,LEVEL_NAME_LENGTH);
2577+ }
2578+
2579+ assert((S - Stream) == SIZEOF_directory_data);
2580+ return S;
2581+}
2582+
2583+// ZZZ: gnu cc swears this is currently unused, and I don't see any sneaky #includes that might need it...
2584+/*
2585+static uint8 *pack_directory_data(uint8 *Stream, directory_data *Objects, int Count)
2586+{
2587+ uint8* S = Stream;
2588+ directory_data* ObjPtr = Objects;
2589+
2590+ for (int k = 0; k < Count; k++, ObjPtr++)
2591+ {
2592+ ValueToStream(S,ObjPtr->mission_flags);
2593+ ValueToStream(S,ObjPtr->environment_flags);
2594+ ValueToStream(S,ObjPtr->entry_point_flags);
2595+ BytesToStream(S,ObjPtr->level_name,LEVEL_NAME_LENGTH);
2596+ }
2597+
2598+ assert((S - Stream) == SIZEOF_directory_data);
2599+ return S;
2600+}
2601+*/
旧リポジトリブラウザで表示