diff --git a/artifacts/config_files/Perks.ini b/artifacts/config_files/Perks.ini index 37e82fc1..22232654 100644 --- a/artifacts/config_files/Perks.ini +++ b/artifacts/config_files/Perks.ini @@ -28,7 +28,7 @@ WeaponHandlingBonus=3 ;############################################################################## [Perks] -;Set to 1 to enable the modifications to perks +;Set to 1 to enable modifications to perks Enable=0 ;Name=The name of the perk (max 63 characters) @@ -125,7 +125,7 @@ Skill5Mod=0 ;############################################################################## [Traits] -;Set to 1 to enable the modifications to traits +;Set to 1 to enable modifications to traits Enable=0 ;This is a modification to trait 0 diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index 2b9b09bc..ccafafd9 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -141,11 +141,11 @@ DWORD _stdcall GetHSArg() { return (cArg == argCount) ? 0 : args[cArg++]; } -void _stdcall SetHSArg(DWORD id, DWORD value) { +void SetHSArg(DWORD id, DWORD value) { if (id < argCount) args[id] = value; } -DWORD* _stdcall GetHSArgs() { +DWORD* GetHSArgs() { return args; } diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index 0a81b86b..75c0f8f1 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -88,8 +88,8 @@ public: DWORD _stdcall GetHSArgCount(); DWORD _stdcall GetHSArg(); -DWORD* _stdcall GetHSArgs(); -void _stdcall SetHSArg(DWORD id, DWORD value); +DWORD* GetHSArgs(); +void SetHSArg(DWORD id, DWORD value); void _stdcall SetHSReturn(DWORD d); // register hook by proc num (special values: -1 - use default (start) procedure, 0 - unregister) diff --git a/sfall/Modules/Perks.cpp b/sfall/Modules/Perks.cpp index af0573fb..a9d22ef0 100644 --- a/sfall/Modules/Perks.cpp +++ b/sfall/Modules/Perks.cpp @@ -29,6 +29,8 @@ namespace sfall { using namespace fo; +long Perks::PerkLevelMod = 0; + constexpr int maxNameLen = 64; // don't change size constexpr int maxDescLen = 512; // don't change size static const int descLen = 256; // maximum text length for interface @@ -1291,7 +1293,7 @@ void PerksReset() { // Reset some settable game values back to the defaults // Perk level mod - SafeWrite32(0x496880, 0x019078); + Perks::PerkLevelMod = 0; // Pyromaniac bonus SafeWrite8(0x424AB6, 5); // Swift Learner bonus diff --git a/sfall/Modules/Perks.h b/sfall/Modules/Perks.h index 5b448286..dab65212 100644 --- a/sfall/Modules/Perks.h +++ b/sfall/Modules/Perks.h @@ -39,6 +39,8 @@ public: static DWORD HasFakeTrait(const char* name); static DWORD HasFakePerkOwner(const char* name, long objId); static DWORD HasFakeTraitOwner(const char* name, long objId); + + static long PerkLevelMod; }; void PerksEnterCharScreen(); diff --git a/sfall/Modules/Scripting/Handlers/Core.cpp b/sfall/Modules/Scripting/Handlers/Core.cpp index b086ab59..ea0a17e1 100644 --- a/sfall/Modules/Scripting/Handlers/Core.cpp +++ b/sfall/Modules/Scripting/Handlers/Core.cpp @@ -35,13 +35,11 @@ namespace script void __declspec(naked) op_set_global_script_repeat() { __asm { push ecx; - push edx; mov ecx, eax; _GET_ARG_INT(end); mov edx, eax; // frames call SetGlobalScriptRepeat; // ecx - script end: - pop edx; pop ecx; retn; } @@ -50,13 +48,11 @@ end: void __declspec(naked) op_set_global_script_type() { __asm { push ecx; - push edx; mov ecx, eax; _GET_ARG_INT(end); mov edx, eax; // type call SetGlobalScriptType; // ecx - script end: - pop edx; pop ecx; retn; } @@ -65,10 +61,8 @@ end: void __declspec(naked) op_available_global_script_types() { __asm { push ecx; - push edx; mov edx, availableGlobalScriptTypes; _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } @@ -114,79 +108,37 @@ void sf_get_sfall_global_float(OpcodeContext& ctx) { void __declspec(naked) op_get_sfall_arg() { __asm { push ecx; - push edx; push eax; call GetHSArg; mov edx, eax; pop eax; _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } } -static DWORD _stdcall GetSfallArgs() { +void sf_get_sfall_args(OpcodeContext& ctx) { DWORD argCount = GetHSArgCount(); DWORD id = TempArray(argCount, 0); DWORD* args = GetHSArgs(); for (DWORD i = 0; i < argCount; i++) { arrays[id].val[i].set(*(long*)&args[i]); } - return id; + ctx.setReturn(id); } -void __declspec(naked) op_get_sfall_args() { // rewrite to c++ - __asm { - push ecx; - push edx; - push eax; - call GetSfallArgs; - mov edx, eax; - pop eax; - _RET_VAL_INT(ecx); - pop edx; - pop ecx; - retn; - } -} - -void __declspec(naked) op_set_sfall_arg() { - __asm { - pushad; - mov ecx, eax; - call fo::funcoffs::interpretPopShort_; - mov edi, eax; - mov eax, ecx; - call fo::funcoffs::interpretPopLong_; - mov edx, eax; - mov eax, ecx; - call fo::funcoffs::interpretPopShort_; - mov esi, eax; - mov eax, ecx; - call fo::funcoffs::interpretPopLong_; - cmp di, VAR_TYPE_INT; - jnz end; - cmp si, VAR_TYPE_INT; - jnz end; - push edx; - push eax; - call SetHSArg; -end: - popad; - retn; - } +void sf_set_sfall_arg(OpcodeContext& ctx) { + SetHSArg(ctx.arg(0).rawValue(), ctx.arg(1).rawValue()); } void __declspec(naked) op_set_sfall_return() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call SetHSReturn; end: - pop edx; pop ecx; retn; } @@ -194,26 +146,22 @@ end: void __declspec(naked) op_init_hook() { __asm { - push edx; push ecx; mov edx, initingHookScripts; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } -void __declspec(naked) op_set_self() { // rewrite to c++ +void __declspec(naked) op_set_self() { __asm { push ecx; - push edx; mov ecx, eax; _GET_ARG_INT(end); mov edx, eax; // object call SetSelfObject; // ecx - script end: - pop edx; pop ecx; retn; } diff --git a/sfall/Modules/Scripting/Handlers/Core.h b/sfall/Modules/Scripting/Handlers/Core.h index eb1ead6e..f3d76a91 100644 --- a/sfall/Modules/Scripting/Handlers/Core.h +++ b/sfall/Modules/Scripting/Handlers/Core.h @@ -41,9 +41,9 @@ void sf_get_sfall_global_float(OpcodeContext&); void __declspec() op_get_sfall_arg(); -void __declspec() op_get_sfall_args(); +void sf_get_sfall_args(OpcodeContext&); -void __declspec() op_set_sfall_arg(); +void sf_set_sfall_arg(OpcodeContext&); void __declspec() op_set_sfall_return(); diff --git a/sfall/Modules/Scripting/Handlers/Graphics.cpp b/sfall/Modules/Scripting/Handlers/Graphics.cpp index 39d7d2e5..18b4c9d5 100644 --- a/sfall/Modules/Scripting/Handlers/Graphics.cpp +++ b/sfall/Modules/Scripting/Handlers/Graphics.cpp @@ -32,14 +32,12 @@ namespace script void __declspec(naked) op_graphics_funcs_available() { __asm { - push edx; push ecx; cmp Graphics::mode, 3; seta dl; and edx, 0xFF; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -86,12 +84,10 @@ result: void __declspec(naked) op_free_shader() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call FreeShader; end: - pop edx; pop ecx; retn; } @@ -100,12 +96,10 @@ end: void __declspec(naked) op_activate_shader() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call ActivateShader; end: - pop edx; pop ecx; retn; } @@ -114,12 +108,10 @@ end: void __declspec(naked) op_deactivate_shader() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call DeactivateShader; end: - pop edx; pop ecx; retn; } @@ -414,13 +406,11 @@ end: void __declspec(naked) op_get_shader_version() { __asm { push ecx; - push edx; push eax; call GetShaderVersion; mov edx, eax; pop eax; _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } @@ -464,12 +454,10 @@ end: void __declspec(naked) op_force_graphics_refresh() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call ForceGraphicsRefresh; end: - pop edx; pop ecx; retn; } diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index f8ef13e7..8a778538 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -35,10 +35,8 @@ namespace script void __declspec(naked) op_input_funcs_available() { __asm { push ecx; - push edx; mov edx, 1; // They're always available from 2.9 on _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } @@ -51,7 +49,6 @@ void sf_key_pressed(OpcodeContext& ctx) { void __declspec(naked) op_tap_key() { __asm { push ecx; - push edx; _GET_ARG_INT(end); test eax, eax; jl end; @@ -60,7 +57,6 @@ void __declspec(naked) op_tap_key() { push eax; call TapKey; end: - pop edx; pop ecx; retn; } @@ -68,26 +64,22 @@ end: void __declspec(naked) op_get_mouse_x() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_mouse_x_]; add edx, ds:[FO_VAR_mouse_hotx]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } void __declspec(naked) op_get_mouse_y() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_mouse_y_]; add edx, ds:[FO_VAR_mouse_hoty]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -103,40 +95,34 @@ void sf_get_mouse_buttons(OpcodeContext& ctx) { void __declspec(naked) op_get_window_under_mouse() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_last_button_winID]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } void __declspec(naked) op_get_screen_width() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_scr_size + 8]; // _scr_size.offx sub edx, ds:[FO_VAR_scr_size]; // _scr_size.x inc edx; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } void __declspec(naked) op_get_screen_height() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_scr_size + 12]; // _scr_size.offy sub edx, ds:[FO_VAR_scr_size + 4]; // _scr_size.y inc edx; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -165,24 +151,20 @@ void sf_create_message_window(OpcodeContext &ctx) { void __declspec(naked) op_get_viewport_x() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_wmWorldOffsetX]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } void __declspec(naked) op_get_viewport_y() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_wmWorldOffsetY]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -190,11 +172,9 @@ void __declspec(naked) op_get_viewport_y() { void __declspec(naked) op_set_viewport_x() { __asm { push ecx; - push edx; _GET_ARG_INT(end); mov ds:[FO_VAR_wmWorldOffsetX], eax; end: - pop edx; pop ecx; retn; } @@ -203,11 +183,9 @@ end: void __declspec(naked) op_set_viewport_y() { __asm { push ecx; - push edx; _GET_ARG_INT(end); mov ds:[FO_VAR_wmWorldOffsetY], eax; end: - pop edx; pop ecx; retn; } @@ -323,19 +301,23 @@ void sf_set_iface_tag_text(OpcodeContext& ctx) { void sf_inventory_redraw(OpcodeContext& ctx) { int mode; - DWORD loopFlag = GetLoopFlags(); - if (loopFlag & INVENTORY) { - mode = 0; - } else if (loopFlag & INTFACEUSE) { - mode = 1; - } else if (loopFlag & INTFACELOOT) { - mode = 2; - } else if (loopFlag & BARTER) { - mode = 3; - } else { - return; + DWORD loopFlag = GetLoopFlags() & (INVENTORY | INTFACEUSE | INTFACELOOT | BARTER); + switch (loopFlag) { + case INVENTORY: + mode = 0; + break; + case INTFACEUSE: + mode = 1; + break; + case INTFACELOOT: + mode = 2; + break; + case BARTER: + mode = 3; + break; + default: + return; } - if (!ctx.arg(0).asBool()) { fo::var::stack_offset[fo::var::curr_stack] = 0; fo::func::display_inventory(0, -1, mode); diff --git a/sfall/Modules/Scripting/Handlers/Misc.cpp b/sfall/Modules/Scripting/Handlers/Misc.cpp index ea1248c8..af73e0e0 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.cpp +++ b/sfall/Modules/Scripting/Handlers/Misc.cpp @@ -289,8 +289,6 @@ void sf_set_object_knockback(OpcodeContext& ctx) { case 0x197: mode = 2; break; - default: - break; } fo::GameObject* object = ctx.arg(0).asObject(); if (mode) { @@ -316,8 +314,6 @@ void sf_remove_object_knockback(OpcodeContext& ctx) { case 0x19a: mode = 2; break; - default: - break; } KnockbackRemoveMod(ctx.arg(0).asObject(), mode); } @@ -390,12 +386,10 @@ end: void __declspec(naked) op_active_hand() { __asm { - push edx; push ecx; mov edx, dword ptr ds:[FO_VAR_itemCurrentItem]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -409,12 +403,10 @@ void __declspec(naked) op_toggle_active_hand() { void __declspec(naked) op_eax_available() { __asm { - push edx; push ecx; xor edx, edx _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -589,13 +581,11 @@ void sf_get_ini_string(OpcodeContext& ctx) { void __declspec(naked) op_get_uptime() { __asm { push ecx; - push edx; push eax; call GetTickCount; mov edx, eax; pop eax; _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } @@ -604,11 +594,9 @@ void __declspec(naked) op_get_uptime() { void __declspec(naked) op_set_car_current_town() { __asm { push ecx; - push edx; _GET_ARG_INT(end); mov ds:[FO_VAR_carCurrentArea], eax; end: - pop edx; pop ecx; retn; } @@ -617,13 +605,11 @@ end: void __declspec(naked) op_set_hp_per_level_mod() { // rewrite to c++ __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; // allowed -/+127 push 0x4AFBC1; call SafeWrite8; end: - pop edx; pop ecx; retn; } @@ -736,11 +722,9 @@ void sf_reset_critical_table(OpcodeContext& ctx) { void __declspec(naked) op_set_unspent_ap_bonus() { __asm { push ecx; - push edx; _GET_ARG_INT(end); - mov standardApAcBonus, eax; + mov Stats::standardApAcBonus, eax; end: - pop edx; pop ecx; retn; } @@ -748,12 +732,10 @@ end: void __declspec(naked) op_get_unspent_ap_bonus() { __asm { - push edx; push ecx; - mov edx, standardApAcBonus; + mov edx, Stats::standardApAcBonus; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -761,11 +743,9 @@ void __declspec(naked) op_get_unspent_ap_bonus() { void __declspec(naked) op_set_unspent_ap_perk_bonus() { __asm { push ecx; - push edx; _GET_ARG_INT(end); - mov extraApAcBonus, eax; + mov Stats::extraApAcBonus, eax; end: - pop edx; pop ecx; retn; } @@ -773,12 +753,10 @@ end: void __declspec(naked) op_get_unspent_ap_perk_bonus() { __asm { - push edx; push ecx; - mov edx, extraApAcBonus; + mov edx, Stats::extraApAcBonus; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -835,12 +813,10 @@ void __declspec(naked) op_nb_create_char() { void __declspec(naked) op_hero_select_win() { // for opening the appearance selection window __asm { push ecx; - push edx; _GET_ARG_INT(fail); push eax; call HeroSelectWindow; fail: - pop edx; pop ecx; retn; } @@ -849,12 +825,10 @@ fail: void __declspec(naked) op_set_hero_style() { // for setting the hero style/appearance takes an 1 int __asm { push ecx; - push edx; _GET_ARG_INT(fail); push eax; call SetHeroStyle; fail: - pop edx; pop ecx; retn; } @@ -863,12 +837,10 @@ fail: void __declspec(naked) op_set_hero_race() { // for setting the hero race takes an 1 int __asm { push ecx; - push edx; _GET_ARG_INT(fail); push eax; call SetHeroRace; fail: - pop edx; pop ecx; retn; } @@ -876,12 +848,10 @@ fail: void __declspec(naked) op_get_light_level() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_ambient_light]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -889,9 +859,7 @@ void __declspec(naked) op_get_light_level() { void __declspec(naked) op_refresh_pc_art() { __asm { push ecx; - push edx; call RefreshPCArt; - pop edx; pop ecx; retn; } @@ -945,12 +913,10 @@ end: void __declspec(naked) op_stop_sfall_sound() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call StopSfallSound; end: - pop edx; pop ecx; retn; } @@ -992,12 +958,10 @@ end: void __declspec(naked) op_modified_ini() { __asm { - push edx; push ecx; mov edx, modifiedIni; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -1005,12 +969,10 @@ void __declspec(naked) op_modified_ini() { void __declspec(naked) op_force_aimed_shots() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call ForceAimedShots; end: - pop edx; pop ecx; retn; } @@ -1019,12 +981,10 @@ end: void __declspec(naked) op_disable_aimed_shots() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call DisableAimedShots; end: - pop edx; pop ecx; retn; } @@ -1033,7 +993,6 @@ end: void __declspec(naked) op_mark_movie_played() { __asm { push ecx; - push edx; _GET_ARG_INT(end); test eax, eax; jl end; @@ -1041,7 +1000,6 @@ void __declspec(naked) op_mark_movie_played() { jge end; mov byte ptr ds:[eax + FO_VAR_gmovie_played_list], 1; end: - pop edx; pop ecx; retn; } @@ -1104,12 +1062,10 @@ end: void __declspec(naked) op_block_combat() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call AIBlockCombat; end: - pop edx; pop ecx; retn; } @@ -1145,12 +1101,10 @@ void __declspec(naked) op_tile_under_cursor() { void __declspec(naked) op_gdialog_get_barter_mod() { __asm { - push edx; push ecx; mov edx, dword ptr ds:[FO_VAR_gdBarterMod]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -1158,12 +1112,10 @@ void __declspec(naked) op_gdialog_get_barter_mod() { void __declspec(naked) op_set_inven_ap_cost() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call SetInvenApCost; end: - pop edx; pop ecx; retn; } diff --git a/sfall/Modules/Scripting/Handlers/Perks.cpp b/sfall/Modules/Scripting/Handlers/Perks.cpp index a470bfa8..1a3c5f30 100644 --- a/sfall/Modules/Scripting/Handlers/Perks.cpp +++ b/sfall/Modules/Scripting/Handlers/Perks.cpp @@ -30,12 +30,10 @@ namespace script void __declspec(naked) op_get_perk_owed() { __asm { - push edx; push ecx; movzx edx, byte ptr ds:[FO_VAR_free_perk]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -43,14 +41,12 @@ void __declspec(naked) op_get_perk_owed() { void __declspec(naked) op_set_perk_owed() { __asm { push ecx; - push edx; _GET_ARG_INT(end); and eax, 0xFF; cmp eax, 250; jg end; mov byte ptr ds:[FO_VAR_free_perk], al; end: - pop edx; pop ecx; retn; } @@ -59,12 +55,10 @@ end: void __declspec(naked) op_set_perk_freq() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call SetPerkFreq; end: - pop edx; pop ecx; retn; } @@ -309,12 +303,10 @@ void sf_has_fake_trait_npc(OpcodeContext& ctx) { void __declspec(naked) op_perk_add_mode() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; call AddPerkMode; end: - pop edx; pop ecx; retn; } @@ -347,13 +339,11 @@ next: void __declspec(naked) op_set_pyromaniac_mod() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; push 0x424AB6; call SafeWrite8; end: - pop edx; pop ecx; retn; } @@ -371,13 +361,45 @@ void __declspec(naked) op_apply_heaveho_fix() { void __declspec(naked) op_set_swiftlearner_mod() { __asm { push ecx; - push edx; _GET_ARG_INT(end); push eax; push 0x4AFAE2; call SafeWrite32; end: - pop edx; + pop ecx; + retn; + } +} + +static void __declspec(naked) perk_can_add_hook() { + __asm { + call fo::funcoffs::stat_pc_get_; + add eax, Perks::PerkLevelMod; + js jneg; // level < 0 + retn; +jneg: + xor eax, eax; + retn; + } +} + +static void __fastcall SetPerkLevelMod(long mod) { + static bool perkLevelModPatch = false; + if (mod < -25 || mod > 25) return; + Perks::PerkLevelMod = mod; + + if (perkLevelModPatch) return; + perkLevelModPatch = true; + HookCall(0x49687F, perk_can_add_hook); +} + +void __declspec(naked) op_set_perk_level_mod() { + __asm { + push ecx; + _GET_ARG_INT(end); + mov ecx, eax; + call SetPerkLevelMod; +end: pop ecx; retn; } diff --git a/sfall/Modules/Scripting/Handlers/Perks.h b/sfall/Modules/Scripting/Handlers/Perks.h index 1e2d6c84..1a781bb4 100644 --- a/sfall/Modules/Scripting/Handlers/Perks.h +++ b/sfall/Modules/Scripting/Handlers/Perks.h @@ -75,5 +75,7 @@ void __declspec() op_apply_heaveho_fix(); void __declspec() op_set_swiftlearner_mod(); +void __declspec() op_set_perk_level_mod(); + } } diff --git a/sfall/Modules/Scripting/Handlers/Stats.cpp b/sfall/Modules/Scripting/Handlers/Stats.cpp index 9d3f4402..b4db3776 100644 --- a/sfall/Modules/Scripting/Handlers/Stats.cpp +++ b/sfall/Modules/Scripting/Handlers/Stats.cpp @@ -237,13 +237,11 @@ end: void __declspec(naked) op_set_available_skill_points() { __asm { push ecx; - push edx; _GET_ARG_INT(end); mov edx, eax; xor eax, eax; call fo::funcoffs::stat_pc_set_; end: - pop edx; pop ecx; retn; } @@ -251,12 +249,10 @@ end: void __declspec(naked) op_get_available_skill_points() { __asm { - push edx; push ecx; mov edx, dword ptr ds:[FO_VAR_curr_pc_stat]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } @@ -264,7 +260,6 @@ void __declspec(naked) op_get_available_skill_points() { void __declspec(naked) op_mod_skill_points_per_level() { __asm { push ecx; - push edx; _GET_ARG_INT(end); cmp eax, 100; jg end; @@ -275,7 +270,6 @@ void __declspec(naked) op_mod_skill_points_per_level() { push 0x43C27A; call SafeWrite8; end: - pop edx; pop ecx; retn; } @@ -876,88 +870,29 @@ end: } } -static float xpmod; -static DWORD xptmp; -static void __declspec(naked) SetXpMod3() { +static DWORD xpTemp; +static void __declspec(naked) statPCAddExperienceCheckPMs_hack() { __asm { - push ebx; - push ecx; - push esi; - push edi; - push ebp; - mov xptmp, eax; - fild xptmp; - fmul xpmod; - fistp xptmp; - mov eax, xptmp; - push 0x4AFABD; - retn; + mov ebp, [esp]; // return addr + mov xpTemp, eax; // experience + fild xpTemp; + fmul Stats::experienceMod; + fistp xpTemp; + mov eax, xpTemp; + sub esp, 0xC; // instead of 0x10 + mov edi, eax; + jmp ebp; } } -static void _stdcall SetXpMod2(DWORD percent) { - MakeJump(0x4AFAB8, SetXpMod3); - xpmod = (float)percent / 100.0f; -} +void sf_set_xp_mod(OpcodeContext& ctx) { + static bool xpModPatch = false; + DWORD percent = ctx.arg(0).rawValue() & 0xFFFF; + Stats::experienceMod = (float)percent / 100.0f; -static int PerkLevelMod; -static void __declspec(naked) SetPerkLevelMod3() { - __asm { - push ebx; - call fo::funcoffs::stat_pc_get_; - pop ebx; - add eax, PerkLevelMod; - cmp eax, 0; - jge end; - xor eax, eax; -end: - retn; - } -} - -static void _stdcall SetPerkLevelMod2(int mod) { - if (mod < -25 || mod > 25) return; - PerkLevelMod = mod; - HookCall(0x49687F, &SetPerkLevelMod3); -} - -void __declspec(naked) op_set_xp_mod() { - __asm { - push ebx; - push ecx; - push edx; - push edi; - mov ecx, eax; - call fo::funcoffs::interpretPopShort_; - mov edx, eax; - mov eax, ecx; - call fo::funcoffs::interpretPopLong_; - cmp dx, VAR_TYPE_INT; - jnz end; - and eax, 0xFFFF; - push eax; - call SetXpMod2; -end: - pop edi; - pop edx; - pop ecx; - pop ebx; - retn; - } -} - -void __declspec(naked) op_set_perk_level_mod() { - __asm { - push ecx; - push edx; - _GET_ARG_INT(end); - push eax; - call SetPerkLevelMod2; -end: - pop edx; - pop ecx; - retn; - } + if (xpModPatch) return; + xpModPatch = true; + MakeCall(0x4AFABD, statPCAddExperienceCheckPMs_hack); } } diff --git a/sfall/Modules/Scripting/Handlers/Stats.h b/sfall/Modules/Scripting/Handlers/Stats.h index df8062a9..90b6f608 100644 --- a/sfall/Modules/Scripting/Handlers/Stats.h +++ b/sfall/Modules/Scripting/Handlers/Stats.h @@ -84,9 +84,7 @@ void __declspec() op_set_npc_stat_max(); void __declspec() op_set_npc_stat_min(); -void __declspec() op_set_xp_mod(); - -void __declspec() op_set_perk_level_mod(); +void sf_set_xp_mod(OpcodeContext&); } } diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.cpp b/sfall/Modules/Scripting/Handlers/Worldmap.cpp index 50bc6bd7..7afb68fd 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.cpp +++ b/sfall/Modules/Scripting/Handlers/Worldmap.cpp @@ -89,13 +89,11 @@ void sf_force_encounter(OpcodeContext& cxt) { void __declspec(naked) op_in_world_map() { __asm { push ecx; - push edx; push eax; call InWorldMap; mov edx, eax; pop eax; _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } @@ -104,13 +102,11 @@ void __declspec(naked) op_in_world_map() { void __declspec(naked) op_get_game_mode() { __asm { push ecx; - push edx; push eax; call GetLoopFlags; mov edx, eax; pop eax; _RET_VAL_INT(ecx); - pop edx; pop ecx; retn; } @@ -118,24 +114,20 @@ void __declspec(naked) op_get_game_mode() { void __declspec(naked) op_get_world_map_x_pos() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_world_xpos]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } void __declspec(naked) op_get_world_map_y_pos() { __asm { - push edx; push ecx; mov edx, ds:[FO_VAR_world_ypos]; _RET_VAL_INT(ecx); pop ecx; - pop edx; retn; } } diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index edb15565..e4bf2fa4 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -86,6 +86,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = { {0x19e, "get_sfall_global_int", sf_get_sfall_global_int, 1, true, {ARG_INTSTR}}, {0x19f, "get_sfall_global_float", sf_get_sfall_global_float, 1, true, {ARG_INTSTR}}, {0x1a5, "inc_npc_level", sf_inc_npc_level, 1, false, {ARG_INTSTR}}, + {0x1aa, "set_xp_mod", sf_set_xp_mod, 1, false, {ARG_INT}}, {0x1ac, "get_ini_setting", sf_get_ini_setting, 1, true, {ARG_STRING}}, {0x1bb, "set_fake_perk", sf_set_fake_perk, 4, false, {ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}}, @@ -159,6 +160,8 @@ static SfallOpcodeInfo opcodeInfoArray[] = { {0x237, "atoi", sf_atoi, 1, true, {ARG_STRING}}, {0x238, "atof", sf_atof, 1, true, {ARG_STRING}}, {0x239, "scan_array", sf_scan_array, 2, true, {ARG_OBJECT, ARG_ANY}}, + {0x23c, "get_sfall_args", sf_get_sfall_args, 0, true}, + {0x23d, "set_sfall_arg", sf_set_sfall_arg, 2, false, {ARG_INT, ARG_INT}}, {0x241, "get_npc_level", sf_get_npc_level, 1, true, {ARG_INTSTR}}, {0x24e, "substr", sf_substr, 3, true, {ARG_STRING, ARG_INT, ARG_INT}}, @@ -327,7 +330,6 @@ void InitNewOpcodes() { opcodes[0x1a7] = op_get_viewport_y; opcodes[0x1a8] = op_set_viewport_x; opcodes[0x1a9] = op_set_viewport_y; - opcodes[0x1aa] = op_set_xp_mod; opcodes[0x1ab] = op_set_perk_level_mod; opcodes[0x1ad] = op_get_shader_version; opcodes[0x1ae] = op_set_shader_mode; @@ -394,8 +396,6 @@ void InitNewOpcodes() { opcodes[0x23a] = op_get_tile_fid; opcodes[0x23b] = op_modified_ini; - opcodes[0x23c] = op_get_sfall_args; - opcodes[0x23d] = op_set_sfall_arg; opcodes[0x23e] = op_force_aimed_shots; opcodes[0x23f] = op_disable_aimed_shots; opcodes[0x240] = op_mark_movie_played; diff --git a/sfall/Modules/Stats.cpp b/sfall/Modules/Stats.cpp index 0602ac20..f2ab8b23 100644 --- a/sfall/Modules/Stats.cpp +++ b/sfall/Modules/Stats.cpp @@ -16,9 +16,6 @@ * along with this program. If not, see . */ -#include -#include - #include "..\main.h" #include "..\FalloutEngine\Fallout2.h" #include "CritterStats.h" @@ -36,6 +33,10 @@ static DWORD statMinimumsNPC[fo::STAT_max_stat]; static DWORD xpTable[99]; +float Stats::experienceMod = 1.0f; // set_xp_mod func +DWORD Stats::standardApAcBonus = 4; +DWORD Stats::extraApAcBonus = 4; + static struct StatFormula { long base; long min; @@ -43,9 +44,6 @@ static struct StatFormula { double multi[fo::STAT_lu + 1]; } statFormulas[fo::STAT_max_derived + 1] = {0}; -DWORD standardApAcBonus = 4; -DWORD extraApAcBonus = 4; - static fo::GameObject* cCritter; static const DWORD StatLevelHack_Ret = 0x4AEF52; @@ -136,12 +134,12 @@ static void __declspec(naked) CalcApToAcBonus() { mov edx, PERK_hth_evade_perk; mov eax, dword ptr ds:[FO_VAR_obj_dude]; call fo::funcoffs::perk_level_; - imul eax, extraApAcBonus; // bonus = perkLvl * extraApBonus - imul eax, edi; // perkBonus = bonus * curAP + imul eax, Stats::extraApAcBonus; // bonus = perkLvl * extraApBonus + imul eax, edi; // perkBonus = bonus * curAP standard: - imul edi, standardApAcBonus; // stdBonus = curAP * standardApBonus - add eax, edi; // bonus = perkBonus + stdBonus - shr eax, 2; // acBonus = bonus / 4 + imul edi, Stats::standardApAcBonus; // stdBonus = curAP * standardApBonus + add eax, edi; // bonus = perkBonus + stdBonus + shr eax, 2; // acBonus = bonus / 4 end: retn; } @@ -212,13 +210,11 @@ allow: } } -void StatsReset() { +static void StatsReset() { for (int i = 0; i < fo::STAT_max_stat; i++) { statMaximumsPC[i] = statMaximumsNPC[i] = fo::var::stat_data[i].maxValue; statMinimumsPC[i] = statMinimumsNPC[i] = fo::var::stat_data[i].minValue; } - standardApAcBonus = 4; - extraApAcBonus = 4; } void Stats::init() { @@ -228,13 +224,14 @@ void Stats::init() { LoadGameHook::OnGameReset() += []() { StatsReset(); - //Reset some settable game values back to the defaults - //xp mod - SafeWrite8(0x4AFAB8, 0x53); - SafeWrite32(0x4AFAB9, 0x55575651); - //HP bonus + // Reset some settable game values back to the defaults + standardApAcBonus = 4; + extraApAcBonus = 4; + // XP mod set to 100% + experienceMod = 1.0f; + // HP bonus SafeWrite8(0x4AFBC1, 2); - //skill points per level mod + // Skill points per level mod SafeWrite8(0x43C27A, 5); }; diff --git a/sfall/Modules/Stats.h b/sfall/Modules/Stats.h index 3eec3b23..13c009e8 100644 --- a/sfall/Modules/Stats.h +++ b/sfall/Modules/Stats.h @@ -27,13 +27,15 @@ class Stats : public Module { public: const char* name() { return "Stats"; } void init(); + + static float experienceMod; + static DWORD standardApAcBonus; + static DWORD extraApAcBonus; }; void _stdcall SetPCStatMax(int stat, int i); void _stdcall SetPCStatMin(int stat, int i); void _stdcall SetNPCStatMax(int stat, int i); void _stdcall SetNPCStatMin(int stat, int i); -extern DWORD standardApAcBonus; -extern DWORD extraApAcBonus; }