mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Fixed getting perks/traits from the real dude_obj while controlling other NPCs.
Added "real_dude_obj" script function and updated documents.
This commit is contained in:
@@ -240,6 +240,7 @@
|
||||
#define npc_engine_level_up(toggle) sfall_func1("npc_engine_level_up", toggle)
|
||||
#define obj_under_cursor(crSwitch, inclDude) sfall_func2("obj_under_cursor", crSwitch, inclDude)
|
||||
#define outlined_object sfall_func0("outlined_object")
|
||||
#define real_dude_obj sfall_func0("real_dude_obj")
|
||||
#define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode)
|
||||
#define set_flags(obj, flags) sfall_func2("set_flags", obj, flags)
|
||||
#define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value)
|
||||
|
||||
@@ -415,6 +415,9 @@ Some utility/math functions are available:
|
||||
> object sfall_func0("outlined_object")
|
||||
- returns an object that is currently highlighted by hovering the mouse above it
|
||||
|
||||
> void sfall_func0("real_dude_obj")
|
||||
- returns the initial dude_obj after taking control of other critters
|
||||
|
||||
> int sfall_func0("get_cursor_mode")
|
||||
- returns the current cursor mode (0 - movement cursor, 1 - command cursor, 2 - targeting cursor)
|
||||
- mode 4 to 10 are Skilldex skills (yellow targeting cursor)
|
||||
|
||||
@@ -1004,6 +1004,21 @@ long __stdcall StatLevel(TGameObj* critter, long statId) {
|
||||
}
|
||||
}
|
||||
|
||||
long __stdcall PerkLevel(TGameObj* critter, long perkId) {
|
||||
__asm {
|
||||
mov edx, perkId;
|
||||
mov eax, critter;
|
||||
call perk_level_;
|
||||
}
|
||||
}
|
||||
|
||||
long __stdcall TraitLevel(long traitID) {
|
||||
__asm {
|
||||
mov eax, traitID;
|
||||
call trait_level_;
|
||||
}
|
||||
}
|
||||
|
||||
long __stdcall QueueFindFirst(TGameObj* object, long qType) {
|
||||
__asm {
|
||||
mov edx, qType;
|
||||
|
||||
@@ -1028,6 +1028,10 @@ void __fastcall DisplayTargetInventory(long inventoryOffset, long visibleOffset,
|
||||
|
||||
long __stdcall StatLevel(TGameObj* critter, long statId);
|
||||
|
||||
long __stdcall PerkLevel(TGameObj* critter, long perkId);
|
||||
|
||||
long __stdcall TraitLevel(long traitID);
|
||||
|
||||
long __stdcall QueueFindFirst(TGameObj* object, long qType);
|
||||
|
||||
long __stdcall NewObjId();
|
||||
|
||||
@@ -147,13 +147,7 @@ static DWORD _stdcall CombatSaveTest() {
|
||||
return 0;
|
||||
}
|
||||
int ap = StatLevel(*ptr_obj_dude, STAT_max_move_points);
|
||||
int bonusmove;
|
||||
__asm {
|
||||
mov edx, PERK_bonus_move;
|
||||
mov eax, ds:[_obj_dude];
|
||||
call perk_level_;
|
||||
mov bonusmove, eax;
|
||||
}
|
||||
int bonusmove = PerkLevel(*ptr_obj_dude, PERK_bonus_move);
|
||||
if (*(DWORD*)(*(DWORD*)_obj_dude + 0x40) != ap || bonusmove * 2 != *(DWORD*)_combat_free_move) {
|
||||
DisplayConsoleMessage(SaveFailMsg);
|
||||
return 0;
|
||||
|
||||
+56
-33
@@ -35,7 +35,7 @@ bool npcAutoLevelEnabled;
|
||||
bool npcEngineLevelUp = true;
|
||||
|
||||
static DWORD Mode;
|
||||
static int IsControllingNPC = 0;
|
||||
static bool IsControllingNPC = false;
|
||||
static bool SkipCounterAnim = false;
|
||||
static std::vector<WORD> Chars;
|
||||
static int DelayedExperience;
|
||||
@@ -52,7 +52,7 @@ static DWORD real_unspent_skill_points;
|
||||
static DWORD real_sneak_working;
|
||||
//static DWORD real_sneak_queue_time;
|
||||
static DWORD real_hand;
|
||||
static DWORD real_itemButtonItems[6*2];
|
||||
static DWORD real_itemButtonItems[6 * 2];
|
||||
static DWORD real_perkLevelDataList[PERK_count];
|
||||
//static DWORD real_drug_gvar[6];
|
||||
//static DWORD real_jet_gvar;
|
||||
@@ -74,10 +74,10 @@ static bool _stdcall IsInPidList(TGameObj* obj) {
|
||||
static void _stdcall SetInventoryCheck(bool skip) {
|
||||
if (skip) {
|
||||
SafeWrite16(0x46E7CD, 0x9090); //Inventory check
|
||||
SafeWrite32(0x46E7Cf, 0x90909090);
|
||||
SafeWrite32(0x46E7CF, 0x90909090);
|
||||
} else {
|
||||
SafeWrite16(0x46E7CD, 0x850F); //Inventory check
|
||||
SafeWrite32(0x46E7Cf, 0x4B1);
|
||||
SafeWrite32(0x46E7CF, 0x4B1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ static void TakeControlOfNPC(TGameObj* npc) {
|
||||
*ptr_obj_dude = npc;
|
||||
*ptr_inven_dude = npc;
|
||||
|
||||
IsControllingNPC = 1;
|
||||
IsControllingNPC = true;
|
||||
DelayedExperience = 0;
|
||||
SetInventoryCheck(true);
|
||||
|
||||
@@ -165,10 +165,13 @@ static void TakeControlOfNPC(TGameObj* npc) {
|
||||
|
||||
// restores the real dude state
|
||||
static void RestoreRealDudeState() {
|
||||
assert(real_dude != nullptr);
|
||||
|
||||
*ptr_map_elevation = real_dude->elevation;
|
||||
|
||||
*ptr_obj_dude = real_dude;
|
||||
*ptr_inven_dude = real_dude;
|
||||
*ptr_inven_pid = real_dude->pid;
|
||||
|
||||
*ptr_itemCurrentItem = real_hand;
|
||||
memcpy(ptr_itemButtonItems, real_itemButtonItems, sizeof(DWORD) * 6 * 2);
|
||||
@@ -183,8 +186,6 @@ static void RestoreRealDudeState() {
|
||||
*ptr_sneak_working = real_sneak_working;
|
||||
SkillSetTags(real_tag_skill, 4);
|
||||
|
||||
*ptr_inven_pid = real_dude->pid;
|
||||
|
||||
if (DelayedExperience > 0) {
|
||||
StatPcAddExperience(DelayedExperience);
|
||||
}
|
||||
@@ -196,7 +197,7 @@ static void RestoreRealDudeState() {
|
||||
InterfaceRedraw();
|
||||
|
||||
SetInventoryCheck(false);
|
||||
IsControllingNPC = 0;
|
||||
IsControllingNPC = false;
|
||||
real_dude = nullptr;
|
||||
}
|
||||
|
||||
@@ -235,8 +236,8 @@ static void __declspec(naked) FidChangeHook() {
|
||||
je skip;
|
||||
push eax;
|
||||
mov eax, [eax+0x20]; // current fid
|
||||
and eax, 0xffff0fff;
|
||||
and edx, 0x0000f000;
|
||||
and eax, 0xFFFF0FFF;
|
||||
and edx, 0x0000F000;
|
||||
or edx, eax; // only change one octet with weapon type
|
||||
pop eax;
|
||||
skip:
|
||||
@@ -260,7 +261,7 @@ static void __stdcall DisplayCantDoThat() {
|
||||
|
||||
// 1 skip handler, -1 don't skip
|
||||
int __stdcall PartyControl_SwitchHandHook(TGameObj* item) {
|
||||
if (IsControllingNPC > 0 && ItemGetType(item) == item_type_weapon) {
|
||||
if (IsControllingNPC && ItemGetType(item) == item_type_weapon) {
|
||||
int canUse;
|
||||
/* check below uses AI packets and skills to check if weapon is usable
|
||||
__asm {
|
||||
@@ -273,7 +274,7 @@ int __stdcall PartyControl_SwitchHandHook(TGameObj* item) {
|
||||
}*/
|
||||
int fId = (*ptr_obj_dude)->artFID;
|
||||
char weaponCode = AnimCodeByWeapon(item);
|
||||
fId = (fId & 0xffff0fff) | (weaponCode << 12);
|
||||
fId = (fId & 0xFFFF0FFF) | (weaponCode << 12);
|
||||
// check if art with this weapon exists
|
||||
__asm {
|
||||
mov eax, fId;
|
||||
@@ -288,6 +289,19 @@ int __stdcall PartyControl_SwitchHandHook(TGameObj* item) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
long __fastcall GetRealDudePerk(TGameObj* source, long perk) {
|
||||
if (IsControllingNPC && source == real_dude) {
|
||||
return real_perkLevelDataList[perk];
|
||||
}
|
||||
return PerkLevel(source, perk);
|
||||
}
|
||||
|
||||
long __fastcall GetRealDudeTrait(TGameObj* source, long trait) {
|
||||
if (IsControllingNPC && source == real_dude) {
|
||||
return (trait == real_traits[0] || trait == real_traits[1]) ? 1 : 0;
|
||||
}
|
||||
return TraitLevel(trait);
|
||||
}
|
||||
|
||||
static void __declspec(naked) CombatWrapper_v2() {
|
||||
__asm {
|
||||
@@ -329,38 +343,42 @@ gonormal:
|
||||
|
||||
static void __declspec(naked) stat_pc_add_experience_hook() {
|
||||
__asm {
|
||||
xor eax, eax
|
||||
cmp IsControllingNPC, eax
|
||||
je skip
|
||||
add DelayedExperience, esi
|
||||
retn
|
||||
cmp IsControllingNPC, 0;
|
||||
je skip;
|
||||
add DelayedExperience, esi;
|
||||
retn;
|
||||
skip:
|
||||
xchg esi, eax
|
||||
jmp stat_pc_add_experience_
|
||||
xchg esi, eax;
|
||||
jmp stat_pc_add_experience_;
|
||||
}
|
||||
}
|
||||
|
||||
// prevents using sneak when controlling NPCs
|
||||
static void __declspec(naked) pc_flag_toggle_hook() {
|
||||
__asm {
|
||||
cmp IsControllingNPC, 0
|
||||
je end
|
||||
call DisplayCantDoThat
|
||||
retn
|
||||
cmp IsControllingNPC, 0;
|
||||
je end;
|
||||
call DisplayCantDoThat;
|
||||
retn;
|
||||
end:
|
||||
call pc_flag_toggle_
|
||||
retn
|
||||
jmp pc_flag_toggle_;
|
||||
}
|
||||
}
|
||||
|
||||
void __stdcall PartyControlReset() {
|
||||
if (real_dude != nullptr && IsControllingNPC > 0) {
|
||||
if (real_dude != nullptr && IsControllingNPC) {
|
||||
RestoreRealDudeState();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsNpcControlled() {
|
||||
return IsControllingNPC != 0;
|
||||
return IsControllingNPC;
|
||||
}
|
||||
|
||||
TGameObj* RealDudeObject() {
|
||||
return real_dude != nullptr
|
||||
? real_dude
|
||||
: *ptr_obj_dude;
|
||||
}
|
||||
|
||||
static char levelMsg[12], armorClassMsg[12], addictMsg[16];
|
||||
@@ -442,15 +460,20 @@ void PartyControlInit() {
|
||||
}
|
||||
dlog_f(" Mode %d, Chars read: %d.\n", DL_INIT, Mode, Chars.size());
|
||||
|
||||
HookCall(0x46EBEE, &FidChangeHook);
|
||||
HookCall(0x46EBEE, FidChangeHook);
|
||||
|
||||
MakeJump(0x422354, CombatHack_add_noncoms_);
|
||||
HookCall(0x422D87, &CombatWrapper_v2);
|
||||
HookCall(0x422E20, &CombatWrapper_v2);
|
||||
HookCall(0x422D87, CombatWrapper_v2);
|
||||
HookCall(0x422E20, CombatWrapper_v2);
|
||||
|
||||
HookCall(0x454218, &stat_pc_add_experience_hook); // call inside op_give_exp_points_hook
|
||||
HookCall(0x4124F1, &pc_flag_toggle_hook);
|
||||
HookCall(0x41279A, &pc_flag_toggle_hook);
|
||||
HookCall(0x454218, stat_pc_add_experience_hook); // call inside op_give_exp_points_hook
|
||||
HookCall(0x4124F1, pc_flag_toggle_hook);
|
||||
HookCall(0x41279A, pc_flag_toggle_hook);
|
||||
|
||||
// Gets dude perks and traits from script while controlling another NPC
|
||||
// WARNING: Handling dude perks/traits in the engine code while controlling another NPC remains impossible, this requires serious hacking of the engine code
|
||||
HookCall(0x458242, GetRealDudePerk); //op_has_trait_hook_
|
||||
HookCall(0x458326, GetRealDudeTrait); //op_has_trait_hook_
|
||||
} else
|
||||
dlogr(" Disabled.", DL_INIT);
|
||||
|
||||
|
||||
@@ -25,4 +25,5 @@ void PartyControlInit();
|
||||
void __stdcall PartyControlReset();
|
||||
int __stdcall PartyControl_SwitchHandHook(TGameObj* item);
|
||||
bool IsNpcControlled();
|
||||
TGameObj* RealDudeObject();
|
||||
void NpcEngineLevelUpReset();
|
||||
|
||||
@@ -130,6 +130,7 @@ static const SfallMetarule metaruleArray[] = {
|
||||
{"npc_engine_level_up", sf_npc_engine_level_up, 1, 1},
|
||||
{"obj_under_cursor", sf_get_obj_under_cursor, 2, 2},
|
||||
{"outlined_object", sf_outlined_object, 0, 0},
|
||||
{"real_dude_obj", sf_real_dude_obj, 0, 0},
|
||||
{"set_cursor_mode", sf_set_cursor_mode, 1, 1},
|
||||
{"set_flags", sf_set_flags, 2, 2},
|
||||
{"set_ini_setting", sf_set_ini_setting, 2, 2},
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "main.h"
|
||||
|
||||
#include "Inventory.h"
|
||||
#include "PartyControl.h"
|
||||
#include "ScriptExtender.h"
|
||||
|
||||
//script control functions
|
||||
@@ -596,6 +597,10 @@ static void sf_item_weight() {
|
||||
opHandler.setReturn(weight);
|
||||
}
|
||||
|
||||
static void sf_real_dude_obj() {
|
||||
opHandler.setReturn(RealDudeObject());
|
||||
}
|
||||
|
||||
static void sf_lock_is_jammed() {
|
||||
TGameObj* obj = opHandler.arg(0).asObject();
|
||||
int result;
|
||||
|
||||
+5
-1
@@ -18,8 +18,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
//#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "SafeWrite.h"
|
||||
#include "Logging.h"
|
||||
|
||||
@@ -94,4 +98,4 @@ T SimplePatch(DWORD *addrs, int numAddrs, const char* iniSection, const char* in
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user