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:
NovaRain
2018-12-26 10:20:22 +08:00
parent 6cce07991e
commit 62e6c41620
5 changed files with 199 additions and 210 deletions
+6 -69
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2 -1
View File
@@ -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
View File
@@ -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);