diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 2baca3ac..922de4ee 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -389,6 +389,7 @@ #define set_quest_failure_value(gvar, threshold) sfall_func2("set_quest_failure_value", gvar, threshold) #define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time) #define set_rest_mode(mode) sfall_func1("set_rest_mode", mode) +#define set_scr_name(name) sfall_func1("set_scr_name", name) #define set_terrain_name(x, y, name) sfall_func3("set_terrain_name", x, y, name) #define set_town_title(areaID, title) sfall_func2("set_town_title", areaID, title) #define set_unique_id(obj) sfall_func1("set_unique_id", obj) @@ -405,6 +406,7 @@ #define tile_by_position(x, y) sfall_func2("tile_by_position", x, y) #define tile_refresh_display sfall_func0("tile_refresh_display") #define unjam_lock(obj) sfall_func1("unjam_lock", obj) +#define unset_scr_name sfall_func0("set_scr_name") /* sets the name of the script object from pro_*.msg instead of scrname.msg */ #define unset_unique_id(obj) sfall_func2("set_unique_id", obj, -1) #define unwield_slot(critter, slot) sfall_func2("unwield_slot", critter, slot) #define win_fill_color(x, y, width, height, color) sfall_func5("win_fill_color", x, y, width, height, color) diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index a36df9df..1cf17f0f 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -199,6 +199,7 @@ WRAP_WATCOM_FUNC2(long, perk_level, fo::GameObject*, critter, long, perkId) //WRAP_WATCOM_FUNC2(void, perk_remove_effect, fo::GameObject*, critter, long, perkId) WRAP_WATCOM_FUNC6(long, pick_death, fo::GameObject*, attacker, fo::GameObject*, target, fo::GameObject*, weapon, long, amount, long, anim, long, hitFromBack) WRAP_WATCOM_FUNC0(void, process_bk) +WRAP_WATCOM_FUNC2(const char*, proto_get_msg_info, long, pid, long, msgType) // msgType: 0 - name, 1 - desc WRAP_WATCOM_FUNC0(void, proto_dude_update_gender) WRAP_WATCOM_FUNC2(void, proto_make_path, char*, buffer, long, pid) // Places pointer to a prototype structure into ptrPtr and returns 0 on success or -1 on failure diff --git a/sfall/Modules/DamageMod.cpp b/sfall/Modules/DamageMod.cpp index 27abb8f8..92dbdfe7 100644 --- a/sfall/Modules/DamageMod.cpp +++ b/sfall/Modules/DamageMod.cpp @@ -460,7 +460,7 @@ void DamageMod::init() { }); HookCalls(CommonDmgRngDispFix_hook, { 0x472266, // MeleeWeap (display_stats_) - 0x472546 // Unarmed (display_stats_) + //0x472546 // Unarmed (display_stats_) }); } //MakeCall(0x478492, HtHDamageFix1a_hack); // Unarmed (item_w_damage_) diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index d2314bba..a3715f42 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -346,15 +346,14 @@ static void ResetDevice(bool create) { } #if !(NDEBUG) && !(_DEBUG) +static DWORD lastTime = GetTickCount(); static long frameCount; static long elapsedTime; static long fps; -static long palCounter; -static long lockCounter; +//static long palCounter; +//static long lockCounter; static void CalcFPS() { - static DWORD lastTime = GetTickCount(); - frameCount++; DWORD time = GetTickCount(); @@ -940,7 +939,7 @@ public: if (Graphics::GPUBlt) { D3DLOCKED_RECT pal; if (c != 256) { - RECT rect = { b, 0, b + c, 1 }; + RECT rect = { static_cast(b), 0, static_cast(b + c), 1 }; paletteTex->LockRect(0, &pal, &rect, D3DLOCK_NO_DIRTY_UPDATE); paletteTex->AddDirtyRect(&rect); b = 0; diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 4bf72cee..610e5d97 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -65,6 +65,7 @@ static Delegate onGameModeChange; static Delegate<> onBeforeGameClose; static Delegate<> onCombatStart; static Delegate<> onCombatEnd; +static Delegate<> onBeforeMapLoad; static DWORD inLoop = 0; static DWORD saveInCombatFix; @@ -365,6 +366,10 @@ static void __stdcall GameClose() { onBeforeGameClose.invoke(); } +static void __stdcall MapLoadHook() { + onBeforeMapLoad.invoke(); +} + static void __declspec(naked) main_init_system_hook() { __asm { pushadc; @@ -442,8 +447,13 @@ static void __declspec(naked) map_load_hook() { mov ecx, 4; rep movsd; // copy the name of the loaded map to mapLoadingName mov onLoadingMap, 1; + push eax; + push edx; + call MapLoadHook; + pop edx; + pop eax; call fo::funcoffs::map_load_file_; - mov onLoadingMap, cl; // unset + mov onLoadingMap, 0; retn; } } @@ -883,4 +893,9 @@ Delegate<>& LoadGameHook::OnCombatStart() { Delegate<>& LoadGameHook::OnCombatEnd() { return onCombatEnd; } + +Delegate<>& LoadGameHook::OnBeforeMapLoad() { + return onBeforeMapLoad; +} + } diff --git a/sfall/Modules/LoadGameHook.h b/sfall/Modules/LoadGameHook.h index f56c89eb..01496e16 100644 --- a/sfall/Modules/LoadGameHook.h +++ b/sfall/Modules/LoadGameHook.h @@ -62,6 +62,8 @@ public: static Delegate<>& OnCombatStart(); static Delegate<>& OnCombatEnd(); + static Delegate<>& OnBeforeMapLoad(); + static bool IsMapLoading(); static char mapLoadingName[16]; diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index 08d8ea6e..8d6d1efe 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -32,6 +32,8 @@ #include "MainLoopHook.h" #include "Worldmap.h" +#include "SubModules\ObjectName.h" + #include "Scripting\Arrays.h" #include "Scripting\Opcodes.h" #include "Scripting\OpcodeContext.h" @@ -1008,6 +1010,7 @@ void ScriptExtender::init() { } Opcodes::InitNew(); + ObjectName::init(); ScriptExtender::OnMapExit() += ClearEventsOnMapExit; // for reordering the execution of functions before exiting the map } diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 513d70e5..4d8a04d0 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -139,6 +139,7 @@ static const SfallMetarule metarules[] = { {"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_rest_mode", mf_set_rest_mode, 1, 1, -1, {ARG_INT}}, + {"set_scr_name", mf_set_src_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}}, {"set_terrain_name", mf_set_terrain_name, 3, 3, -1, {ARG_INT, ARG_INT, ARG_STRING}}, {"set_town_title", mf_set_town_title, 2, 2, -1, {ARG_INT, ARG_STRING}}, diff --git a/sfall/Modules/Scripting/Handlers/Misc.cpp b/sfall/Modules/Scripting/Handlers/Misc.cpp index 6d765da7..7873343f 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.cpp +++ b/sfall/Modules/Scripting/Handlers/Misc.cpp @@ -31,6 +31,8 @@ #include "..\..\ScriptExtender.h" #include "..\..\Sound.h" +#include "..\..\SubModules\ObjectName.h" + #include "..\Arrays.h" #include "Misc.h" @@ -501,5 +503,12 @@ void mf_set_quest_failure_value(OpcodeContext& ctx) { QuestList::AddQuestFailureValue(ctx.arg(0).rawValue(), ctx.arg(1).rawValue()); } +void mf_set_src_name(OpcodeContext& ctx) { + long sid = fo::func::scr_find_sid_from_program(ctx.program()); + if (sid == -1) return; + + ObjectName::SetName(sid, ctx.arg(0).strValue()); +} + } } diff --git a/sfall/Modules/Scripting/Handlers/Misc.h b/sfall/Modules/Scripting/Handlers/Misc.h index 1af23a26..4287a317 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.h +++ b/sfall/Modules/Scripting/Handlers/Misc.h @@ -104,5 +104,7 @@ void mf_get_ini_section(OpcodeContext&); void mf_set_quest_failure_value(OpcodeContext&); +void mf_set_src_name(OpcodeContext&); + } } diff --git a/sfall/Modules/SubModules/ObjectName.cpp b/sfall/Modules/SubModules/ObjectName.cpp new file mode 100644 index 00000000..652ecda9 --- /dev/null +++ b/sfall/Modules/SubModules/ObjectName.cpp @@ -0,0 +1,140 @@ +/* + * sfall + * Copyright (C) 2008-2021 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "..\..\main.h" +#include "..\..\FalloutEngine\Fallout2.h" + +#include "..\LoadGameHook.h" + +#include "ObjectName.h" + +namespace sfall +{ + +static std::unordered_map overrideScrName; + +static long lastNamePid = -1; +static long lastNameSid = -1; +static long lastItemPid = -1; + +void ObjectName::SetName(long sid, const char* name) { + if (!name) name = ""; + overrideScrName.emplace(sid, name); +} + +const char* __stdcall ObjectName::GetName(fo::GameObject* object) { + if (!overrideScrName.empty()) { + auto name = overrideScrName.find(object->scriptId); + if (name != overrideScrName.cend()) { + return (name->second.length() > 0) + ? name->second.c_str() + : fo::func::proto_get_msg_info(object->protoId, 0); + } + } + return nullptr; +} + +static void __declspec(naked) critter_name_hack() { + static DWORD critter_name_hack_ret = 0x42D125; + using namespace fo::Fields; + __asm { + push ebx; // object + call ObjectName::GetName; + test eax, eax; + jnz override; + mov edi, [ebx + scriptIndex]; + retn; +override: + add esp, 4; + jmp critter_name_hack_ret; + } +} + +static void __declspec(naked) critter_name_hack_check() { + static DWORD critter_name_hack_ret = 0x42D12F; + using namespace fo::Fields; + __asm { + mov ecx, [ebx + scriptId]; + cmp ecx, -1; + je checkPid; // has no script, check only the PID + cmp ecx, lastNameSid; + jne default; + add esp, 4; + mov eax, ds:[FO_VAR_name_critter]; + jmp critter_name_hack_ret; +checkPid: + mov ecx, [ebx + protoId]; + cmp ecx, lastNamePid; + jne default; + add esp, 4; + mov eax, ds:[FO_VAR_name_critter]; + jmp critter_name_hack_ret; +default: + mov ecx, [ebx + scriptIndex]; + retn; + } +} + +static void __declspec(naked) critter_name_hack_end() { + using namespace fo::Fields; + __asm { + mov edx, [ebx + protoId]; + mov lastNamePid, edx; + mov ecx, [ebx + scriptId]; + mov lastNameSid, ecx; + retn; + } +} + +static void __declspec(naked) object_name_hook() { + using namespace fo::Fields; + __asm { + mov edx, [eax + protoId]; + cmp edx, lastItemPid; + je getLast; + mov lastItemPid, edx; + jmp fo::funcoffs::item_name_; +getLast: + mov eax, ds:[FO_VAR_name_item]; + retn; + } +} + +static void Reset() { + overrideScrName.clear(); + lastNameSid = -1; +} + +void ObjectName::init() { + // Returns the redefined object name + MakeCall(0x42D0F2, critter_name_hack, 1); + + // Tweak for quickly getting last object name + MakeCall(0x42D0C4, critter_name_hack_check, 1); + MakeCall(0x42D12A, critter_name_hack_end); + HookCall(0x48C901, object_name_hook); + + LoadGameHook::OnBeforeMapLoad() += Reset; + LoadGameHook::OnGameReset() += []() { + Reset(); + lastNamePid = -1; + lastItemPid = -1; + }; +} + +} \ No newline at end of file diff --git a/sfall/Modules/SubModules/ObjectName.h b/sfall/Modules/SubModules/ObjectName.h new file mode 100644 index 00000000..ca7aff59 --- /dev/null +++ b/sfall/Modules/SubModules/ObjectName.h @@ -0,0 +1,32 @@ +/* + * sfall + * Copyright (C) 2008-2021 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +namespace sfall +{ + +class ObjectName { +public: + static void init(); + + static const char* __stdcall GetName(fo::GameObject* object); + static void SetName(long sid, const char* name); +}; + +} diff --git a/sfall/ddraw.vcxproj b/sfall/ddraw.vcxproj index 0c2b2350..4960ce07 100644 --- a/sfall/ddraw.vcxproj +++ b/sfall/ddraw.vcxproj @@ -335,6 +335,7 @@ + @@ -450,6 +451,7 @@ + diff --git a/sfall/ddraw.vcxproj.filters b/sfall/ddraw.vcxproj.filters index 6a618c96..e6d61404 100644 --- a/sfall/ddraw.vcxproj.filters +++ b/sfall/ddraw.vcxproj.filters @@ -367,6 +367,9 @@ Modules + + Modules\SubModules + @@ -675,6 +678,9 @@ Modules + + Modules\SubModules +