mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
WorldMapHealingRatePatch & set_world_map_heal_time metarule (#539)
Fixes bug: healing time on worldmap is tied to real time clock, instead of game time.
This commit is contained in:
@@ -1427,6 +1427,14 @@
|
||||
detail: void set_rest_heal_time(int time)
|
||||
doc: 'Sets the time interval in minutes for healing during resting. The default is 180. Note: The interval will be reset each time the player reloads the game.'
|
||||
macro: sfall.h
|
||||
- name: set_worldmap_heal_time
|
||||
detail: void set_worldmap_heal_time(int time)
|
||||
doc: |
|
||||
Sets the time interval in minutes for healing during worldmap travel.
|
||||
- passing 0 will revert to 1 second per real time (vanilla behavior)
|
||||
- passing -1 will disable healing during travel
|
||||
- the interval will be reset each time the player reloads the game
|
||||
macro: sfall.h
|
||||
- name: set_rest_mode
|
||||
detail: void set_rest_mode(int flags)
|
||||
doc: 'Sets the bit flags for the rest mode (see `RESTMODE_*` constants in **sfall.h**). Passing 0 will reset the rest mode. It will also be reset each time the player reloads the game.'
|
||||
|
||||
@@ -395,6 +395,7 @@
|
||||
#define set_unique_id(obj) sfall_func1("set_unique_id", obj)
|
||||
#define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time)
|
||||
#define set_window_flag(winID, flag, value) sfall_func3("set_window_flag", winID, flag, value)
|
||||
#define set_worldmap_heal_time(time) sfall_func1("set_worldmap_heal_time", time)
|
||||
#define show_win sfall_func0("show_window")
|
||||
#define show_window(winName) sfall_func1("show_window", winName)
|
||||
#define signal_close_game sfall_func0("signal_close_game")
|
||||
|
||||
@@ -151,6 +151,7 @@ static const SfallMetarule metarules[] = {
|
||||
{"set_outline", mf_set_outline, 2, 2, -1, {ARG_OBJECT, ARG_INT}},
|
||||
{"set_quest_failure_value", mf_set_quest_failure_value, 2, 2, -1, {ARG_INT, ARG_INT}},
|
||||
{"set_rest_heal_time", mf_set_rest_heal_time, 1, 1, -1, {ARG_INT}},
|
||||
{"set_worldmap_heal_time", mf_set_worldmap_heal_time, 1, 1, -1, {ARG_INT}},
|
||||
{"set_rest_mode", mf_set_rest_mode, 1, 1, -1, {ARG_INT}},
|
||||
{"set_scr_name", mf_set_scr_name, 0, 1, -1, {ARG_STRING}},
|
||||
{"set_selectable_perk_npc", mf_set_selectable_perk_npc, 5, 5, -1, {ARG_OBJECT, ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
|
||||
|
||||
@@ -202,6 +202,10 @@ void mf_set_rest_heal_time(OpcodeContext& ctx) {
|
||||
Worldmap::SetRestHealTime(ctx.arg(0).rawValue());
|
||||
}
|
||||
|
||||
void mf_set_worldmap_heal_time(OpcodeContext& ctx) {
|
||||
Worldmap::SetWorldMapHealTime(ctx.arg(0).rawValue());
|
||||
}
|
||||
|
||||
void mf_set_rest_mode(OpcodeContext& ctx) {
|
||||
Worldmap::SetRestMode(ctx.arg(0).rawValue());
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ void mf_get_map_enter_position(OpcodeContext&);
|
||||
|
||||
void mf_set_rest_heal_time(OpcodeContext&);
|
||||
|
||||
void mf_set_worldmap_heal_time(OpcodeContext&);
|
||||
|
||||
void mf_set_rest_mode(OpcodeContext&);
|
||||
|
||||
void mf_set_rest_on_map(OpcodeContext&);
|
||||
|
||||
@@ -61,6 +61,11 @@ static DWORD worldMapTicks;
|
||||
|
||||
static DWORD WorldMapEncounterRate;
|
||||
|
||||
static constexpr long WorldMapHealingDefaultInterval = 0;
|
||||
// Healing interval in game time
|
||||
static long worldMapHealingInterval = WorldMapHealingDefaultInterval;
|
||||
static DWORD worldMapLastHealTime;
|
||||
|
||||
static double tickFract = 0.0;
|
||||
static double mapMultiMod = 1.0;
|
||||
static float scriptMapMulti = 1.0f;
|
||||
@@ -454,6 +459,40 @@ static void WorldmapFpsPatch() {
|
||||
}
|
||||
}
|
||||
|
||||
// Original function checks how many system Ticks (not game ticks) passed since last WM loop iteration and if more than 1000 ms,
|
||||
// applies one healing to the whole party according to their healing rate.
|
||||
// So we hijack it and return number bigger than 1000 to force the event, or 0 to skip it.
|
||||
static DWORD __fastcall wmWorldMap_HealingTimeElapsed(DWORD elapsedTocks) {
|
||||
if (worldMapHealingInterval == 0) return elapsedTocks;
|
||||
if (worldMapHealingInterval > 0 && ((long)(fo::var::fallout_game_time - worldMapLastHealTime) > worldMapHealingInterval)) {
|
||||
worldMapLastHealTime = fo::var::fallout_game_time;
|
||||
return 10000; // force healing
|
||||
}
|
||||
return 0; // skip healing
|
||||
}
|
||||
|
||||
static void __declspec(naked) wmWorldMap_elapsed_tocks_hook() {
|
||||
__asm {
|
||||
push ecx;
|
||||
call fo::funcoffs::elapsed_tocks_;
|
||||
mov ecx, eax;
|
||||
call wmWorldMap_HealingTimeElapsed;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void WorldmapHealingRatePatch() {
|
||||
dlogr("Applying world map healing rate patch.", DL_INIT);
|
||||
HookCall(0x4C0085, wmWorldMap_elapsed_tocks_hook);
|
||||
LoadGameHook::OnGameModeChange() += [](DWORD state) {
|
||||
if (InWorldMap()) worldMapLastHealTime = fo::var::fallout_game_time;
|
||||
};
|
||||
LoadGameHook::OnGameReset() += []() {
|
||||
worldMapHealingInterval = WorldMapHealingDefaultInterval;
|
||||
};
|
||||
}
|
||||
|
||||
static void PathfinderFixInit() {
|
||||
//if (IniReader::GetConfigInt("Misc", "PathfinderFix", 0)) {
|
||||
dlogr("Applying Pathfinder patch.", DL_INIT);
|
||||
@@ -585,6 +624,13 @@ void Worldmap::SetRestHealTime(DWORD minutes) {
|
||||
}
|
||||
}
|
||||
|
||||
void Worldmap::SetWorldMapHealTime(long minutes) {
|
||||
worldMapHealingInterval = minutes >= 0
|
||||
? minutes * 60 * 10
|
||||
: -1;
|
||||
worldMapLastHealTime = fo::var::fallout_game_time;
|
||||
}
|
||||
|
||||
void Worldmap::SetRestMode(DWORD mode) {
|
||||
RestRestore(); // restore default
|
||||
|
||||
@@ -601,8 +647,8 @@ void Worldmap::SetRestMode(DWORD mode) {
|
||||
SafeWrite32(0x42E588, 0x94); // jmp 0x42E620
|
||||
}
|
||||
if (mode & 4) { // bit3 - disable healing during resting
|
||||
SafeWrite16(0x499FD4, 0x9090);
|
||||
SafeWrite16(0x499E93, 0x8FEB); // jmp 0x499E24
|
||||
SafeWrite16(0x499FD4, 0x9090); // Check4Health_
|
||||
SafeWrite16(0x499E93, 0x8FEB); // TimedRest_: jmp 0x499E24
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,6 +737,7 @@ void Worldmap::init() {
|
||||
MapLimitsPatches();
|
||||
WorldmapFpsPatch();
|
||||
PipBoyAutomapsPatch();
|
||||
WorldmapHealingRatePatch();
|
||||
|
||||
// Add a flashing icon to the Horrigan encounter
|
||||
HookCall(0x4C071C, wmRndEncounterOccurred_hook);
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
|
||||
static void SetCarInterfaceArt(DWORD artIndex);
|
||||
static void SetRestHealTime(DWORD minutes);
|
||||
static void SetWorldMapHealTime(long minutes);
|
||||
static void SetRestMode(DWORD mode);
|
||||
static void SetRestMapLevel(int mapId, long elev, bool canRest);
|
||||
static long __fastcall GetRestMapLevel(long elev, int mapId);
|
||||
|
||||
Reference in New Issue
Block a user