From 361ebbe939ae9fe9b8f88e56405f272d0cf49d4a Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 14 Jul 2019 10:38:17 +0800 Subject: [PATCH 1/7] Added PerksList option to gl_partycontrol --- artifacts/config_files/sfall-mods.ini | 3 +++ artifacts/mods/gl_partycontrol.int | Bin 3904 -> 4120 bytes artifacts/mods/gl_partycontrol.ssl | 24 +++++++++++++++--------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/artifacts/config_files/sfall-mods.ini b/artifacts/config_files/sfall-mods.ini index d466e0fae..9779535f7 100644 --- a/artifacts/config_files/sfall-mods.ini +++ b/artifacts/config_files/sfall-mods.ini @@ -39,6 +39,9 @@ MotionScanner=0 Mode=0 ;PIDList=62,89,97,107,160,161 +;Set a comma delimited list of perk IDs for perks to be inherited from the player during the combat control +PerksList=0,73 + ;Choose a notification box to display the name of the controlled critter above the interface bar ;Must be between 5 and (4 + the value of BoxBarCount in ddraw.ini) ;For sfall 4.1.6+ the number for the notification box is set automatically, so just use any value diff --git a/artifacts/mods/gl_partycontrol.int b/artifacts/mods/gl_partycontrol.int index dae6ac02a8c535e3d40ddd278104b6c13b7c505e..4617d653739379f994d0e39036f5394e4e3e5d51 100644 GIT binary patch delta 1479 zcmZ8gPi%}q6rcGz-~T_mKD8{WRnZ@WV`Ezz`flkMtaWTiq#yg~MCo5P4a-$V)0Y=KxwPXmr+%Svn;Z)KWo71CJ{ho|p=8cd9e8c*2{> z6TXQTQ5M|PRyl~0{nv}ulM0qa_*Gs>np2B*k??OQF&(Z|YY9v^O9~A-EECl+R27J& zG0L|fSEugWN8C61pm;Psi}GJ*b#t*+?6fz$HrVX09TPf|MA7+UlpImW%Q|CW9j_@nuC7YQFR66=5~5z(Gu|W3 z(mh4w`FDt^#QvOD7*AGdVUubE?~7=fU1{5RbMV7$H~bQ`dRwUlN4%EUS0Q9b{0ja> zsCvyAT_>XN4`00QI8fQi4p-C<(Cz1PL5a`Gh85*}$n}Q`mcxL5Hx3&y9r1SRL@;wF zXbL}yoOB}xAE7fi7i7u!am5G+U@}OIa01>21^NoSu+7L4D26#BieOLJ0S_YE$@HOL z8%D!UBV)l-*ltAk;dQu{PQ!fI-0@S{^;?*tQ8DAFt{lXMZBc%;t==G$Q*S_s?y3~u p2A84^*U_xg@FXf1Gt)ej{Yx8hoy2g4zO1Qt_0i=&D#6#N|2Hw~D2D(5 delta 1466 zcmZ8gO-NKx6n^*3`M4s34d{2)b|;;UXkLY7^2T+!X~8*1hN6r%w0r?m6c>zxSMbA0J#P4^ef6 zD2fuMeonQ@`=O>xiUE8@1aWtb;~w@`xrm_J4@On?w-n;~g2XoqapMA$c~b7TXBl6F zkRkRSl(BYN$mGAozG8{D7ux%tOMIXZccvvisDzFdEQZ@XBe%LHlB0<+I6=<9EV&d8 zUmd#HGje5o;_P@LnM@?d6!=A^$lU9cI!B;V8&sWXNNZhW1D3SAB{}S*N~0^}FI%*k z?&pX;3IlqAe1s+a2ssJg^mF7ZbQ_2Ey+wOM!@|yZ3TdN>xESz+89>7j~3+fg%2+j3*lrU)tXb$yU(G@Lb&BQ%;-kW*?)p{FIqr)-p;R>A=p?=-9 zMtVJ$MykO@>j3e<9jh$nT|vm+IV39-5m9U}@+7N@k`#inMe(?nMl~*5xGOs3t%_Eb z8nJuQk~Nbqvu~aKTQo1?SVC*Kqp$sXe}U0xxnx>J%k5Gcp{Lww*kLw}8r6=&PrJ>-PWd1d zfw*C0>_v3r9c0ELggYFRdg*s*ft|6pQQ~#tb+zBKG;HMAmxy=L&fPfD68#iWHOpMk zPnh>rboge_l3!hn>Fba&Hxc)+r-7CEX6Q1%hHPl_?sM^_VB7bw-I Date: Mon, 15 Jul 2019 09:54:41 +0800 Subject: [PATCH 2/7] Fixed key_pressed function not working in KEYPRESS hook (#248) Minor text edits to CombatHs.cpp. Updated version number. --- artifacts/ddraw.ini | 2 +- sfall/InputFuncs.cpp | 9 +++++++-- sfall/Modules/HookScripts/CombatHs.cpp | 14 +++++++------- sfall/version.h | 6 +++--- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 36e6fc87b..32a5c2abf 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -1,5 +1,5 @@ ;sfall configuration settings -;v4.1.9 +;v4.2.0 [Main] ;Change to 1 if you want to use command line args to tell sfall to use another ini file. diff --git a/sfall/InputFuncs.cpp b/sfall/InputFuncs.cpp index 29f71f665..f2087fd8c 100644 --- a/sfall/InputFuncs.cpp +++ b/sfall/InputFuncs.cpp @@ -282,9 +282,14 @@ class FakeDirectInputDevice : public IDirectInputDeviceA { for (DWORD i = 0; i < *c; i++) { DWORD dxKey = b[i].dwOfs; DWORD state = b[i].dwData & 0x80; + DWORD oldState = keysDown[dxKey]; + keysDown[dxKey] = state; HookScripts::KeyPressHook(&dxKey, (state > 0), MapVirtualKeyEx(dxKey, MAPVK_VSC_TO_VK, keyboardLayout)); - if (dxKey != b[i].dwOfs && dxKey > 0) b[i].dwOfs = dxKey; // Override key - keysDown[b[i].dwOfs] = state; + if (dxKey > 0 && dxKey != b[i].dwOfs) { + keysDown[b[i].dwOfs] = oldState; + b[i].dwOfs = dxKey; // Override key + keysDown[b[i].dwOfs] = state; + } onKeyPressed.invoke(b[i].dwOfs, (state > 0)); } return hr; diff --git a/sfall/Modules/HookScripts/CombatHs.cpp b/sfall/Modules/HookScripts/CombatHs.cpp index e13b6a8a2..1302525aa 100644 --- a/sfall/Modules/HookScripts/CombatHs.cpp +++ b/sfall/Modules/HookScripts/CombatHs.cpp @@ -128,7 +128,7 @@ static void __declspec(naked) CalcApCostHook2() { } } -static void __fastcall ComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DWORD rounds, DWORD multiply) { +static void __fastcall ComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DWORD rounds, DWORD multiplier) { BeginHook(); argCount = 12; @@ -140,8 +140,8 @@ static void __fastcall ComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DW args[5] = ctd.attackerFlags; // flagsSource args[6] = (DWORD)ctd.weapon; args[7] = ctd.bodyPart; - args[8] = multiply; // multiply damage - args[9] = rounds; // number rounds + args[8] = multiplier; // damage multiplier + args[9] = rounds; // number of rounds args[10] = ctd.knockbackValue; args[11] = ctd.hitMode; // attack type @@ -166,13 +166,13 @@ static void __fastcall ComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DW static void __declspec(naked) ComputeDamageHook() { __asm { push ecx; - push ebx; // store dmg multiply args[8] - push edx; // store num rounds args[9] + push ebx; // store dmg multiplier args[8] + push edx; // store num of rounds args[9] push eax; // store ctd call fo::funcoffs::compute_damage_; pop ecx; // restore ctd (eax) - pop edx; // restore num rounds - call ComputeDamageHook_Script; // stack - arg multiply + pop edx; // restore num of rounds + call ComputeDamageHook_Script; // stack - arg multiplier pop ecx; retn; } diff --git a/sfall/version.h b/sfall/version.h index bb7f34b3c..d31d22a38 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -23,11 +23,11 @@ #define LEGAL_COPYRIGHT "Copyright (C) 2006-2019, sfall team" #define VERSION_MAJOR 4 -#define VERSION_MINOR 1 -#define VERSION_BUILD 9 +#define VERSION_MINOR 2 +#define VERSION_BUILD 0 #define VERSION_REV 0 -#define VERSION_STRING "4.1.9" +#define VERSION_STRING "4.2.0" //#define CHECK_VAL (4) From b33277c35a5ab1c8a16b29c6442f8c70701aa452 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 15 Jul 2019 20:49:55 +0800 Subject: [PATCH 3/7] Fixed the error handling on loading sfallgv.sav * to improve backward compatibility with older saved games. --- artifacts/ddraw.ini | 2 +- sfall/Modules/BugFixes.cpp | 2 +- sfall/Modules/LoadGameHook.cpp | 9 +++++--- sfall/Modules/Scripting/Arrays.cpp | 33 ++++++++++++++++-------------- sfall/Modules/Scripting/Arrays.h | 2 +- sfall/version.h | 2 +- 6 files changed, 28 insertions(+), 22 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 32a5c2abf..26d9edd52 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -1,5 +1,5 @@ ;sfall configuration settings -;v4.2.0 +;v4.2 [Main] ;Change to 1 if you want to use command line args to tell sfall to use another ini file. diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index f6738b916..43483c3a3 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -45,7 +45,7 @@ void BugFixes::DrugsSaveFix(HANDLE file) { bool BugFixes::DrugsLoadFix(HANDLE file) { DWORD count, sizeRead; ReadFile(file, &count, 4, &sizeRead, 0); - //if (sizeRead != 4) return true; + if (sizeRead != 4) return false; for (DWORD i = 0; i < count; i++) { DWORD pid; ReadFile(file, &pid, 4, &sizeRead, 0); diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 04fedf562..bd96c7197 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -229,8 +229,10 @@ static bool LoadGame_Before() { if (uID > UniqueID::Start) Objects::uniqueID = uID; ReadFile(h, &data, 4, &size, 0); Worldmap::SetAddedYears(data >> 16); - if (size != 4 || !Perks::load(h) || script::LoadArrays(h)) goto errorLoad; - if (BugFixes::DrugsLoadFix(h)) goto errorLoad; + if (size != 4 || !Perks::load(h)) goto errorLoad; + long result = script::LoadArrays(h); // 1 - old save, -1 - broken save + if (result == -1) goto errorLoad; + if (!result && BugFixes::DrugsLoadFix(h)) goto errorLoad; CloseHandle(h); } else { dlogr("Cannot open sfallgv.sav - assuming non-sfall save.", DL_MAIN); @@ -245,12 +247,13 @@ static bool LoadGame_Before() { } else { dlogr("Cannot open sfalldb.sav.", DL_MAIN); } - return false; + ///////////////////////////////////////////////// errorLoad: CloseHandle(h); dlog_f("ERROR reading data: %s\n", DL_MAIN, buf); + fo::func::debug_printf("\n[SFALL] ERROR reading data: %s", buf); return (true & !isDebug); } diff --git a/sfall/Modules/Scripting/Arrays.cpp b/sfall/Modules/Scripting/Arrays.cpp index 045667afd..b2332c7bb 100644 --- a/sfall/Modules/Scripting/Arrays.cpp +++ b/sfall/Modules/Scripting/Arrays.cpp @@ -183,12 +183,13 @@ bool LoadArrayElement(sArrayElement* el, HANDLE h) return (el->len) ? (unused != el->len) : (unused != 4); } -static bool LoadArraysOld(HANDLE h) { - dlogr("Loading arrays (old fmt)", DL_MAIN); - +static long LoadArraysOld(HANDLE h) { DWORD count, unused, id; ReadFile(h, &count, 4, &unused, 0); // count of saved arrays - if (unused != 4) return true; + if (unused != 4) return -1; + if (!count) return 0; + + dlogr("Loading arrays (old fmt)", DL_MAIN); sArrayVarOld var; sArrayVar varN; @@ -196,7 +197,7 @@ static bool LoadArraysOld(HANDLE h) { for (DWORD i = 0; i < count; i++) { ReadFile(h, &id, 4, &unused, 0); ReadFile(h, &var, 8, &unused, 0); - if (unused != 8) return true; + if (unused != 8) return -1; var.types = new DWORD[var.len]; var.data = new char[var.len * var.datalen]; @@ -226,23 +227,25 @@ static bool LoadArraysOld(HANDLE h) { arrays.insert(array_pair(id, varN)); savedArrays[varN.key] = id; } - return false; + return 1; } -bool LoadArrays(HANDLE h) { +long LoadArrays(HANDLE h) { nextArrayID = 1; - if (LoadArraysOld(h)) return true; - - dlogr("Loading arrays (new fmt)", DL_MAIN); + long result = LoadArraysOld(h); + if (result) return result; DWORD count, unused, elCount; ReadFile(h, &count, 4, &unused, 0); // count of saved arrays - if (unused != 4) return true; + if (unused != 4 && !result) return 1; + + dlogr("Loading arrays (new fmt)", DL_MAIN); + if (unused != 4) return -1; sArrayVar arrayVar; for (DWORD i = 0; i < count; i++) { - if (LoadArrayElement(&arrayVar.key, h)) return true; + if (LoadArrayElement(&arrayVar.key, h)) return -1; if (arrayVar.key.intVal == 0 || static_cast(arrayVar.key.type) >= 4) { // partial compatibility with 3.4 arrayVar.key.intVal = static_cast(arrayVar.key.type); arrayVar.key.type = DataType::INT; @@ -250,12 +253,12 @@ bool LoadArrays(HANDLE h) { ReadFile(h, &arrayVar.flags, 4, &unused, 0); ReadFile(h, &elCount, 4, &unused, 0); // actual number of elements: keys+values - if (unused != 4) return true; + if (unused != 4) return -1; bool isAssoc = arrayVar.isAssoc(); arrayVar.val.resize(elCount); for (size_t j = 0; j < elCount; j++) { // normal and associative arrays stored and loaded equally - if (LoadArrayElement(&arrayVar.val[j], h)) return true; + if (LoadArrayElement(&arrayVar.val[j], h)) return -1; if (isAssoc && (j % 2) == 0) { // only difference is that keyHash is filled with appropriate indexes arrayVar.keyHash[arrayVar.val[j]] = j; } @@ -267,7 +270,7 @@ bool LoadArrays(HANDLE h) { savedArrays[arrayVar.key] = nextArrayID++; arrayVar.keyHash.clear(); } - return false; + return 0; } void SaveArrays(HANDLE h) { diff --git a/sfall/Modules/Scripting/Arrays.h b/sfall/Modules/Scripting/Arrays.h index f2a457c90..0d2ccfd45 100644 --- a/sfall/Modules/Scripting/Arrays.h +++ b/sfall/Modules/Scripting/Arrays.h @@ -151,7 +151,7 @@ extern DWORD arraysBehavior; // saved arrays: arrayKey => arrayId extern ArrayKeysMap savedArrays; -bool LoadArrays(HANDLE h); +long LoadArrays(HANDLE h); void SaveArrays(HANDLE h); int GetNumArrays(); void GetArrays(int* arrays); diff --git a/sfall/version.h b/sfall/version.h index d31d22a38..33d512a48 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -27,7 +27,7 @@ #define VERSION_BUILD 0 #define VERSION_REV 0 -#define VERSION_STRING "4.2.0" +#define VERSION_STRING "4.2" //#define CHECK_VAL (4) From 2bfb886ecebdecc9a81e2a5ac84f7cc796341f52 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 16 Jul 2019 10:51:26 +0800 Subject: [PATCH 4/7] Fixed two issues in party control code * perks picked in combat disappeared after switching control to other critters. * player's selected weapon mode was not saved. --- sfall/Modules/LoadGameHook.cpp | 5 +-- sfall/Modules/PartyControl.cpp | 58 ++++++++++++++++------------- sfall/Modules/PartyControl.h | 1 - sfall/Modules/Scripting/Opcodes.cpp | 33 +++++++--------- 4 files changed, 48 insertions(+), 49 deletions(-) diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index bd96c7197..b9099f463 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -157,8 +157,8 @@ static void _stdcall SaveGame2() { } else { goto errorSave; } - return; + ///////////////////////////////////////////////// errorSave: dlog_f("ERROR creating: %s\n", DL_MAIN, buf); @@ -231,8 +231,7 @@ static bool LoadGame_Before() { Worldmap::SetAddedYears(data >> 16); if (size != 4 || !Perks::load(h)) goto errorLoad; long result = script::LoadArrays(h); // 1 - old save, -1 - broken save - if (result == -1) goto errorLoad; - if (!result && BugFixes::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/Modules/PartyControl.cpp b/sfall/Modules/PartyControl.cpp index 084f89faa..116f2d9ac 100644 --- a/sfall/Modules/PartyControl.cpp +++ b/sfall/Modules/PartyControl.cpp @@ -33,8 +33,8 @@ namespace sfall bool npcAutoLevelEnabled; bool npcEngineLevelUp = true; -bool isControllingNPC = false; -bool skipCounterAnim = false; +static bool isControllingNPC = false; +static bool skipCounterAnim = false; static int delayedExperience; static bool switchHandHookInjected = false; @@ -272,7 +272,7 @@ static void RestoreRealDudeState(bool redraw = true) { realDude.isSaved = false; isControllingNPC = false; - if (isDebug) fo::func::debug_printf("\n[SFALL] Restore control to dude."); + if (isDebug) fo::func::debug_printf("\n[SFALL] Restore control to dude.\n"); } static void __stdcall DisplayCantDoThat() { @@ -294,14 +294,14 @@ int __stdcall PartyControl::SwitchHandHook(fo::GameObject* item) { return -1; } -long __fastcall GetRealDudePerk(fo::GameObject* source, long perk) { +static long __fastcall GetRealDudePerk(fo::GameObject* source, long perk) { if (isControllingNPC && source == realDude.obj_dude) { return realDude.perkLevelDataList[perk]; } return fo::func::perk_level(source, perk); } -long __fastcall GetRealDudeTrait(fo::GameObject* source, long trait) { +static long __fastcall GetRealDudeTrait(fo::GameObject* source, long trait) { if (isControllingNPC && source == realDude.obj_dude) { return (trait == realDude.traits[0] || trait == realDude.traits[1]) ? 1 : 0; } @@ -332,7 +332,7 @@ static void __declspec(naked) pc_flag_toggle_hook() { } } -void __stdcall PartyControlReset() { +static void PartyControlReset() { if (realDude.obj_dude != nullptr && isControllingNPC) { RestoreRealDudeState(false); } @@ -345,7 +345,7 @@ bool PartyControl::IsNpcControlled() { return isControllingNPC; } -bool CopyItemSlots(WeaponStateSlot &element, bool isSwap) { +static bool CopyItemSlots(WeaponStateSlot &element, bool isSwap) { bool isCopy = false; if (fo::var::itemButtonItems[0 + isSwap].itsWeapon && fo::var::itemButtonItems[0 + isSwap].item) { memcpy(&element.leftSlot, &fo::var::itemButtonItems[0 + isSwap], 0x14); @@ -368,7 +368,7 @@ bool CopyItemSlots(WeaponStateSlot &element, bool isSwap) { return isCopy; } -void SaveWeaponMode(bool isSwap) { +static void SaveWeaponMode(bool isSwap) { for (size_t i = 0; i < weaponState.size(); i++) { if (weaponState[i].npcID == fo::var::obj_dude->id) { CopyItemSlots(weaponState[i], isSwap); @@ -382,29 +382,35 @@ void SaveWeaponMode(bool isSwap) { } } -void PartyControl::SwitchToCritter(fo::GameObject* critter) { - if (isControllingNPC) { - bool isSwap = false; - if (fo::var::itemCurrentItem == fo::ActiveSlot::Left) { - // set active left item to right slot - fo::GameObject* lItem = fo::func::inven_left_hand(fo::var::obj_dude); - if (lItem) { - isSwap = true; - fo::GameObject* rItem = fo::func::inven_right_hand(fo::var::obj_dude); - lItem->flags &= ~fo::ObjectFlag::Left_Hand; - lItem->flags |= fo::ObjectFlag::Right_Hand; - if (rItem) { - rItem->flags &= ~fo::ObjectFlag::Right_Hand; - rItem->flags |= fo::ObjectFlag::Left_Hand; - } +// Moves the weapon from the active left slot to the right slot and saves the selected weapon mode for NPC +static void NPCWeaponTweak() { + bool isSwap = false; + if (fo::var::itemCurrentItem == fo::ActiveSlot::Left) { + // set active left item to right slot + fo::GameObject* lItem = fo::func::inven_left_hand(fo::var::obj_dude); + if (lItem) { + isSwap = true; + fo::GameObject* rItem = fo::func::inven_right_hand(fo::var::obj_dude); + lItem->flags &= ~fo::ObjectFlag::Left_Hand; + lItem->flags |= fo::ObjectFlag::Right_Hand; + if (rItem) { + rItem->flags &= ~fo::ObjectFlag::Right_Hand; + rItem->flags |= fo::ObjectFlag::Left_Hand; } } - SaveWeaponMode(isSwap); + } + SaveWeaponMode(isSwap); +} + +void PartyControl::SwitchToCritter(fo::GameObject* critter) { + if (isControllingNPC) { + NPCWeaponTweak(); if (critter == nullptr || critter == realDude.obj_dude) RestoreRealDudeState(); // return control to dude - } else if (critter != nullptr && realDude.isSaved == false) { - SaveRealDudeState(); } if (critter != nullptr && critter != PartyControl::RealDudeObject()) { + if (!isControllingNPC && realDude.isSaved == false) { + SaveRealDudeState(); + } SetCurrentDude(critter); if (switchHandHookInjected) return; diff --git a/sfall/Modules/PartyControl.h b/sfall/Modules/PartyControl.h index ba66f9641..66c761e6e 100644 --- a/sfall/Modules/PartyControl.h +++ b/sfall/Modules/PartyControl.h @@ -39,7 +39,6 @@ class PartyControl : public Module { static fo::GameObject* RealDudeObject(); }; -extern bool isControllingNPC; extern bool npcAutoLevelEnabled; extern bool npcEngineLevelUp; diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index 466c161a1..7503ff165 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -248,21 +248,25 @@ void __declspec(naked) defaultOpcodeHandler() { } void InitNewOpcodes() { - bool AllowUnsafeScripting = isDebug - && GetPrivateProfileIntA("Debugging", "AllowUnsafeScripting", 0, ::sfall::ddrawIni) != 0; - dlogr("Adding additional opcodes", DL_SCRIPT); - if (AllowUnsafeScripting) { - dlogr(" Unsafe opcodes enabled.", DL_SCRIPT); - } else { - dlogr(" Unsafe opcodes disabled.", DL_SCRIPT); - } SafeWrite32(0x46E370, opcodeCount); // Maximum number of allowed opcodes SafeWrite32(0x46CE34, (DWORD)opcodes); // cmp check to make sure opcode exists SafeWrite32(0x46CE6C, (DWORD)opcodes); // call that actually jumps to the opcode SafeWrite32(0x46E390, (DWORD)opcodes); // mov that writes to the opcode + if (isDebug && (GetPrivateProfileIntA("Debugging", "AllowUnsafeScripting", 0, ::sfall::ddrawIni) != 0)) { + dlogr(" Unsafe opcodes enabled.", DL_SCRIPT); + opcodes[0x1cf] = op_write_byte; + opcodes[0x1d0] = op_write_short; + opcodes[0x1d1] = op_write_int; + opcodes[0x21b] = op_write_string; + for (int i = 0x1d2; i < 0x1dc; i++) { + opcodes[i] = op_call_offset; + } + } else { + dlogr(" Unsafe opcodes disabled.", DL_SCRIPT); + } opcodes[0x156] = op_read_byte; opcodes[0x157] = op_read_short; opcodes[0x158] = op_read_int; @@ -350,14 +354,7 @@ void InitNewOpcodes() { opcodes[0x1cc] = op_apply_heaveho_fix; opcodes[0x1cd] = op_set_swiftlearner_mod; opcodes[0x1ce] = op_set_hp_per_level_mod; - if (AllowUnsafeScripting) { - opcodes[0x1cf] = op_write_byte; - opcodes[0x1d0] = op_write_short; - opcodes[0x1d1] = op_write_int; - for (int i = 0x1d2; i < 0x1dc; i++) { - opcodes[i] = op_call_offset; - } - } + opcodes[0x1df] = op_get_bodypart_hit_modifier; opcodes[0x1e0] = op_set_bodypart_hit_modifier; opcodes[0x1e4] = op_get_sfall_arg; @@ -376,9 +373,7 @@ void InitNewOpcodes() { opcodes[0x213] = op_hero_select_win; opcodes[0x214] = op_set_hero_race; opcodes[0x215] = op_set_hero_style; - if (AllowUnsafeScripting) { - opcodes[0x21b] = op_write_string; - } + opcodes[0x21c] = op_get_mouse_x; opcodes[0x21d] = op_get_mouse_y; opcodes[0x21f] = op_get_window_under_mouse; From 16fbc0f93f425d07d4cb21b6b2d04cbde00d7382 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 16 Jul 2019 12:45:22 +0800 Subject: [PATCH 5/7] Changed "add_extra_msg_file" script function (#249) * added auto ID assignment for the message file. --- artifacts/scripting/headers/sfall.h | 2 +- artifacts/scripting/sfall function notes.txt | 9 ++++++--- sfall/Modules/Message.cpp | 13 +++++++++++-- sfall/Modules/Scripting/Handlers/Metarule.cpp | 2 +- sfall/Modules/Scripting/Handlers/Utils.cpp | 13 +++++++++++-- 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 70d11940a..5320b9115 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -244,7 +244,7 @@ #define ADD_PERK_MODE_REMOVE (4) // remove from the list of selectable perks // sfall_funcX macros -#define add_extra_msg_file(name, number) sfall_func2("add_extra_msg_file", name, number) +#define add_extra_msg_file(name) sfall_func1("add_extra_msg_file", name) #define add_iface_tag sfall_func0("add_iface_tag") #define art_cache_clear sfall_func0("art_cache_clear") #define attack_is_aimed sfall_func0("attack_is_aimed") diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index fd6deaf71..0da5a1dfe 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -609,10 +609,13 @@ optional arguments: > int sfall_func2("has_fake_trait_npc", object npc, string nameTrait) - these functions are similar to has_fake_*/set_fake_*/set_selectable_perk functions, but apply to the specified party member NPC (including dude_obj) -> void sfall_func2("add_extra_msg_file", string fileName, int fileNumber) -- loads the custom message file and assigns it with the specified ID number +> int sfall_func1("add_extra_msg_file", string fileName) +> int sfall_func2("add_extra_msg_file", string fileName, int fileNumber) +- loads the custom message file, and returns the file ID number assigned to it in range from 0x3000 to 0x3FFF for the message_str_game function to get messages from the file - fileName: the name of the custom message file (including the .msg extension) in "text\\game\" directory -- fileNumber: the file ID number for the message_str_game function to get messages from the file. The available range is from 0x3000 to 0x3FFF +optional argument: +- fileNumber: the file ID number for the message_str_game function. The available range is from 0x2000 to 0x2FFF (see ExtraGameMsgFileList setting in ddraw.ini) + use fileNumber only if you want to add a message file without editing ddraw.ini or existing scripts to support the old way ------------------------ ------ MORE INFO ------- diff --git a/sfall/Modules/Message.cpp b/sfall/Modules/Message.cpp index 7887c1069..638a99b58 100644 --- a/sfall/Modules/Message.cpp +++ b/sfall/Modules/Message.cpp @@ -56,6 +56,8 @@ const fo::MessageList* gameMsgFiles[] = { ExtraGameMessageListsMap gExtraGameMsgLists; static std::vector msgFileList; +static long msgNumCounter = 0x3000; + fo::MessageNode *GetMsgNode(fo::MessageList *msgList, int msgRef) { if (msgList != nullptr && msgList->numMsgs > 0) { fo::MessageNode *msgNode = msgList->nodes; @@ -115,16 +117,22 @@ static void ReadExtraGameMsgFiles() { } long Message::AddExtraMsgFile(const char* msgName, long msgNumber) { - if (msgNumber < 0x3000 || msgNumber > 0x3FFF || gExtraGameMsgLists.count(msgNumber)) return -1; + if (msgNumber) { + if (msgNumber < 0x2000 || msgNumber > 0x2FFF) return -1; + if (gExtraGameMsgLists.count(msgNumber)) return 0; // file has already been added + } else if (msgNumCounter > 0x3FFF) return -3; + std::string path("game\\"); path += msgName; fo::MessageList* list = new fo::MessageList(); if (fo::func::message_load(list, path.c_str())) { + if (msgNumber == 0) msgNumber = msgNumCounter++; gExtraGameMsgLists.emplace(msgNumber, list); } else { delete list; + msgNumber = -2; } - return 0; + return msgNumber; } static void ClearScriptAddedExtraGameMsg() { // C++11 @@ -136,6 +144,7 @@ static void ClearScriptAddedExtraGameMsg() { // C++11 ++it; } } + msgNumCounter = 0x3000; } static void ClearReadExtraGameMsgFiles() { diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 026f9faf9..618e1cc5b 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -59,7 +59,7 @@ static MetaruleTableType metaruleTable; - arg1, arg2, ... - argument types for automatic validation */ static const SfallMetarule metarules[] = { - {"add_extra_msg_file", sf_add_extra_msg_file, 2, 2, {ARG_STRING, ARG_INT}}, + {"add_extra_msg_file", sf_add_extra_msg_file, 1, 2, {ARG_STRING, ARG_INT}}, {"add_iface_tag", sf_add_iface_tag, 0, 0}, {"art_cache_clear", sf_art_cache_flush, 0, 0}, {"attack_is_aimed", sf_attack_is_aimed, 0, 0}, diff --git a/sfall/Modules/Scripting/Handlers/Utils.cpp b/sfall/Modules/Scripting/Handlers/Utils.cpp index ddef6a85d..1feda9cd6 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.cpp +++ b/sfall/Modules/Scripting/Handlers/Utils.cpp @@ -298,8 +298,17 @@ void sf_message_str_game(OpcodeContext& ctx) { } void sf_add_extra_msg_file(OpcodeContext& ctx) { - long result = Message::AddExtraMsgFile(ctx.arg(0).strValue(), ctx.arg(1).rawValue()); - if (result == -1) ctx.printOpcodeError("%s() - cannot add message file with the specified number.", ctx.getMetaruleName()); + long result = Message::AddExtraMsgFile(ctx.arg(0).strValue(), (ctx.numArgs() == 2) ? ctx.arg(1).rawValue() : 0); + switch (result) { + case -1 : + ctx.printOpcodeError("%s() - cannot add message file with the specified number.", ctx.getMetaruleName()); + break; + case -2 : + ctx.printOpcodeError("%s() - error loading message file.", ctx.getMetaruleName()); + break; + case -3 : + ctx.printOpcodeError("%s() - the limit of adding message files has been exceeded.", ctx.getMetaruleName()); + } ctx.setReturn(result); } From 01bbd111d33af97c9854e90ffb204c50e5e6939b Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 17 Jul 2019 09:15:00 +0800 Subject: [PATCH 6/7] Fixed elevation check in get/set_can_rest_on_map Changed DebugMode to not require enabling sfall debugging mode. Changed version to 4.1.9.1 as maintenance release. --- artifacts/ddraw.ini | 10 ++++++---- sfall/Modules/DebugEditor.cpp | 3 ++- sfall/Modules/Scripting/Handlers/Worldmap.cpp | 4 ++-- sfall/version.h | 9 ++++----- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 26d9edd52..6cb4c4c34 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -1,5 +1,5 @@ ;sfall configuration settings -;v4.2 +;v4.1.9.1 [Main] ;Change to 1 if you want to use command line args to tell sfall to use another ini file. @@ -186,7 +186,7 @@ FastMoveFromContainer=0 ;A key to press to open a debug game editor ;Set to 0 to disable, or a DX scancode otherwise -;Requires sfall debugging mode and FalloutClient.exe from the modders pack +;Requires sfall debugging mode to be enabled and FalloutClient.exe from the modders pack DebugEditorKey=0 ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX @@ -727,6 +727,7 @@ Enable=0 ;Fallout 2 Debug Patch ;Set to 1 to send debug output to the screen, 2 to a debug.log file, or 3 to both the screen and a debug.log file +;Does not require enabling sfall debugging mode ;While you don't need to create an environment variable, you do still need to set the appropriate lines in fallout2.cfg: ;------- ;[debug] @@ -745,12 +746,12 @@ DebugMode=0 SkipCompatModeCheck=0 ;Set to 1 to skip the executable file size check -;Does not require sfall debugging mode +;Does not require enabling sfall debugging mode SkipSizeCheck=0 ;If you're testing changes to the Fallout exe, you can override the CRC that sfall looks for here ;You can use several hex values, separated by commas -;Does not require sfall debugging mode +;Does not require enabling sfall debugging mode ;ExtraCRC=0x00000000,0x00000000 ;Set to 1 to stop Fallout from deleting non read-only protos at startup @@ -767,6 +768,7 @@ AlwaysFindScripts=0 InjectAllGameHooks=0 ;Set to 1 to hide error messages in debug output when a null value is passed to the function as an object +;Does not require enabling sfall debugging mode HideObjIsNullMsg=0 ;Set to 1 to force critters to display combat float messages diff --git a/sfall/Modules/DebugEditor.cpp b/sfall/Modules/DebugEditor.cpp index b54207353..02fa3d64c 100644 --- a/sfall/Modules/DebugEditor.cpp +++ b/sfall/Modules/DebugEditor.cpp @@ -358,8 +358,9 @@ void DontDeleteProtosPatch() { } void DebugEditor::init() { - if (!isDebug) return; DebugModePatch(); + + if (!isDebug) return; DontDeleteProtosPatch(); debugEditorKey = GetConfigInt("Input", "DebugEditorKey", 0); diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.cpp b/sfall/Modules/Scripting/Handlers/Worldmap.cpp index 17024b872..16da68130 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.cpp +++ b/sfall/Modules/Scripting/Handlers/Worldmap.cpp @@ -266,7 +266,7 @@ void sf_set_rest_on_map(OpcodeContext& ctx) { return; } long elev = ctx.arg(1).asInt(); - if (elev < -1 && elev > 2) { + if (elev < -1 || elev > 2) { ctx.printOpcodeError("%s() - invalid map elevation argument.", ctx.getMetaruleName()); } else { Worldmap::SetRestMapLevel(mapId, elev, ctx.arg(2).asBool()); @@ -275,7 +275,7 @@ void sf_set_rest_on_map(OpcodeContext& ctx) { void sf_get_rest_on_map(OpcodeContext& ctx) { long elev = ctx.arg(1).asInt(); - if (elev < 0 && elev > 2) { + if (elev < 0 || elev > 2) { ctx.printOpcodeError("%s() - invalid map elevation argument.", ctx.getMetaruleName()); } else { ctx.setReturn(Worldmap::GetRestMapLevel(elev, ctx.arg(0).asInt())); diff --git a/sfall/version.h b/sfall/version.h index 33d512a48..ced3fc393 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -23,11 +23,10 @@ #define LEGAL_COPYRIGHT "Copyright (C) 2006-2019, sfall team" #define VERSION_MAJOR 4 -#define VERSION_MINOR 2 -#define VERSION_BUILD 0 -#define VERSION_REV 0 +#define VERSION_MINOR 1 +#define VERSION_BUILD 9 +#define VERSION_REV 1 -#define VERSION_STRING "4.2" +#define VERSION_STRING "4.1.9.1" //#define CHECK_VAL (4) - From 839e8d263622ae743a8284997790c7f89d4908ca Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 18 Jul 2019 09:26:47 +0800 Subject: [PATCH 7/7] Minor edits to ddraw.ini --- artifacts/ddraw.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 6cb4c4c34..181bc1b44 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -31,7 +31,7 @@ UseCommandLine=0 NumSoundBuffers=0 ;Set to 1 to allow attaching sound files to combat float messages -AllowSoundForFloats=1 +AllowSoundForFloats=0 ;Set to 1 to automatically search for alternative formats (mp3/wma/wav) when Fallout tries to play an acm ;Set to 2 to play alternative music files even if original acm files are not present in the music folder @@ -768,7 +768,7 @@ AlwaysFindScripts=0 InjectAllGameHooks=0 ;Set to 1 to hide error messages in debug output when a null value is passed to the function as an object -;Does not require enabling sfall debugging mode +;Requires DebugMode to be enabled HideObjIsNullMsg=0 ;Set to 1 to force critters to display combat float messages