diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index ce67aa67..7307a3be 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -341,6 +341,53 @@ #define OBJ_DATA_DAMAGE_LAST_TURN (0x48) #define OBJ_DATA_WHO_HIT_ME (0x54) // current target of the critter +// compute attack result data offsets +#define C_ATTACK_SOURCE (0x00) +#define C_ATTACK_HIT_MODE (0x04) +#define C_ATTACK_WEAPON (0x08) +#define C_ATTACK_UNUSED (0x0C) +#define C_ATTACK_DAMAGE_SOURCE (0x10) // Amount +#define C_ATTACK_FLAGS_SOURCE (0x14) // see DAM_* values in define.h +#define C_ATTACK_ROUNDS (0x18) +#define C_ATTACK_MESSAGE (0x1C) // message number set from the critical table +#define C_ATTACK_TARGET (0x20) +#define C_ATTACK_BODY_PART (0x28) +#define C_ATTACK_DAMAGE_TARGET (0x2C) // Amount +#define C_ATTACK_FLAGS_TARGET (0x30) // see DAM_* +#define C_ATTACK_KNOCKBACK_VALUE (0x34) +#define C_ATTACK_MAIN_TARGET (0x38) +#define C_ATTACK_AROUND_NUMBER (0x3C) // The number of critters around the target +#define C_ATTACK_TARGET1 (0x40) +#define C_ATTACK_TARGET2 (0x44) +#define C_ATTACK_TARGET3 (0x48) +#define C_ATTACK_TARGET4 (0x4C) +#define C_ATTACK_TARGET5 (0x50) +#define C_ATTACK_TARGET6 (0x54) +#define C_ATTACK_BODY_PART1 (0x58) +#define C_ATTACK_BODY_PART2 (0x5C) +#define C_ATTACK_BODY_PART3 (0x60) +#define C_ATTACK_BODY_PART4 (0x64) +#define C_ATTACK_BODY_PART5 (0x68) +#define C_ATTACK_BODY_PART6 (0x6C) +#define C_ATTACK_DAMAGE_TARGET1 (0x70) // Amount +#define C_ATTACK_DAMAGE_TARGET2 (0x74) +#define C_ATTACK_DAMAGE_TARGET3 (0x78) +#define C_ATTACK_DAMAGE_TARGET4 (0x7C) +#define C_ATTACK_DAMAGE_TARGET5 (0x80) +#define C_ATTACK_DAMAGE_TARGET6 (0x84) +#define C_ATTACK_FLAGS_TARGET1 (0x88) // see DAM_* +#define C_ATTACK_FLAGS_TARGET2 (0x8C) +#define C_ATTACK_FLAGS_TARGET3 (0x90) +#define C_ATTACK_FLAGS_TARGET4 (0x94) +#define C_ATTACK_FLAGS_TARGET5 (0x98) +#define C_ATTACK_FLAGS_TARGET6 (0x9C) +#define C_ATTACK_KNOCKBACK_VALUE1 (0xA0) +#define C_ATTACK_KNOCKBACK_VALUE2 (0xA4) +#define C_ATTACK_KNOCKBACK_VALUE3 (0xA8) +#define C_ATTACK_KNOCKBACK_VALUE4 (0xAC) +#define C_ATTACK_KNOCKBACK_VALUE5 (0xB0) +#define C_ATTACK_KNOCKBACK_VALUE6 (0xB4) + /* Playback mode defines for the soundplay function */ #define soundraw (0x80000000) // sfall flag #define Stereo8bit (soundstereo) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 43f57d67..afc7cacc 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -264,6 +264,7 @@ #define add_trait(traitID) sfall_func1("add_trait", traitID) #define art_cache_clear sfall_func0("art_cache_clear") #define attack_is_aimed sfall_func0("attack_is_aimed") +#define combat_data sfall_func0("combat_data") #define create_win(winName, x, y, w, h) sfall_func5("create_win", winName, x, y, w, h) #define create_win_flag(winName, x, y, w, h, flag) sfall_func6("create_win", winName, x, y, w, h, flag) #define critter_inven_obj2(obj, type) sfall_func2("critter_inven_obj2", obj, type) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index cf0e01c0..e793b01e 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -174,6 +174,7 @@ int arg9 - Damage Multiplier (this is divided by 2, so a value of 3 does 1. int arg10 - Number of bullets actually hit the target (1 for melee attacks) int arg11 - The amount of knockback to the target int arg12 - Attack Type (see ATKTYPE_* constants) +mixed arg13 - computed attack data (see C_ATTACK_* for offsets and use get/set_object_data functions to get/set the data) int ret1 - The damage to the target int ret2 - The damage to the attacker diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 570ca41f..5539ff0a 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -675,6 +675,11 @@ optional arguments: 0x2000000 - fills the background of the text with black color, the 'textnofill' compiler constant (works the other way around) - width (optional): the maximum width of the text. The text will be wrapped to fit within the specified width +> mixed sfall_func0("combat_data") +- returns a pointer to the C_ATTACK_* data for the current combat attack turn (see defined constants in define_extra.h) +- can be used in conjunction with the get_object_data and set_object_data functions + example: sfall_func3("set_object_data", sfall_func0("combat_data"), C_ATTACK_UNUSED, 255); + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/BugFixes.cpp b/sfall/BugFixes.cpp index 20ff1265..5b205fc3 100644 --- a/sfall/BugFixes.cpp +++ b/sfall/BugFixes.cpp @@ -32,7 +32,7 @@ static int __fastcall DrugPidPop() { return pid; } -void DrugsSaveFix(HANDLE file) { +void BugFixes_DrugsSaveFix(HANDLE file) { DWORD sizeWrite, count = drugsPid.size(); WriteFile(file, &count, 4, &sizeWrite, 0); if (!count) return; @@ -44,7 +44,7 @@ void DrugsSaveFix(HANDLE file) { return; } -bool DrugsLoadFix(HANDLE file) { +bool BugFixes_DrugsLoadFix(HANDLE file) { DWORD count, sizeRead; ReadFile(file, &count, 4, &sizeRead, 0); if (sizeRead != 4) return false; diff --git a/sfall/BugFixes.h b/sfall/BugFixes.h index 83572ecf..ce1a4646 100644 --- a/sfall/BugFixes.h +++ b/sfall/BugFixes.h @@ -4,8 +4,8 @@ void BugFixesInit(); void BugFixes_OnGameLoad(); void BugFixes_Initialization(); -void DrugsSaveFix(HANDLE file); -bool DrugsLoadFix(HANDLE file); +void BugFixes_DrugsSaveFix(HANDLE file); +bool BugFixes_DrugsLoadFix(HANDLE file); void ResetBodyState(); extern int tagSkill4LevelBase; diff --git a/sfall/Graphics.cpp b/sfall/Graphics.cpp index b3c3c1c3..92535437 100644 --- a/sfall/Graphics.cpp +++ b/sfall/Graphics.cpp @@ -1486,6 +1486,7 @@ void GraphicsInit() { // Enable support for transparent interface windows SafeWrite16(0x4D5D46, 0x9090); // win_init_ (create screen_buffer) + SafeWrite8(0x42F869, WinFlags::MoveOnTop | WinFlags::OwnerFlag); // addWindow_ (remove Transparent flag) if (GraphicsMode) { // custom implementation of the GNW_win_refresh function MakeJump(0x4D6FD9, GNW_win_refresh_hack, 1); diff --git a/sfall/HookScripts.cpp b/sfall/HookScripts.cpp index 39297480..2074ae5d 100644 --- a/sfall/HookScripts.cpp +++ b/sfall/HookScripts.cpp @@ -221,17 +221,13 @@ static DWORD __fastcall AfterHitRollHook_Script(TComputeAttack &ctd, DWORD hitCh static void __declspec(naked) AfterHitRollHook() { __asm { - push ecx; - push edx; - mov ecx, esi; // ctd - mov edx, [esp + 0x18 + 12]; // hit chance - push eax; // was it a hit? + mov ecx, esi; // ctd + mov edx, [esp + 0x18 + 4]; // hit chance + push eax; // was it a hit? call AfterHitRollHook_Script; - pop edx; - pop ecx; // engine code mov ebx, eax; - cmp ebx, ROLL_FAILURE; + cmp eax, ROLL_FAILURE; retn; } } @@ -386,7 +382,7 @@ static void __declspec(naked) CalcDeathAnim2Hook() { // 4.x backport static void __fastcall ComputeDamageHook_Script(TComputeAttack &ctd, DWORD rounds, DWORD multiplier) { BeginHook(); - argCount = 12; + argCount = 13; args[0] = (DWORD)ctd.target; // Target args[1] = (DWORD)ctd.attacker; // Attacker @@ -400,6 +396,7 @@ static void __fastcall ComputeDamageHook_Script(TComputeAttack &ctd, DWORD round args[9] = rounds; // number of rounds args[10] = ctd.knockbackValue; args[11] = ctd.hitMode; // attack type + args[12] = (DWORD)&ctd; // main_ctd/shoot_ctd/explosion_ctd RunHookScript(HOOK_COMBATDAMAGE); diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index e4d505d5..99cc309b 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -132,11 +132,11 @@ static void __stdcall SaveGame2() { if (h != INVALID_HANDLE_VALUE) { SaveGlobals(h); WriteFile(h, &objUniqueID, 4, &size, 0); // save unique id counter - data = GetAddedYears(false) << 16; // save to high bytes (short) + data = Worldmap_GetAddedYears(false) << 16; // save to high bytes (short) WriteFile(h, &data, 4, &size, 0); PerksSave(h); SaveArrays(h); - DrugsSaveFix(h); + BugFixes_DrugsSaveFix(h); CloseHandle(h); } else { goto errorSave; @@ -220,10 +220,10 @@ static bool __stdcall LoadGame_Before() { ReadFile(h, &uID, 4, &size, 0); if (uID > UID_START) objUniqueID = uID; ReadFile(h, &data, 4, &size, 0); - SetAddedYears(data >> 16); + Worldmap_SetAddedYears(data >> 16); if (size != 4 || !PerksLoad(h)) goto errorLoad; long result = LoadArrays(h); // 1 - old save, -1 - broken save - if (result == -1 || (!result && DrugsLoadFix(h))) goto errorLoad; + if (result == -1 || (!result && BugFixes_DrugsLoadFix(h))) goto errorLoad; CloseHandle(h); } else { dlogr("Cannot open sfallgv.sav - assuming non-sfall save.", DL_MAIN); diff --git a/sfall/ScriptOps/MetaruleOps.hpp b/sfall/ScriptOps/MetaruleOps.hpp index 79925996..7cf90d5c 100644 --- a/sfall/ScriptOps/MetaruleOps.hpp +++ b/sfall/ScriptOps/MetaruleOps.hpp @@ -120,6 +120,7 @@ static const SfallMetarule metaruleArray[] = { {"add_trait", mf_add_trait, 1, 1}, {"art_cache_clear", mf_art_cache_flush, 0, 0}, {"attack_is_aimed", mf_attack_is_aimed, 0, 0}, + {"combat_data", mf_combat_data, 0, 0}, {"create_win", mf_create_win, 5, 6}, {"critter_inven_obj2", mf_critter_inven_obj2, 2, 2}, {"dialog_obj", mf_get_dialog_object, 0, 0}, diff --git a/sfall/ScriptOps/MiscOps.hpp b/sfall/ScriptOps/MiscOps.hpp index 5e8f9e8e..30b22fb5 100644 --- a/sfall/ScriptOps/MiscOps.hpp +++ b/sfall/ScriptOps/MiscOps.hpp @@ -1161,3 +1161,11 @@ static void mf_npc_engine_level_up() { npcEngineLevelUp = false; } } + +static void mf_combat_data() { + TComputeAttack* ctd = nullptr; + if (*ptr_combat_state & 1) { + ctd = ptr_main_ctd; + } + opHandler.setReturn((DWORD)ctd, DATATYPE_INT); +} diff --git a/sfall/ScriptOps/ObjectsOps.hpp b/sfall/ScriptOps/ObjectsOps.hpp index edae5c10..3882db5b 100644 --- a/sfall/ScriptOps/ObjectsOps.hpp +++ b/sfall/ScriptOps/ObjectsOps.hpp @@ -615,31 +615,21 @@ static void __declspec(naked) op_set_proto_data() { } static void mf_get_object_data() { - DWORD result = 0; TGameObj* obj = opHandler.arg(0).asObject(); const ScriptValue &offsetArg = opHandler.arg(1); if (obj && offsetArg.isInt()) { DWORD* object_ptr = (DWORD*)obj; - if (*(object_ptr - 1) != 0xFEEDFACE) { - opHandler.printOpcodeError("get_object_data() - invalid object pointer."); - } else { - result = *(long*)((BYTE*)object_ptr + offsetArg.rawValue()); - } + opHandler.setReturn(*(long*)((BYTE*)object_ptr + offsetArg.rawValue())); } else { OpcodeInvalidArgs("get_object_data"); + opHandler.setReturn(0); } - opHandler.setReturn(result); } static void mf_set_object_data() { DWORD* object_ptr = (DWORD*)opHandler.arg(0).rawValue(); - if (*(object_ptr - 1) != 0xFEEDFACE) { - opHandler.printOpcodeError("set_object_data() - invalid object pointer."); - opHandler.setReturn(-1); - } else { - *(long*)((BYTE*)object_ptr + opHandler.arg(1).rawValue()) = opHandler.arg(2).rawValue(); - } + *(long*)((BYTE*)object_ptr + opHandler.arg(1).rawValue()) = opHandler.arg(2).rawValue(); } static void mf_set_unique_id() { diff --git a/sfall/Worldmap.cpp b/sfall/Worldmap.cpp index d4037c28..032383a5 100644 --- a/sfall/Worldmap.cpp +++ b/sfall/Worldmap.cpp @@ -454,11 +454,11 @@ void __stdcall SetMapMulti(float value) { scriptMapMulti = value; } -void SetAddedYears(DWORD years) { +void Worldmap_SetAddedYears(DWORD years) { addedYears = years; } -DWORD GetAddedYears(bool isCheck) { +DWORD Worldmap_GetAddedYears(bool isCheck) { return (isCheck && !addYear) ? 0 : addedYears; } diff --git a/sfall/Worldmap.h b/sfall/Worldmap.h index 7959d9a1..341d9ad3 100644 --- a/sfall/Worldmap.h +++ b/sfall/Worldmap.h @@ -21,8 +21,8 @@ void WorldmapInit(); void Worldmap_OnGameLoad(); -DWORD GetAddedYears(bool isCheck = true); -void SetAddedYears(DWORD years); +DWORD Worldmap_GetAddedYears(bool isCheck = true); +void Worldmap_SetAddedYears(DWORD years); void Worldmap_SetTerrainTypeName(long x, long y, const char* name); //const char* Worldmap_GetTerrainTypeName(long x, long y);