• R/O
  • SSH
  • HTTPS

marathon: Commit


Commit MetaInfo

Revision524 (tree)
Zeit2012-06-02 13:56:58
Autorookawa_mi

Log Message

1.0.2対応
改行コード修正

Ändern Zusammenfassung

Diff

--- marathon/trunk/Source_Files/GameWorld/platforms.cpp (revision 523)
+++ marathon/trunk/Source_Files/GameWorld/platforms.cpp (revision 524)
@@ -82,8 +82,6 @@
8282
8383 #include <string.h>
8484
85-#include "editor.h" // MARATHON_ONE_DATA_VERSION
86-
8785 #ifdef env68k
8886 #pragma segment doors
8987 #endif
@@ -136,8 +134,7 @@
136134
137135 short new_platform(
138136 struct static_platform_data *data,
139- short polygon_index,
140- short version)
137+ short polygon_index)
141138 {
142139 short platform_index= NONE;
143140 struct platform_data *platform;
@@ -168,17 +165,6 @@
168165 platform->polygon_index= polygon_index;
169166 platform->parent_platform_index= NONE;
170167 calculate_platform_extrema(platform_index, data->minimum_height, data->maximum_height);
171-
172- if (version == MARATHON_ONE_DATA_VERSION)
173- {
174- switch (platform->type)
175- {
176- case 0: // marathon door
177- case 3: // pfhor door
178- SET_PLATFORM_IS_DOOR(platform, true);
179- break;
180- }
181- }
182168
183169 #if 0
184170 switch (platform->type)
--- marathon/trunk/Source_Files/GameWorld/platforms.h (revision 523)
+++ marathon/trunk/Source_Files/GameWorld/platforms.h (revision 524)
@@ -260,7 +260,7 @@
260260
261261 /* --------- prototypes/PLATFORMS.C */
262262
263-short new_platform(struct static_platform_data *data, short polygon_index, short version);
263+short new_platform(struct static_platform_data *data, short polygon_index);
264264 struct static_platform_data *get_defaults_for_platform_type(short type);
265265
266266 void update_platforms(void);
--- marathon/trunk/Source_Files/GameWorld/marathon2.cpp (revision 523)
+++ marathon/trunk/Source_Files/GameWorld/marathon2.cpp (revision 524)
@@ -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+ if (film_profile.reset_action_queues) 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+*/
Show on old repository browser