Added "get/set_rest_on_map" script functions (from Mr.Stalin)

This commit is contained in:
NovaRain
2018-09-28 13:59:09 +08:00
parent f162a5ab0c
commit 7f8481d03a
10 changed files with 158 additions and 5 deletions
+2
View File
@@ -230,6 +230,7 @@
#define display_stats sfall_func0("display_stats") #define display_stats sfall_func0("display_stats")
#define exec_map_update_scripts sfall_func0("exec_map_update_scripts") #define exec_map_update_scripts sfall_func0("exec_map_update_scripts")
#define floor2(value) sfall_func1("floor2", value) #define floor2(value) sfall_func1("floor2", value)
#define get_can_rest_on_map(map, elev) sfall_func2("get_can_rest_on_map", map, elev)
#define get_current_inven_size(obj) sfall_func1("get_current_inven_size", obj) #define get_current_inven_size(obj) sfall_func1("get_current_inven_size", obj)
#define get_cursor_mode sfall_func0("get_cursor_mode") #define get_cursor_mode sfall_func0("get_cursor_mode")
#define get_flags(obj) sfall_func1("get_flags", obj) #define get_flags(obj) sfall_func1("get_flags", obj)
@@ -247,6 +248,7 @@
#define lock_is_jammed(obj) sfall_func1("lock_is_jammed", obj) #define lock_is_jammed(obj) sfall_func1("lock_is_jammed", obj)
#define outlined_object sfall_func0("outlined_object") #define outlined_object sfall_func0("outlined_object")
#define real_dude_obj sfall_func0("real_dude_obj") #define real_dude_obj sfall_func0("real_dude_obj")
#define set_can_rest_on_map(map, elev, value) sfall_func3("set_can_rest_on_map", map, elev, value)
#define set_car_intface_art(artIndex) sfall_func1("set_car_intface_art", artIndex) #define set_car_intface_art(artIndex) sfall_func1("set_car_intface_art", artIndex)
#define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode) #define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode)
#define set_dude_obj(critter) sfall_func1("set_dude_obj", critter) #define set_dude_obj(critter) sfall_func1("set_dude_obj", critter)
@@ -505,6 +505,17 @@ Some utility/math functions are available:
- works just like vanilla CreateWin function, but creates a window with MoveOnTop flag if flags argument is not specified, and allows to set additional flags for the created window - works just like vanilla CreateWin function, but creates a window with MoveOnTop flag if flags argument is not specified, and allows to set additional flags for the created window
- MoveOnTop flag allows the created window to be placed on top of the game interface - MoveOnTop flag allows the created window to be placed on top of the game interface
> void sfall_func3("set_can_rest_on_map", int mapNum, int elev, bool value)
- allows/disallows to rest on the map for the specified level, overrides the can_rest_here values in maps.txt
- mapNum is the map index from maps.txt
- passing -1 to the elev argument will set the rest value for all map elevations
- the set rest value will be stored in sfalldb.sav file (in savegame)
> int sfall_func2("get_can_rest_on_map", int mapNum, int elev)
- returns the set rest value of the map after using the set_can_rest_on_map function
- returns -1 if the rest value of the map was not previously set (i.e. no data for the map in sfalldb.sav)
- the can_rest_here values in maps.txt are ignored
------------------------ ------------------------
------ MORE INFO ------- ------ MORE INFO -------
------------------------ ------------------------
+1
View File
@@ -109,6 +109,7 @@
#define FO_VAR_main_window 0x5194F0 #define FO_VAR_main_window 0x5194F0
#define FO_VAR_map_elevation 0x519578 #define FO_VAR_map_elevation 0x519578
#define FO_VAR_map_global_vars 0x51956C #define FO_VAR_map_global_vars 0x51956C
#define FO_VAR_map_number 0x631D88
#define FO_VAR_map_state 0x631D28 #define FO_VAR_map_state 0x631D28
#define FO_VAR_master_db_handle 0x58E948 #define FO_VAR_master_db_handle 0x58E948
#define FO_VAR_max 0x56FB50 #define FO_VAR_max 0x56FB50
-3
View File
@@ -44,7 +44,4 @@ void _stdcall EndHook();
#define HookBegin __asm pushad __asm call BeginHook __asm popad #define HookBegin __asm pushad __asm call BeginHook __asm popad
#define hookbegin(a) __asm pushad __asm call BeginHook __asm popad __asm mov argCount, a
#define hookend __asm pushad __asm call EndHook __asm popad
} }
+22 -2
View File
@@ -33,6 +33,7 @@
#include "ScriptExtender.h" #include "ScriptExtender.h"
#include "Scripting\Arrays.h" #include "Scripting\Arrays.h"
#include "ExtraSaveSlots.h" #include "ExtraSaveSlots.h"
#include "Worldmap.h"
#include "LoadGameHook.h" #include "LoadGameHook.h"
@@ -131,6 +132,14 @@ static void _stdcall SaveGame2() {
fo::DisplayPrint(saveSfallDataFailMsg); fo::DisplayPrint(saveSfallDataFailMsg);
fo::func::gsound_play_sfx_file("IISXXXX1"); fo::func::gsound_play_sfx_file("IISXXXX1");
} }
GetSavePath(buf, "db");
h = CreateFileA(buf, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (h != INVALID_HANDLE_VALUE) {
Worldmap::SaveData(h);
}
CloseHandle(h);
GetSavePath(buf, "fs"); GetSavePath(buf, "fs");
h = CreateFileA(buf, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); h = CreateFileA(buf, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (h != INVALID_HANDLE_VALUE) { if (h != INVALID_HANDLE_VALUE) {
@@ -207,6 +216,17 @@ static void _stdcall LoadGame_Before() {
} else { } else {
dlogr("Cannot read sfallgv.sav - assuming non-sfall save.", DL_MAIN); dlogr("Cannot read sfallgv.sav - assuming non-sfall save.", DL_MAIN);
} }
GetSavePath(buf, "db");
h = CreateFileA(buf, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (h != INVALID_HANDLE_VALUE) {
dlog("Loading data from sfalldb.sav...", DL_INIT);
Worldmap::LoadData(h);
CloseHandle(h);
dlogr(" Done", DL_INIT);
} else {
dlogr("Cannot read sfalldb.sav.", DL_INIT);
}
} }
// called whenever game is being reset (prior to loading a save or when returning to main menu) // called whenever game is being reset (prior to loading a save or when returning to main menu)
@@ -278,9 +298,9 @@ static void __stdcall NewGame_After() {
static void __declspec(naked) main_load_new_hook() { static void __declspec(naked) main_load_new_hook() {
__asm { __asm {
pushad; pushad;
push eax; mov esi, eax; // keep
call NewGame_Before; call NewGame_Before;
pop eax; mov eax, esi; // restore
call fo::funcoffs::main_load_new_; call fo::funcoffs::main_load_new_;
call NewGame_After; call NewGame_After;
popad; popad;
@@ -85,6 +85,7 @@ static const SfallMetarule metarules[] = {
{"display_stats", sf_display_stats, 0, 0}, {"display_stats", sf_display_stats, 0, 0},
{"exec_map_update_scripts", sf_exec_map_update_scripts, 0, 0}, {"exec_map_update_scripts", sf_exec_map_update_scripts, 0, 0},
{"floor2", sf_floor2, 1, 1, {ARG_NUMBER}}, {"floor2", sf_floor2, 1, 1, {ARG_NUMBER}},
{"get_can_rest_on_map", sf_get_rest_on_map, 2, 2, {ARG_INT, ARG_INT}},
{"get_current_inven_size", sf_get_current_inven_size, 1, 1, {ARG_OBJECT}}, {"get_current_inven_size", sf_get_current_inven_size, 1, 1, {ARG_OBJECT}},
{"get_cursor_mode", sf_get_cursor_mode, 0, 0}, {"get_cursor_mode", sf_get_cursor_mode, 0, 0},
{"get_flags", sf_get_flags, 1, 1, {ARG_OBJECT}}, {"get_flags", sf_get_flags, 1, 1, {ARG_OBJECT}},
@@ -103,6 +104,7 @@ static const SfallMetarule metarules[] = {
{"lock_is_jammed", sf_lock_is_jammed, 1, 1, {ARG_OBJECT}}, {"lock_is_jammed", sf_lock_is_jammed, 1, 1, {ARG_OBJECT}},
{"outlined_object", sf_outlined_object, 0, 0}, {"outlined_object", sf_outlined_object, 0, 0},
{"real_dude_obj", sf_real_dude_obj, 0, 0}, {"real_dude_obj", sf_real_dude_obj, 0, 0},
{"set_can_rest_on_map", sf_set_rest_on_map, 3, 3, {ARG_INT, ARG_INT, ARG_INT}},
{"set_car_intface_art", sf_set_car_intface_art, 1, 1, {ARG_INT}}, {"set_car_intface_art", sf_set_car_intface_art, 1, 1, {ARG_INT}},
{"set_cursor_mode", sf_set_cursor_mode, 1, 1, {ARG_INT}}, {"set_cursor_mode", sf_set_cursor_mode, 1, 1, {ARG_INT}},
{"set_dude_obj", sf_set_dude_obj, 1, 1, {ARG_OBJECT}}, {"set_dude_obj", sf_set_dude_obj, 1, 1, {ARG_OBJECT}},
@@ -263,5 +263,28 @@ void sf_set_rest_mode(OpcodeContext& ctx) {
Worldmap::SetRestMode(ctx.arg(0).asInt()); Worldmap::SetRestMode(ctx.arg(0).asInt());
} }
void sf_set_rest_on_map(OpcodeContext& ctx) {
long mapId = ctx.arg(0).asInt();
if (mapId < 0) {
ctx.printOpcodeError("set_rest_on_map() - invalid map number argument.");
return;
}
long elev = ctx.arg(1).asInt();
if (elev < -1 && elev > 2) {
ctx.printOpcodeError("set_rest_on_map() - invalid map elevation argument.");
} else {
Worldmap::SetRestMapLevel(mapId, elev, ctx.arg(2).asBool());
}
}
void sf_get_rest_on_map(OpcodeContext& ctx) {
long elev = ctx.arg(1).asInt();
if (elev < 0 && elev > 2) {
ctx.printOpcodeError("get_rest_on_map() - invalid map elevation argument.");
} else {
ctx.setReturn(Worldmap::GetRestMapLevel(elev, ctx.arg(0).asInt()));
}
}
} }
} }
@@ -50,5 +50,9 @@ void sf_set_rest_heal_time(OpcodeContext&);
void sf_set_rest_mode(OpcodeContext&); void sf_set_rest_mode(OpcodeContext&);
void sf_set_rest_on_map(OpcodeContext&);
void sf_get_rest_on_map(OpcodeContext&);
} }
} }
+88
View File
@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <map>
#include <math.h> #include <math.h>
#include "..\main.h" #include "..\main.h"
@@ -32,6 +33,12 @@ static Delegate<> onWorldmapLoop;
static DWORD ViewportX; static DWORD ViewportX;
static DWORD ViewportY; static DWORD ViewportY;
struct levelRest {
char level[4];
};
std::map<int, levelRest> mapRestInfo;
static bool restMap;
static bool restMode; static bool restMode;
static bool restTime; static bool restTime;
@@ -209,6 +216,24 @@ static void __declspec(naked) wmInterfaceInit_text_font_hook() {
} }
} }
static void __declspec(naked) critter_can_obj_dude_rest_hook() {
using namespace fo;
__asm {
push eax;
mov ecx, eax; // elevation
mov edx, dword ptr ds:[FO_VAR_map_number];
call Worldmap::GetRestMapLevel;
xor edx, edx;
cmp eax, edx;
jge skip;
pop eax;
jmp fo::funcoffs::wmMapCanRestHere_;
skip:
add esp, 4;
retn; // overrides
}
}
static void RestRestore() { static void RestRestore() {
if (!restMode) return; if (!restMode) return;
@@ -413,6 +438,31 @@ void WorldMapFontPatch() {
} }
} }
void Worldmap::SaveData(HANDLE file) {
DWORD sizeWrite, count = mapRestInfo.size();
WriteFile(file, &count, 4, &sizeWrite, 0);
std::map<int, levelRest>::iterator it;
for (it = mapRestInfo.begin(); it != mapRestInfo.end(); it++) {
WriteFile(file, &it->first, 4, &sizeWrite, 0);
WriteFile(file, &it->second, sizeof(levelRest), &sizeWrite, 0);
}
}
void Worldmap::LoadData(HANDLE file) {
DWORD count, sizeRead;
ReadFile(file, &count, 4, &sizeRead, 0);
if (sizeRead != 4) return;
if (!restMap) HookCall(0x42E57A, critter_can_obj_dude_rest_hook);
for (DWORD i = 0; i < count; i++) {
DWORD mID;
levelRest elevData;
ReadFile(file, &mID, 4, &sizeRead, 0);
ReadFile(file, &elevData, sizeof(levelRest), &sizeRead, 0);
mapRestInfo.insert(std::make_pair(mID, elevData));
}
restMap = true;
}
void Worldmap::init() { void Worldmap::init() {
PathfinderFixInit(); PathfinderFixInit();
StartingStatePatches(); StartingStatePatches();
@@ -426,6 +476,7 @@ void Worldmap::init() {
SetCarInterfaceArt(0x1B1); SetCarInterfaceArt(0x1B1);
if (restTime) SetRestHealTime(180); if (restTime) SetRestHealTime(180);
RestRestore(); RestRestore();
mapRestInfo.clear();
}; };
} }
@@ -465,4 +516,41 @@ void Worldmap::SetRestMode(DWORD mode) {
} }
} }
void Worldmap::SetRestMapLevel(int mapId, long elev, bool canRest) {
auto keyIt = mapRestInfo.find(mapId);
if (keyIt != mapRestInfo.end()) {
if (elev == -1) {
keyIt->second.level[++elev] = canRest;
keyIt->second.level[++elev] = canRest;
elev++;
}
keyIt->second.level[elev] = canRest;
} else {
if (!restMap) {
HookCall(0x42E57A, critter_can_obj_dude_rest_hook);
restMap = true;
}
levelRest elevData = {-1, -1, -1, -1};
std::pair<int, levelRest> info (mapId, elevData);
if (elev == -1) {
info.second.level[++elev] = canRest;
info.second.level[++elev] = canRest;
elev++;
}
info.second.level[elev] = canRest;
mapRestInfo.insert(info);
}
}
long __fastcall Worldmap::GetRestMapLevel(long elev, int mapId) {
if (mapRestInfo.empty()) return -1;
auto keyIt = mapRestInfo.find(mapId);
if (keyIt != mapRestInfo.end()) {
return keyIt->second.level[elev];
}
return -1;
}
} }
+5
View File
@@ -31,9 +31,14 @@ public:
static Delegate<>& OnWorldmapLoop(); static Delegate<>& OnWorldmapLoop();
static void Worldmap::SaveData(HANDLE);
static void Worldmap::LoadData(HANDLE);
static void SetCarInterfaceArt(DWORD artIndex); static void SetCarInterfaceArt(DWORD artIndex);
static void SetRestHealTime(DWORD minutes); static void SetRestHealTime(DWORD minutes);
static void SetRestMode(DWORD mode); static void SetRestMode(DWORD mode);
static void SetRestMapLevel(int mapId, long elev, bool canRest);
static long __fastcall GetRestMapLevel(long elev, int mapId);
}; };
} }