mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Refactored assembler code in Skills.cpp.
Moved PickpocketMod function from Combat.cpp to Skills.cpp module. Refactored structs in Skills.cpp and Combat.cpp.
This commit is contained in:
@@ -40,17 +40,8 @@ static std::vector<KnockbackModifier> mTargets;
|
||||
static std::vector<KnockbackModifier> mAttackers;
|
||||
static std::vector<KnockbackModifier> mWeapons;
|
||||
|
||||
struct ChanceModifier {
|
||||
fo::GameObject* id;
|
||||
int maximum { 95 };
|
||||
int mod { 0 };
|
||||
};
|
||||
|
||||
static std::vector<ChanceModifier> hitChanceMods;
|
||||
static std::vector<ChanceModifier> pickpocketMods;
|
||||
|
||||
static ChanceModifier baseHitChance;
|
||||
static ChanceModifier basePickpocket;
|
||||
|
||||
static bool hookedAimedShot;
|
||||
static std::vector<DWORD> disabledAS;
|
||||
@@ -111,28 +102,6 @@ static void __declspec(naked) compute_dmg_damage_hack() {
|
||||
}
|
||||
}
|
||||
|
||||
static int __fastcall PickpocketMod(int base, fo::GameObject* critter) {
|
||||
for (DWORD i = 0; i < pickpocketMods.size(); i++) {
|
||||
if (critter == pickpocketMods[i].id) {
|
||||
return min(base + pickpocketMods[i].mod, pickpocketMods[i].maximum);
|
||||
}
|
||||
}
|
||||
return min(base + basePickpocket.mod, basePickpocket.maximum);
|
||||
}
|
||||
|
||||
static void __declspec(naked) skill_check_stealing_hack() {
|
||||
__asm {
|
||||
push edx;
|
||||
push ecx;
|
||||
mov edx, esi; // critter
|
||||
mov ecx, eax; // base (calculated chance)
|
||||
call PickpocketMod;
|
||||
pop ecx;
|
||||
pop edx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static int __fastcall HitChanceMod(int base, fo::GameObject* critter) {
|
||||
for (DWORD i = 0; i < hitChanceMods.size(); i++) {
|
||||
if (critter == hitChanceMods[i].id) {
|
||||
@@ -237,31 +206,7 @@ void _stdcall SetHitChanceMax(fo::GameObject* critter, DWORD maximum, DWORD mod)
|
||||
return;
|
||||
}
|
||||
}
|
||||
ChanceModifier cm;
|
||||
cm.id = critter;
|
||||
cm.maximum = maximum;
|
||||
cm.mod = mod;
|
||||
hitChanceMods.push_back(cm);
|
||||
}
|
||||
|
||||
void _stdcall SetPickpocketMax(fo::GameObject* critter, DWORD maximum, DWORD mod) {
|
||||
if ((DWORD)critter == -1) {
|
||||
basePickpocket.maximum = maximum;
|
||||
basePickpocket.mod = mod;
|
||||
return;
|
||||
}
|
||||
for (DWORD i = 0; i < pickpocketMods.size(); i++) {
|
||||
if (critter == pickpocketMods[i].id) {
|
||||
pickpocketMods[i].maximum = maximum;
|
||||
pickpocketMods[i].mod = mod;
|
||||
return;
|
||||
}
|
||||
}
|
||||
ChanceModifier cm;
|
||||
cm.id = critter;
|
||||
cm.maximum = maximum;
|
||||
cm.mod = mod;
|
||||
pickpocketMods.push_back(cm);
|
||||
hitChanceMods.push_back(ChanceModifier(critter, maximum, mod));
|
||||
}
|
||||
|
||||
void _stdcall SetNoBurstMode(fo::GameObject* critter, bool on) {
|
||||
@@ -334,36 +279,28 @@ void _stdcall ForceAimedShots(DWORD pid) {
|
||||
forcedAS.push_back(pid);
|
||||
}
|
||||
|
||||
static void Knockback_OnGameLoad() {
|
||||
baseHitChance.maximum = 95;
|
||||
baseHitChance.mod = 0;
|
||||
basePickpocket.maximum = 95;
|
||||
basePickpocket.mod = 0;
|
||||
static void Combat_OnGameLoad() {
|
||||
baseHitChance.SetDefault();
|
||||
mTargets.clear();
|
||||
mAttackers.clear();
|
||||
mWeapons.clear();
|
||||
hitChanceMods.clear();
|
||||
pickpocketMods.clear();
|
||||
noBursts.clear();
|
||||
disabledAS.clear();
|
||||
forcedAS.clear();
|
||||
}
|
||||
|
||||
void Combat::init() {
|
||||
MakeCall(0x424B76, compute_damage_hack, 2); // KnockbackMod
|
||||
MakeCall(0x424B76, compute_damage_hack, 2); // KnockbackMod
|
||||
MakeJump(0x4136D3, compute_dmg_damage_hack); // for op_critter_dmg
|
||||
|
||||
MakeCall(0x424791, determine_to_hit_func_hack); // HitChanceMod
|
||||
BlockCall(0x424796);
|
||||
|
||||
MakeCall(0x4ABC62, skill_check_stealing_hack); // PickpocketMod
|
||||
SafeWrite8(0x4ABC67, 0x89); // mov [esp + 0x54], eax
|
||||
SafeWrite32(0x4ABC6B, 0x90909090);
|
||||
|
||||
// Actually disables all secondary attacks for the critter, regardless of whether the weapon has a burst attack
|
||||
MakeCall(0x429E44, ai_pick_hit_mode_hack, 1); // NoBurst
|
||||
MakeCall(0x429E44, ai_pick_hit_mode_hack, 1); // NoBurst
|
||||
|
||||
LoadGameHook::OnGameReset() += Knockback_OnGameLoad;
|
||||
LoadGameHook::OnGameReset() += Combat_OnGameLoad;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-1
@@ -29,7 +29,25 @@ public:
|
||||
void init();
|
||||
};
|
||||
|
||||
void _stdcall SetPickpocketMax(fo::GameObject* critter, DWORD maximum, DWORD mod);
|
||||
struct ChanceModifier {
|
||||
fo::GameObject* id;
|
||||
int maximum;
|
||||
int mod;
|
||||
|
||||
ChanceModifier() : maximum(95), mod(0) {}
|
||||
|
||||
ChanceModifier(fo::GameObject* critter, int max, int mod) {
|
||||
id = critter;
|
||||
maximum = max;
|
||||
mod = mod;
|
||||
}
|
||||
|
||||
void SetDefault() {
|
||||
maximum = 95;
|
||||
mod = 0;
|
||||
}
|
||||
};
|
||||
|
||||
void _stdcall SetHitChanceMax(fo::GameObject* critter, DWORD maximum, DWORD mod);
|
||||
void _stdcall KnockbackSetMod(fo::GameObject* id, DWORD type, float val, DWORD on);
|
||||
void _stdcall KnockbackRemoveMod(fo::GameObject* id, DWORD on);
|
||||
|
||||
+170
-137
@@ -32,17 +32,57 @@ namespace sfall
|
||||
{
|
||||
|
||||
struct SkillModifier {
|
||||
DWORD id { 0 };
|
||||
int maximum { 300 };
|
||||
int mod { 0 };
|
||||
fo::GameObject* id;
|
||||
int maximum;
|
||||
//int mod;
|
||||
|
||||
SkillModifier() : maximum(300)/*, mod(0)*/ {}
|
||||
|
||||
SkillModifier(fo::GameObject* critter, int max) {
|
||||
id = critter;
|
||||
maximum = max;
|
||||
//mod = mod;
|
||||
}
|
||||
|
||||
void SetDefault() {
|
||||
maximum = 300;
|
||||
//mod = 0;
|
||||
}
|
||||
};
|
||||
|
||||
static std::vector<SkillModifier> skillMaxMods;
|
||||
static SkillModifier baseSkillMax;
|
||||
|
||||
static BYTE skillCosts[512 * fo::SKILL_count];
|
||||
static DWORD basedOnPoints;
|
||||
static double* multipliers;
|
||||
|
||||
static int _stdcall SkillMaxHook2(int base, DWORD critter) {
|
||||
static std::vector<ChanceModifier> pickpocketMods;
|
||||
static ChanceModifier basePickpocket;
|
||||
|
||||
static int __fastcall PickpocketMod(int base, fo::GameObject* critter) {
|
||||
for (DWORD i = 0; i < pickpocketMods.size(); i++) {
|
||||
if (critter == pickpocketMods[i].id) {
|
||||
return min(base + pickpocketMods[i].mod, pickpocketMods[i].maximum);
|
||||
}
|
||||
}
|
||||
return min(base + basePickpocket.mod, basePickpocket.maximum);
|
||||
}
|
||||
|
||||
static void __declspec(naked) skill_check_stealing_hack() {
|
||||
__asm {
|
||||
push edx;
|
||||
push ecx;
|
||||
mov edx, esi; // critter
|
||||
mov ecx, eax; // base (calculated chance)
|
||||
call PickpocketMod;
|
||||
pop ecx;
|
||||
pop edx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static int __fastcall CheckSkillMax(fo::GameObject* critter, int base) {
|
||||
for (DWORD i = 0; i < skillMaxMods.size(); i++) {
|
||||
if (critter == skillMaxMods[i].id) {
|
||||
return min(base, skillMaxMods[i].maximum);
|
||||
@@ -51,60 +91,117 @@ static int _stdcall SkillMaxHook2(int base, DWORD critter) {
|
||||
return min(base, baseSkillMax.maximum);
|
||||
}
|
||||
|
||||
static void __declspec(naked) SkillHookA() {
|
||||
static void __declspec(naked) skill_level_hack() {
|
||||
__asm {
|
||||
push ecx;
|
||||
push esi;
|
||||
call SkillMaxHook2;
|
||||
push 0x4AA64B;
|
||||
retn;
|
||||
mov edx, esi; // level skill (base)
|
||||
call CheckSkillMax; // ecx - critter
|
||||
mov edx, 0x4AA64B;
|
||||
jmp edx;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) SkillHookB() {
|
||||
static void __declspec(naked) skill_inc_point_force_hack() {
|
||||
__asm {
|
||||
push edx;
|
||||
push ecx;
|
||||
push ebx;
|
||||
push eax;
|
||||
push ecx;
|
||||
push 0x7fffffff;
|
||||
call SkillMaxHook2;
|
||||
pop edx;
|
||||
cmp edx, eax;
|
||||
pop ebx;
|
||||
mov edx, 0x7FFFFFFF; // base
|
||||
call CheckSkillMax; // ecx - critter
|
||||
pop edx; // skill level (from eax)
|
||||
cmp edx, eax; // eax = max
|
||||
pop ecx;
|
||||
pop edx;
|
||||
jl win;
|
||||
push 0x4AA84E;
|
||||
retn;
|
||||
win:
|
||||
push 0x4AA85C;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD SkillHookWin = 0x4AA738;
|
||||
static const DWORD SkillHookFail = 0x4AA72C;
|
||||
static void __declspec(naked) SkillHookC() {
|
||||
static void __declspec(naked) skill_inc_point_hack() {
|
||||
__asm {
|
||||
pushad;
|
||||
push ecx;
|
||||
push eax;
|
||||
push esi;
|
||||
push 0x7fffffff;
|
||||
call SkillMaxHook2;
|
||||
pop edx;
|
||||
cmp edx, eax;
|
||||
popad;
|
||||
jl win;
|
||||
jmp SkillHookFail;
|
||||
win:
|
||||
jmp SkillHookWin;
|
||||
mov edx, 0x7FFFFFFF; // base
|
||||
mov ecx, esi; // critter
|
||||
call CheckSkillMax;
|
||||
pop edx; // skill level (from eax)
|
||||
cmp edx, eax; // eax = max
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
void _stdcall SetSkillMax(DWORD critter, DWORD maximum) {
|
||||
if (critter == -1) {
|
||||
static int __fastcall GetStatBonus(fo::GameObject* critter, const fo::SkillInfo* info, int skill, int points) {
|
||||
double result = 0;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
result += fo::func::stat_level(critter, i) * multipliers[skill * 7 + i];
|
||||
}
|
||||
result += points * info->skillPointMulti;
|
||||
result += info->base;
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
//On input, ebx/edx contains the skill id, ecx contains the critter, edi contains a SkillInfo*, ebp contains the number of skill points
|
||||
//On exit ebx, ecx, edi, ebp are preserved, esi contains skill base + stat bonus + skillpoints * multiplier
|
||||
static const DWORD StatBonusHookRet = 0x4AA5D6;
|
||||
static void __declspec(naked) skill_level_hack_bonus() {
|
||||
__asm {
|
||||
push ecx;
|
||||
push ebp;
|
||||
push ebx;
|
||||
mov edx, edi;
|
||||
call GetStatBonus; // ecx - critter
|
||||
mov esi, eax;
|
||||
pop ecx;
|
||||
jmp StatBonusHookRet;
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD SkillIncCostRet = 0x4AA7C1;
|
||||
static void __declspec(naked) skill_inc_point_hack_cost() {
|
||||
__asm { // eax - current skill level, ebx - current skill, ecx - num free skill points
|
||||
mov edx, basedOnPoints;
|
||||
test edx, edx;
|
||||
jz next;
|
||||
mov edx, ebx;
|
||||
mov eax, esi;
|
||||
call fo::funcoffs::skill_points_;
|
||||
next:
|
||||
mov edx, ebx;
|
||||
shl edx, 9;
|
||||
add edx, eax;
|
||||
movzx eax, skillCosts[edx]; // eax - cost of the skill
|
||||
jmp SkillIncCostRet;
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD SkillDecCostRet = 0x4AA98D;
|
||||
static void __declspec(naked) skill_dec_point_hack_cost() {
|
||||
__asm { // eax - current skill level, ebx - current skill, ecx - num free skill points
|
||||
mov edx, basedOnPoints;
|
||||
test edx, edx;
|
||||
jz next;
|
||||
mov edx, ebx;
|
||||
mov eax, edi;
|
||||
call fo::funcoffs::skill_points_;
|
||||
lea ecx, [eax - 1];
|
||||
next:
|
||||
mov edx, ebx;
|
||||
shl edx, 9;
|
||||
add edx, ecx;
|
||||
movzx eax, skillCosts[edx]; // eax - cost of the skill
|
||||
jmp SkillDecCostRet;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) skill_dec_point_hook_cost() {
|
||||
__asm {
|
||||
mov edx, ebx;
|
||||
shl edx, 9;
|
||||
add edx, eax;
|
||||
movzx eax, skillCosts[edx];
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
void _stdcall SetSkillMax(fo::GameObject* critter, int maximum) {
|
||||
if ((DWORD)critter == -1) {
|
||||
baseSkillMax.maximum = maximum;
|
||||
return;
|
||||
}
|
||||
@@ -114,107 +211,41 @@ void _stdcall SetSkillMax(DWORD critter, DWORD maximum) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SkillModifier cm;
|
||||
cm.id = critter;
|
||||
cm.maximum = maximum;
|
||||
cm.mod = 0;
|
||||
skillMaxMods.push_back(cm);
|
||||
skillMaxMods.push_back(SkillModifier(critter, maximum));
|
||||
}
|
||||
|
||||
double* multipliers;
|
||||
|
||||
static int _stdcall GetStatBonusHook2(const fo::SkillInfo* info, int skill, int points, fo::GameObject* critter) {
|
||||
double result = 0;
|
||||
for (int i = fo::Stat::STAT_st; i <= fo::Stat::STAT_lu; i++) {
|
||||
result += fo::func::stat_level(critter, i) * multipliers[skill * 7 + i];
|
||||
void _stdcall SetPickpocketMax(fo::GameObject* critter, DWORD maximum, DWORD mod) {
|
||||
if ((DWORD)critter == -1) {
|
||||
basePickpocket.maximum = maximum;
|
||||
basePickpocket.mod = mod;
|
||||
return;
|
||||
}
|
||||
result += points * info->skillPointMulti;
|
||||
result += info->base;
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
//On input, ebx contains the skill id, ecx contains the critter, edx contains the skill id, edi contains a SkillInfo*, ebp contains the number of skill points
|
||||
//On exit ebx, ecx, edi, ebp are preserved, esi contains skill base + stat bonus + skillpoints * multiplier
|
||||
static const DWORD StatBonusHookRet = 0x4AA5D6;
|
||||
static void __declspec(naked) GetStatBonusHook() {
|
||||
__asm {
|
||||
push edx;
|
||||
push ecx;
|
||||
push ecx;
|
||||
push ebp;
|
||||
push ebx;
|
||||
push edi;
|
||||
call GetStatBonusHook2;
|
||||
mov esi, eax;
|
||||
pop ecx;
|
||||
pop edx;
|
||||
jmp StatBonusHookRet;
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD SkillIncCostRet = 0x4AA7C1;
|
||||
static void __declspec(naked) SkillIncCostHook() {
|
||||
__asm {
|
||||
//eax - current skill level, ebx - current skill, ecx - num free skill points
|
||||
mov edx, basedOnPoints;
|
||||
test edx, edx;
|
||||
jz next;
|
||||
mov edx, ebx;
|
||||
mov eax, esi;
|
||||
call fo::funcoffs::skill_points_;
|
||||
next:
|
||||
mov edx, ebx;
|
||||
shl edx, 9;
|
||||
add edx, eax;
|
||||
movzx eax, skillCosts[edx];
|
||||
//eax - cost of the skill
|
||||
jmp SkillIncCostRet;
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD SkillDecCostRet = 0x4AA98D;
|
||||
static void __declspec(naked) SkillDecCostHook() {
|
||||
__asm {
|
||||
//eax - current skill level, ebx - current skill, ecx - num free skill points
|
||||
mov edx, basedOnPoints;
|
||||
test edx, edx;
|
||||
jz next;
|
||||
mov edx, ebx;
|
||||
mov eax, edi;
|
||||
call fo::funcoffs::skill_points_;
|
||||
next:
|
||||
lea ecx, [eax-1];
|
||||
mov edx, ebx;
|
||||
shl edx, 9;
|
||||
add edx, ecx;
|
||||
movzx eax, skillCosts[edx];
|
||||
//eax - cost of the skill
|
||||
jmp SkillDecCostRet;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) SkillLevelCostHook() {
|
||||
__asm {
|
||||
push edx;
|
||||
mov edx, ebx;
|
||||
shl edx, 9;
|
||||
add edx, eax;
|
||||
movzx eax, skillCosts[edx];
|
||||
pop edx;
|
||||
retn;
|
||||
for (DWORD i = 0; i < pickpocketMods.size(); i++) {
|
||||
if (critter == pickpocketMods[i].id) {
|
||||
pickpocketMods[i].maximum = maximum;
|
||||
pickpocketMods[i].mod = mod;
|
||||
return;
|
||||
}
|
||||
}
|
||||
pickpocketMods.push_back(ChanceModifier(critter, maximum, mod));
|
||||
}
|
||||
|
||||
void Skills_OnGameLoad() {
|
||||
pickpocketMods.clear();
|
||||
basePickpocket.SetDefault();
|
||||
|
||||
skillMaxMods.clear();
|
||||
baseSkillMax.maximum = 300;
|
||||
baseSkillMax.mod = 0;
|
||||
baseSkillMax.SetDefault();
|
||||
}
|
||||
|
||||
void Skills::init() {
|
||||
MakeJump(0x4AA63C, SkillHookA);
|
||||
MakeJump(0x4AA847, SkillHookB);
|
||||
MakeJump(0x4AA725, SkillHookC);
|
||||
MakeJump(0x4AA63C, skill_level_hack, 1);
|
||||
MakeCall(0x4AA847, skill_inc_point_force_hack);
|
||||
MakeCall(0x4AA725, skill_inc_point_hack);
|
||||
|
||||
MakeCall(0x4ABC62, skill_check_stealing_hack); // PickpocketMod
|
||||
SafeWrite8(0x4ABC67, 0x89); // mov [esp + 0x54], eax
|
||||
SafeWrite32(0x4ABC6B, 0x90909090);
|
||||
|
||||
char buf[512], key[16], file[64];
|
||||
auto skillsFile = GetConfigString("Misc", "SkillsFile", "");
|
||||
@@ -272,19 +303,21 @@ void Skills::init() {
|
||||
}
|
||||
sprintf(key, "SkillBase%d", i);
|
||||
skills[i].base = GetPrivateProfileIntA("Skills", key, skills[i].base, file);
|
||||
|
||||
sprintf(key, "SkillMulti%d", i);
|
||||
skills[i].skillPointMulti = GetPrivateProfileIntA("Skills", key, skills[i].skillPointMulti, file);
|
||||
|
||||
sprintf(key, "SkillImage%d", i);
|
||||
skills[i].image = GetPrivateProfileIntA("Skills", key, skills[i].image, file);
|
||||
}
|
||||
|
||||
MakeJump(0x4AA59D, GetStatBonusHook);
|
||||
MakeJump(0x4AA738, SkillIncCostHook);
|
||||
MakeJump(0x4AA93D, SkillDecCostHook);
|
||||
HookCall(0x4AA9E1, &SkillLevelCostHook);
|
||||
HookCall(0x4AA9F1, &SkillLevelCostHook);
|
||||
MakeJump(0x4AA59D, skill_level_hack_bonus, 1);
|
||||
MakeJump(0x4AA738, skill_inc_point_hack_cost);
|
||||
MakeJump(0x4AA940, skill_dec_point_hack_cost, 1);
|
||||
HookCalls(skill_dec_point_hook_cost, {0x4AA9E1, 0x4AA9F1});
|
||||
|
||||
basedOnPoints = GetPrivateProfileIntA("Skills", "BasedOnPoints", 0, file);
|
||||
if (basedOnPoints) HookCall(0x4AA9EC, (void*)fo::funcoffs::skill_points_);
|
||||
if (basedOnPoints) HookCall(0x4AA9EC, (void*)fo::funcoffs::skill_points_); // skill_dec_point_
|
||||
}
|
||||
|
||||
LoadGameHook::OnGameReset() += Skills_OnGameLoad;
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
void init();
|
||||
};
|
||||
|
||||
void _stdcall SetSkillMax(DWORD critter, DWORD maximum);
|
||||
void _stdcall SetSkillMax(fo::GameObject* critter, int maximum);
|
||||
void _stdcall SetPickpocketMax(fo::GameObject* critter, DWORD maximum, DWORD mod);
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -63,8 +63,8 @@ namespace sfall
|
||||
#endif
|
||||
|
||||
// Macros for quick replacement of pushad/popad assembler opcodes
|
||||
#define pushadc _asm push eax _asm push edx _asm push ecx
|
||||
#define popadc _asm pop ecx _asm pop edx _asm pop eax
|
||||
#define pushadc __asm push eax __asm push edx __asm push ecx
|
||||
#define popadc __asm pop ecx __asm pop edx __asm pop eax
|
||||
|
||||
// Gets the integer value from Sfall configuration INI file.
|
||||
unsigned int GetConfigInt(const char* section, const char* setting, int defaultValue);
|
||||
|
||||
Reference in New Issue
Block a user