mirror of
https://github.com/astromaddie/HaloCE-VR.git
synced 2026-10-19 17:00:15 +02:00
The frames between ticks are placed by the game clock, which the main loop stepped by its own measure (the performance counter) of each pass. That pass also holds the game's tick and the drawing, which wander by milliseconds from frame to frame (game 6 to 9 ms on the device), so what moves steadily was drawn at uneven places between the ticks: cutscene pans and flying banshees juddered (reported worn). The runtime's frame is now begun at the top of the loop (vr_frame_seconds) and the clock steps from the last frame's predicted display time to this one's, whole periods; the loop's own measure stays for when there is no runtime frame.
3338 lines
85 KiB
C
3338 lines
85 KiB
C
/*
|
|
MAIN.C
|
|
|
|
symbols in this file:
|
|
000EF6F0 0010:
|
|
_main_get_seconds_elapsed (0000)
|
|
000EF700 0080:
|
|
_gamepad_button_is_down (0000)
|
|
000EF780 0010:
|
|
_game_connection_set (0000)
|
|
000EF790 0010:
|
|
_game_connection (0000)
|
|
000EF7A0 0010:
|
|
_main_disallow_persistent_storage (0000)
|
|
000EF7B0 0060:
|
|
_main_set_map_name (0000)
|
|
000EF810 0010:
|
|
_main_defer_map_map_change (0000)
|
|
000EF820 0030:
|
|
_main_set_multiplayer_map_name (0000)
|
|
000EF850 0010:
|
|
_main_get_map_name (0000)
|
|
000EF860 0010:
|
|
_main_get_multiplayer_map_name (0000)
|
|
000EF870 0020:
|
|
_main_set_difficulty (0000)
|
|
000EF890 0010:
|
|
_main_get_difficulty (0000)
|
|
000EF8A0 0040:
|
|
_sort_desired_local_player_controllers (0000)
|
|
000EF8E0 01d0:
|
|
_code_000ef8e0 (0000)
|
|
000EFAB0 0020:
|
|
_main_reset_map (0000)
|
|
000EFAD0 0020:
|
|
_main_revert_map (0000)
|
|
000EFAF0 0020:
|
|
_main_skip_cinematic (0000)
|
|
000EFB10 0010:
|
|
_main_save_map_nonsafe (0000)
|
|
000EFB20 0010:
|
|
_main_saving_map (0000)
|
|
000EFB30 0010:
|
|
_main_save_cancel (0000)
|
|
000EFB40 0040:
|
|
_main_save_map_safe (0000)
|
|
000EFB80 0010:
|
|
_main_won_map (0000)
|
|
000EFB90 0010:
|
|
_main_lost_map (0000)
|
|
000EFBA0 0020:
|
|
_main_respawn (0000)
|
|
000EFBC0 0020:
|
|
_main_save_core (0000)
|
|
000EFBE0 0050:
|
|
_main_save_core_name (0000)
|
|
000EFC30 0020:
|
|
_main_load_core (0000)
|
|
000EFC50 0020:
|
|
_main_load_core_at_startup (0000)
|
|
000EFC70 0050:
|
|
_main_load_core_name (0000)
|
|
000EFCC0 0050:
|
|
_main_load_core_name_at_startup (0000)
|
|
000EFD10 0060:
|
|
_main_switch_structure_bsp (0000)
|
|
000EFD70 0030:
|
|
_main_skip (0000)
|
|
000EFDA0 0040:
|
|
_main_queue_map_name (0000)
|
|
000EFDE0 0050:
|
|
_code_000efde0 (0000)
|
|
000EFE30 0020:
|
|
_main_goto_main_menu (0000)
|
|
000EFE50 0050:
|
|
_main_menu_precache_resources (0000)
|
|
000EFEA0 0020:
|
|
_main_menu_unload (0000)
|
|
000EFEC0 0010:
|
|
_main_menu_ensure_player_queues_exist (0000)
|
|
000EFED0 0010:
|
|
_main_menu_fade_active (0000)
|
|
000EFEE0 0010:
|
|
_main_menu_switch_to_single_player (0000)
|
|
000EFEF0 0010:
|
|
_main_set_game_connection_to_film_playback (0000)
|
|
000EFF00 0170:
|
|
_main_get_solo_level_from_name (0000)
|
|
000F0070 0010:
|
|
_main_get_current_solo_level (0000)
|
|
000F0080 0020:
|
|
_main_get_solo_level_name (0000)
|
|
000F00A0 0010:
|
|
_main_run_demos (0000)
|
|
000F00B0 0070:
|
|
_code_000f00b0 (0000)
|
|
000F0120 01f0:
|
|
_compute_window_bounds (0000)
|
|
000F0310 0040:
|
|
_main_get_window_count (0000)
|
|
000F0350 00d0:
|
|
_code_000f0350 (0000)
|
|
000F0420 0180:
|
|
_code_000f0420 (0000)
|
|
000F05A0 0020:
|
|
_code_000f05a0 (0000)
|
|
000F05C0 0030:
|
|
_code_000f05c0 (0000)
|
|
000F05F0 00b0:
|
|
_code_000f05f0 (0000)
|
|
000F06A0 0020:
|
|
_code_000f06a0 (0000)
|
|
000F06C0 00e0:
|
|
_code_000f06c0 (0000)
|
|
000F07A0 0030:
|
|
_code_000f07a0 (0000)
|
|
000F07D0 0040:
|
|
_code_000f07d0 (0000)
|
|
000F0810 0040:
|
|
_code_000f0810 (0000)
|
|
000F0850 0060:
|
|
_code_000f0850 (0000)
|
|
000F08B0 0020:
|
|
_code_000f08b0 (0000)
|
|
000F08D0 0020:
|
|
_code_000f08d0 (0000)
|
|
000F08F0 0040:
|
|
_code_000f08f0 (0000)
|
|
000F0930 0010:
|
|
_code_000f0930 (0000)
|
|
000F0940 0220:
|
|
_code_000f0940 (0000)
|
|
000F0B60 0050:
|
|
_code_000f0b60 (0000)
|
|
000F0BB0 0030:
|
|
_code_000f0bb0 (0000)
|
|
000F0BE0 0010:
|
|
_main_framerate_throttle_enabled (0000)
|
|
000F0BF0 05a0:
|
|
_code_000f0bf0 (0000)
|
|
000F1190 0210:
|
|
_main_rasterizer_throttle (0000)
|
|
000F13A0 0020:
|
|
_code_000f13a0 (0000)
|
|
000F13C0 0020:
|
|
_main_taking_screenshot (0000)
|
|
000F13E0 00b0:
|
|
_main_movie_start (0000)
|
|
000F1490 0020:
|
|
_main_movie_stop (0000)
|
|
000F14B0 0010:
|
|
_main_stop_time (0000)
|
|
000F14C0 0010:
|
|
_main_start_time (0000)
|
|
000F14D0 0010:
|
|
_main_crash (0000)
|
|
000F14E0 0010:
|
|
_main_print_version (0000)
|
|
000F14F0 00c0:
|
|
_main_vertical_blank_interrupt_handler (0000)
|
|
000F15B0 0070:
|
|
_main_save_current_solo_map (0000)
|
|
000F1620 00c0:
|
|
_main_load_last_solo_map (0000)
|
|
000F16E0 0040:
|
|
_main_save_map_no_timeout (0000)
|
|
000F1720 00e0:
|
|
_main_load_ui_scenario (0000)
|
|
000F1800 0090:
|
|
_main_menu_load (0000)
|
|
000F1890 0020:
|
|
_main_roll_credits (0000)
|
|
000F18B0 0130:
|
|
_main_pregame_render (0000)
|
|
000F19E0 01b0:
|
|
_set_window_camera_values (0000)
|
|
000F1B90 0090:
|
|
_main_present_frame (0000)
|
|
000F1C20 00c0:
|
|
_code_000f1c20 (0000)
|
|
000F1CE0 0050:
|
|
_code_000f1ce0 (0000)
|
|
000F1D30 01f0:
|
|
_code_000f1d30 (0000)
|
|
000F1F20 02a0:
|
|
_main_framerate_render (0000)
|
|
000F21C0 02a0:
|
|
_halt_and_catch_fire (0000)
|
|
000F2460 0040:
|
|
_main_loop_of_death (0000)
|
|
000F24A0 01c0:
|
|
_code_000f24a0 (0000)
|
|
000F2660 0670:
|
|
_main_loop (0000)
|
|
002795A8 003a:
|
|
??_C@_0DK@GMPCKHNN@button_index?$DO?$DN0?5?$CG?$CG?5button_index?$DM@ (0000)
|
|
002795E4 001b:
|
|
??_C@_0BL@EKABHJPH@c?3?2halo?2SOURCE?2main?2main?4c?$AA@ (0000)
|
|
00279600 0037:
|
|
??_C@_0DH@DGKBOONK@?$CIgamepad_index?$DO?$DN0?$CJ?5?$CG?$CG?5?$CIgamepad_i@ (0000)
|
|
00279638 0013:
|
|
??_C@_0BD@OOOKAGFE@j?$DMMAXIMUM_GAMEPADS?$AA@ (0000)
|
|
00279650 0049:
|
|
??_C@_0EJ@DIAKEACK@?$CIdesired_controllers?$FLi?$FN?$DO?$DN0?$CJ?5?$CG?$CG?5?$CI@ (0000)
|
|
0027969C 002c:
|
|
??_C@_0CM@EOEJOPGF@game_connection?$CI?$CJ?5?$DN?$DN?5_game_conne@ (0000)
|
|
002796C8 0009:
|
|
??_C@_08FLLKDKH@core?4bin?$AA@ (0000)
|
|
002796D4 003b:
|
|
??_C@_0DL@LKJEADLD@warning?0?5core?5file?5name?5will?5be?5@ (0000)
|
|
00279710 002c:
|
|
??_C@_0CM@BPJFOCNH@tried?5to?5switch?5to?5invalid?5struc@ (0000)
|
|
0027973C 002c:
|
|
??_C@_0CM@IOHNOMHF@tried?5to?5switch?5to?5current?5struc@ (0000)
|
|
00279768 0030:
|
|
??_C@_0DA@FGIPPFOE@cannot?5skip?5more?5than?515?5frames?5@ (0000)
|
|
00279798 0029:
|
|
??_C@_0CJ@GNBMIDNC@scenario?9?$DOtype?$DN?$DN_scenario_type_m@ (0000)
|
|
002797C4 000e:
|
|
??_C@_0O@OJNPMJKK@num_players?$DO0?$AA@ (0000)
|
|
002797D4 0039:
|
|
??_C@_0DJ@LGIIGICN@horizontal_index?$DO?$DN0?5?$CG?$CG?5horizonta@ (0000)
|
|
00279810 0033:
|
|
??_C@_0DD@NNOBFMAG@vertical_index?$DO?$DN0?5?$CG?$CG?5vertical_in@ (0000)
|
|
00279844 0019:
|
|
??_C@_0BJ@LDIFOEOI@player_index?$DMnum_players?$AA@ (0000)
|
|
00279860 0017:
|
|
??_C@_0BH@PGKHPIFN@main_new_map?$CI?$CJ?5failed?4?$AA@ (0000)
|
|
00279878 0014:
|
|
??_C@_0BE@HPJEDLPC@game_load?$CI?$CJ?5failed?4?$AA@ (0000)
|
|
00279890 0041:
|
|
??_C@_0EB@NLDLOJCN@manual?5skipping?5doesn?8t?5work?5out@ (0000)
|
|
002798D4 000c:
|
|
??_C@_0M@NBLPJHAH@unsafe?5save?$AA@ (0000)
|
|
002798E0 0017:
|
|
??_C@_0BH@JAFGAFKC@gave?5up?5trying?5to?5save?$AA@ (0000)
|
|
002798F8 001f:
|
|
??_C@_0BP@JOHDPJOL@?$DLcore_load_name_at_startup?5?$CFs?6?$AA@ (0000)
|
|
00279918 0004:
|
|
??_C@_03CCGKKFHG@a?$CLt?$AA@ (0000)
|
|
0027991C 000d:
|
|
??_C@_0N@HMFDKLFI@map_name?5?$CFs?6?$AA@ (0000)
|
|
0027992C 0003:
|
|
??_C@_02BKFDOEMK@wt?$AA@ (0000)
|
|
00279930 000f:
|
|
??_C@_0P@JFNDGJMB@d?3?2?$CFs_init?4txt?$AA@ (0000)
|
|
00279940 001e:
|
|
??_C@_0BO@EFIKKGLE@?$CFs_slow_?$CFd_?$CFd_?$CFd_?$CFd_?$CFd_?$CFd?4bin?$AA@ (0000)
|
|
00279960 0008:
|
|
__real@3fa26e978d4fdf3c (0000)
|
|
00279968 0013:
|
|
??_C@_0BD@BANPCAEP@?5des?5?$CFd?5targ?$CF6I64d?$AA@ (0000)
|
|
0027997C 000d:
|
|
??_C@_0N@ONKBMNKN@?5MAINTAIN?5?$CFd?$AA@ (0000)
|
|
0027998C 000d:
|
|
??_C@_0N@MLBLHBF@?5RESTORE?5?5?$CFd?$AA@ (0000)
|
|
0027999C 000d:
|
|
??_C@_0N@KHJNGILI@?5FAILDOWN?5?$CFd?$AA@ (0000)
|
|
002799AC 000d:
|
|
??_C@_0N@KAJPDIPB@?$CI?$CFs?$CF2d?1?$CF2d?$CJ?5?$AA@ (0000)
|
|
002799BC 0003:
|
|
??_C@_02LEBOADDI@dn?$AA@ (0000)
|
|
002799C0 000c:
|
|
??_C@_0M@FONKJGHM@?$CIok?5?5?5?$CF2d?$CJ?5?$AA@ (0000)
|
|
002799CC 0006:
|
|
??_C@_05MPKPLMMK@ignor?$AA@ (0000)
|
|
002799D4 0009:
|
|
??_C@_08NGBFCLJE@?$CI?$CFs?$CF2d?$CJ?5?$AA@ (0000)
|
|
002799E0 0006:
|
|
??_C@_05KGKFECIJ@fail?5?$AA@ (0000)
|
|
002799E8 003a:
|
|
??_C@_0DK@KGLGNIMB@last?$CF6I64d?5init?$CF6I64d?5achv?$CF6I64d@ (0000)
|
|
00279A24 0019:
|
|
??_C@_0BJ@GBFFHJIM@?$CF6I64d?$CItarg?$CF6I64d?5?$CFs?$CF2d?$CJ?$AA@ (0000)
|
|
00279A40 0009:
|
|
??_C@_08EEAEDAMO@LAPSED?5?5?$AA@ (0000)
|
|
00279A4C 0009:
|
|
??_C@_08KMBEHCPI@SYNCED?5?5?$AA@ (0000)
|
|
00279A58 0009:
|
|
??_C@_08PLAGFMEO@THROTTLE?$AA@ (0000)
|
|
00279A68 004a:
|
|
??_C@_0EK@OBDHCGCK@stuck?5waiting?5for?5VBLANK?5callbac@ (0000)
|
|
00279AB4 0006:
|
|
??_C@_05PAONDCEJ@movie?$AA@ (0000)
|
|
00279ABC 0019:
|
|
??_C@_0BJ@MFOKCFOP@main_globals?4movie?$DN?$DNNULL?$AA@ (0000)
|
|
00279AD8 002a:
|
|
??_C@_0CK@IJIKLLCA@chucky?5was?5here?$CB?5?5NULL?5belongs?5t@ (0000)
|
|
00279B04 0031:
|
|
??_C@_0DB@HPIOCFDH@halobeta?5xbox?501?401?414?42342?5Jan?5@ (0000)
|
|
00279B38 0038:
|
|
??_C@_0DI@IKBOMHNJ@Couldn?8t?5create?5a?5file?5to?5write?5@ (0000)
|
|
00279B70 0011:
|
|
??_C@_0BB@HAHOOKLD@z?3?2last_solo?4txt?$AA@ (0000)
|
|
00279B84 0028:
|
|
??_C@_0CI@KPDFMEMF@?$CBmain_globals?4main_menu_scenario@ (0000)
|
|
00279BAC 000d:
|
|
??_C@_0N@CBIELCEF@levels?2ui?2ui?$AA@ (0000)
|
|
00279BBC 0023:
|
|
??_C@_0CD@IMDNHNHI@congratulations?0?5you?5won?5the?5gam@ (0000)
|
|
00279BE0 0014:
|
|
??_C@_0BE@BDDOCJAN@movie?2frame?$CF06d?4tga?$AA@ (0000)
|
|
00279BF4 0019:
|
|
??_C@_0BJ@CKCGDFO@error?5opening?5saved?5film?$AA@ (0000)
|
|
00279C10 0015:
|
|
??_C@_0BF@LPIHHLNO@?$CFdscreenshot?$CFd?$CFd?4tif?$AA@ (0000)
|
|
00279C28 003b:
|
|
??_C@_0DL@LMMABMNB@halobeta?5xbox?501?401?414?42342?5buil@ (0000)
|
|
00279C64 001f:
|
|
??_C@_0BP@HEAODFIJ@old?5tags?2internal?5system?5plain?$AA@ (0000)
|
|
00279C84 0012:
|
|
??_C@_0BC@FLAPBDJB@end?5of?5saved?5film?$AA@ (0000)
|
|
00279C98 0018:
|
|
??_C@_0BI@HBMJOOEK@the?5game?5host?5went?5down?$AA@ (0000)
|
|
00307818 0034:
|
|
_global_difficulty_level (0000)
|
|
_player_spawn_count (0004)
|
|
_global_frame_rate_throttle (0006)
|
|
_global_screenshot_size (0008)
|
|
00455750 0a63:
|
|
_bss_00455750 (0000)
|
|
_debug_force_frame_rate_update (06d0)
|
|
_debug_no_drawing (06d1)
|
|
_debug_game_save (06d2)
|
|
_debug_frame_rate (06d3)
|
|
_display_framerate (06d4)
|
|
_display_vblank_deltas (06d5)
|
|
_display_precache_progress (06d6)
|
|
_global_screenshot_count (06d8)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "errors.h"
|
|
#include "cseries/profile.h"
|
|
#include "cseries/cseries_windows.h"
|
|
#include "main.h"
|
|
#include "real_math.h"
|
|
#include "game.h"
|
|
#include "game_engine.h"
|
|
#include "camera/camera_scripting.h"
|
|
#include "game/cheats.h"
|
|
#include "game/player_control_runtime.h"
|
|
#include "game/players.h"
|
|
#include "game/local_players.h"
|
|
#include "game/player_queues_new.h"
|
|
#include "integer_math.h"
|
|
#include "input.h"
|
|
#include "input/input_abstraction.h"
|
|
#include "shell.h"
|
|
#include "event_manager.h"
|
|
#include "telnet_console.h"
|
|
#include "ui_widget.h"
|
|
#include "editor_stubs.h"
|
|
#include "console.h"
|
|
#include "debug_keys.h"
|
|
#include "scenario.h"
|
|
#include "scenario/scenario_definitions.h"
|
|
#include "cache/cache_files.h"
|
|
#include "cache/predicted_resources.h"
|
|
#include "bitmaps/bitmap_group.h"
|
|
#include "bitmaps/bitmaps.h"
|
|
#include "bitmaps/tiff_file.h"
|
|
#include "interface/hud.h"
|
|
#include "interface/hud_definitions.h"
|
|
#include "interface/attract_mode.h"
|
|
#include "interface/interface.h"
|
|
#include "interface/marketing_and_strategic_business_development.h"
|
|
#include "interface/player_ui.h"
|
|
#include "interface/terminal.h"
|
|
#include "saved games/player_profile.h"
|
|
#include "saved games/game_state.h"
|
|
#include "sound/sound_manager.h"
|
|
#include "rasterizer/rasterizer.h"
|
|
#include "rasterizer/rasterizer_console_vars.h"
|
|
#include "bink/bink_playback.h"
|
|
#include "main/d3d_intimacy.h"
|
|
#include "networking/network_game_globals.h"
|
|
#include "camera/director.h"
|
|
#include "camera/observer.h"
|
|
#include "cutscene/cinematics.h"
|
|
#include "effects/player_effects.h"
|
|
#include "physics/collision_usage.h"
|
|
#include "physics/collision_debug.h"
|
|
#include "hs/hs.h"
|
|
#include "render/render.h"
|
|
#include "text/draw_string.h"
|
|
#include "text/font_group.h"
|
|
#include "tag_files/files.h"
|
|
#include "halo_vr.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
_bitmap_format_x8r8g8b8 = 10,
|
|
};
|
|
|
|
enum
|
|
{
|
|
_text_justification_left = 0,
|
|
_text_justification_right,
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
/*
|
|
struct _main_globals
|
|
{
|
|
long long last_time_clocks; // 0x0
|
|
unsigned long last_time_msec; // 0x8
|
|
long long last_render_clocks; // 0x10
|
|
long long last_vblank_index; // 0x18
|
|
long long last_initial_vblank_index; // 0x20
|
|
long long last_achievable_vblank_index; // 0x28
|
|
long long last_present_vblank_index; // 0x30
|
|
unsigned char did_time_overflow_occur; // 0x38
|
|
float seconds_elapsed; // 0x3C
|
|
short connection; // 0x40
|
|
unsigned short screenshot_identifier; // 0x42
|
|
bitmap_data *movie; // 0x44
|
|
long recording_start_tick; // 0x48
|
|
long recording_stop_tick; // 0x4C
|
|
long recording_frame_index; // 0x50
|
|
float recording_dt; // 0x54
|
|
unsigned char reset_map; // 0x58
|
|
unsigned char rename_map; // 0x59
|
|
unsigned char revert_map; // 0x5A
|
|
unsigned char skip_cinematic; // 0x5B
|
|
unsigned char save_map; // 0x5C
|
|
unsigned char save_map_safely; // 0x5D
|
|
unsigned char save_map_timeout; // 0x5E
|
|
unsigned char saving_map; // 0x5F
|
|
long ticks_until_next_save_check; // 0x60
|
|
long ticks_unable_to_save; // 0x64
|
|
unsigned long map_change_load_timer; // 0x68
|
|
short safe_intervals; // 0x6C
|
|
unsigned char won_map; // 0x6E
|
|
unsigned char lost_map; // 0x6F
|
|
unsigned char respawn; // 0x70
|
|
unsigned char save_core; // 0x71
|
|
unsigned char load_core; // 0x72
|
|
unsigned char load_core_at_startup; // 0x73
|
|
short switch_to_structure_bsp_index; // 0x74
|
|
unsigned char main_menu_scenario_loaded; // 0x76
|
|
unsigned char want_to_be_at_main_menu; // 0x77
|
|
unsigned char run_xdemos; // 0x78
|
|
unsigned char fade_to_dashboard; // 0x79
|
|
unsigned char exit_to_dashboard; // 0x7A
|
|
unsigned char want_to_exit; // 0x7B
|
|
long idle_timeout; // 0x7C
|
|
long idle_last_interesting; // 0x80
|
|
long idle_last_activity; // 0x84
|
|
unsigned char playback_last_recording; // 0x88
|
|
unsigned char halt_time_scale; // 0x89
|
|
unsigned char restart_time; // 0x8A
|
|
unsigned char load_last_solo_level; // 0x8B
|
|
unsigned char cutscene_skip; // 0x8C
|
|
short skip_ticks; // 0x8E
|
|
short loss_timer; // 0x90
|
|
short respawn_timer; // 0x92
|
|
unsigned char queue_map; // 0x94
|
|
unsigned char pad0[3]; // 0x95
|
|
unsigned char solo_try_and_load_from_persistent_storage; // 0x98
|
|
char soloplayer_map_name[256]; // 0x99
|
|
char multiplayer_map_name[256]; // 0x199
|
|
char queued_map_name[256]; // 0x299
|
|
unsigned char want_to_connect; // 0x399
|
|
char connect_address[32]; // 0x39A
|
|
char connect_password[9]; // 0x3BA
|
|
short vblank_interval_current; // 0x3C4
|
|
short vblank_interval_minimum; // 0x3C6
|
|
unsigned char vblank_interval_held; // 0x3C8
|
|
short vblank_failure_count[6]; // 0x3CA
|
|
long long vblank_last_failure_time[6]; // 0x3D8
|
|
unsigned long *vblank_flip_counter; // 0x408
|
|
short vblank_flip_delta_next_index; // 0x40C
|
|
short vblank_flip_deltas[15]; // 0x40E
|
|
};
|
|
*/
|
|
|
|
struct _main_globals
|
|
{
|
|
unsigned long frame_start_milliseconds;
|
|
byte reserved04[4];
|
|
union
|
|
{
|
|
__int64 rasterizer_target_index;
|
|
struct
|
|
{
|
|
unsigned long rasterizer_frame_index;
|
|
unsigned long rasterizer_vertical_blank_index;
|
|
};
|
|
};
|
|
__int64 rasterizer_initial_index;
|
|
__int64 rasterizer_throttle_start_index;
|
|
__int64 rasterizer_throttle_end_index;
|
|
real seconds_elapsed;
|
|
short connection;
|
|
unsigned short screenshot_identifier;
|
|
struct bitmap_data *movie;
|
|
long recording_start_tick;
|
|
long recording_stop_tick;
|
|
long recording_frame_index;
|
|
real recording_dt;
|
|
boolean reset_map;
|
|
boolean defer_map_change;
|
|
boolean revert_map;
|
|
boolean skip_cinematic;
|
|
boolean saving_map;
|
|
boolean save_map_safely;
|
|
boolean save_map_timeout;
|
|
boolean save_map_completed;
|
|
long ticks_until_next_save_check;
|
|
long ticks_unable_to_save;
|
|
unsigned long map_change_load_timer;
|
|
short safe_intervals;
|
|
boolean won_map;
|
|
boolean lost_map;
|
|
boolean respawn;
|
|
boolean save_core;
|
|
boolean load_core;
|
|
boolean load_core_at_startup;
|
|
short switch_to_structure_bsp_index;
|
|
boolean main_menu_scenario_loaded;
|
|
boolean want_to_be_at_main_menu;
|
|
boolean run_xdemos;
|
|
boolean playback_last_recording;
|
|
boolean halt_time_scale;
|
|
boolean restart_time;
|
|
boolean load_last_solo_level;
|
|
boolean skip;
|
|
short skip_ticks;
|
|
short loss_timer;
|
|
short respawn_timer;
|
|
boolean queue_map;
|
|
byte __unknown121[0x3];
|
|
boolean allow_persistent_storage;
|
|
char soloplayer_map_name[256];
|
|
char multiplayer_map_name[256];
|
|
char queued_map_name[256];
|
|
char core_name[64];
|
|
byte reserved3B5;
|
|
short vblank_interval_current;
|
|
short vblank_interval_requested;
|
|
boolean vblank_interval_held;
|
|
byte reserved3BB;
|
|
short vblank_failure_counts[6];
|
|
__int64 vblank_last_failure_indices[6];
|
|
volatile unsigned int *d3d_flip_count;
|
|
short vblank_flip_delta_index;
|
|
short vblank_flip_deltas[15];
|
|
char vblank_debug_string[0x200];
|
|
byte reserved61C[4];
|
|
};
|
|
|
|
typedef char main_hud_globals_font_tag_index_offset_assert[
|
|
offsetof(struct hud_globals_definition, messaging.single_player_font.index) == 0x54 ? 1 : -1];
|
|
|
|
typedef char main_globals_size_assert[
|
|
sizeof(struct _main_globals) == 0x620 ? 1 : -1];
|
|
typedef char main_globals_frame_start_milliseconds_offset_assert[
|
|
offsetof(struct _main_globals, frame_start_milliseconds) == 0x00 ? 1 : -1];
|
|
typedef char main_globals_rasterizer_target_index_offset_assert[
|
|
offsetof(struct _main_globals, rasterizer_target_index) == 0x08 ? 1 : -1];
|
|
typedef char main_globals_rasterizer_initial_index_offset_assert[
|
|
offsetof(struct _main_globals, rasterizer_initial_index) == 0x10 ? 1 : -1];
|
|
typedef char main_globals_rasterizer_throttle_start_index_offset_assert[
|
|
offsetof(struct _main_globals, rasterizer_throttle_start_index) == 0x18 ? 1 : -1];
|
|
typedef char main_globals_rasterizer_throttle_end_index_offset_assert[
|
|
offsetof(struct _main_globals, rasterizer_throttle_end_index) == 0x20 ? 1 : -1];
|
|
typedef char main_globals_seconds_elapsed_offset_assert[
|
|
offsetof(struct _main_globals, seconds_elapsed) == 0x28 ? 1 : -1];
|
|
typedef char main_globals_connection_offset_assert[
|
|
offsetof(struct _main_globals, connection) == 0x2C ? 1 : -1];
|
|
typedef char main_globals_movie_offset_assert[
|
|
offsetof(struct _main_globals, movie) == 0x30 ? 1 : -1];
|
|
typedef char main_globals_defer_map_change_offset_assert[
|
|
offsetof(struct _main_globals, defer_map_change) == 0x45 ? 1 : -1];
|
|
typedef char main_globals_reset_map_offset_assert[
|
|
offsetof(struct _main_globals, reset_map) == 0x44 ? 1 : -1];
|
|
typedef char main_globals_revert_map_offset_assert[
|
|
offsetof(struct _main_globals, revert_map) == 0x46 ? 1 : -1];
|
|
typedef char main_globals_skip_cinematic_offset_assert[
|
|
offsetof(struct _main_globals, skip_cinematic) == 0x47 ? 1 : -1];
|
|
typedef char main_globals_saving_map_offset_assert[
|
|
offsetof(struct _main_globals, saving_map) == 0x48 ? 1 : -1];
|
|
typedef char main_globals_save_map_safely_offset_assert[
|
|
offsetof(struct _main_globals, save_map_safely) == 0x49 ? 1 : -1];
|
|
typedef char main_globals_won_map_offset_assert[
|
|
offsetof(struct _main_globals, won_map) == 0x5A ? 1 : -1];
|
|
typedef char main_globals_halt_time_scale_offset_assert[
|
|
offsetof(struct _main_globals, halt_time_scale) == 0x66 ? 1 : -1];
|
|
typedef char main_globals_respawn_timer_offset_assert[
|
|
offsetof(struct _main_globals, respawn_timer) == 0x6E ? 1 : -1];
|
|
typedef char main_globals_loss_timer_offset_assert[
|
|
offsetof(struct _main_globals, loss_timer) == 0x6C ? 1 : -1];
|
|
typedef char main_globals_allow_persistent_storage_offset_assert[
|
|
offsetof(struct _main_globals, allow_persistent_storage) == 0x74 ? 1 : -1];
|
|
typedef char main_globals_soloplayer_map_name_offset_assert[
|
|
offsetof(struct _main_globals, soloplayer_map_name) == 0x75 ? 1 : -1];
|
|
typedef char main_globals_multiplayer_map_name_offset_assert[
|
|
offsetof(struct _main_globals, multiplayer_map_name) == 0x175 ? 1 : -1];
|
|
typedef char main_globals_core_name_offset_assert[
|
|
offsetof(struct _main_globals, core_name) == 0x375 ? 1 : -1];
|
|
typedef char main_globals_vblank_interval_current_offset_assert[
|
|
offsetof(struct _main_globals, vblank_interval_current) == 0x3B6 ? 1 : -1];
|
|
typedef char main_globals_vblank_interval_requested_offset_assert[
|
|
offsetof(struct _main_globals, vblank_interval_requested) == 0x3B8 ? 1 : -1];
|
|
typedef char main_globals_vblank_interval_held_offset_assert[
|
|
offsetof(struct _main_globals, vblank_interval_held) == 0x3BA ? 1 : -1];
|
|
typedef char main_globals_vblank_failure_counts_offset_assert[
|
|
offsetof(struct _main_globals, vblank_failure_counts) == 0x3BC ? 1 : -1];
|
|
typedef char main_globals_vblank_last_failure_indices_offset_assert[
|
|
offsetof(struct _main_globals, vblank_last_failure_indices) == 0x3C8 ? 1 : -1];
|
|
typedef char main_globals_d3d_flip_count_offset_assert[
|
|
offsetof(struct _main_globals, d3d_flip_count) == 0x3F8 ? 1 : -1];
|
|
typedef char main_globals_vblank_flip_delta_index_offset_assert[
|
|
offsetof(struct _main_globals, vblank_flip_delta_index) == 0x3FC ? 1 : -1];
|
|
typedef char main_globals_vblank_flip_deltas_offset_assert[
|
|
offsetof(struct _main_globals, vblank_flip_deltas) == 0x3FE ? 1 : -1];
|
|
typedef char main_globals_vblank_debug_string_offset_assert[
|
|
offsetof(struct _main_globals, vblank_debug_string) == 0x41C ? 1 : -1];
|
|
|
|
struct game_options
|
|
{
|
|
unsigned long flags;
|
|
short code_version;
|
|
short difficulty;
|
|
unsigned long random_seed;
|
|
char map_name[256];
|
|
};
|
|
|
|
typedef char game_options_size_assert[
|
|
sizeof(struct game_options) == 0x10C ? 1 : -1];
|
|
|
|
#pragma pack(push, 1)
|
|
struct _screenshot_and_framerate_globals
|
|
{
|
|
short count;
|
|
byte reserved002[6];
|
|
struct render_window windows[MAXIMUM_WINDOWS + 1];
|
|
real framerate_samples[8];
|
|
word framerate_flags;
|
|
char framerate_sample_index;
|
|
boolean framerate_active;
|
|
char framerate_counter;
|
|
boolean framerate_reset;
|
|
boolean halt_recursion_lock;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
typedef char screenshot_and_framerate_globals_size_assert[
|
|
sizeof(struct _screenshot_and_framerate_globals) == 0x38B ? 1 : -1];
|
|
|
|
void network_test_update(boolean main_menu_loaded, real seconds);
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static long sort_desired_local_player_controllers(
|
|
short const *a,
|
|
short const *b);
|
|
static void main_setup_connection(
|
|
void);
|
|
static void main_initialize_time(
|
|
void);
|
|
static void main_skip_private(
|
|
void);
|
|
static void main_update_time(
|
|
void);
|
|
static void main_frame_rate_debug(
|
|
void);
|
|
|
|
static void main_new_map(
|
|
struct game_options *options);
|
|
static void main_game_render(
|
|
double time_delta_since_tick_sec);
|
|
|
|
/* ---------- globals */
|
|
|
|
short global_difficulty_level = 1;
|
|
short player_spawn_count = 1;
|
|
boolean global_frame_rate_throttle = TRUE;
|
|
short global_screenshot_size = 1;
|
|
|
|
static char const *scenario_paths[10] =
|
|
{
|
|
"levels\\a10\\a10",
|
|
"levels\\a30\\a30",
|
|
"levels\\a50\\a50",
|
|
"levels\\b30\\b30",
|
|
"levels\\b40\\b40",
|
|
"levels\\c10\\c10",
|
|
"levels\\c20\\c20",
|
|
"levels\\c40\\c40",
|
|
"levels\\d20\\d20",
|
|
"levels\\d40\\d40"
|
|
};
|
|
|
|
static struct _main_globals main_globals = { 0 };
|
|
boolean debug_force_frame_rate_update = FALSE;
|
|
boolean debug_no_drawing = FALSE;
|
|
boolean debug_game_save = FALSE;
|
|
boolean debug_frame_rate = FALSE;
|
|
boolean display_framerate = FALSE;
|
|
boolean display_vblank_deltas = FALSE;
|
|
boolean display_precache_progress = FALSE;
|
|
struct _screenshot_and_framerate_globals global_screenshot_count = { 0 };
|
|
boolean debug_render_freeze;
|
|
|
|
/* ---------- public code */
|
|
|
|
real main_get_seconds_elapsed(
|
|
void)
|
|
{
|
|
return main_globals.seconds_elapsed;
|
|
}
|
|
|
|
boolean gamepad_button_is_down(
|
|
short button_index)
|
|
{
|
|
short gamepad_index;
|
|
boolean result = FALSE;
|
|
|
|
match_assert("c:\\halo\\SOURCE\\main\\main.c", 245,
|
|
button_index>=0 && button_index<NUMBER_OF_GAMEPAD_BUTTONS);
|
|
gamepad_index = 0;
|
|
|
|
do
|
|
{
|
|
if (input_has_gamepad(gamepad_index))
|
|
break;
|
|
|
|
gamepad_index++;
|
|
}
|
|
while (gamepad_index < MAXIMUM_GAMEPADS);
|
|
|
|
if (gamepad_index < MAXIMUM_GAMEPADS)
|
|
{
|
|
struct gamepad_state const *gamepad = input_get_gamepad_state(gamepad_index);
|
|
|
|
result = gamepad->buttons[button_index] > 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void create_local_players(
|
|
void)
|
|
{
|
|
short used_controllers[MAXIMUM_GAMEPADS];
|
|
short default_controllers[MAXIMUM_GAMEPADS];
|
|
short desired_controllers[MAXIMUM_GAMEPADS];
|
|
long i;
|
|
long j;
|
|
long player;
|
|
short gamepad_index;
|
|
|
|
if (main_globals.main_menu_scenario_loaded)
|
|
{
|
|
player = player_new(0, NONE, 0, NULL);
|
|
local_player_set_player_index(
|
|
0,
|
|
player);
|
|
}
|
|
else
|
|
{
|
|
csmemset(used_controllers, NONE, sizeof(used_controllers));
|
|
csmemset(desired_controllers, NONE, sizeof(desired_controllers));
|
|
default_controllers[0] = 0;
|
|
default_controllers[1] = 1;
|
|
default_controllers[2] = 2;
|
|
default_controllers[3] = 3;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
741,
|
|
game_connection() == _game_connection_local);
|
|
for (i = 0; i < player_spawn_count; i++)
|
|
{
|
|
gamepad_index =
|
|
player_ui_get_single_player_local_player_controller(i);
|
|
desired_controllers[i] = gamepad_index;
|
|
if (desired_controllers[i] == NONE)
|
|
desired_controllers[i] = default_controllers[i];
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
755,
|
|
(desired_controllers[i]>=0) && (desired_controllers[i]<MAXIMUM_GAMEPADS));
|
|
|
|
if (used_controllers[desired_controllers[i]] != NONE)
|
|
{
|
|
for (j = 0; j < MAXIMUM_GAMEPADS; j++)
|
|
{
|
|
if (used_controllers[j] == NONE)
|
|
{
|
|
desired_controllers[i] = (short)j;
|
|
used_controllers[(short)j] = (short)j;
|
|
break;
|
|
}
|
|
}
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
768,
|
|
j<MAXIMUM_GAMEPADS);
|
|
}
|
|
else
|
|
{
|
|
used_controllers[desired_controllers[i]] = desired_controllers[i];
|
|
}
|
|
}
|
|
|
|
qsort(
|
|
desired_controllers,
|
|
MAXIMUM_GAMEPADS,
|
|
sizeof(*desired_controllers),
|
|
(int (__cdecl *)(void const *, void const *))sort_desired_local_player_controllers);
|
|
for (i = 0; i < player_spawn_count; i++)
|
|
{
|
|
gamepad_index = desired_controllers[i];
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
784,
|
|
(gamepad_index>=0) && (gamepad_index<MAXIMUM_GAMEPADS));
|
|
player = player_new(0, NONE, gamepad_index, NULL);
|
|
local_player_set_player_index(
|
|
gamepad_index,
|
|
player);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void game_connection_set(
|
|
short connection)
|
|
{
|
|
main_globals.connection = connection;
|
|
return;
|
|
}
|
|
|
|
short game_connection(
|
|
void)
|
|
{
|
|
return main_globals.connection;
|
|
}
|
|
|
|
void main_disallow_persistent_storage(
|
|
void)
|
|
{
|
|
main_globals.allow_persistent_storage = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_defer_map_map_change(
|
|
void)
|
|
{
|
|
main_globals.defer_map_change = FALSE;
|
|
return;
|
|
}
|
|
|
|
char *main_get_map_name(
|
|
void)
|
|
{
|
|
return main_globals.soloplayer_map_name;
|
|
}
|
|
|
|
char *main_get_multiplayer_map_name(
|
|
void)
|
|
{
|
|
return main_globals.multiplayer_map_name;
|
|
}
|
|
|
|
short main_get_difficulty(
|
|
void)
|
|
{
|
|
return global_difficulty_level;
|
|
}
|
|
|
|
boolean main_saving_map(
|
|
void)
|
|
{
|
|
return main_globals.saving_map;
|
|
}
|
|
|
|
void main_save_cancel(
|
|
void)
|
|
{
|
|
main_globals.saving_map = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_won_map(
|
|
void)
|
|
{
|
|
main_globals.saving_map = FALSE;
|
|
main_globals.won_map = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_lost_map(
|
|
void)
|
|
{
|
|
main_globals.saving_map = FALSE;
|
|
main_globals.lost_map = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_stop_time(
|
|
void)
|
|
{
|
|
main_globals.halt_time_scale = FALSE;
|
|
main_globals.restart_time = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_start_time(
|
|
void)
|
|
{
|
|
main_globals.restart_time = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_reset_map(
|
|
void)
|
|
{
|
|
main_globals.switch_to_structure_bsp_index = NONE;
|
|
main_globals.saving_map = FALSE;
|
|
main_globals.reset_map = TRUE;
|
|
main_globals.lost_map = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_revert_map(
|
|
void)
|
|
{
|
|
main_globals.switch_to_structure_bsp_index = NONE;
|
|
main_globals.saving_map = FALSE;
|
|
main_globals.revert_map = TRUE;
|
|
main_globals.lost_map = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_skip_cinematic(
|
|
void)
|
|
{
|
|
main_globals.switch_to_structure_bsp_index = NONE;
|
|
main_globals.saving_map = FALSE;
|
|
main_globals.skip_cinematic = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_save_map_nonsafe(
|
|
void)
|
|
{
|
|
main_globals.saving_map = TRUE;
|
|
main_globals.save_map_safely = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_respawn(
|
|
boolean in_multiplayer)
|
|
{
|
|
main_globals.respawn = TRUE;
|
|
if (in_multiplayer)
|
|
main_globals.respawn_timer = 91;
|
|
return;
|
|
}
|
|
|
|
void main_save_core(
|
|
void)
|
|
{
|
|
main_globals.save_core = TRUE;
|
|
csstrcpy(main_globals.core_name, "core.bin");
|
|
return;
|
|
}
|
|
|
|
void main_save_core_name(
|
|
char const *core_name)
|
|
{
|
|
match_vwarn("c:\\halo\\SOURCE\\main\\main.c", 0x3a5, csstrlen(core_name) < 64, "warning, core file name will be truncated to 63 characters");
|
|
csstrncpy(main_globals.core_name, core_name, 63);
|
|
main_globals.save_core = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_load_core(
|
|
void)
|
|
{
|
|
main_globals.load_core = TRUE;
|
|
csstrcpy(main_globals.core_name, "core.bin");
|
|
return;
|
|
}
|
|
|
|
void main_load_core_at_startup(
|
|
void)
|
|
{
|
|
main_globals.load_core_at_startup = TRUE;
|
|
csstrcpy(main_globals.core_name, "core.bin");
|
|
return;
|
|
}
|
|
|
|
void main_load_core_name(
|
|
char const *core_name)
|
|
{
|
|
match_vwarn("c:\\halo\\SOURCE\\main\\main.c", 0x3c9, csstrlen(core_name) < 64, "warning, core file name will be truncated to 63 characters");
|
|
csstrncpy(main_globals.core_name, core_name, 63);
|
|
main_globals.load_core = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_load_core_name_at_startup(
|
|
char const *core_name)
|
|
{
|
|
match_vwarn("c:\\halo\\SOURCE\\main\\main.c", 0x3d7, csstrlen(core_name) < 64, "warning, core file name will be truncated to 63 characters");
|
|
csstrncpy(main_globals.core_name, core_name, 63);
|
|
main_globals.load_core_at_startup = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_switch_structure_bsp(
|
|
short structure_bsp_index)
|
|
{
|
|
struct scenario *scenario = global_scenario_get();
|
|
if (structure_bsp_index < 0 || structure_bsp_index >= scenario->structure_bsp_references.count)
|
|
{
|
|
console_warning("tried to switch to invalid structure-bsp %d", structure_bsp_index);
|
|
return;
|
|
}
|
|
if (structure_bsp_index == global_structure_bsp_index)
|
|
{
|
|
console_warning("tried to switch to current structure-bsp %d", structure_bsp_index);
|
|
return;
|
|
}
|
|
main_globals.switch_to_structure_bsp_index = structure_bsp_index;
|
|
hud_load(TRUE);
|
|
return;
|
|
}
|
|
|
|
void main_goto_main_menu(
|
|
void)
|
|
{
|
|
main_globals.switch_to_structure_bsp_index = NONE;
|
|
main_globals.saving_map = FALSE;
|
|
main_globals.want_to_be_at_main_menu = TRUE;
|
|
return;
|
|
}
|
|
|
|
static void main_queue_map_private(
|
|
void)
|
|
{
|
|
real progress;
|
|
if (cache_files_precache_in_progress() && cache_files_precache_map_status(&progress) == 1)
|
|
cache_files_precache_map_end();
|
|
if (!cache_files_precache_in_progress())
|
|
{
|
|
cache_files_precache_map_begin(main_globals.queued_map_name, FALSE);
|
|
main_globals.queue_map = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void main_menu_precache_resources(
|
|
void)
|
|
{
|
|
struct scenario *scenario = global_scenario_get();
|
|
if (scenario)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\main\\main.c", 0x46d, scenario->type==_scenario_type_main_menu);
|
|
predicted_resources_precache(&scenario->predicted_ui_resources);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void main_menu_unload(
|
|
void)
|
|
{
|
|
ui_stop_main_menu_music();
|
|
main_menu_active(FALSE);
|
|
main_globals.main_menu_scenario_loaded = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_menu_load(
|
|
void)
|
|
{
|
|
if (!main_globals.main_menu_scenario_loaded)
|
|
main_load_ui_scenario(FALSE);
|
|
main_screen_shell_load();
|
|
main_menu_precache_resources();
|
|
update_server_delete();
|
|
update_server_new();
|
|
update_server_start();
|
|
game_time_dispose_from_old_map();
|
|
game_time_initialize_for_new_map();
|
|
game_time_start();
|
|
hs_runtime_dispose_from_old_map();
|
|
hs_runtime_initialize_for_new_map();
|
|
main_globals.want_to_be_at_main_menu = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
static void screenshot_record(
|
|
struct bitmap_data *screen,
|
|
struct file_reference *file)
|
|
{
|
|
char const *error_message = tiff_export(file, screen);
|
|
|
|
if (error_message)
|
|
error(_error_silent, error_message);
|
|
return;
|
|
}
|
|
|
|
void set_window_camera_values(
|
|
struct render_window *window,
|
|
struct observer_result const *observer)
|
|
{
|
|
if (observer)
|
|
{
|
|
window->rasterizer_camera.position = observer->position;
|
|
window->rasterizer_camera.forward = observer->forward;
|
|
window->rasterizer_camera.up = observer->up;
|
|
window->rasterizer_camera.vertical_field_of_view =
|
|
2.0f * arctangent(
|
|
0.75f * render_camera_get_adjusted_field_of_view_tangent(
|
|
observer->field_of_view),
|
|
1.0f);
|
|
|
|
if (window->local_player_index != NONE &&
|
|
!console_is_active() &&
|
|
!game_time_get_paused() &&
|
|
director_get_perspective(window->local_player_index) !=
|
|
_director_perspective_neutral)
|
|
{
|
|
real_matrix4x3 effect_matrix;
|
|
real_matrix4x3 view_matrix;
|
|
|
|
player_effect_get_camera_effect_matrix(
|
|
window->local_player_index,
|
|
&effect_matrix);
|
|
matrix4x3_from_point_and_vectors(
|
|
&view_matrix,
|
|
&observer->position,
|
|
&observer->forward,
|
|
&observer->up);
|
|
matrix4x3_multiply(&view_matrix, &effect_matrix, &view_matrix);
|
|
matrix4x3_to_point_and_vectors(
|
|
&view_matrix,
|
|
&window->rasterizer_camera.position,
|
|
&window->rasterizer_camera.forward,
|
|
&window->rasterizer_camera.up);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
window->rasterizer_camera.position = *global_origin3d;
|
|
window->rasterizer_camera.forward = *global_forward3d;
|
|
window->rasterizer_camera.up = *global_up3d;
|
|
window->rasterizer_camera.vertical_field_of_view =
|
|
2.0f * arctangent(
|
|
0.75f * render_camera_get_adjusted_field_of_view_tangent(
|
|
DEGREES_TO_RADIANS(80.0f)),
|
|
1.0f);
|
|
}
|
|
|
|
window->rasterizer_camera.mirrored = FALSE;
|
|
window->rasterizer_camera.z_near = rasterizer_globals.near_clip_distance;
|
|
window->rasterizer_camera.z_far = rasterizer_globals.far_clip_distance;
|
|
if (!debug_render_freeze)
|
|
window->render_camera = window->rasterizer_camera;
|
|
|
|
return;
|
|
}
|
|
|
|
void main_present_frame(
|
|
void)
|
|
{
|
|
struct file_reference reference;
|
|
char path[512];
|
|
|
|
render_frame_present(NULL, main_globals.movie);
|
|
if (global_screenshot_count.count <= 0 && main_globals.movie)
|
|
{
|
|
_snprintf(
|
|
path,
|
|
NUMBEROF(path),
|
|
"movie\\frame%06d.tga",
|
|
main_globals.recording_frame_index++);
|
|
file_reference_create_from_path(&reference, path, FALSE);
|
|
screenshot_record(main_globals.movie, &reference);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void main_menu_ensure_player_queues_exist(
|
|
void)
|
|
{
|
|
update_server_delete();
|
|
update_server_new();
|
|
update_server_start();
|
|
return;
|
|
}
|
|
|
|
boolean main_menu_fade_active(
|
|
void)
|
|
{
|
|
return main_globals.map_change_load_timer != 0;
|
|
}
|
|
|
|
void main_menu_switch_to_single_player(
|
|
void)
|
|
{
|
|
main_globals.defer_map_change = TRUE;
|
|
return;
|
|
}
|
|
|
|
void main_set_game_connection_to_film_playback(
|
|
void)
|
|
{
|
|
main_globals.playback_last_recording = TRUE;
|
|
return;
|
|
}
|
|
|
|
short main_get_solo_level_from_name(
|
|
char const *name)
|
|
{
|
|
char lower_name[128] = { 0 };
|
|
short level;
|
|
|
|
csstrncpy(lower_name, name, NUMBEROF(lower_name) - 1);
|
|
lower_name[NUMBEROF(lower_name) - 1] = 0;
|
|
strlwr(lower_name);
|
|
|
|
if (strstr(lower_name, "a10"))
|
|
level = 0;
|
|
else if (strstr(lower_name, "a30"))
|
|
level = 1;
|
|
else if (strstr(lower_name, "a50"))
|
|
level = 2;
|
|
else if (strstr(lower_name, "b30"))
|
|
level = 3;
|
|
else if (strstr(lower_name, "b40"))
|
|
level = 4;
|
|
else if (strstr(lower_name, "c10"))
|
|
level = 5;
|
|
else if (strstr(lower_name, "c20"))
|
|
level = 6;
|
|
else if (strstr(lower_name, "c40"))
|
|
level = 7;
|
|
else if (strstr(lower_name, "d20"))
|
|
level = 8;
|
|
else
|
|
level = strstr(lower_name, "d40") ? 9 : NONE;
|
|
|
|
return level;
|
|
}
|
|
|
|
short main_get_current_solo_level(
|
|
void)
|
|
{
|
|
return main_get_solo_level_from_name(main_globals.soloplayer_map_name);
|
|
}
|
|
|
|
char const *main_get_solo_level_name(
|
|
short level)
|
|
{
|
|
char const *result = NULL;
|
|
|
|
if (level >= 0 && level < NUMBEROF(scenario_paths))
|
|
result = scenario_paths[level];
|
|
|
|
return result;
|
|
}
|
|
|
|
void main_run_demos(
|
|
void)
|
|
{
|
|
main_globals.run_xdemos = TRUE;
|
|
return;
|
|
}
|
|
|
|
static void compute_subframe_counts(
|
|
long num_players,
|
|
long *horizontal_count,
|
|
long *vertical_count)
|
|
{
|
|
long horizontal = 1;
|
|
long vertical = 1;
|
|
boolean split_horizontally = TRUE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
1308,
|
|
num_players>0);
|
|
while (horizontal*vertical<num_players)
|
|
{
|
|
boolean add_column = split_horizontally ? horizontal<vertical : horizontal<=vertical;
|
|
|
|
if (add_column)
|
|
{
|
|
horizontal++;
|
|
}
|
|
else
|
|
{
|
|
horizontal = 1;
|
|
vertical++;
|
|
}
|
|
}
|
|
|
|
*horizontal_count = horizontal;
|
|
*vertical_count = vertical;
|
|
return;
|
|
}
|
|
|
|
void compute_window_bounds(
|
|
long player_index,
|
|
long num_players,
|
|
rectangle2d *pixel_bounds,
|
|
rectangle2d *safe_frame_bounds)
|
|
{
|
|
long vertical_count;
|
|
long horizontal_count;
|
|
long horizontal_index;
|
|
long vertical_index;
|
|
long subframe_width;
|
|
long subframe_height;
|
|
short safe_frame_inset;
|
|
boolean first_player_spans_two_columns;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
1359,
|
|
player_index<num_players);
|
|
safe_frame_inset = num_players>1 ? 4 : 0;
|
|
first_player_spans_two_columns = FALSE;
|
|
compute_subframe_counts(
|
|
num_players,
|
|
&horizontal_count,
|
|
&vertical_count);
|
|
|
|
if (horizontal_count*vertical_count>num_players)
|
|
{
|
|
if (!player_index)
|
|
first_player_spans_two_columns = TRUE;
|
|
else
|
|
player_index++;
|
|
}
|
|
|
|
vertical_index = player_index/horizontal_count;
|
|
horizontal_index = player_index-vertical_index*horizontal_count;
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
1390,
|
|
vertical_index>=0 && vertical_index<vertical_count);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\main\\main.c",
|
|
1391,
|
|
horizontal_index>=0 && horizontal_index<horizontal_count);
|
|
|
|
subframe_height =
|
|
(rasterizer_globals.reserved04.frame_bounds.y1-
|
|
rasterizer_globals.reserved04.frame_bounds.y0)/vertical_count;
|
|
subframe_width =
|
|
(rasterizer_globals.reserved04.frame_bounds.x1-
|
|
rasterizer_globals.reserved04.frame_bounds.x0)/horizontal_count;
|
|
subframe_width *= first_player_spans_two_columns ? 2 : 1;
|
|
|
|
safe_frame_bounds->x0 =
|
|
subframe_width*horizontal_index+
|
|
rasterizer_globals.reserved04.frame_bounds.x0;
|
|
safe_frame_bounds->x1 =
|
|
subframe_width*(horizontal_index+1)+
|
|
rasterizer_globals.reserved04.frame_bounds.x0;
|
|
safe_frame_bounds->y0 =
|
|
subframe_height*vertical_index+
|
|
rasterizer_globals.reserved04.frame_bounds.y0;
|
|
safe_frame_bounds->y1 =
|
|
subframe_height*(vertical_index+1)+
|
|
rasterizer_globals.reserved04.frame_bounds.y0;
|
|
*pixel_bounds = *safe_frame_bounds;
|
|
|
|
safe_frame_bounds->x0 += horizontal_index*safe_frame_inset;
|
|
safe_frame_bounds->x1 -= (horizontal_index==0)*safe_frame_inset;
|
|
safe_frame_bounds->y0 += vertical_index*safe_frame_inset;
|
|
safe_frame_bounds->y1 -= (vertical_index==0)*safe_frame_inset;
|
|
|
|
if (!horizontal_index)
|
|
pixel_bounds->x0 = rasterizer_globals.reserved04.screen_bounds.x0;
|
|
if ((first_player_spans_two_columns!=FALSE)+horizontal_index+1==horizontal_count)
|
|
pixel_bounds->x1 = rasterizer_globals.reserved04.screen_bounds.x1;
|
|
if (!vertical_index)
|
|
pixel_bounds->y0 = rasterizer_globals.reserved04.screen_bounds.y0;
|
|
if (vertical_index+1==vertical_count)
|
|
pixel_bounds->y1 = rasterizer_globals.reserved04.screen_bounds.y1;
|
|
|
|
return;
|
|
}
|
|
|
|
short main_get_window_count(
|
|
void)
|
|
{
|
|
boolean single_window = game_engine_force_single_screen() || cinematic_in_progress();
|
|
|
|
return single_window ? 1 : PIN(local_player_count(), 1, MAXIMUM_WINDOWS);
|
|
}
|
|
|
|
static void main_new_map(
|
|
struct game_options *options)
|
|
{
|
|
input_flush();
|
|
if (game_load(options))
|
|
{
|
|
game_initialize_for_new_map();
|
|
}
|
|
else
|
|
{
|
|
error(_error_immediate, "game_load() failed.");
|
|
}
|
|
|
|
if (!errors_handle())
|
|
{
|
|
create_local_players();
|
|
game_time_start();
|
|
}
|
|
else
|
|
{
|
|
error(_error_immediate, "main_new_map() failed.");
|
|
}
|
|
game_initial_pulse();
|
|
|
|
main_globals.reset_map = FALSE;
|
|
main_globals.defer_map_change = FALSE;
|
|
main_globals.revert_map = FALSE;
|
|
main_globals.skip_cinematic = FALSE;
|
|
main_globals.saving_map = FALSE;
|
|
main_globals.won_map = FALSE;
|
|
main_globals.lost_map = FALSE;
|
|
main_globals.respawn = FALSE;
|
|
main_globals.save_core = FALSE;
|
|
main_globals.switch_to_structure_bsp_index = NONE;
|
|
main_globals.load_core = main_globals.load_core_at_startup;
|
|
main_globals.load_core_at_startup = FALSE;
|
|
|
|
if (main_globals.allow_persistent_storage)
|
|
game_state_try_and_load_from_persistent_storage();
|
|
ui_widgets_disable_pause_game(30);
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_change_map_name(
|
|
void)
|
|
{
|
|
if (main_globals.main_menu_scenario_loaded == TRUE)
|
|
{
|
|
if (!main_globals.map_change_load_timer)
|
|
{
|
|
if (ui_main_menu_music_active() == TRUE)
|
|
{
|
|
main_globals.map_change_load_timer =
|
|
main_globals.frame_start_milliseconds + 1000;
|
|
main_screen_shell_begin_fade(1000);
|
|
ui_widgets_inhibit_processing(TRUE);
|
|
ui_widgets_set_fade_value(0.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned long remaining_milliseconds =
|
|
main_globals.map_change_load_timer - main_globals.frame_start_milliseconds;
|
|
|
|
ui_widgets_set_fade_value(
|
|
1.0f - (real)remaining_milliseconds * 0.001f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
main_globals.map_change_load_timer = 0;
|
|
}
|
|
|
|
if (main_globals.frame_start_milliseconds >= main_globals.map_change_load_timer)
|
|
{
|
|
ui_widgets_set_fade_value(-1.0f);
|
|
ui_stop_main_menu_music();
|
|
main_menu_active(FALSE);
|
|
main_globals.main_menu_scenario_loaded = FALSE;
|
|
ui_widgets_inhibit_processing(FALSE);
|
|
|
|
if (game_in_progress() && main_globals.connection == _game_connection_local)
|
|
{
|
|
struct game_options options;
|
|
short local_player_index;
|
|
|
|
game_options_new(&options);
|
|
csstrncpy(
|
|
options.map_name,
|
|
main_globals.soloplayer_map_name,
|
|
NUMBEROF(options.map_name) - 1);
|
|
options.map_name[NUMBEROF(options.map_name) - 1] = 0;
|
|
options.difficulty = global_difficulty_level;
|
|
game_dispose_from_old_map();
|
|
game_precache_new_map(options.map_name, TRUE);
|
|
game_unload();
|
|
main_new_map(&options);
|
|
|
|
for (local_player_index = 0;
|
|
local_player_index < player_spawn_count;
|
|
local_player_index++)
|
|
{
|
|
player_profile_save_last_level_played(local_player_index);
|
|
}
|
|
}
|
|
|
|
main_globals.map_change_load_timer = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void main_set_multiplayer_map_name(
|
|
char const *map_name)
|
|
{
|
|
csstrncpy(main_globals.multiplayer_map_name, map_name, NUMBEROF(main_globals.multiplayer_map_name) - 1);
|
|
main_globals.multiplayer_map_name[NUMBEROF(main_globals.multiplayer_map_name) - 1] = 0;
|
|
cache_files_give_time_to_precache(main_globals.multiplayer_map_name);
|
|
return;
|
|
}
|
|
|
|
void main_set_difficulty(
|
|
short difficulty)
|
|
{
|
|
if (difficulty >= _game_difficulty_level_easy && difficulty < NUMBER_OF_GAME_DIFFICULTY_LEVELS)
|
|
global_difficulty_level = difficulty;
|
|
return;
|
|
}
|
|
|
|
static long sort_desired_local_player_controllers(
|
|
short const *a,
|
|
short const *b)
|
|
{
|
|
short value_a = *a;
|
|
short value_b = *b;
|
|
if (value_a == NONE && value_b != value_a)
|
|
return 1;
|
|
if (value_a != NONE && value_b == NONE)
|
|
return -1;
|
|
if (value_a > value_b)
|
|
return 1;
|
|
return (value_a >= value_b) - 1;
|
|
}
|
|
|
|
void main_save_map_safe(
|
|
void)
|
|
{
|
|
if (!main_globals.saving_map || main_globals.save_map_timeout)
|
|
{
|
|
main_globals.saving_map = TRUE;
|
|
main_globals.save_map_safely = TRUE;
|
|
main_globals.save_map_timeout = TRUE;
|
|
main_globals.ticks_until_next_save_check = 0;
|
|
main_globals.ticks_unable_to_save = 0;
|
|
main_globals.safe_intervals = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void main_save_map_no_timeout(
|
|
void)
|
|
{
|
|
if (!main_globals.saving_map || main_globals.save_map_timeout)
|
|
{
|
|
main_globals.saving_map = TRUE;
|
|
main_globals.save_map_safely = TRUE;
|
|
main_globals.ticks_until_next_save_check = 0;
|
|
main_globals.ticks_unable_to_save = 0;
|
|
main_globals.safe_intervals = 0;
|
|
}
|
|
main_globals.save_map_timeout = FALSE;
|
|
return;
|
|
}
|
|
|
|
void main_skip(
|
|
short ticks)
|
|
{
|
|
if (ticks <= 15)
|
|
{
|
|
main_globals.skip_ticks = ticks;
|
|
main_globals.skip = TRUE;
|
|
}
|
|
else
|
|
{
|
|
error(_error_silent, "cannot skip more than 15 frames (half a second)");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void main_queue_map_name(
|
|
char const *map_name)
|
|
{
|
|
if (map_name)
|
|
{
|
|
csstrncpy(main_globals.queued_map_name, map_name, NUMBEROF(main_globals.queued_map_name) - 1);
|
|
main_globals.queue_map = TRUE;
|
|
}
|
|
else
|
|
{
|
|
main_globals.queued_map_name[0] = 0;
|
|
main_globals.queue_map = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
boolean main_taking_screenshot(
|
|
void)
|
|
{
|
|
return global_screenshot_count.count > 0 || main_globals.movie != NULL;
|
|
}
|
|
|
|
void main_movie_start(
|
|
real frames_per_second)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\main\\main.c", 2715, main_globals.movie==NULL);
|
|
|
|
main_globals.movie = bitmap_2d_new(640, 480, 0, 10);
|
|
if (main_globals.movie)
|
|
{
|
|
directory_create_or_delete_contents("movie");
|
|
main_globals.recording_frame_index = 0;
|
|
if (frames_per_second > 0.0001f)
|
|
main_globals.recording_dt = 1.0f / frames_per_second;
|
|
else
|
|
main_globals.recording_dt = 1.0f / 30.0f;
|
|
game_time_set_speed(1.0f);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void main_movie_stop(
|
|
void)
|
|
{
|
|
if (main_globals.movie)
|
|
{
|
|
bitmap_delete(main_globals.movie);
|
|
main_globals.movie = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void main_crash(
|
|
char const *str)
|
|
{
|
|
/* BUG (original, deliberate): the "crash" script command ("crashes (for debugging).")
|
|
* faults on purpose by storing this literal through the null pointer; the August and
|
|
* September 2001 builds (debug and retail) and January all emit this one store. */
|
|
*(char **)NULL = "chucky was here! NULL belongs to me!!!!!";
|
|
return;
|
|
}
|
|
|
|
void main_print_version(
|
|
void)
|
|
{
|
|
console_printf(FALSE, "halobeta xbox 01.01.14.2342 Jan 14 2002 12:49:20");
|
|
return;
|
|
}
|
|
|
|
void main_vertical_blank_interrupt_handler(
|
|
unsigned long context)
|
|
{
|
|
rasterizer_globals.frame_and_vertical_blank_index++;
|
|
if (!main_globals.d3d_flip_count)
|
|
{
|
|
rasterizer_globals.previous_frame_and_vertical_blank_index =
|
|
rasterizer_globals.frame_and_vertical_blank_index;
|
|
}
|
|
else if (*main_globals.d3d_flip_count != rasterizer_globals.d3d_flip_count)
|
|
{
|
|
main_globals.vblank_flip_deltas[main_globals.vblank_flip_delta_index] =
|
|
(short)((short)rasterizer_globals.frame_and_vertical_blank_index -
|
|
(short)rasterizer_globals.previous_frame_and_vertical_blank_index);
|
|
main_globals.vblank_flip_delta_index =
|
|
(short)((main_globals.vblank_flip_delta_index + 1) % 15);
|
|
rasterizer_globals.previous_frame_and_vertical_blank_index =
|
|
rasterizer_globals.frame_and_vertical_blank_index;
|
|
rasterizer_globals.d3d_flip_count = *main_globals.d3d_flip_count;
|
|
}
|
|
|
|
input_vertical_blank_interrupt();
|
|
return;
|
|
}
|
|
|
|
void main_save_current_solo_map(
|
|
char const *map_name)
|
|
{
|
|
FILE *file;
|
|
|
|
if ((short)main_get_solo_level_from_name(map_name) != NONE)
|
|
{
|
|
file = fopen("z:\\last_solo.txt", "w");
|
|
if (file)
|
|
{
|
|
fwrite(map_name, 1, csstrlen(map_name) + 1, file);
|
|
fclose(file);
|
|
}
|
|
else
|
|
{
|
|
error(_error_silent, "Couldn't create a file to write the current solo map to");
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void main_load_last_solo_map(
|
|
void)
|
|
{
|
|
char map_name[256];
|
|
boolean valid_map_name = FALSE;
|
|
|
|
if (main_globals.load_last_solo_level && !bink_playback_active())
|
|
{
|
|
FILE *file;
|
|
|
|
file = fopen("z:\\last_solo.txt", "r");
|
|
|
|
if (file)
|
|
{
|
|
long character_count;
|
|
|
|
character_count = fread(map_name, 1, 255, file);
|
|
fclose(file);
|
|
map_name[MIN(character_count, 255)] = 0;
|
|
valid_map_name = main_get_solo_level_from_name(map_name) != NONE;
|
|
}
|
|
|
|
if (valid_map_name)
|
|
main_set_map_name(map_name);
|
|
else
|
|
main_set_map_name(scenario_paths[0]);
|
|
main_globals.defer_map_change = FALSE;
|
|
main_globals.load_last_solo_level = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void main_load_ui_scenario(
|
|
boolean precache_resources)
|
|
{
|
|
struct game_options options;
|
|
|
|
game_precache_new_map("levels\\ui\\ui", TRUE);
|
|
match_assert("c:\\halo\\SOURCE\\main\\main.c", 1092,
|
|
!main_globals.main_menu_scenario_loaded);
|
|
game_options_new(&options);
|
|
csstrncpy(options.map_name, "levels\\ui\\ui", NUMBEROF(options.map_name) - 1);
|
|
options.map_name[NUMBEROF(options.map_name) - 1] = 0;
|
|
game_precache_new_map(options.map_name, TRUE);
|
|
game_dispose_from_old_map();
|
|
game_unload();
|
|
game_engine_dispose();
|
|
game_set_game_variant(NULL);
|
|
main_globals.main_menu_scenario_loaded = TRUE;
|
|
main_new_map(&options);
|
|
director_script_camera(TRUE);
|
|
scripted_camera_set(0, 0, NONE);
|
|
main_menu_active(TRUE);
|
|
main_globals.load_last_solo_level = TRUE;
|
|
if (precache_resources)
|
|
main_menu_precache_resources();
|
|
|
|
return;
|
|
}
|
|
|
|
void main_roll_credits(
|
|
void)
|
|
{
|
|
error(_error_silent, "congratulations, you won the game!");
|
|
main_menu_load();
|
|
game_end_credits_start();
|
|
return;
|
|
}
|
|
|
|
void main_pregame_render(
|
|
void)
|
|
{
|
|
/* Name, type and function scope from the 2003 PC demo PDB and the HCEX PDB (static local
|
|
struct render_window window of main_pregame_render). Neither PDB records the block: placing it
|
|
at the top of the function is unattested. January corroborates: .bss +0, the 0xAC-byte window
|
|
padded to 0xB0 before main_globals, referenced only by this function. */
|
|
static struct render_window window;
|
|
|
|
collision_log_continue_period(TRUE);
|
|
sound_render();
|
|
{
|
|
real_point3d position = { 0.0f, 0.0f, 0.0f };
|
|
real_vector3d forward = { 0.0f, 0.0f, 1.0f };
|
|
real_vector3d up = { 0.0f, 1.0f, 0.0f };
|
|
|
|
window.local_player_index = NONE;
|
|
window.console_window = TRUE;
|
|
window.rasterizer_camera.position = position;
|
|
window.rasterizer_camera.forward = forward;
|
|
window.rasterizer_camera.up = up;
|
|
window.rasterizer_camera.mirrored = FALSE;
|
|
window.rasterizer_camera.vertical_field_of_view =
|
|
2.0f * arctangent(
|
|
0.75f * render_camera_get_adjusted_field_of_view_tangent(
|
|
DEGREES_TO_RADIANS(80.0f)),
|
|
1.0f);
|
|
compute_window_bounds(
|
|
0,
|
|
1,
|
|
&window.rasterizer_camera.viewport_bounds,
|
|
&window.rasterizer_camera.window_bounds);
|
|
window.rasterizer_camera.z_near = 0.01f;
|
|
window.rasterizer_camera.z_far = 1.0f;
|
|
window.render_camera = window.rasterizer_camera;
|
|
render_frame_pregame(
|
|
&window,
|
|
main_globals.movie);
|
|
}
|
|
collision_log_end_period();
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_revert_map_private(
|
|
void)
|
|
{
|
|
game_state_revert();
|
|
ui_widgets_disable_pause_game(30);
|
|
main_globals.revert_map = FALSE;
|
|
return;
|
|
}
|
|
|
|
static void main_skip_cinematic_private(
|
|
void)
|
|
{
|
|
if (cinematic_can_be_skipped())
|
|
{
|
|
game_state_revert();
|
|
ui_widgets_disable_pause_game(30);
|
|
main_globals.revert_map = FALSE;
|
|
}
|
|
main_globals.skip_cinematic = FALSE;
|
|
return;
|
|
}
|
|
|
|
static void main_skip_private(
|
|
void)
|
|
{
|
|
if (main_globals.skip_ticks && cinematic_in_progress())
|
|
{
|
|
real saved_speed = game_time_get_speed();
|
|
|
|
game_time_set_speed(1.0f);
|
|
while (main_globals.skip_ticks-- > 0)
|
|
game_time_update(1.0f / TICKS_PER_SECOND);
|
|
game_time_set_speed(saved_speed);
|
|
}
|
|
else
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"manual skipping doesn't work outside of cinemtatic start/stop...");
|
|
}
|
|
|
|
main_globals.skip_ticks = 0;
|
|
main_globals.skip = FALSE;
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_saving_map_private(
|
|
void)
|
|
{
|
|
game_state_save();
|
|
hud_autosave(FALSE);
|
|
main_globals.save_map_completed = FALSE;
|
|
return;
|
|
}
|
|
|
|
static void main_save_map_private(
|
|
void)
|
|
{
|
|
if (!game_time_get_paused())
|
|
{
|
|
boolean save_map_safely = main_globals.save_map_safely;
|
|
boolean save_map = FALSE;
|
|
|
|
if (save_map_safely)
|
|
{
|
|
if (main_globals.ticks_unable_to_save++ >= 240 &&
|
|
main_globals.save_map_timeout)
|
|
{
|
|
if (debug_game_save)
|
|
console_printf(FALSE, "gave up trying to save");
|
|
main_globals.saving_map = FALSE;
|
|
return;
|
|
}
|
|
else if (main_globals.ticks_until_next_save_check-- <= 0)
|
|
{
|
|
if (game_safe_to_save())
|
|
{
|
|
if (main_globals.safe_intervals++ >= 3)
|
|
save_map = TRUE;
|
|
}
|
|
else
|
|
{
|
|
main_globals.safe_intervals = 0;
|
|
}
|
|
main_globals.ticks_until_next_save_check = 10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (debug_game_save)
|
|
console_printf(FALSE, "unsafe save");
|
|
save_map = TRUE;
|
|
}
|
|
|
|
if (save_map)
|
|
{
|
|
hud_autosave(TRUE);
|
|
main_globals.save_map_completed = TRUE;
|
|
main_globals.saving_map = FALSE;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_switch_to_structure_bsp_private(
|
|
void)
|
|
{
|
|
scenario_switch_structure_bsp(main_globals.switch_to_structure_bsp_index);
|
|
main_globals.switch_to_structure_bsp_index = NONE;
|
|
hud_load(0);
|
|
return;
|
|
}
|
|
|
|
static void main_lost_map_private(
|
|
void)
|
|
{
|
|
if (!game_time_get_paused())
|
|
{
|
|
if (main_globals.loss_timer++ > 90)
|
|
{
|
|
main_globals.lost_map = FALSE;
|
|
main_globals.loss_timer = 0;
|
|
game_state_revert();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void main_respawn_private(
|
|
void)
|
|
{
|
|
if (!game_time_get_paused() && !cinematic_in_progress())
|
|
{
|
|
if (main_globals.respawn_timer++ > 90 && players_respawn_coop())
|
|
{
|
|
main_globals.respawn = FALSE;
|
|
main_globals.respawn_timer = 0;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void main_load_core_private(
|
|
void)
|
|
{
|
|
game_state_load_core(main_globals.core_name);
|
|
main_globals.load_core = FALSE;
|
|
return;
|
|
}
|
|
|
|
static void main_save_core_private(
|
|
void)
|
|
{
|
|
game_state_save_core(main_globals.core_name);
|
|
main_globals.save_core = FALSE;
|
|
return;
|
|
}
|
|
|
|
static void main_run_demos_private(
|
|
void)
|
|
{
|
|
main_globals.run_xdemos = FALSE;
|
|
xbox_demos_launch();
|
|
return;
|
|
}
|
|
|
|
static void main_frame_rate_debug(
|
|
void)
|
|
{
|
|
char sample_index;
|
|
|
|
if (global_screenshot_count.framerate_reset)
|
|
{
|
|
if (debug_frame_rate)
|
|
{
|
|
sample_index = global_screenshot_count.framerate_sample_index;
|
|
}
|
|
else
|
|
{
|
|
global_screenshot_count.framerate_reset = FALSE;
|
|
csmemset(
|
|
global_screenshot_count.framerate_samples,
|
|
0,
|
|
sizeof(global_screenshot_count.framerate_samples));
|
|
sample_index = 0;
|
|
global_screenshot_count.framerate_flags = 0;
|
|
global_screenshot_count.framerate_sample_index = sample_index;
|
|
global_screenshot_count.framerate_active = FALSE;
|
|
global_screenshot_count.framerate_counter = 0;
|
|
global_screenshot_count.framerate_reset = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sample_index = global_screenshot_count.framerate_sample_index;
|
|
}
|
|
|
|
if (debug_frame_rate)
|
|
{
|
|
global_screenshot_count.framerate_samples[sample_index] =
|
|
main_globals.seconds_elapsed;
|
|
SET_FLAG(
|
|
global_screenshot_count.framerate_flags,
|
|
sample_index,
|
|
main_globals.seconds_elapsed > 1.08/TICKS_PER_SECOND);
|
|
|
|
sample_index++;
|
|
sample_index = (char)(sample_index % (long)NUMBEROF(global_screenshot_count.framerate_samples));
|
|
global_screenshot_count.framerate_sample_index = sample_index;
|
|
global_screenshot_count.framerate_reset = TRUE;
|
|
|
|
if (global_screenshot_count.framerate_active)
|
|
{
|
|
if (global_screenshot_count.framerate_sample_index == 0)
|
|
{
|
|
if (global_screenshot_count.framerate_flags == 0)
|
|
{
|
|
if (++global_screenshot_count.framerate_counter >= 60)
|
|
{
|
|
global_screenshot_count.framerate_counter = 0;
|
|
global_screenshot_count.framerate_active = FALSE;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
global_screenshot_count.framerate_counter = 0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (global_screenshot_count.framerate_flags == 0xFF)
|
|
{
|
|
SYSTEMTIME system_time;
|
|
char core_name[256];
|
|
char init_file_name[260];
|
|
char const *scenario_name =
|
|
tag_name_strip_path(tag_get_name(global_scenario_index));
|
|
FILE *file;
|
|
|
|
GetSystemTime(&system_time);
|
|
sprintf(
|
|
core_name,
|
|
"%s_slow_%d_%d_%d_%d_%d_%d.bin",
|
|
scenario_name,
|
|
system_time.wMonth,
|
|
system_time.wDay,
|
|
system_time.wYear,
|
|
system_time.wHour,
|
|
system_time.wMinute,
|
|
system_time.wSecond);
|
|
game_state_save_core(core_name);
|
|
sprintf(init_file_name, "d:\\%s_init.txt", scenario_name);
|
|
|
|
file = fopen(init_file_name, "r");
|
|
if (!file)
|
|
{
|
|
file = fopen(init_file_name, "wt");
|
|
fprintf(file, "map_name %s\n", scenario_name);
|
|
}
|
|
else
|
|
{
|
|
fclose(file);
|
|
file = fopen(init_file_name, "a+t");
|
|
}
|
|
|
|
fprintf(file, ";core_load_name_at_startup %s\n", core_name);
|
|
fflush(file);
|
|
fclose(file);
|
|
global_screenshot_count.framerate_active = TRUE;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_won_map_private(
|
|
void)
|
|
{
|
|
short level;
|
|
short local_player_index;
|
|
main_globals.want_to_be_at_main_menu = TRUE;
|
|
main_globals.won_map = FALSE;
|
|
level = main_get_solo_level_from_name(main_globals.soloplayer_map_name) + 1;
|
|
if (level >= 10)
|
|
level = NONE;
|
|
for (local_player_index = 0; local_player_index < player_spawn_count; local_player_index++)
|
|
player_profile_save_level_completed(local_player_index);
|
|
ui_set_next_level(level);
|
|
return;
|
|
}
|
|
|
|
void main_set_map_name(
|
|
char const *map_name)
|
|
{
|
|
main_globals.want_to_be_at_main_menu = FALSE;
|
|
csstrncpy(main_globals.soloplayer_map_name, map_name, NUMBEROF(main_globals.soloplayer_map_name) - 1);
|
|
main_globals.soloplayer_map_name[NUMBEROF(main_globals.soloplayer_map_name) - 1] = 0;
|
|
main_globals.allow_persistent_storage = TRUE;
|
|
if ((game_in_editor() || game_in_progress()) && main_globals.connection == _game_connection_local)
|
|
main_globals.defer_map_change = TRUE;
|
|
return;
|
|
}
|
|
|
|
static void main_exit(
|
|
void)
|
|
{
|
|
switch (main_globals.connection)
|
|
{
|
|
case _game_connection_network_server:
|
|
dispose_global_network_game_client();
|
|
dispose_global_network_game_server();
|
|
break;
|
|
case _game_connection_network_client:
|
|
dispose_global_network_game_client();
|
|
break;
|
|
}
|
|
|
|
game_dispose_from_old_map();
|
|
game_dispose();
|
|
debug_keys_dispose();
|
|
console_dispose();
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_reset_time(
|
|
void)
|
|
{
|
|
main_globals.frame_start_milliseconds = system_milliseconds();
|
|
main_globals.rasterizer_target_index = rasterizer_globals.vertical_blank_index;
|
|
return;
|
|
}
|
|
|
|
static boolean main_framerate_throttle_enabled(
|
|
void)
|
|
{
|
|
return rasterizer_globals.framerate_throttle;
|
|
}
|
|
|
|
/* The native ports draw a frame whenever the display can show one, paced
|
|
by vsync, and frames fall between the 30 Hz ticks
|
|
(port/linux/game/render_interpolation.c): no vertical blank throttle, and
|
|
the frame is timed with the performance counter. */
|
|
static void main_update_time_unthrottled(
|
|
void)
|
|
{
|
|
static LARGE_INTEGER previous_counter;
|
|
LARGE_INTEGER counter;
|
|
LARGE_INTEGER frequency;
|
|
real seconds_elapsed = 0.0f;
|
|
|
|
QueryPerformanceCounter(&counter);
|
|
QueryPerformanceFrequency(&frequency);
|
|
if (previous_counter.QuadPart && frequency.QuadPart)
|
|
{
|
|
seconds_elapsed = (real)((double)(counter.QuadPart - previous_counter.QuadPart) /
|
|
(double)frequency.QuadPart);
|
|
}
|
|
previous_counter = counter;
|
|
#ifdef HALO_VR
|
|
{
|
|
double display_seconds;
|
|
|
|
/* in the headset, the step between the frames' display times
|
|
(port/linux/src/vr_frame.c) */
|
|
if (vr_frame_seconds(&display_seconds))
|
|
seconds_elapsed = (real)display_seconds;
|
|
}
|
|
#endif
|
|
|
|
if (main_globals.movie)
|
|
{
|
|
seconds_elapsed = main_globals.recording_dt;
|
|
}
|
|
else
|
|
{
|
|
seconds_elapsed = PIN(seconds_elapsed, 0.0f, 1.0f);
|
|
if (main_globals.connection == _game_connection_local)
|
|
{
|
|
if (debug_force_frame_rate_update)
|
|
seconds_elapsed = CEILING(seconds_elapsed, 0.03333333507180214f);
|
|
else
|
|
seconds_elapsed = CEILING(seconds_elapsed, 0.06666667014360428f);
|
|
}
|
|
}
|
|
|
|
main_globals.frame_start_milliseconds = system_milliseconds();
|
|
main_globals.seconds_elapsed = seconds_elapsed;
|
|
profile_seconds_elapsed(seconds_elapsed);
|
|
main_globals.rasterizer_initial_index =
|
|
rasterizer_globals.frame_and_vertical_blank_index;
|
|
}
|
|
|
|
static void main_update_time(
|
|
void)
|
|
{
|
|
unsigned long end_milliseconds;
|
|
long milliseconds_elapsed;
|
|
short requested_rate;
|
|
short requested_interval;
|
|
short elapsed_game_ticks;
|
|
short slot;
|
|
boolean framerate_throttle;
|
|
__int64 target_index;
|
|
__int64 minimum_target_index;
|
|
short short_target_index;
|
|
real seconds_elapsed;
|
|
|
|
if (halo_interpolation_enabled())
|
|
{
|
|
main_update_time_unthrottled();
|
|
return;
|
|
}
|
|
end_milliseconds = system_milliseconds();
|
|
minimum_target_index = MAX(
|
|
main_globals.rasterizer_target_index,
|
|
main_globals.rasterizer_throttle_end_index);
|
|
target_index = minimum_target_index;
|
|
framerate_throttle = main_framerate_throttle_enabled();
|
|
|
|
if (framerate_throttle)
|
|
{
|
|
csstrcpy(main_globals.vblank_debug_string, "");
|
|
if (global_frame_rate_throttle && rasterizer_globals.framerate_throttle_target >= 0)
|
|
{
|
|
requested_interval = (short)(
|
|
60 / (rasterizer_globals.framerate_throttle_target ? rasterizer_globals.framerate_throttle_target : 30));
|
|
main_globals.vblank_interval_requested = requested_interval;
|
|
|
|
if (rasterizer_globals.framerate_throttle_debug)
|
|
{
|
|
short best_interval;
|
|
short current_interval;
|
|
|
|
elapsed_game_ticks = game_time_get_elapsed();
|
|
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
"last%6I64d init%6I64d achv%6I64d pres%6I64d g%d cur%d... ",
|
|
main_globals.rasterizer_target_index,
|
|
main_globals.rasterizer_initial_index,
|
|
main_globals.rasterizer_throttle_start_index,
|
|
main_globals.rasterizer_throttle_end_index,
|
|
elapsed_game_ticks,
|
|
main_globals.vblank_interval_current);
|
|
|
|
best_interval = 5;
|
|
short_target_index = (short)minimum_target_index;
|
|
for (slot = 5; slot > 0; slot--)
|
|
{
|
|
short displayed_failure_count;
|
|
short target_age;
|
|
short slot_bucket;
|
|
boolean ignore_failure;
|
|
char const *label;
|
|
__int64 last_failure_index;
|
|
__int64 target_age_raw;
|
|
|
|
ignore_failure = FALSE;
|
|
displayed_failure_count = main_globals.vblank_failure_counts[slot];
|
|
if (displayed_failure_count >= 99)
|
|
displayed_failure_count = 99;
|
|
|
|
last_failure_index = main_globals.vblank_last_failure_indices[slot];
|
|
target_age_raw = short_target_index - last_failure_index;
|
|
if (target_age_raw < 99)
|
|
target_age = (short)target_age_raw;
|
|
else
|
|
target_age = 99;
|
|
|
|
slot_bucket = (short)((slot + 1) / 2);
|
|
current_interval = main_globals.vblank_interval_current;
|
|
if ((short)((current_interval + 1) / 2) > slot_bucket &&
|
|
(short)(current_interval / 2) <= slot_bucket &&
|
|
elapsed_game_ticks > slot_bucket)
|
|
{
|
|
ignore_failure = TRUE;
|
|
}
|
|
|
|
if (main_globals.rasterizer_throttle_start_index >
|
|
main_globals.rasterizer_initial_index + slot)
|
|
{
|
|
if (!ignore_failure)
|
|
{
|
|
long failure_count;
|
|
|
|
failure_count = main_globals.vblank_failure_counts[slot];
|
|
main_globals.vblank_failure_counts[slot] =
|
|
(short)(failure_count + 1);
|
|
main_globals.vblank_last_failure_indices[slot] = minimum_target_index;
|
|
}
|
|
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
"(%s%2d) ",
|
|
ignore_failure ? "ignor" : "fail ",
|
|
displayed_failure_count);
|
|
}
|
|
else
|
|
{
|
|
if (minimum_target_index >= last_failure_index + 15)
|
|
{
|
|
main_globals.vblank_failure_counts[slot] = 0;
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
"(ok %2d) ",
|
|
target_age);
|
|
}
|
|
else
|
|
{
|
|
label = main_globals.vblank_failure_counts[slot] >= 4 ? "dn" : "wt";
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
"(%s%2d/%2d) ",
|
|
label,
|
|
displayed_failure_count,
|
|
target_age);
|
|
}
|
|
}
|
|
|
|
if (slot >= main_globals.vblank_interval_requested &&
|
|
main_globals.vblank_failure_counts[slot] < 4)
|
|
{
|
|
best_interval = slot;
|
|
}
|
|
}
|
|
|
|
if (best_interval == 0)
|
|
requested_rate = 999;
|
|
else
|
|
requested_rate = (short)(60 / best_interval);
|
|
|
|
if (main_globals.vblank_interval_current < best_interval)
|
|
{
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
" FAILDOWN %d",
|
|
requested_rate);
|
|
}
|
|
else if (best_interval < main_globals.vblank_interval_current)
|
|
{
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
" RESTORE %d",
|
|
requested_rate);
|
|
}
|
|
else
|
|
{
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
" MAINTAIN %d",
|
|
requested_rate);
|
|
}
|
|
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
" des %d targ%6I64d",
|
|
best_interval,
|
|
minimum_target_index + best_interval);
|
|
main_globals.vblank_interval_current = best_interval;
|
|
}
|
|
else
|
|
{
|
|
main_globals.vblank_interval_current = requested_interval;
|
|
}
|
|
|
|
target_index += main_globals.vblank_interval_current;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
milliseconds_elapsed = (long)(real)(
|
|
(long)end_milliseconds - (long)main_globals.frame_start_milliseconds);
|
|
main_globals.vblank_interval_held = FALSE;
|
|
if (milliseconds_elapsed < 33)
|
|
{
|
|
profile_idle_start();
|
|
if (global_frame_rate_throttle)
|
|
Sleep(33 - milliseconds_elapsed);
|
|
profile_idle_end();
|
|
}
|
|
else
|
|
{
|
|
profile_lapsed_msec(milliseconds_elapsed - 33);
|
|
}
|
|
}
|
|
|
|
end_milliseconds = system_milliseconds();
|
|
if ((__int64)rasterizer_globals.frame_and_vertical_blank_index > target_index)
|
|
target_index = (__int64)rasterizer_globals.frame_and_vertical_blank_index;
|
|
|
|
if (framerate_throttle)
|
|
{
|
|
seconds_elapsed =
|
|
(real)(target_index - (__int64)main_globals.rasterizer_target_index) *
|
|
0.01666666753590107f;
|
|
}
|
|
else
|
|
{
|
|
seconds_elapsed =
|
|
(real)(end_milliseconds - main_globals.frame_start_milliseconds) *
|
|
0.001000000047497451f;
|
|
}
|
|
|
|
if (main_globals.movie)
|
|
{
|
|
seconds_elapsed = main_globals.recording_dt;
|
|
}
|
|
else
|
|
{
|
|
seconds_elapsed = PIN(seconds_elapsed, 0.0f, 1.0f);
|
|
if (main_globals.connection == _game_connection_local)
|
|
{
|
|
if (debug_force_frame_rate_update)
|
|
seconds_elapsed = CEILING(seconds_elapsed, 0.03333333507180214f);
|
|
else
|
|
seconds_elapsed = CEILING(seconds_elapsed, 0.06666667014360428f);
|
|
}
|
|
}
|
|
|
|
main_globals.frame_start_milliseconds = end_milliseconds;
|
|
main_globals.rasterizer_target_index = target_index;
|
|
main_globals.seconds_elapsed = seconds_elapsed;
|
|
profile_seconds_elapsed(seconds_elapsed);
|
|
main_globals.rasterizer_initial_index =
|
|
rasterizer_globals.frame_and_vertical_blank_index;
|
|
|
|
return;
|
|
}
|
|
|
|
void main_rasterizer_throttle(
|
|
void)
|
|
{
|
|
__int64 entry_index;
|
|
__int64 target_index;
|
|
__int64 end_index;
|
|
__int64 index_delta;
|
|
__int64 elapsed_index;
|
|
unsigned long start_milliseconds;
|
|
short lapsed_frames;
|
|
boolean did_throttle;
|
|
boolean precache_in_progress;
|
|
boolean synchronized;
|
|
char const *description;
|
|
|
|
entry_index = rasterizer_globals.frame_and_vertical_blank_index;
|
|
did_throttle = FALSE;
|
|
main_globals.rasterizer_throttle_start_index =
|
|
rasterizer_globals.frame_and_vertical_blank_index + 1;
|
|
if (rasterizer_globals.framerate_throttle && !halo_interpolation_enabled())
|
|
{
|
|
target_index = main_globals.rasterizer_target_index;
|
|
target_index--;
|
|
if ((__int64)rasterizer_globals.frame_and_vertical_blank_index < target_index)
|
|
{
|
|
start_milliseconds = system_milliseconds();
|
|
precache_in_progress = cache_files_precache_in_progress();
|
|
did_throttle = TRUE;
|
|
profile_idle_start();
|
|
while ((__int64)rasterizer_globals.frame_and_vertical_blank_index < target_index)
|
|
{
|
|
if (precache_in_progress)
|
|
{
|
|
Sleep(1);
|
|
}
|
|
if (system_milliseconds() > start_milliseconds + 1000)
|
|
{
|
|
console_warning(
|
|
"stuck waiting for VBLANK callback! disabling rasterizer framerate control");
|
|
rasterizer_globals.framerate_throttle = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
profile_idle_end();
|
|
}
|
|
}
|
|
|
|
end_index = rasterizer_globals.frame_and_vertical_blank_index + 1;
|
|
synchronized =
|
|
main_globals.vblank_interval_current == main_globals.vblank_interval_requested;
|
|
main_globals.rasterizer_throttle_end_index = end_index;
|
|
index_delta = end_index - main_globals.rasterizer_target_index;
|
|
lapsed_frames = (short)PIN(index_delta, 0, 0x7FFF);
|
|
|
|
if (did_throttle)
|
|
{
|
|
elapsed_index = rasterizer_globals.frame_and_vertical_blank_index - entry_index;
|
|
description = "THROTTLE";
|
|
}
|
|
else
|
|
{
|
|
elapsed_index = lapsed_frames;
|
|
description = lapsed_frames == 0 ? "SYNCED " : "LAPSED ";
|
|
}
|
|
|
|
_snprintf(
|
|
main_globals.vblank_debug_string + csstrlen(main_globals.vblank_debug_string),
|
|
sizeof(main_globals.vblank_debug_string) - csstrlen(main_globals.vblank_debug_string),
|
|
"%6I64d(targ%6I64d %s%2d)",
|
|
entry_index,
|
|
main_globals.rasterizer_target_index,
|
|
description,
|
|
elapsed_index);
|
|
main_globals.vblank_interval_held =
|
|
main_globals.vblank_interval_current > 0 && lapsed_frames == 0;
|
|
profile_lapsed_frames(
|
|
lapsed_frames,
|
|
synchronized,
|
|
main_globals.vblank_debug_string);
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_setup_connection(
|
|
void)
|
|
{
|
|
struct game_options options;
|
|
|
|
if (main_globals.playback_last_recording)
|
|
main_globals.want_to_be_at_main_menu = FALSE;
|
|
|
|
if (main_globals.want_to_be_at_main_menu)
|
|
{
|
|
main_menu_load();
|
|
return;
|
|
}
|
|
|
|
if (main_globals.playback_last_recording)
|
|
{
|
|
main_globals.connection = _game_connection_film_playback;
|
|
error(_error_silent, "error opening saved film");
|
|
main_globals.want_to_be_at_main_menu = TRUE;
|
|
main_menu_load();
|
|
}
|
|
else
|
|
{
|
|
main_globals.connection = _game_connection_local;
|
|
game_options_new(&options);
|
|
csstrncpy(
|
|
options.map_name,
|
|
main_globals.soloplayer_map_name,
|
|
NUMBEROF(options.map_name) - 1);
|
|
options.map_name[NUMBEROF(options.map_name) - 1] = 0;
|
|
options.difficulty = global_difficulty_level;
|
|
game_precache_new_map(options.map_name, TRUE);
|
|
game_dispose_from_old_map();
|
|
main_new_map(&options);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_initialize_time(
|
|
void)
|
|
{
|
|
main_globals.frame_start_milliseconds = system_milliseconds();
|
|
main_globals.rasterizer_target_index = 0;
|
|
rasterizer_set_vblank_callback(main_vertical_blank_interrupt_handler);
|
|
main_globals.vblank_flip_delta_index = 0;
|
|
csmemset(main_globals.vblank_flip_deltas, 0, sizeof(main_globals.vblank_flip_deltas));
|
|
main_globals.d3d_flip_count = d3d_find_flipcount();
|
|
return;
|
|
}
|
|
|
|
static void main_reset_map_private(
|
|
void)
|
|
{
|
|
if (!game_time_get_paused())
|
|
{
|
|
scenario_switch_structure_bsp(0);
|
|
game_dispose_from_old_map();
|
|
input_flush();
|
|
game_initialize_for_new_map();
|
|
create_local_players();
|
|
game_time_start();
|
|
game_initial_pulse();
|
|
ui_widgets_disable_pause_game(30);
|
|
|
|
main_globals.reset_map = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void screenshot_render(
|
|
struct render_window *windows)
|
|
{
|
|
char path[512];
|
|
struct file_reference reference;
|
|
point2d screenshot_page_index;
|
|
point2d screenshot_index;
|
|
struct bitmap_data *bitmap;
|
|
long screenshot_width;
|
|
long screenshot_height;
|
|
|
|
global_screenshot_size = PIN(global_screenshot_size, 1, 3);
|
|
screenshot_width =
|
|
rasterizer_globals.reserved04.screen_bounds.x1 -
|
|
rasterizer_globals.reserved04.screen_bounds.x0;
|
|
screenshot_height =
|
|
rasterizer_globals.reserved04.screen_bounds.y1 -
|
|
rasterizer_globals.reserved04.screen_bounds.y0;
|
|
bitmap = bitmap_2d_new(
|
|
global_screenshot_size * screenshot_width,
|
|
global_screenshot_size * screenshot_height,
|
|
0,
|
|
_bitmap_format_x8r8g8b8);
|
|
|
|
if (bitmap && bitmap->base_address)
|
|
{
|
|
console_printf(TRUE, "");
|
|
console_close();
|
|
|
|
for (screenshot_page_index.y = 0;
|
|
screenshot_page_index.y < global_screenshot_count.count;
|
|
screenshot_page_index.y++)
|
|
{
|
|
for (screenshot_page_index.x = 0;
|
|
screenshot_page_index.x < global_screenshot_count.count;
|
|
screenshot_page_index.x++)
|
|
{
|
|
for (screenshot_index.y = 0;
|
|
screenshot_index.y < global_screenshot_size;
|
|
screenshot_index.y++)
|
|
{
|
|
for (screenshot_index.x = 0;
|
|
screenshot_index.x < global_screenshot_size;
|
|
screenshot_index.x++)
|
|
{
|
|
if (global_screenshot_count.count > 1 ||
|
|
global_screenshot_size > 1)
|
|
{
|
|
render_frame(
|
|
windows,
|
|
1,
|
|
&screenshot_page_index,
|
|
&screenshot_index,
|
|
bitmap,
|
|
0.0f);
|
|
render_frame_present(&screenshot_index, bitmap);
|
|
}
|
|
else
|
|
{
|
|
render_frame(windows, 1, NULL, NULL, bitmap, 0.0f);
|
|
render_frame_present(NULL, bitmap);
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf(
|
|
path,
|
|
"%dscreenshot%d%d.tif",
|
|
main_globals.screenshot_identifier,
|
|
screenshot_page_index.y,
|
|
screenshot_page_index.x);
|
|
file_reference_create_from_path(&reference, path, FALSE);
|
|
screenshot_record(bitmap, &reference);
|
|
}
|
|
}
|
|
|
|
main_globals.screenshot_identifier++;
|
|
bitmap_delete(bitmap);
|
|
}
|
|
|
|
global_screenshot_count.count = 0;
|
|
return;
|
|
}
|
|
|
|
void main_framerate_render(
|
|
void)
|
|
{
|
|
if (display_framerate)
|
|
{
|
|
long font_tag_index;
|
|
|
|
font_tag_index = hud_globals->messaging.single_player_font.index;
|
|
if (font_tag_index != NONE)
|
|
{
|
|
real frame_seconds;
|
|
real frame_rate_real;
|
|
long frame_rate;
|
|
rectangle2d bounds;
|
|
/* room for three digits under C99 snprintf, which (unlike MSVC's
|
|
_snprintf) keeps a byte of the count for the terminator */
|
|
char frame_rate_string[8];
|
|
|
|
bounds = render.camera.window_bounds;
|
|
/* The native ports draw at the display's refresh rate, up to
|
|
hundreds of frames a second: show frames per second averaged over
|
|
half a second, counting each frame once (split screen draws this
|
|
once per view), with no 100 cap. */
|
|
{
|
|
static unsigned long counted_frame_start = 0;
|
|
static real window_seconds = 0.0f;
|
|
static long window_frames = 0;
|
|
static long average_frame_rate = 0;
|
|
|
|
if (main_globals.frame_start_milliseconds != counted_frame_start)
|
|
{
|
|
counted_frame_start = main_globals.frame_start_milliseconds;
|
|
window_seconds += main_globals.seconds_elapsed;
|
|
window_frames++;
|
|
if (window_seconds >= 0.5f)
|
|
{
|
|
average_frame_rate = fast_ftol(window_frames / window_seconds);
|
|
window_seconds = 0.0f;
|
|
window_frames = 0;
|
|
}
|
|
}
|
|
frame_rate = PIN(average_frame_rate, 0, 999);
|
|
(void)frame_seconds;
|
|
(void)frame_rate_real;
|
|
}
|
|
|
|
_snprintf(
|
|
frame_rate_string,
|
|
NUMBEROF(frame_rate_string) - 1,
|
|
"%d",
|
|
(short)frame_rate);
|
|
frame_rate_string[NUMBEROF(frame_rate_string) - 1] = 0;
|
|
bounds.x0 = (short)(bounds.x1 - 50);
|
|
bounds.y0 = (short)(bounds.y1 - 50);
|
|
draw_string_set_format(NONE, _text_justification_left, 0);
|
|
draw_string_set_color(
|
|
(short)frame_rate >= 30 ? global_real_argb_green : global_real_argb_red);
|
|
draw_string_set_font(font_tag_index);
|
|
rasterizer_draw_string(&bounds, NULL, NULL, 0, frame_rate_string);
|
|
}
|
|
}
|
|
|
|
if (display_vblank_deltas)
|
|
{
|
|
long font_tag_index;
|
|
|
|
font_tag_index = hud_globals->messaging.single_player_font.index;
|
|
if (font_tag_index != NONE)
|
|
{
|
|
short index;
|
|
rectangle2d bounds;
|
|
char delta_string[4];
|
|
|
|
bounds = render.camera.window_bounds;
|
|
bounds.x0 = (short)(bounds.x1 - 50);
|
|
bounds.y0 = (short)(bounds.y1 - 50);
|
|
index = (short)((main_globals.vblank_flip_delta_index + 14) % 15);
|
|
while (index != main_globals.vblank_flip_delta_index)
|
|
{
|
|
bounds.y0 -= 20;
|
|
bounds.y1 -= 20;
|
|
_snprintf(
|
|
delta_string,
|
|
NUMBEROF(delta_string) - 1,
|
|
"%d",
|
|
main_globals.vblank_flip_deltas[index]);
|
|
delta_string[NUMBEROF(delta_string) - 1] = 0;
|
|
draw_string_set_format(NONE, _text_justification_right, 0);
|
|
draw_string_set_font(font_tag_index);
|
|
draw_string_set_color(
|
|
main_globals.vblank_flip_deltas[index] == 2
|
|
? global_real_argb_white
|
|
: global_real_argb_red);
|
|
rasterizer_draw_string(&bounds, NULL, NULL, 0, delta_string);
|
|
index = (short)((index + 14) % 15);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (display_precache_progress && cache_files_precache_in_progress())
|
|
{
|
|
long font_tag_index;
|
|
|
|
font_tag_index = hud_globals->messaging.single_player_font.index;
|
|
if (font_tag_index != NONE)
|
|
{
|
|
real progress;
|
|
long progress_percent;
|
|
rectangle2d bounds;
|
|
char progress_string[4];
|
|
|
|
if (cache_files_precache_map_status(&progress) == 0)
|
|
{
|
|
real progress_percent_real;
|
|
|
|
bounds = render.camera.window_bounds;
|
|
progress_percent_real = progress * 100.0f;
|
|
progress_percent = fast_ftol(progress_percent_real);
|
|
_snprintf(
|
|
progress_string,
|
|
NUMBEROF(progress_string) - 1,
|
|
"%d",
|
|
(short)progress_percent);
|
|
progress_string[NUMBEROF(progress_string) - 1] = 0;
|
|
bounds.x0 = (short)(bounds.x1 - 50);
|
|
bounds.y0 = (short)(bounds.y1 - 100);
|
|
draw_string_set_format(NONE, _text_justification_left, 0);
|
|
draw_string_set_color(global_real_argb_purple);
|
|
draw_string_set_font(font_tag_index);
|
|
rasterizer_draw_string(&bounds, NULL, NULL, 0, progress_string);
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void halt_and_catch_fire(
|
|
void)
|
|
{
|
|
short gamepad_index;
|
|
long font_tag_index;
|
|
struct scenario *scenario;
|
|
struct rasterizer_frame_begin_parameters frame_parameters;
|
|
struct rasterizer_window_begin_parameters window_parameters;
|
|
|
|
if (!global_screenshot_count.halt_recursion_lock)
|
|
{
|
|
scenario = global_scenario_try_and_get();
|
|
global_screenshot_count.halt_recursion_lock = TRUE;
|
|
for (gamepad_index = 0; gamepad_index < MAXIMUM_GAMEPADS; gamepad_index++)
|
|
{
|
|
if (input_has_gamepad(gamepad_index))
|
|
{
|
|
input_set_gamepad_rumbler_state(
|
|
gamepad_index,
|
|
0,
|
|
0);
|
|
}
|
|
}
|
|
|
|
if (scenario)
|
|
{
|
|
font_tag_index = interface_get_tag_index(_interface_font_terminal);
|
|
}
|
|
if (!scenario || font_tag_index == NONE)
|
|
{
|
|
font_tag_index = tag_loaded(
|
|
FONT_GROUP_TAG,
|
|
"old tags\\internal system plain");
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
rasterizer_reset_state();
|
|
csmemset(&frame_parameters, 0, sizeof(frame_parameters));
|
|
rasterizer_frame_begin(&frame_parameters);
|
|
rasterizer_windows_begin();
|
|
|
|
csmemset(&window_parameters, 0, sizeof(window_parameters));
|
|
window_parameters.camera.position = *global_origin3d;
|
|
window_parameters.camera.forward = *global_forward3d;
|
|
window_parameters.camera.up = *global_up3d;
|
|
window_parameters.camera.mirrored = FALSE;
|
|
window_parameters.camera.vertical_field_of_view =
|
|
2.0f * arctangent(
|
|
0.75f * render_camera_get_adjusted_field_of_view_tangent(
|
|
DEGREES_TO_RADIANS(80.0f)),
|
|
1.0f);
|
|
window_parameters.camera.z_near = rasterizer_globals.near_clip_distance;
|
|
window_parameters.camera.viewport_bounds.x0 = 0;
|
|
window_parameters.camera.viewport_bounds.x1 = (short)halo_screen_width();
|
|
window_parameters.camera.viewport_bounds.y0 = 0;
|
|
window_parameters.camera.viewport_bounds.y1 = 480;
|
|
window_parameters.camera.z_far = rasterizer_globals.far_clip_distance;
|
|
render_camera_build_frustum(
|
|
&window_parameters.camera,
|
|
NULL,
|
|
&window_parameters.frustum,
|
|
TRUE);
|
|
window_parameters.rasterizer_target = 0;
|
|
window_parameters.fog.atmospheric_color = *global_real_rgb_blue;
|
|
window_parameters.fog.atmospheric_maximum_distance = 0.0f;
|
|
window_parameters.fog.atmospheric_minimum_distance = 0.0f;
|
|
window_parameters.fog.planar_mode = 0;
|
|
render.camera = window_parameters.camera;
|
|
rasterizer_window_begin(&window_parameters);
|
|
|
|
if (font_tag_index != NONE)
|
|
{
|
|
point2d cursor = { 0, 0 };
|
|
rectangle2d bounds = rasterizer_globals.reserved04.frame_bounds;
|
|
|
|
draw_string_set_draw_mode(
|
|
font_tag_index,
|
|
NONE,
|
|
0,
|
|
0,
|
|
global_real_argb_white);
|
|
draw_string_set_tab_stops(NULL, 0);
|
|
draw_string_set_color(global_real_argb_white);
|
|
rasterizer_draw_string(
|
|
&bounds,
|
|
NULL,
|
|
&cursor,
|
|
-4,
|
|
"halobeta xbox 01.01.14.2342 built at: Jan 14 2002 12:49:20");
|
|
bounds.y0 = cursor.y - 1;
|
|
rasterizer_draw_string(
|
|
&bounds,
|
|
NULL,
|
|
&cursor,
|
|
-4,
|
|
error_get());
|
|
}
|
|
|
|
rasterizer_transparent_geometry_draw(TRUE);
|
|
rasterizer_transparent_geometry_draw(FALSE);
|
|
rasterizer_debug_draw();
|
|
rasterizer_window_end();
|
|
rasterizer_windows_end();
|
|
rasterizer_frame_end();
|
|
rasterizer_present(NULL, NULL);
|
|
input_update();
|
|
}
|
|
}
|
|
|
|
exit(0);
|
|
return;
|
|
}
|
|
|
|
void main_loop_of_death(
|
|
void)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
input_frame_begin();
|
|
input_update();
|
|
shell_idle();
|
|
event_manager_update();
|
|
telnet_console_process();
|
|
process_ui_widgets();
|
|
main_pregame_render();
|
|
main_rasterizer_throttle();
|
|
main_present_frame();
|
|
input_frame_end();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void main_game_render(
|
|
double time_delta_since_tick_sec)
|
|
{
|
|
boolean force_single_screen;
|
|
long window_index;
|
|
struct render_window *window;
|
|
struct observer_result const *observer;
|
|
long player_window_count;
|
|
long window_count;
|
|
short last_local_player_index;
|
|
|
|
lock_global_random_seed();
|
|
collision_log_continue_period(TRUE);
|
|
sound_render();
|
|
force_single_screen = game_engine_force_single_screen();
|
|
last_local_player_index = NONE;
|
|
|
|
window_count = PIN(local_player_count(), 1, MAXIMUM_LOCAL_PLAYERS);
|
|
player_window_count = window_count;
|
|
if (force_single_screen || cinematic_in_progress())
|
|
{
|
|
window_count = 1;
|
|
player_window_count = 1;
|
|
}
|
|
|
|
for (window_index = 0; window_index < player_window_count; window_index++)
|
|
{
|
|
window = &global_screenshot_count.windows[window_index];
|
|
observer = NULL;
|
|
|
|
compute_window_bounds(
|
|
window_index,
|
|
player_window_count,
|
|
&window->rasterizer_camera.viewport_bounds,
|
|
&window->rasterizer_camera.window_bounds);
|
|
if (force_single_screen)
|
|
{
|
|
window->local_player_index = NONE;
|
|
}
|
|
else if (window_index < window_count)
|
|
{
|
|
if (!rasterizer_debug_options.force_all_player_views_to_default_player ||
|
|
last_local_player_index == NONE)
|
|
{
|
|
if (game_connection() == _game_connection_film_playback)
|
|
{
|
|
last_local_player_index = 0;
|
|
}
|
|
else
|
|
{
|
|
last_local_player_index = local_player_get_next(last_local_player_index);
|
|
}
|
|
}
|
|
|
|
window->local_player_index = last_local_player_index;
|
|
observer = observer_get_camera(window->local_player_index);
|
|
observer = render_interpolation_camera(window->local_player_index, observer);
|
|
}
|
|
else
|
|
{
|
|
window->local_player_index = NONE;
|
|
}
|
|
|
|
set_window_camera_values(window, observer);
|
|
window->console_window = FALSE;
|
|
}
|
|
|
|
window = &global_screenshot_count.windows[player_window_count];
|
|
compute_window_bounds(
|
|
0,
|
|
1,
|
|
&window->rasterizer_camera.viewport_bounds,
|
|
&window->rasterizer_camera.window_bounds);
|
|
window->local_player_index = NONE;
|
|
window->console_window = TRUE;
|
|
set_window_camera_values(window, NULL);
|
|
|
|
if (global_screenshot_count.count <= 0)
|
|
{
|
|
short render_window_count = (short)(player_window_count + 1);
|
|
|
|
#ifdef HALO_VR
|
|
/* the headset's eyes and HUD in place of the one player window */
|
|
render_window_count = vr_render_windows(global_screenshot_count.windows, render_window_count);
|
|
#endif
|
|
render_frame(
|
|
global_screenshot_count.windows,
|
|
render_window_count,
|
|
NULL,
|
|
NULL,
|
|
main_globals.movie,
|
|
(real)time_delta_since_tick_sec);
|
|
}
|
|
else
|
|
{
|
|
screenshot_render(global_screenshot_count.windows);
|
|
}
|
|
|
|
collision_log_end_period();
|
|
unlock_global_random_seed();
|
|
return;
|
|
}
|
|
|
|
void main_loop(
|
|
void)
|
|
{
|
|
boolean render_frame;
|
|
long connection;
|
|
|
|
if (!game_in_editor())
|
|
{
|
|
csstrncpy(main_globals.soloplayer_map_name, "levels\\b30\\b30", NUMBEROF(main_globals.soloplayer_map_name)-1);
|
|
main_globals.soloplayer_map_name[NUMBEROF(main_globals.soloplayer_map_name)-1] = '\0';
|
|
}
|
|
|
|
main_globals.want_to_be_at_main_menu = !game_in_editor();
|
|
main_globals.switch_to_structure_bsp_index = NONE;
|
|
main_globals.halt_time_scale = TRUE;
|
|
|
|
console_initialize();
|
|
debug_keys_initialize();
|
|
game_initialize();
|
|
console_startup();
|
|
main_setup_connection();
|
|
main_initialize_time();
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!game_in_editor())
|
|
{
|
|
if (main_globals.switch_to_structure_bsp_index!=NONE)
|
|
{
|
|
main_switch_to_structure_bsp_private();
|
|
}
|
|
|
|
if (main_globals.lost_map)
|
|
{
|
|
main_lost_map_private();
|
|
}
|
|
|
|
if (main_globals.won_map)
|
|
{
|
|
main_won_map_private();
|
|
}
|
|
|
|
if (main_globals.respawn)
|
|
{
|
|
main_respawn_private();
|
|
}
|
|
|
|
if (main_globals.save_map_completed)
|
|
{
|
|
main_saving_map_private();
|
|
}
|
|
|
|
if (main_globals.defer_map_change)
|
|
{
|
|
main_change_map_name();
|
|
}
|
|
|
|
if (main_globals.revert_map)
|
|
{
|
|
main_revert_map_private();
|
|
}
|
|
|
|
if (main_globals.skip_cinematic)
|
|
{
|
|
main_skip_cinematic_private();
|
|
}
|
|
|
|
if (main_globals.reset_map)
|
|
{
|
|
main_reset_map_private();
|
|
}
|
|
|
|
if (main_globals.save_core)
|
|
{
|
|
main_save_core_private();
|
|
}
|
|
|
|
if (main_globals.load_core)
|
|
{
|
|
main_load_core_private();
|
|
}
|
|
|
|
if (main_globals.want_to_be_at_main_menu)
|
|
{
|
|
main_menu_load();
|
|
}
|
|
|
|
if (main_globals.load_last_solo_level)
|
|
{
|
|
main_load_last_solo_map();
|
|
}
|
|
|
|
if (main_globals.run_xdemos)
|
|
{
|
|
main_run_demos_private();
|
|
}
|
|
|
|
if (main_globals.skip)
|
|
{
|
|
main_skip_private();
|
|
}
|
|
|
|
if (main_globals.queue_map)
|
|
{
|
|
main_queue_map_private();
|
|
}
|
|
}
|
|
else if (main_globals.reset_map)
|
|
{
|
|
main_reset_map_private();
|
|
}
|
|
|
|
profile_frame_start();
|
|
input_frame_begin();
|
|
input_update();
|
|
input_abstraction_update();
|
|
shell_idle();
|
|
event_manager_update();
|
|
telnet_console_process();
|
|
|
|
if (!shell_application_is_paused())
|
|
{
|
|
render_frame = TRUE;
|
|
|
|
/* automated system link tests (port/linux/game/network_test.c) */
|
|
network_test_update(main_globals.main_menu_scenario_loaded, main_globals.seconds_elapsed);
|
|
connection = main_globals.connection;
|
|
if (connection==_game_connection_network_client)
|
|
{
|
|
if (!network_game_client_start_frame())
|
|
{
|
|
display_error_when_main_menu_loaded(6);
|
|
error(_error_silent, "the game host went down");
|
|
network_game_abort();
|
|
}
|
|
}
|
|
else if (connection==_game_connection_network_server)
|
|
{
|
|
if (!network_game_client_start_frame())
|
|
{
|
|
display_error_when_main_menu_loaded(1);
|
|
error(_error_silent, "the game host went down");
|
|
network_game_abort();
|
|
}
|
|
else if (!network_game_server_start_frame())
|
|
{
|
|
display_error_when_main_menu_loaded(1);
|
|
error(_error_silent, "the game host went down");
|
|
network_game_abort();
|
|
}
|
|
}
|
|
else if (connection==_game_connection_film_playback)
|
|
{
|
|
break;
|
|
}
|
|
|
|
main_update_time();
|
|
process_ui_widgets();
|
|
bink_playback_update();
|
|
|
|
if ((!game_in_editor() && (input_key_is_down(_key_end) || input_key_is_down(_key_escape))) || editor_should_exit())
|
|
{
|
|
main_movie_stop();
|
|
|
|
if (!game_engine_running())
|
|
{
|
|
main_reset_map();
|
|
}
|
|
}
|
|
|
|
if (game_in_progress())
|
|
{
|
|
terminal_update();
|
|
|
|
if (!console_update() || main_globals.connection!=_game_connection_local)
|
|
{
|
|
debug_keys_update();
|
|
cheats_update();
|
|
player_control_update((real)main_globals.halt_time_scale*main_globals.seconds_elapsed);
|
|
|
|
connection = main_globals.connection;
|
|
if (connection>_game_connection_local && connection<=_game_connection_network_server && !network_game_client_end_frame())
|
|
{
|
|
display_error_when_main_menu_loaded(1);
|
|
network_game_abort();
|
|
}
|
|
|
|
game_time_update((real)main_globals.halt_time_scale*main_globals.seconds_elapsed);
|
|
|
|
render_frame = main_globals.main_menu_scenario_loaded ||
|
|
(main_globals.halt_time_scale &&
|
|
(game_time_get_paused() || game_time_get_elapsed()>0 || game_time_get_speed()<1.0f));
|
|
/* frames between ticks too (render_interpolation.c) */
|
|
if (halo_interpolation_enabled())
|
|
render_frame = main_globals.main_menu_scenario_loaded || main_globals.halt_time_scale;
|
|
render_frame &= !game_engine_running() || game_time_get()>=3;
|
|
|
|
collision_log_continue_period(1);
|
|
director_update((real)main_globals.halt_time_scale*main_globals.seconds_elapsed);
|
|
observer_update((real)main_globals.halt_time_scale*main_globals.seconds_elapsed);
|
|
collision_log_end_period();
|
|
game_engine_update_non_deterministic((real)main_globals.halt_time_scale*main_globals.seconds_elapsed);
|
|
}
|
|
|
|
if (main_globals.saving_map)
|
|
{
|
|
main_save_map_private();
|
|
}
|
|
|
|
if (render_frame && !debug_no_drawing)
|
|
{
|
|
profile_render_start();
|
|
render_interpolation_frame_begin();
|
|
main_game_render((double)main_globals.seconds_elapsed);
|
|
render_interpolation_frame_end();
|
|
profile_render_end();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
profile_render_start();
|
|
main_pregame_render();
|
|
profile_render_end();
|
|
}
|
|
|
|
main_rasterizer_throttle();
|
|
|
|
if (render_frame && !debug_no_drawing)
|
|
{
|
|
main_present_frame();
|
|
}
|
|
}
|
|
|
|
input_frame_end();
|
|
profile_frame_end();
|
|
main_frame_rate_debug();
|
|
|
|
if (main_globals.restart_time)
|
|
{
|
|
main_globals.restart_time = FALSE;
|
|
main_reset_time();
|
|
main_globals.halt_time_scale = TRUE;
|
|
}
|
|
}
|
|
|
|
error(_error_silent, "end of saved film");
|
|
main_exit();
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------- private code */
|