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;
}