Added a patch to allow setting custom colors for object outlines

Added a tweak to ObjCanSeeObj_ShootThru_Fix to allow critters to see
through other critters.

Fixed the internal variable for Horrigan encounter always being reset if
DisableHorrigan=0 (commit 74d3cb9)

Corrected some code.
This commit is contained in:
NovaRain
2020-08-05 16:18:19 +08:00
parent 8e3ae04aec
commit 112c931ea3
6 changed files with 59 additions and 29 deletions
+4 -3
View File
@@ -106,7 +106,7 @@ AllowSoundForFloats=0
AllowDShowSound=0 AllowDShowSound=0
;Set to 1 to override the default music path with data\sound\music\ if music_path is not present in the cfg ;Set to 1 to override the default music path with data\sound\music\ if music_path is not present in the cfg
;Set to 2 to overwrite all occurances of the music path ;Set to 2 to overwrite all occurrences of the music path
OverrideMusicDir=1 OverrideMusicDir=1
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -184,6 +184,7 @@ HighlightCorpses=1
;16 - bright yellow ;16 - bright yellow
;32 - dark yellow ;32 - dark yellow
;64 - purple ;64 - purple
;You can set a custom color from the game palette by multiplying the color index value by 256 (available since sfall 3.8.27)
OutlineColor=16 OutlineColor=16
;A key to press to reload your currently equipped weapon or use the active item ;A key to press to reload your currently equipped weapon or use the active item
@@ -560,8 +561,8 @@ SuperStimExploitFix=0
InventoryApCost=4 InventoryApCost=4
QuickPocketsApCostReduction=2 QuickPocketsApCostReduction=2
;Set to 1 to allow objects seeing through other objects that have their ShootThru flag set ;Set to 1 to fix obj_can_see_obj script function to allow critters to see through other critters and objects with 'ShootThru' flag set
;Note that enabling this option can cause unexpected NPC behavior in some situations ;Note that enabling this option can cause unexpected NPC behavior in some situations, e.g. able to attack or enter into a dialogue with the player behind some objects
ObjCanSeeObj_ShootThru_Fix=0 ObjCanSeeObj_ShootThru_Fix=0
;Set to 1 to fix the broken obj_can_hear_obj script function ;Set to 1 to fix the broken obj_can_hear_obj script function
+3 -2
View File
@@ -417,8 +417,9 @@ Some utility/math functions are available:
- gets the current outline color for an object - gets the current outline color for an object
> void sfall_func2("set_outline", object, int color) > void sfall_func2("set_outline", object, int color)
- sets the outline color of an object - sets the outline color of an object (see OUTLINE_* constants in sfall.h)
- 0 means or any value above 0x00FFFFFF disables the outline - can also set a custom color from the game palette by shifting the color index value 8 bits left: 0xCC00 where CC is the palette index (available since sfall 4.2.7/3.8.27)
- passing 0 will disable the outline
- call "tile_refresh_display" after changing outline of objects to properly redraw the scene - call "tile_refresh_display" after changing outline of objects to properly redraw the scene
> int sfall_func1("get_flags", object) > int sfall_func1("get_flags", object)
+2 -2
View File
@@ -246,8 +246,8 @@ checkArt:
call db_access_; // check art file exists call db_access_; // check art file exists
test eax, eax; test eax, eax;
jz notExists; jz notExists;
//mov eax, _art_name; mov eax, _art_name;
jmp LoadOrder_art_get_name_hack; //retn; Not sure if we need a jump to: art_get_name_hack retn;
notExists: // if file not found load regular critter art instead notExists: // if file not found load regular critter art instead
sub esi, critterArraySize; sub esi, critterArraySize;
add esp, 4; // drop func ret address add esp, 4; // drop func ret address
+5 -8
View File
@@ -50,13 +50,11 @@
#include "version.h" #include "version.h"
#include "Worldmap.h" #include "Worldmap.h"
#define MAX_GLOBAL_SIZE (MaxGlobalVars * 12 + 4)
static DWORD inLoop = 0; static DWORD inLoop = 0;
static DWORD saveInCombatFix; static DWORD saveInCombatFix;
static bool gameLoaded = false;
static bool disableHorrigan = false; static bool disableHorrigan = false;
static bool pipBoyAvailableAtGameStart = false; static bool pipBoyAvailableAtGameStart = false;
static bool gameLoaded = false;
// True if game was started, false when on the main menu // True if game was started, false when on the main menu
bool IsGameLoaded() { bool IsGameLoaded() {
@@ -239,7 +237,7 @@ errorLoad:
static void __stdcall LoadGame_After() { static void __stdcall LoadGame_After() {
CritLoad(); CritLoad();
*ptr_Meet_Frank_Horrigan = disableHorrigan; if (disableHorrigan) *ptr_Meet_Frank_Horrigan = true;
LoadGlobalScripts(); LoadGlobalScripts();
gameLoaded = true; gameLoaded = true;
} }
@@ -321,7 +319,7 @@ static void NewGame2() {
CritLoad(); CritLoad();
SetNewCharAppearanceGlobals(); SetNewCharAppearanceGlobals();
LoadHeroAppearance(); LoadHeroAppearance();
*ptr_Meet_Frank_Horrigan = disableHorrigan; if (disableHorrigan) *ptr_Meet_Frank_Horrigan = true;
LoadGlobalScripts(); LoadGlobalScripts();
dlogr("New Game started.", DL_MAIN); dlogr("New Game started.", DL_MAIN);
@@ -339,8 +337,7 @@ static void __declspec(naked) NewGame() {
} }
static void ReadExtraGameMsgFilesIfNeeded() { static void ReadExtraGameMsgFilesIfNeeded() {
if (gExtraGameMsgLists.empty()) if (gExtraGameMsgLists.empty()) ReadExtraGameMsgFiles();
ReadExtraGameMsgFiles();
} }
static void __declspec(naked) MainMenuHook() { static void __declspec(naked) MainMenuHook() {
@@ -349,7 +346,7 @@ static void __declspec(naked) MainMenuHook() {
push 0; push 0;
call ResetState; call ResetState;
mov al, pipBoyAvailableAtGameStart; mov al, pipBoyAvailableAtGameStart;
mov byte ptr ds:[_gmovie_played_list + 0x3], al; mov byte ptr ds:[_gmovie_played_list + 3], al;
call ReadExtraGameMsgFilesIfNeeded; call ReadExtraGameMsgFilesIfNeeded;
popad; popad;
jmp main_menu_loop_; jmp main_menu_loop_;
+5 -7
View File
@@ -269,16 +269,14 @@ void __declspec(naked) LoadOrder_art_get_name_hack() {
jne artHasAlias; jne artHasAlias;
retn; retn;
artHasAlias: artHasAlias:
sub esp, 4; call db_access_;
mov edx, esp; test eax, eax;
call db_dir_entry_; jz artNotExist;
add esp, 4;
cmp eax, -1;
je artNotExist;
mov aliasFID, -1; mov aliasFID, -1;
mov eax, _art_name; mov eax, _art_name;
retn; retn;
artNotExist: artNotExist:
dec eax; // -1
xchg eax, aliasFID xchg eax, aliasFID
add esp, 4; add esp, 4;
jmp art_get_name_Alias; // get name of art alias jmp art_get_name_Alias; // get name of art alias
@@ -304,7 +302,7 @@ void LoadOrderInit() {
HookCall(0x44436D, game_init_databases_hook1); HookCall(0x44436D, game_init_databases_hook1);
} }
// Predefined behavior for replacing art aliases for critters // Redefined behavior for replacing art aliases for critters
// first check the existence of the art file of the current critter and then replace the art alias if file not found // first check the existence of the art file of the current critter and then replace the art alias if file not found
HookCall(0x419440, art_get_name_hook); HookCall(0x419440, art_get_name_hook);
SafeWrite16(0x419521, 0x003B); // jmp 0x419560 SafeWrite16(0x419521, 0x003B); // jmp 0x419560
+38 -5
View File
@@ -125,13 +125,31 @@ fail:
} }
static void __declspec(naked) op_obj_can_see_obj_hook() { static void __declspec(naked) op_obj_can_see_obj_hook() {
using namespace Fields;
__asm { __asm {
mov edi, [esp + 4]; // buf **ret_objStruct
push obj_shoot_blocking_at_; // check hex objects func pointer push obj_shoot_blocking_at_; // check hex objects func pointer
push 0x20; // flags, 0x20 = check ShootThru push 0x20; // flags, 0x20 = check ShootThru
mov ecx, dword ptr [esp + 0x0C]; // buf **ret_objStruct push edi;
push ecx; call make_straight_path_func_;
xor ecx, ecx; // fix: see through critters
call make_straight_path_func_; // (EAX *objStruct, EDX hexNum1, EBX hexNum2, ECX 0, stack1 **ret_objStruct, stack2 flags, stack3 *check_hex_objs_func) mov edx, [esp + 4];
mov ebx, [edx];
test ebx, ebx;
jz skip;
cmp ebx, [edx - 8]; // target
jne noTarget;
skip:
retn 8;
noTarget:
mov eax, [ebx + protoId];
shr eax, 24;
cmp eax, OBJ_TYPE_CRITTER;
je isCritter;
retn 8;
isCritter:
mov [edx - 4], ebx; // replace source
mov dword ptr [esp], 0x456BAB; // continue
retn 8; retn 8;
} }
} }
@@ -198,6 +216,18 @@ skip:
} }
} }
static void __declspec(naked) obj_render_outline_hack() {
__asm {
test eax, 0xFF00;
jnz palColor;
mov al, ds:[_GoodColor];
retn;
palColor:
mov al, ah;
retn;
}
}
static void AdditionalWeaponAnimsPatch() { static void AdditionalWeaponAnimsPatch() {
if (GetConfigInt("Misc", "AdditionalWeaponAnims", 0)) { if (GetConfigInt("Misc", "AdditionalWeaponAnims", 0)) {
dlog("Applying additional weapon animations patch.", DL_INIT); dlog("Applying additional weapon animations patch.", DL_INIT);
@@ -352,7 +382,7 @@ static void DisablePipboyAlarmPatch() {
static void ObjCanSeeShootThroughPatch() { static void ObjCanSeeShootThroughPatch() {
if (GetConfigInt("Misc", "ObjCanSeeObj_ShootThru_Fix", 0)) { if (GetConfigInt("Misc", "ObjCanSeeObj_ShootThru_Fix", 0)) {
dlog("Applying ObjCanSeeObj ShootThru Fix.", DL_INIT); dlog("Applying obj_can_see_obj fix for critters and ShootThru objects.", DL_INIT);
HookCall(0x456BC6, op_obj_can_see_obj_hook); HookCall(0x456BC6, op_obj_can_see_obj_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
} }
@@ -593,6 +623,9 @@ void MiscPatchesInit() {
const DWORD drawCardAddr[] = {0x43ACD5, 0x43DD37}; // 136, 133 const DWORD drawCardAddr[] = {0x43ACD5, 0x43DD37}; // 136, 133
SafeWriteBatch<BYTE>(145, drawCardAddr); SafeWriteBatch<BYTE>(145, drawCardAddr);
// Allow setting custom colors from the game palette for object outlines
MakeCall(0x48EE00, obj_render_outline_hack);
F1EngineBehaviorPatch(); F1EngineBehaviorPatch();
DialogueFix(); DialogueFix();
AdditionalWeaponAnimsPatch(); AdditionalWeaponAnimsPatch();