From bf4c47d1c00403d5e749824ddd08446e6a1eb96a Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 18 Jan 2020 17:28:05 +0800 Subject: [PATCH] Added "set_terrain_name" script function Fixed minor bugs in WorldMapTerrainInfo, TravelMarkerStyles features. Minor edits to Console.cpp, Logging.cpp. --- artifacts/scripting/headers/sfall.h | 1 + artifacts/scripting/sfall function notes.txt | 3 ++ sfall/FalloutEngine/EngineUtils.cpp | 5 --- sfall/FalloutEngine/EngineUtils.h | 2 - sfall/Logging.cpp | 8 ++-- sfall/Modules/Console.cpp | 16 ++++---- sfall/Modules/Interface.cpp | 41 +++++++++++++++---- sfall/Modules/Movies.cpp | 2 +- sfall/Modules/Scripting/Handlers/Metarule.cpp | 1 + sfall/Modules/Scripting/Handlers/Worldmap.cpp | 4 ++ sfall/Modules/Scripting/Handlers/Worldmap.h | 2 + sfall/Modules/Worldmap.cpp | 33 +++++++++++++++ sfall/Modules/Worldmap.h | 4 ++ 13 files changed, 92 insertions(+), 30 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index d31383ef..111b5f40 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -315,6 +315,7 @@ #define set_outline(obj, color) sfall_func2("set_outline", obj, color) #define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time) #define set_rest_mode(mode) sfall_func1("set_rest_mode", mode) +#define set_terrain_name(x, y, name) sfall_func3("set_terrain_name", x, y, name) #define set_unique_id(obj) sfall_func1("set_unique_id", obj) #define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time) #define set_window_flag(winID, flag, value) sfall_func3("set_window_flag", winID, flag, value) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 245f19bd..618e2b25 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -702,6 +702,9 @@ optional argument: - toCase: 0 - lowercase, 1 - uppercase - NOTE: this function works only for English letters of A-Z/a-z +> void sfall_func3("set_terrain_name", int x, int y, string name) +- overrides the terrain type name for the sub-tile by the specified coordinates on the world map + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index a5df6f73..d65cf89d 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -225,11 +225,6 @@ long wmGetCurrentTerrainType() { return *terrainId; } -// Returns the name of the terrain type at the the player's position on the world map -const char* wmGetCurrentTerrainName() { - return GetMessageStr(&fo::var::wmMsgFile, 1000 + wmGetCurrentTerrainType()); -} - //--------------------------------------------------------- // copy the area from the interface buffer to the data array void RectCopyToMemory(long fromX, long fromY, long width, long height, long fromWidth, BYTE* fromBuff, BYTE* toMem) { diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index d4f77343..56b01a6c 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -82,8 +82,6 @@ void GetObjectsTileRadius(std::vector &objs, long sourceTile, l long wmGetCurrentTerrainType(); -const char* wmGetCurrentTerrainName(); - void RectCopyToMemory(long fromX, long fromY, long width, long height, long fromWidth, BYTE* fromBuff, BYTE* toMem); void MemCopyToWinBuffer(long toX, long toY, long width, long height, long toWidth, BYTE* toBuff, BYTE* fromMem); diff --git a/sfall/Logging.cpp b/sfall/Logging.cpp index 4721eec0..573c4449 100644 --- a/sfall/Logging.cpp +++ b/sfall/Logging.cpp @@ -26,10 +26,8 @@ namespace sfall { -using namespace std; - -static int DebugTypes=0; -static ofstream Log; +static int DebugTypes = 0; +static std::ofstream Log; void dlog(const std::string& a, int type) { if (isDebug && (type == DL_MAIN || (type & DebugTypes))) { @@ -58,7 +56,7 @@ void dlog_f(const char *fmt, int type, ...) { } void LoggingInit() { - Log.open("sfall-log.txt", ios_base::out | ios_base::trunc); + Log.open("sfall-log.txt", std::ios_base::out | std::ios_base::trunc); if (iniGetInt("Debugging", "Init", 0, ::sfall::ddrawIni)) { DebugTypes |= DL_INIT; } diff --git a/sfall/Modules/Console.cpp b/sfall/Modules/Console.cpp index f6246b7e..8e53493d 100644 --- a/sfall/Modules/Console.cpp +++ b/sfall/Modules/Console.cpp @@ -25,12 +25,10 @@ namespace sfall { -using namespace std; +static std::ofstream consoleFile; -static ofstream consolefile; - -static void _stdcall ConsoleFilePrint(const char* msg) { - consolefile << msg << endl; +static void __stdcall ConsoleFilePrint(const char* msg) { + consoleFile << msg << std::endl; } static const DWORD ConsoleHookRet = 0x431871; @@ -52,16 +50,16 @@ static void __declspec(naked) ConsoleHook() { void Console::init() { auto path = GetConfigString("Misc", "ConsoleOutputPath", "", MAX_PATH); if (!path.empty()) { - consolefile.open(path); - if (consolefile.is_open()) { + consoleFile.open(path); + if (consoleFile.is_open()) { MakeJump(0x43186C, ConsoleHook); } } } void Console::exit() { - if (consolefile.is_open()) { - consolefile.close(); + if (consoleFile.is_open()) { + consoleFile.close(); } } diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index fcc03817..4f22ab37 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -24,6 +24,7 @@ #include "..\Utils.h" #include "Graphics.h" #include "LoadGameHook.h" +#include "Worldmap.h" #include "Interface.h" @@ -471,9 +472,10 @@ enum DotStyleDefault { }; enum TerrainHoverImage { - width = 100, + width = 200, height = 15, - size = width * height + size = width * height, + x_shift = (width / 4 ) + 25 // adjust x position }; static std::array wmTmpBuffer; @@ -563,7 +565,7 @@ static void __declspec(naked) DrawingDots() { } static void PrintTerrainType(long x, long y) { - char* terrainText = (char*)fo::wmGetCurrentTerrainName(); + char* terrainText = (char*)Worldmap::GetCurrentTerrainName(); long txtWidth = fo::GetTextWidthFM(terrainText); if (txtWidth > TerrainHoverImage::width) txtWidth = TerrainHoverImage::width; @@ -583,7 +585,12 @@ static void __declspec(naked) wmInterfaceRefresh_hook() { // player stops moving dots.clear(); // Reinitialize on next AddNewDot - dotLen = spaceLen = 99; + if (terrainCount) + dotLen = spaceLen = 99; + else { + dotLen = DotStyleDefault::DotLen; + spaceLen = DotStyleDefault::SpaceLen; + } } } if (isHoveringHotspot && !fo::var::In_WorldMap) { @@ -594,8 +601,13 @@ static void __declspec(naked) wmInterfaceRefresh_hook() { } static long __fastcall wmDetectHotspotHover(long wmMouseX, long wmMouseY) { - long deltaX = abs((long)fo::var::world_xpos - (wmMouseX - 20 + fo::var::wmWorldOffsetX)); - long deltaY = abs((long)fo::var::world_ypos - (wmMouseY - 20 + fo::var::wmWorldOffsetY)); + long deltaX = 20, deltaY = 20; + + // mouse cursor is out of viewport area (the zero values of wmMouseX and wmMouseY correspond to the top-left corner of the worldmap interface) + if ((wmMouseX < 25 || wmMouseY < 30 || wmMouseX > wmapViewPortWidth + 15 || wmMouseY > wmapViewPortHeight + 15) == false) { + deltaX = abs((long)fo::var::world_xpos - (wmMouseX - deltaX + fo::var::wmWorldOffsetX)); + deltaY = abs((long)fo::var::world_ypos - (wmMouseY - deltaY + fo::var::wmWorldOffsetY)); + } bool isHovered = isHoveringHotspot; isHoveringHotspot = deltaX < 8 && deltaY < 6; @@ -603,12 +615,12 @@ static long __fastcall wmDetectHotspotHover(long wmMouseX, long wmMouseY) { // upper left corner long y = fo::var::world_ypos - fo::var::wmWorldOffsetY; long x = fo::var::world_xpos - fo::var::wmWorldOffsetX; - long x_offset = x - 25; + long x_offset = x - TerrainHoverImage::x_shift; if (!backImageIsCopy) { backImageIsCopy = true; // copy image to memory (size 100 x 15) fo::RectCopyToMemory(x_offset, y, TerrainHoverImage::width, TerrainHoverImage::height, wmapWinWidth, *(BYTE**)FO_VAR_wmBkWinBuf, wmTmpBuffer.data()); - PrintTerrainType(x, y); + PrintTerrainType(x, y); // TODO: fix text being printed over the interface } else { // restore saved image fo::MemCopyToWinBuffer(x_offset, y, TerrainHoverImage::width, TerrainHoverImage::height, wmapWinWidth, *(BYTE**)FO_VAR_wmBkWinBuf, wmTmpBuffer.data()); @@ -635,12 +647,25 @@ end: checkHover: cmp dword ptr ds:[FO_VAR_WorldMapCurrArea], -1; jne end; // player is in a location circle + cmp esi, 328; + je isScroll; + cmp esi, 331; + je isScroll; + cmp esi, 333; + je isScroll; + cmp esi, 336; + je isScroll; push ecx; mov ecx, [esp + 0x38 - 0x30 + 8]; // x mov edx, [esp + 0x38 - 0x34 + 8]; // y call wmDetectHotspotHover; pop ecx; retn; +isScroll: + mov isHoveringHotspot, 0; + mov backImageIsCopy, 0; + mov eax, dword ptr ds:[FO_VAR_wmWorldOffsetY]; + retn; } } diff --git a/sfall/Modules/Movies.cpp b/sfall/Modules/Movies.cpp index 7d8102b2..5ca43392 100644 --- a/sfall/Modules/Movies.cpp +++ b/sfall/Modules/Movies.cpp @@ -91,8 +91,8 @@ private: HRESULT hr = pAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &surfaces[0]); if (FAILED(hr)) return hr; - dlog_f(" Height: %d,", DL_INIT, lpAllocInfo->dwHeight); dlog_f(" Width: %d,", DL_INIT, lpAllocInfo->dwWidth); + dlog_f(" Height: %d,", DL_INIT, lpAllocInfo->dwHeight); dlog_f(" Format: %d", DL_INIT, lpAllocInfo->Format); hr = surfaces[0]->GetContainer(IID_IDirect3DTexture9, (void**)&pTex); diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 8b44c3a8..db93056e 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -127,6 +127,7 @@ static const SfallMetarule metarules[] = { {"set_rest_heal_time", sf_set_rest_heal_time, 1, 1, -1, {ARG_INT}}, {"set_rest_mode", sf_set_rest_mode, 1, 1, -1, {ARG_INT}}, {"set_selectable_perk_npc", sf_set_selectable_perk_npc, 5, 5, -1, {ARG_OBJECT, ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}}, + {"set_terrain_name", sf_set_terrain_name, 3, 3, -1, {ARG_INT, ARG_INT, ARG_STRING}}, {"set_unique_id", sf_set_unique_id, 1, 2, -1, {ARG_OBJECT, ARG_INT}}, {"set_unjam_locks_time", sf_set_unjam_locks_time, 1, 1, -1, {ARG_INT}}, {"set_window_flag", sf_set_window_flag, 3, 3, -1, {ARG_INTSTR, ARG_INT, ARG_INT}}, diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.cpp b/sfall/Modules/Scripting/Handlers/Worldmap.cpp index 8b44a11d..c33c32fd 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.cpp +++ b/sfall/Modules/Scripting/Handlers/Worldmap.cpp @@ -257,5 +257,9 @@ void sf_tile_by_position(OpcodeContext& ctx) { ctx.setReturn(fo::func::tile_num(ctx.arg(0).rawValue(), ctx.arg(1).rawValue())); } +void sf_set_terrain_name(OpcodeContext& ctx) { + Worldmap::SetTerrainTypeName(ctx.arg(0).rawValue(), ctx.arg(1).rawValue(), ctx.arg(2).strValue()); +} + } } diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.h b/sfall/Modules/Scripting/Handlers/Worldmap.h index ed506622..65850cff 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.h +++ b/sfall/Modules/Scripting/Handlers/Worldmap.h @@ -58,5 +58,7 @@ void sf_get_rest_on_map(OpcodeContext&); void sf_tile_by_position(OpcodeContext&); +void sf_set_terrain_name(OpcodeContext&); + } } diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index 94ca2345..488bd59b 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -42,6 +42,8 @@ struct levelRest { }; std::unordered_map mapRestInfo; +std::vector> wmTerrainTypeNames; // pair first: x + y * number of horizontal sub-tiles + static bool restMap; static bool restMode; static bool restTime; @@ -602,6 +604,36 @@ long __fastcall Worldmap::GetRestMapLevel(long elev, int mapId) { return -1; } +static const char* GetOverrideTerrainName(long x, long y) { + if (wmTerrainTypeNames.empty()) return nullptr; + + long subTileID = x + y * (fo::var::wmNumHorizontalTiles * 7); + auto it = std::find_if(wmTerrainTypeNames.crbegin(), wmTerrainTypeNames.crend(), + [=](const std::pair &el) + { return el.first == subTileID; } + ); + return (it != wmTerrainTypeNames.crend()) ? it->second.c_str() : nullptr; +} + +// x, y - position of the sub-tile on the world map +void Worldmap::SetTerrainTypeName(long x, long y, const char* name) { + long subTileID = x + y * (fo::var::wmNumHorizontalTiles * 7); + wmTerrainTypeNames.push_back(std::make_pair(subTileID, name)); +} + +// TODO: someone might need to know the name of a terrain type? +const char* Worldmap::GetTerrainTypeName(long x, long y) { + //const char* name = GetOverrideTerrainName(x, y); + //return (name) ? name : fo::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::wmGetTerrainType(x, y)); + return nullptr; +} + +// Returns the name of the terrain type in the position of the player's marker on the world map +const char* Worldmap::GetCurrentTerrainName() { + const char* name = GetOverrideTerrainName(fo::var::world_xpos / 50, fo::var::world_ypos / 50); + return (name) ? name : fo::GetMessageStr(&fo::var::wmMsgFile, 1000 + fo::wmGetCurrentTerrainType()); +} + void Worldmap::init() { PathfinderFixInit(); StartingStatePatches(); @@ -616,6 +648,7 @@ void Worldmap::init() { if (restTime) SetRestHealTime(180); RestRestore(); mapRestInfo.clear(); + wmTerrainTypeNames.clear(); }; } diff --git a/sfall/Modules/Worldmap.h b/sfall/Modules/Worldmap.h index d1dce2f8..4c060ba8 100644 --- a/sfall/Modules/Worldmap.h +++ b/sfall/Modules/Worldmap.h @@ -42,6 +42,10 @@ public: static DWORD GetAddedYears(bool isCheck = true); static void SetAddedYears(DWORD years); + + static void SetTerrainTypeName(long x, long y, const char* name); + static const char* GetTerrainTypeName(long x, long y); + static const char* GetCurrentTerrainName(); }; void _stdcall SetMapMulti(float d);