Rewrote the code of force_encounter functions

Added a new flag to force_encounter_with_flags.
This commit is contained in:
NovaRain
2019-08-12 12:06:45 +08:00
parent 50f4885407
commit da864c9789
5 changed files with 54 additions and 66 deletions
+2 -1
View File
@@ -73,7 +73,8 @@
#define LIST_ALL (9) #define LIST_ALL (9)
//Valid flags for force_encounter_with_flags //Valid flags for force_encounter_with_flags
#define ENCOUNTER_FLAG_NO_CAR (1) #define ENCOUNTER_FLAG_NO_CAR (1)
#define ENCOUNTER_FLAG_LOCK (2) // block new forced encounter by the next function call until the current specified encounter occurs
//The attack types returned by get_attack_type //The attack types returned by get_attack_type
#define ATKTYPE_LWEP1 (0) #define ATKTYPE_LWEP1 (0)
+1
View File
@@ -132,6 +132,7 @@
#define FO_VAR_max 0x56FB50 #define FO_VAR_max 0x56FB50
#define FO_VAR_maxScriptNum 0x51C7CC #define FO_VAR_maxScriptNum 0x51C7CC
#define FO_VAR_Meet_Frank_Horrigan 0x672E04 #define FO_VAR_Meet_Frank_Horrigan 0x672E04
#define FO_VAR_Move_on_Car 0x672E64
#define FO_VAR_mouse_hotx 0x6AC7D0 #define FO_VAR_mouse_hotx 0x6AC7D0
#define FO_VAR_mouse_hoty 0x6AC7CC #define FO_VAR_mouse_hoty 0x6AC7CC
#define FO_VAR_mouse_is_hidden 0x6AC790 #define FO_VAR_mouse_is_hidden 0x6AC790
+42 -61
View File
@@ -31,77 +31,58 @@ namespace sfall
namespace script namespace script
{ {
static DWORD EncounteredHorrigan; static DWORD ForceEnconterMapID = -1;
static DWORD ForceEnconterMapID; static DWORD ForceEnconterFlags;
static void _stdcall ForceEncounterRestore() { DWORD ForceEncounterRestore() {
*(DWORD*)0x672E04 = EncounteredHorrigan; long long data = 0x672E043D83; // cmp ds:_Meet_Frank_Horrigan, 0
SafeWrite32(0x4C070E, *(DWORD*)0x4C0718); // map id SafeWriteBytes(0x4C06D1, (BYTE*)&data, 5);
SafeWrite16(0x4C06D8, 0x5175); ForceEnconterFlags = 0;
SafeWrite32(0x4C071D, 0xFFFC2413); DWORD mapID = ForceEnconterMapID;
SafeWrite8(0x4C0706, 0x75); ForceEnconterMapID = -1;
return mapID;
} }
static void __declspec(naked) wmRndEncounterOccurred_hook() { static void __declspec(naked) wmRndEncounterOccurred_hack() {
__asm { __asm {
push ecx; test ForceEnconterFlags, 0x1; // _NoCar flag
call ForceEncounterRestore; jnz noCar;
pop ecx; cmp ds:[FO_VAR_Move_on_Car], 0;
jz noCar;
mov edx, FO_VAR_carCurrentArea;
mov eax, ForceEnconterMapID; mov eax, ForceEnconterMapID;
jmp fo::funcoffs::map_load_idx_; call fo::funcoffs::wmMatchAreaContainingMapIdx_;
noCar:
//push ecx;
// TODO: implement a blinking red icon
call ForceEncounterRestore;
//pop ecx;
push 0x4C0721; // return addr
jmp fo::funcoffs::map_load_idx_; // eax - mapID
} }
} }
static void __fastcall ForceEncounter(DWORD mapID, DWORD flags) { void sf_force_encounter(OpcodeContext& cxt) {
EncounteredHorrigan = *(DWORD*)0x672E04; if (ForceEnconterFlags & (1 << 31)) return; // wait prev. encounter
DWORD mapID = cxt.arg(0).rawValue();
if (mapID < 0) {
cxt.printOpcodeError("%s() - invalid map number.", cxt.getOpcodeName());
return;
}
if (ForceEnconterMapID == -1) MakeJump(0x4C06D1, wmRndEncounterOccurred_hack);
ForceEnconterMapID = mapID; ForceEnconterMapID = mapID;
SafeWrite32(0x4C070E, mapID); DWORD flags = 0;
SafeWrite16(0x4C06D8, 0x13EB); // jmp 0x4C06ED if (cxt.numArgs() > 1) {
HookCall(0x4C071C, wmRndEncounterOccurred_hook); flags = cxt.arg(1).rawValue();
if (flags & 2) { // _Lock flag
if (flags & 1) SafeWrite8(0x4C0706, 0xEB); flags |= (1 << 31); // set bit 31
} } else {
flags = flags & ~(1 << 31);
void __declspec(naked) op_force_encounter() { }
__asm {
push ecx;
push edx;
_GET_ARG_INT(end);
xor edx, edx; // flags
mov ecx, eax; // mapID
call ForceEncounter;
end:
pop edx;
pop ecx;
retn;
}
}
void __declspec(naked) op_force_encounter_with_flags() {
__asm {
pushad;
mov ecx, eax;
call fo::funcoffs::interpretPopShort_;
mov edx, eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
mov ebx, eax;
mov eax, ecx;
call fo::funcoffs::interpretPopShort_;
mov edi, eax;
mov eax, ecx;
call fo::funcoffs::interpretPopLong_;
cmp dx, VAR_TYPE_INT;
jnz end;
cmp di, VAR_TYPE_INT;
jnz end;
mov edx, ebx; // flags
mov ecx, eax; // mapID
call ForceEncounter;
end:
popad;
retn;
} }
ForceEnconterFlags = flags;
} }
// world_map_functions // world_map_functions
+2 -2
View File
@@ -25,9 +25,9 @@ namespace script
class OpcodeContext; class OpcodeContext;
void __declspec() op_force_encounter(); void sf_force_encounter(OpcodeContext&);
void __declspec() op_force_encounter_with_flags(); DWORD ForceEncounterRestore();
// world_map_functions // world_map_functions
void __declspec() op_in_world_map(); void __declspec() op_in_world_map();
+7 -2
View File
@@ -18,6 +18,7 @@
#include "..\..\FalloutEngine\Fallout2.h" #include "..\..\FalloutEngine\Fallout2.h"
#include "..\KillCounter.h" #include "..\KillCounter.h"
#include "..\LoadGameHook.h"
#include "Handlers\Anims.h" #include "Handlers\Anims.h"
#include "Handlers\Arrays.h" #include "Handlers\Arrays.h"
@@ -72,6 +73,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x161, "get_critter_extra_stat", sf_get_critter_extra_stat, 2, true, {ARG_OBJECT, ARG_INT}}, {0x161, "get_critter_extra_stat", sf_get_critter_extra_stat, 2, true, {ARG_OBJECT, ARG_INT}},
{0x163, "get_year", sf_get_year, 0, true}, {0x163, "get_year", sf_get_year, 0, true},
{0x16c, "key_pressed", sf_key_pressed, 1, true, {ARG_INT}}, {0x16c, "key_pressed", sf_key_pressed, 1, true, {ARG_INT}},
{0x171, "force_encounter", sf_force_encounter, 1, false, {ARG_INT}},
{0x190, "get_perk_available", sf_get_perk_available, 1, true, {ARG_INT}}, {0x190, "get_perk_available", sf_get_perk_available, 1, true, {ARG_INT}},
{0x195, "set_weapon_knockback", sf_set_object_knockback, 3, false, {ARG_OBJECT, ARG_INT, ARG_NUMBER}}, {0x195, "set_weapon_knockback", sf_set_object_knockback, 3, false, {ARG_OBJECT, ARG_INT, ARG_NUMBER}},
@@ -143,6 +145,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x224, "create_message_window", sf_create_message_window, 1, false, {ARG_STRING}}, {0x224, "create_message_window", sf_create_message_window, 1, false, {ARG_STRING}},
{0x228, "get_attack_type", sf_get_attack_type, 0, true}, {0x228, "get_attack_type", sf_get_attack_type, 0, true},
{0x229, "force_encounter_with_flags", sf_force_encounter, 2, false, {ARG_INT, ARG_INT}},
{0x22d, "create_array", sf_create_array, 2, true, {ARG_INT, ARG_INT}}, {0x22d, "create_array", sf_create_array, 2, true, {ARG_INT, ARG_INT}},
{0x22e, "set_array", sf_set_array, 3, false, {ARG_OBJECT, ARG_ANY, ARG_ANY}}, {0x22e, "set_array", sf_set_array, 3, false, {ARG_OBJECT, ARG_ANY, ARG_ANY}},
{0x22f, "get_array", sf_get_array, 2, true, {ARG_ANY, ARG_ANY}}, // can also be used on strings {0x22f, "get_array", sf_get_array, 2, true, {ARG_ANY, ARG_ANY}}, // can also be used on strings
@@ -286,7 +289,6 @@ void InitNewOpcodes() {
opcodes[0x16e] = op_set_shader_float; opcodes[0x16e] = op_set_shader_float;
opcodes[0x16f] = op_set_shader_vector; opcodes[0x16f] = op_set_shader_vector;
opcodes[0x170] = op_in_world_map; opcodes[0x170] = op_in_world_map;
opcodes[0x171] = op_force_encounter;
opcodes[0x172] = op_set_world_map_pos; opcodes[0x172] = op_set_world_map_pos;
opcodes[0x173] = op_get_world_map_x_pos; opcodes[0x173] = op_get_world_map_x_pos;
opcodes[0x174] = op_get_world_map_y_pos; opcodes[0x174] = op_get_world_map_y_pos;
@@ -384,7 +386,6 @@ void InitNewOpcodes() {
opcodes[0x225] = op_remove_trait; opcodes[0x225] = op_remove_trait;
opcodes[0x226] = op_get_light_level; opcodes[0x226] = op_get_light_level;
opcodes[0x227] = op_refresh_pc_art; opcodes[0x227] = op_refresh_pc_art;
opcodes[0x229] = op_force_encounter_with_flags;
opcodes[0x22a] = op_set_map_time_multi; opcodes[0x22a] = op_set_map_time_multi;
opcodes[0x22b] = op_play_sfall_sound; opcodes[0x22b] = op_play_sfall_sound;
opcodes[0x22c] = op_stop_sfall_sound; opcodes[0x22c] = op_stop_sfall_sound;
@@ -424,6 +425,10 @@ void InitNewOpcodes() {
InitOpcodeInfoTable(); InitOpcodeInfoTable();
InitMetaruleTable(); InitMetaruleTable();
LoadGameHook::OnGameReset() += []() {
ForceEncounterRestore(); // restore if the encounter did not happen
};
} }
} }