diff --git a/CMakeCache.txt b/CMakeCache.txt new file mode 100644 index 000000000..004daacb6 --- /dev/null +++ b/CMakeCache.txt @@ -0,0 +1,81 @@ +# This is the CMakeCache file. +# For build in directory: c:/Users/Paul/source/repos/dashfaction +# It was generated by CMake: C:/Program Files/CMake/bin/cmake.exe +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Semicolon separated list of supported configuration types, only +// supports Debug, Release, MinSizeRel, and RelWithDebInfo, anything +// else will be ignored. +CMAKE_CONFIGURATION_TYPES:STRING=Debug;Release;MinSizeRel;RelWithDebInfo + +//Value Computed by CMake. +CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=C:/Users/Paul/source/repos/dashfaction/CMakeFiles/pkgRedirects + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=DashFaction + +//Value Computed by CMake +DashFaction_BINARY_DIR:STATIC=C:/Users/Paul/source/repos/dashfaction + +//Value Computed by CMake +DashFaction_IS_TOP_LEVEL:STATIC=ON + +//Value Computed by CMake +DashFaction_SOURCE_DIR:STATIC=C:/Users/Paul/source/repos/dashfaction + + +######################## +# INTERNAL cache entries +######################## + +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=c:/Users/Paul/source/repos/dashfaction +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=26 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=4 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=C:/Program Files/CMake/bin/cmake.exe +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=C:/Program Files/CMake/bin/cpack.exe +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=C:/Program Files/CMake/bin/ctest.exe +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Visual Studio 17 2022 +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL=Win32 +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=C:/Users/Paul/source/repos/dashfaction +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=C:/Program Files/CMake/share/cmake-3.26 + diff --git a/CMakeFiles/3.26.4/CMakeSystem.cmake b/CMakeFiles/3.26.4/CMakeSystem.cmake new file mode 100644 index 000000000..e1deade36 --- /dev/null +++ b/CMakeFiles/3.26.4/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Windows-10.0.22621") +set(CMAKE_HOST_SYSTEM_NAME "Windows") +set(CMAKE_HOST_SYSTEM_VERSION "10.0.22621") +set(CMAKE_HOST_SYSTEM_PROCESSOR "AMD64") + + + +set(CMAKE_SYSTEM "Windows-10.0.22621") +set(CMAKE_SYSTEM_NAME "Windows") +set(CMAKE_SYSTEM_VERSION "10.0.22621") +set(CMAKE_SYSTEM_PROCESSOR "AMD64") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/CMakeFiles/CMakeConfigureLog.yaml b/CMakeFiles/CMakeConfigureLog.yaml new file mode 100644 index 000000000..e0aa31705 --- /dev/null +++ b/CMakeFiles/CMakeConfigureLog.yaml @@ -0,0 +1,11 @@ + +--- +events: + - + kind: "message-v1" + backtrace: + - "C:/Program Files/CMake/share/cmake-3.26/Modules/CMakeDetermineSystem.cmake:204 (message)" + - "CMakeLists.txt:3 (project)" + message: | + The system is: Windows - 10.0.22621 - AMD64 +... diff --git a/CMakeFiles/cmake.check_cache b/CMakeFiles/cmake.check_cache new file mode 100644 index 000000000..3dccd7317 --- /dev/null +++ b/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/common/include/common/config/GameConfig.h b/common/include/common/config/GameConfig.h index 67875b3c8..a199f4998 100644 --- a/common/include/common/config/GameConfig.h +++ b/common/include/common/config/GameConfig.h @@ -88,6 +88,7 @@ struct GameConfig CfgVar reduced_speed_in_background = false; CfgVar player_join_beep = false; CfgVar autosave = true; + CfgVar derandomize_bomb = false; // Internal CfgVar dash_faction_version{""}; diff --git a/common/src/config/GameConfig.cpp b/common/src/config/GameConfig.cpp index 3483f39c0..4ad4d40d5 100644 --- a/common/src/config/GameConfig.cpp +++ b/common/src/config/GameConfig.cpp @@ -172,6 +172,7 @@ bool GameConfig::visit_vars(T&& visitor, bool is_save) result &= visitor(dash_faction_key, "Mesh Static Lighting", mesh_static_lighting); result &= visitor(dash_faction_key, "Player Join Beep", player_join_beep); result &= visitor(dash_faction_key, "Autosave", autosave); + result &= visitor(dash_faction_key, "Derandomize Bomb", derandomize_bomb); return result; } diff --git a/game_patch/misc/misc.cpp b/game_patch/misc/misc.cpp index 08a97ab66..317ad0cfc 100644 --- a/game_patch/misc/misc.cpp +++ b/game_patch/misc/misc.cpp @@ -1,25 +1,25 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "misc.h" -#include "../sound/sound.h" -#include "../os/console.h" #include "../main/main.h" +#include "../object/object.h" +#include "../os/console.h" +#include "../rf/gameseq.h" #include "../rf/gr/gr.h" -#include "../rf/player/player.h" +#include "../rf/misc.h" #include "../rf/multi.h" -#include "../rf/gameseq.h" #include "../rf/os/os.h" -#include "../rf/misc.h" +#include "../rf/player/player.h" #include "../rf/vmesh.h" -#include "../object/object.h" +#include "../sound/sound.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include void apply_main_menu_patches(); void apply_save_restore_patches(); @@ -79,6 +79,26 @@ CodeInjection level_read_data_check_restore_status_patch{ }, }; +CodeInjection derandomize_bomb{ + 0x0043b4c7, + [](auto& regs) { + write_mem(0x0063914C, 1); + write_mem(0x0063914C + 4, 1); + write_mem(0x0063914C + 8, 3); + write_mem(0x0063914C + 12, 2); + + write_mem(0x006390D8, 3); + write_mem(0x006390D8 + 4, 2); + write_mem(0x006390D8 + 8, 1); + write_mem(0x006390D8 + 12, 0); + write_mem(0x006390D8 + 16, 0); + write_mem(0x006390D8 + 20, 2); + write_mem(0x006390D8 + 24, 1); + + regs.eip = 0x0043b632; + }, +}; + void set_jump_to_multi_server_list(bool jump) { g_jump_to_multi_server_list = jump; @@ -93,7 +113,9 @@ void start_join_multi_game_sequence(const rf::NetAddr& addr, const std::string& bool multi_join_game(const rf::NetAddr& addr, const std::string& password) { auto multi_set_current_server_addr = addr_as_ref(0x0044B380); - auto send_join_req_packet = addr_as_ref(0x0047AA40); + auto send_join_req_packet = + addr_as_ref( + 0x0047AA40); if (rf::gameseq_get_state() != rf::GS_MULTI_SERVER_LIST) { return false; @@ -110,10 +132,11 @@ FunHook rf_init_state_hook{ 0x004B1AC0, [](int state, int old_state) { rf_init_state_hook.call_target(state, old_state); - xlog::trace("state %d old_state %d g_jump_to_multi_server_list %d", state, old_state, g_jump_to_multi_server_list); + xlog::trace("state %d old_state %d g_jump_to_multi_server_list %d", state, old_state, + g_jump_to_multi_server_list); - bool exiting_game = state == rf::GS_MAIN_MENU && - (old_state == rf::GS_END_GAME || old_state == rf::GS_NEW_LEVEL); + bool exiting_game = + state == rf::GS_MAIN_MENU && (old_state == rf::GS_END_GAME || old_state == rf::GS_NEW_LEVEL); if (exiting_game && g_in_mp_game) { g_in_mp_game = false; g_jump_to_multi_server_list = true; @@ -164,24 +187,18 @@ FunHook multi_after_players_packet_hook{ }, }; -CodeInjection mover_rotating_keyframe_oob_crashfix{ - 0x0046A559, - [](auto& regs) { - float& unk_time = *reinterpret_cast(regs.esi + 0x308); - unk_time = 0; - regs.eip = 0x0046A89D; - } -}; +CodeInjection mover_rotating_keyframe_oob_crashfix{0x0046A559, [](auto& regs) { + float& unk_time = *reinterpret_cast(regs.esi + 0x308); + unk_time = 0; + regs.eip = 0x0046A89D; + }}; -CodeInjection parser_xstr_oob_fix{ - 0x0051212E, - [](auto& regs) { - if (regs.edi >= 1000) { - xlog::warn("XSTR index is out of bounds: %d!", static_cast(regs.edi)); - regs.edi = -1; - } - } -}; +CodeInjection parser_xstr_oob_fix{0x0051212E, [](auto& regs) { + if (regs.edi >= 1000) { + xlog::warn("XSTR index is out of bounds: %d!", static_cast(regs.edi)); + regs.edi = -1; + } + }}; CodeInjection ammo_tbl_buffer_overflow_fix{ 0x004C218E, @@ -311,7 +328,8 @@ CodeInjection glass_shard_level_init_fix{ }, }; -int debug_print_hook(char* buf, const char *fmt, ...) { +int debug_print_hook(char* buf, const char* fmt, ...) +{ va_list vl; va_start(vl, fmt); int ret = vsprintf(buf, fmt, vl); @@ -322,7 +340,7 @@ int debug_print_hook(char* buf, const char *fmt, ...) { CallHook skeleton_pagein_debug_print_patch{ 0x0053AA73, - reinterpret_cast(debug_print_hook), + reinterpret_cast(debug_print_hook), }; CodeInjection level_load_items_crash_fix{ @@ -360,20 +378,21 @@ CodeInjection explosion_crash_fix{ }, }; -CallHook level_read_geometry_header_light_add_directional_hook{ - 0x004619E1, - [](rf::Vector3 *dir, float intensity, float r, float g, float b, bool is_dynamic, int casts_shadow, int dropoff_type) { - if (rf::gr::lighting_enabled()) { - level_read_geometry_header_light_add_directional_hook.call_target(dir, intensity, r, g, b, is_dynamic, casts_shadow, dropoff_type); - } - }, -}; +CallHook + level_read_geometry_header_light_add_directional_hook{ + 0x004619E1, + [](rf::Vector3* dir, float intensity, float r, float g, float b, bool is_dynamic, int casts_shadow, + int dropoff_type) { + if (rf::gr::lighting_enabled()) { + level_read_geometry_header_light_add_directional_hook.call_target(dir, intensity, r, g, b, is_dynamic, + casts_shadow, dropoff_type); + } + }, + }; CodeInjection vfile_read_stack_corruption_fix{ 0x0052D0E0, - [](auto& regs) { - regs.esi = regs.eax; - }, + [](auto& regs) { regs.esi = regs.eax; }, }; void misc_init() @@ -466,6 +485,10 @@ void misc_init() // Fix stack corruption when packfile has lower size than expected vfile_read_stack_corruption_fix.install(); + if (g_game_config.derandomize_bomb) { + derandomize_bomb.install(); + } + // Improve parse error message // For some reason RF replaces all characters with code lower than 0x20 (space) by character with code 0x16 (SYN) // in "Found this text" and "Prior text" sections. This makes all new line characters (CRLF) and tabs to be diff --git a/game_patch/object/event.cpp b/game_patch/object/event.cpp index ba66dd789..0952ae13a 100644 --- a/game_patch/object/event.cpp +++ b/game_patch/object/event.cpp @@ -1,18 +1,18 @@ -#include -#include -#include -#include -#include -#include -#include -#include "../rf/object.h" #include "../rf/event.h" +#include "../os/console.h" #include "../rf/entity.h" #include "../rf/level.h" #include "../rf/multi.h" -#include "../rf/player/player.h" +#include "../rf/object.h" #include "../rf/os/console.h" -#include "../os/console.h" +#include "../rf/player/player.h" +#include +#include +#include +#include +#include +#include +#include bool event_debug_enabled; @@ -73,7 +73,8 @@ struct EventSetLiquidDepthHook : rf::Event void __fastcall EventSetLiquidDepth_turn_on_new(EventSetLiquidDepthHook* this_) { - xlog::info("Processing Set_Liquid_Depth event: uid %d depth %.2f duration %.2f", this_->uid, this_->depth, this_->duration); + xlog::info("Processing Set_Liquid_Depth event: uid %d depth %.2f duration %.2f", this_->uid, this_->depth, + this_->duration); if (this_->links.size() == 0) { xlog::trace("no links"); rf::add_liquid_depth_update(this_->room, this_->depth, this_->duration); @@ -89,9 +90,10 @@ void __fastcall EventSetLiquidDepth_turn_on_new(EventSetLiquidDepthHook* this_) } } -extern CallHook liquid_depth_update_apply_all_GRoom_reset_liquid_hook; +extern CallHook liquid_depth_update_apply_all_GRoom_reset_liquid_hook; -void __fastcall liquid_depth_update_apply_all_GRoom_reset_liquid(rf::GRoom* room, int edx, rf::GSolid* solid) { +void __fastcall liquid_depth_update_apply_all_GRoom_reset_liquid(rf::GRoom* room, int edx, rf::GSolid* solid) +{ liquid_depth_update_apply_all_GRoom_reset_liquid_hook.call_target(room, edx, solid); // check objects in room if they are in water @@ -116,10 +118,11 @@ void __fastcall liquid_depth_update_apply_all_GRoom_reset_liquid(rf::GRoom* room } } -CallHook liquid_depth_update_apply_all_GRoom_reset_liquid_hook{ - 0x0045E4AC, - liquid_depth_update_apply_all_GRoom_reset_liquid, -}; +CallHook + liquid_depth_update_apply_all_GRoom_reset_liquid_hook{ + 0x0045E4AC, + liquid_depth_update_apply_all_GRoom_reset_liquid, + }; CallHook ai_path_release_on_load_level_event_crash_fix{ 0x004BBD99, @@ -159,12 +162,13 @@ FunHook event_level_init_post_hook{ }, }; -extern FunHook EventMessage__turn_on_hook; -void __fastcall EventMessage__turn_on_new(rf::Event *this_) +extern FunHook EventMessage__turn_on_hook; +void __fastcall EventMessage__turn_on_new(rf::Event* this_) { - if (!rf::is_dedicated_server) EventMessage__turn_on_hook.call_target(this_); + if (!rf::is_dedicated_server) + EventMessage__turn_on_hook.call_target(this_); } -FunHook EventMessage__turn_on_hook{ +FunHook EventMessage__turn_on_hook{ 0x004BB210, EventMessage__turn_on_new, }; @@ -175,8 +179,8 @@ CodeInjection event_activate_injection{ if (event_debug_enabled) { rf::Event* event = regs.esi; bool on = addr_as_ref(regs.esp + 0xC + 0xC); - rf::console::printf("Processing %s message in event %d '%s'", - on ? "ON" : "OFF", event->uid, event->name.c_str()); + rf::console::printf("Processing %s message in event %d '%s'", on ? "ON" : "OFF", event->uid, + event->name.c_str()); } }, }; @@ -187,8 +191,8 @@ CodeInjection event_activate_injection2{ if (event_debug_enabled) { rf::Event* event = regs.esi; bool on = regs.cl; - rf::console::printf("Delaying %s message in event %d '%s'", - on ? "ON" : "OFF", event->uid, event->name.c_str()); + rf::console::printf("Delaying %s message in event %d '%s'", on ? "ON" : "OFF", event->uid, + event->name.c_str()); } }, }; @@ -198,28 +202,21 @@ CodeInjection event_process_injection{ [](auto& regs) { if (event_debug_enabled) { rf::Event* event = regs.esi; - rf::console::printf("Processing %s message in event %d '%s' (delayed)", - event->delayed_msg ? "ON" : "OFF", event->uid, event->name.c_str()); + rf::console::printf("Processing %s message in event %d '%s' (delayed)", event->delayed_msg ? "ON" : "OFF", + event->uid, event->name.c_str()); } }, }; CodeInjection event_load_level_turn_on_injection{ - 0x004BB9C9, - [](auto& regs) { - if (rf::local_player->flags & (rf::PF_KILL_AFTER_BLACKOUT|rf::PF_END_LEVEL_AFTER_BLACKOUT)) { + 0x004BB9C9, [](auto& regs) { + if (rf::local_player->flags & (rf::PF_KILL_AFTER_BLACKOUT | rf::PF_END_LEVEL_AFTER_BLACKOUT)) { // Ignore level transition if the player was going to die or game was going to end after a blackout effect regs.eip = 0x004BBA71; } - } -}; + }}; -ConsoleCommand2 debug_event_msg_cmd{ - "debug_event_msg", - []() { - event_debug_enabled = !event_debug_enabled; - } -}; +ConsoleCommand2 debug_event_msg_cmd{"debug_event_msg", []() { event_debug_enabled = !event_debug_enabled; }}; void apply_event_patches() { @@ -231,8 +228,8 @@ void apply_event_patches() AsmWriter(0x004BCBE0).jmp(&EventSetLiquidDepth_turn_on_new); liquid_depth_update_apply_all_GRoom_reset_liquid_hook.install(); - // Fix crash after level change (Load_Level event) caused by GNavNode pointers in AiPathInfo not being cleared for entities - // being taken from the previous level + // Fix crash after level change (Load_Level event) caused by GNavNode pointers in AiPathInfo not being cleared for + // entities being taken from the previous level ai_path_release_on_load_level_event_crash_fix.install(); // Fix Message event crash on dedicated server diff --git a/game_patch/os/frametime.cpp b/game_patch/os/frametime.cpp index 3747d1f72..b1e273377 100644 --- a/game_patch/os/frametime.cpp +++ b/game_patch/os/frametime.cpp @@ -1,16 +1,17 @@ -#include -#include -#include -#include -#include "console.h" +#include "../rf/os/frametime.h" +#include "../hud/hud.h" +#include "../main/main.h" +#include "../rf/gameseq.h" #include "../rf/gr/gr.h" #include "../rf/gr/gr_font.h" -#include "../rf/multi.h" -#include "../rf/gameseq.h" #include "../rf/hud.h" -#include "../rf/os/frametime.h" -#include "../main/main.h" -#include "../hud/hud.h" +#include "../rf/level.h" +#include "../rf/multi.h" +#include "console.h" +#include +#include +#include +#include static float g_frametime_history[1024]; static int g_frametime_history_index = 0; @@ -57,12 +58,37 @@ static void frametime_render_fps_counter() } } +static void frametime_render_bomb_derandomized() +{ + // This only actually needs to be displayed on L20S3 but you can't access + // the level.filename at this point in code (as this is drawn even when no + // level loaded e.g. on load screens etc.), and having it always showing helps + // prevent splicing for speedruns etc + if (g_game_config.derandomize_bomb) { + auto text = string_format("No Bomb RNG", "null"); + rf::gr::set_color(0, 255, 0, 255); + int x = rf::gr::screen_width() - (g_game_config.big_hud ? 180 : 105); + int y = g_game_config.fps_counter ? 20 : 10; + if (rf::gameseq_in_gameplay()) { + y = g_game_config.big_hud ? 120 : 70; + if (hud_weapons_is_double_ammo()) { + y += g_game_config.big_hud ? 80 : 40; + } + } + + int font_id = hud_get_default_font(); + rf::gr::string(x, y, text.c_str(), font_id); + } +} + void frametime_render_ui() { frametime_render_fps_counter(); frametime_render_graph(); + frametime_render_bomb_derandomized(); } + ConsoleCommand2 fps_counter_cmd{ "fps_counter", []() { @@ -90,7 +116,8 @@ FunHook frametime_reset_hook{ frametime_reset_hook.call_target(); // Set initial FPS limit - unsigned max_fps = rf::is_dedicated_server ? g_game_config.server_max_fps.value() : g_game_config.max_fps.value(); + unsigned max_fps = + rf::is_dedicated_server ? g_game_config.server_max_fps.value() : g_game_config.max_fps.value(); rf::frametime_min = 1.0f / static_cast(max_fps); }, }; @@ -121,9 +148,7 @@ ConsoleCommand2 max_fps_cmd{ ConsoleCommand2 frametime_graph_cmd{ "frametime_graph", - []() { - g_show_frametime_graph = !g_show_frametime_graph; - }, + []() { g_show_frametime_graph = !g_show_frametime_graph; }, }; void frametime_apply_patch() diff --git a/launcher/DashFactionLauncher.rc b/launcher/DashFactionLauncher.rc index 730613466..c01484729 100644 --- a/launcher/DashFactionLauncher.rc +++ b/launcher/DashFactionLauncher.rc @@ -126,13 +126,14 @@ BEGIN AUTOCHECKBOX "Fast animations",IDC_FAST_ANIMS_CHECK,192,150,78,10 AUTOCHECKBOX "High model details",IDC_DISABLE_LOD_CHECK,192,162,78,10 - GROUPBOX "Miscellaneous",IDC_STATIC,6,192,270,84 + GROUPBOX "Miscellaneous",IDC_STATIC,6,192,270,100 AUTOCHECKBOX "Fast Start",IDC_FAST_START_CHECK,12,204,66,10 AUTOCHECKBOX "Allow overriding game files by packages in user_maps",IDC_ALLOW_OVERWRITE_GAME_CHECK,12,216,260,10 AUTOCHECKBOX "Run game at reduced speed when window doesn't have focus",IDC_REDUCED_SPEED_IN_BG_CHECK,12,228,260,10 + AUTOCHECKBOX "Derandomize Bomb", IDC_DERANDOMIZE_BOMB, 12,240,80,10 AUTOCHECKBOX "Beep when another player joins multiplayer game and window doesn't have focus", - IDC_PLAYER_JOIN_BEEP_CHECK,12,240,260,18,BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP | BS_TOP - AUTOCHECKBOX "Autosave",IDC_AUTOSAVE_CHECK,12,258,66,10,BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP | BS_TOP + IDC_PLAYER_JOIN_BEEP_CHECK,12,252,260,18,BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP | BS_TOP + AUTOCHECKBOX "Autosave",IDC_AUTOSAVE_CHECK,12,276,66,10,BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP | BS_TOP GROUPBOX "Audio",IDC_STATIC,282,6,162,36 AUTO3STATE "Level Sounds",IDC_LEVEL_SOUNDS_CHECK,288,18,58,10 diff --git a/launcher/OptionsDlg.cpp b/launcher/OptionsDlg.cpp index bedcebda3..695044ab4 100644 --- a/launcher/OptionsDlg.cpp +++ b/launcher/OptionsDlg.cpp @@ -93,6 +93,7 @@ BOOL OptionsDlg::OnInitDialog() CheckDlgButton(IDC_REDUCED_SPEED_IN_BG_CHECK, m_conf.reduced_speed_in_background ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(IDC_PLAYER_JOIN_BEEP_CHECK, m_conf.player_join_beep ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(IDC_AUTOSAVE_CHECK, m_conf.autosave ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(IDC_DERANDOMIZE_BOMB, m_conf.derandomize_bomb ? BST_CHECKED : BST_UNCHECKED); InitToolTip(); @@ -256,6 +257,7 @@ void OptionsDlg::InitToolTip() m_tool_tip.AddTool(GetDlgItem(IDC_ALLOW_OVERWRITE_GAME_CHECK), "Enable this if you want to modify game content by putting mods into user_maps folder. Can have side effect of level packfiles modyfing common textures/sounds."); m_tool_tip.AddTool(GetDlgItem(IDC_KEEP_LAUNCHER_OPEN_CHECK), "Keep launcher window open after game or editor launch"); m_tool_tip.AddTool(GetDlgItem(IDC_AUTOSAVE_CHECK), "Automatically save the game after a level transition"); + m_tool_tip.AddTool(GetDlgItem(IDC_DERANDOMIZE_BOMB), "Enables a static solution to the bomb which persists across retries. Recommended for first time players"); } void OptionsDlg::OnOK() @@ -369,6 +371,7 @@ void OptionsDlg::OnBnClickedOk() m_conf.reduced_speed_in_background = (IsDlgButtonChecked(IDC_REDUCED_SPEED_IN_BG_CHECK) == BST_CHECKED); m_conf.player_join_beep = (IsDlgButtonChecked(IDC_PLAYER_JOIN_BEEP_CHECK) == BST_CHECKED); m_conf.autosave = (IsDlgButtonChecked(IDC_AUTOSAVE_CHECK) == BST_CHECKED); + m_conf.derandomize_bomb = (IsDlgButtonChecked(IDC_DERANDOMIZE_BOMB) == BST_CHECKED); try { m_conf.save(); diff --git a/launcher/resource.h b/launcher/resource.h index 9fd9a6a26..c74c7f3e3 100644 --- a/launcher/resource.h +++ b/launcher/resource.h @@ -57,6 +57,7 @@ #define IDC_PLAYER_JOIN_BEEP_CHECK 1048 #define IDC_MESH_STATIC_LIGHTING_CHECK 1049 #define IDC_AUTOSAVE_CHECK 1050 +#define IDC_DERANDOMIZE_BOMB 1052 // Next default values for new objects //