Backported FO1 worldmap features from 4.x

* WorldMapTravelMarkers, WorldMapTerrainInfo options.
* set_terrain_name, set_town_title script functions.
This commit is contained in:
NovaRain
2020-01-26 09:26:41 +08:00
parent c9b1a1b583
commit 3b2e23fda6
14 changed files with 545 additions and 3 deletions
+14
View File
@@ -89,6 +89,20 @@ AllowDShowMovies=0
;Default is 100. Decrease/increase this value to speed up/slow down fade effects ;Default is 100. Decrease/increase this value to speed up/slow down fade effects
FadeMultiplier=100 FadeMultiplier=100
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Interface]
;Set to 1 to enable drawing a dotted line when traveling on the world map (similar to Fallout 1)
WorldMapTravelMarkers=0
;Uncomment these lines to change the appearance of the markers
;The color index in Fallout default palette (valid range: 1..228; default is 134)
;TravelMarkerColor=134
;The length and spacing of the dots in pixels for each type of terrain in worldmap.txt
;Syntax is 'length:spacing', with each pair separated by a comma (valid range: 1..10; default is 2)
;TravelMarkerStyles=2:2,2:2,2:2,2:2
;Set to 1 to display terrain types when hovering the cursor over the player's marker on the world map
WorldMapTerrainInfo=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Input] [Input]
;Set to 1 to enable the mouse scroll wheel to scroll through the inventory, barter, and loot screens ;Set to 1 to enable the mouse scroll wheel to scroll through the inventory, barter, and loot screens
+2
View File
@@ -286,6 +286,8 @@
#define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot) #define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot)
#define set_object_data(obj, offset, value) sfall_func3("set_object_data", obj, offset, value) #define set_object_data(obj, offset, value) sfall_func3("set_object_data", obj, offset, value)
#define set_outline(obj, color) sfall_func2("set_outline", obj, color) #define set_outline(obj, color) sfall_func2("set_outline", obj, color)
#define set_terrain_name(x, y, name) sfall_func3("set_terrain_name", x, y, name)
#define set_town_title(areaID, title) sfall_func2("set_town_title", areaID, title)
#define set_unique_id(obj) sfall_func1("set_unique_id", obj) #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_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) #define set_window_flag(winID, flag, value) sfall_func3("set_window_flag", winID, flag, value)
@@ -608,11 +608,18 @@ optional arguments:
- toCase: 0 - lowercase, 1 - uppercase - toCase: 0 - lowercase, 1 - uppercase
- NOTE: this function works only for English letters of A-Z/a-z - 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 on the world map by the specified coordinates
int sfall_func2("get_window_attribute", int winType, int attrType) int sfall_func2("get_window_attribute", int winType, int attrType)
- returns the attribute of the specified interface window by the attrType argument - returns the attribute of the specified interface window by the attrType argument
- winType: the type number of the interface window (see WINTYPE_* constants in sfall.h) - winType: the type number of the interface window (see WINTYPE_* constants in sfall.h)
- attrType: 0 - X position, 1 - Y position (relative to the top-left corner of the game screen) - attrType: 0 - X position, 1 - Y position (relative to the top-left corner of the game screen)
> void sfall_func2("set_town_title", int areaID, string title)
- sets a floating text for a town on the world map when hovering the cursor over the player's marker
- areaID: the ID number of the town from city.txt
------------------------ ------------------------
------ MORE INFO ------- ------ MORE INFO -------
------------------------ ------------------------
+124
View File
@@ -224,6 +224,8 @@ DWORD* ptr_wmAreaInfoList = reinterpret_cast<DWORD*>(_wmAreaInfoList
const DWORD* ptr_wmBkWin = reinterpret_cast<DWORD*>(_wmBkWin); const DWORD* ptr_wmBkWin = reinterpret_cast<DWORD*>(_wmBkWin);
BYTE** ptr_wmBkWinBuf = reinterpret_cast<BYTE**>(_wmBkWinBuf); BYTE** ptr_wmBkWinBuf = reinterpret_cast<BYTE**>(_wmBkWinBuf);
DWORD* ptr_wmLastRndTime = reinterpret_cast<DWORD*>(_wmLastRndTime); DWORD* ptr_wmLastRndTime = reinterpret_cast<DWORD*>(_wmLastRndTime);
MSGList* ptr_wmMsgFile = reinterpret_cast<MSGList*>(_wmMsgFile);
DWORD* ptr_wmNumHorizontalTiles = reinterpret_cast<DWORD*>(_wmNumHorizontalTiles);
long* ptr_wmWorldOffsetX = reinterpret_cast<long*>(_wmWorldOffsetX); long* ptr_wmWorldOffsetX = reinterpret_cast<long*>(_wmWorldOffsetX);
long* ptr_wmWorldOffsetY = reinterpret_cast<long*>(_wmWorldOffsetY); long* ptr_wmWorldOffsetY = reinterpret_cast<long*>(_wmWorldOffsetY);
DWORD* ptr_world_xpos = reinterpret_cast<DWORD*>(_world_xpos); DWORD* ptr_world_xpos = reinterpret_cast<DWORD*>(_world_xpos);
@@ -374,6 +376,9 @@ const DWORD executeProcedure_ = 0x46DD2C;
const DWORD findCurrentProc_ = 0x467160; const DWORD findCurrentProc_ = 0x467160;
const DWORD fadeSystemPalette_ = 0x4C7320; const DWORD fadeSystemPalette_ = 0x4C7320;
const DWORD findVar_ = 0x4410AC; const DWORD findVar_ = 0x4410AC;
const DWORD FMtext_char_width_ = 0x4421DC;
const DWORD FMtext_to_buf_ = 0x4422B4;
const DWORD FMtext_width_ = 0x442188;
const DWORD folder_print_line_ = 0x43E3D8; const DWORD folder_print_line_ = 0x43E3D8;
const DWORD fprintf_ = 0x4F0D56; const DWORD fprintf_ = 0x4F0D56;
const DWORD frame_ptr_ = 0x419880; const DWORD frame_ptr_ = 0x419880;
@@ -717,6 +722,7 @@ const DWORD windowGetBuffer_ = 0x4B82DC;
const DWORD windowHide_ = 0x4B7610; const DWORD windowHide_ = 0x4B7610;
const DWORD windowShow_ = 0x4B7648; const DWORD windowShow_ = 0x4B7648;
const DWORD windowWidth_ = 0x4B7734; const DWORD windowWidth_ = 0x4B7734;
const DWORD wmDrawCursorStopped_ = 0x4C41EC;
const DWORD wmFindCurSubTileFromPos_ = 0x4C0C00; const DWORD wmFindCurSubTileFromPos_ = 0x4C0C00;
const DWORD wmInterfaceRefresh_ = 0x4C3830; const DWORD wmInterfaceRefresh_ = 0x4C3830;
const DWORD wmInterfaceScrollTabsStart_ = 0x4C219C; const DWORD wmInterfaceScrollTabsStart_ = 0x4C219C;
@@ -725,6 +731,7 @@ const DWORD wmMarkSubTileRadiusVisited_ = 0x4C3550;
const DWORD wmMatchAreaContainingMapIdx_ = 0x4C59A4; const DWORD wmMatchAreaContainingMapIdx_ = 0x4C59A4;
const DWORD wmPartyInitWalking_ = 0x4C1E54; const DWORD wmPartyInitWalking_ = 0x4C1E54;
const DWORD wmPartyWalkingStep_ = 0x4C1F90; const DWORD wmPartyWalkingStep_ = 0x4C1F90;
const DWORD wmRefreshInterfaceOverlay_ = 0x4C50F4;
const DWORD wmSubTileMarkRadiusVisited_ = 0x4C35A8; const DWORD wmSubTileMarkRadiusVisited_ = 0x4C35A8;
const DWORD wmWorldMapFunc_ = 0x4BFE10; const DWORD wmWorldMapFunc_ = 0x4BFE10;
const DWORD wmWorldMapLoadTempData_ = 0x4BD6B4; const DWORD wmWorldMapLoadTempData_ = 0x4BD6B4;
@@ -1177,6 +1184,10 @@ void __stdcall WinDraw(DWORD winRef) {
WRAP_WATCOM_CALL1(win_draw_, winRef) WRAP_WATCOM_CALL1(win_draw_, winRef)
} }
void __stdcall WinDrawRect(DWORD winRef, RECT* rect) {
WRAP_WATCOM_CALL2(win_draw_rect_, winRef, rect)
}
void __stdcall WinDelete(DWORD winRef) { void __stdcall WinDelete(DWORD winRef) {
WRAP_WATCOM_CALL1(win_delete_, winRef) WRAP_WATCOM_CALL1(win_delete_, winRef)
} }
@@ -1339,6 +1350,10 @@ long __fastcall ItemAddForce(TGameObj* critter, TGameObj* item, long count) {
WRAP_WATCOM_FCALL3(item_add_force_, critter, item, count) WRAP_WATCOM_FCALL3(item_add_force_, critter, item, count)
} }
long __fastcall MessageFind(DWORD* msgFile, long msgNumber, DWORD* outBuf) {
WRAP_WATCOM_FCALL3(message_find_, msgFile, msgNumber, outBuf)
}
long __fastcall MouseClickIn(long x, long y, long x_end, long y_end) { long __fastcall MouseClickIn(long x, long y, long x_end, long y_end) {
WRAP_WATCOM_FCALL4(mouse_click_in_, x, y, x_end, y_end) WRAP_WATCOM_FCALL4(mouse_click_in_, x, y, x_end, y_end)
} }
@@ -1351,6 +1366,14 @@ long __stdcall LoadFrame(const char* filename, FrmFile** frmPtr) {
WRAP_WATCOM_CALL2(load_frame_, filename, frmPtr) WRAP_WATCOM_CALL2(load_frame_, filename, frmPtr)
} }
long __stdcall FMtextWidth(const char* text) {
WRAP_WATCOM_CALL1(FMtext_width_, text)
}
void __stdcall WmRefreshInterfaceOverlay(long isRedraw) {
WRAP_WATCOM_CALL1(wmRefreshInterfaceOverlay_, isRedraw)
}
///////////////////////////////// ENGINE UTILS ///////////////////////////////// ///////////////////////////////// ENGINE UTILS /////////////////////////////////
static MSGNode messageBuf; static MSGNode messageBuf;
@@ -1512,6 +1535,81 @@ void GetObjectsTileRadius(std::vector<TGameObj*> &objs, long sourceTile, long ra
} }
} }
// Returns the type of the terrain sub tile at the the player's position on the world map
long wmGetCurrentTerrainType() {
long* terrainId = *(long**)_world_subtile;
if (terrainId == nullptr) {
__asm {
lea ebx, terrainId;
mov edx, dword ptr ds:[_world_ypos];
mov eax, dword ptr ds:[_world_xpos];
call wmFindCurSubTileFromPos_;
}
}
return *terrainId;
}
//---------------------------------------------------------
// copy the area from the interface buffer to the data array
void SurfaceCopyToMem(long fromX, long fromY, long width, long height, long fromWidth, BYTE* fromSurface, BYTE* toMem) {
fromSurface += fromY * fromWidth + fromX;
long i = 0;
for (long h = 0; h < height; h++) {
for (long w = 0; w < width; w++) {
toMem[i++] = fromSurface[w];
}
fromSurface += fromWidth;
}
}
// copy data from memory to the area of the interface buffer
void DrawToSurface(long toX, long toY, long width, long height, long toWidth, long toHeight, BYTE* toSurface, BYTE* fromMem) {
BYTE* _toSurface = toSurface + (toY * toWidth + toX);
BYTE* endToSurf = (toWidth * toHeight) + toSurface;
long i = 0;
for (long h = 0; h < height; h++) {
for (long w = 0; w < width; w++) {
if (_toSurface + w > endToSurf) return;
if (_toSurface >= toSurface) _toSurface[w] = fromMem[i++];
}
_toSurface += toWidth;
}
}
void DrawToSurface(long width, long height, long fromX, long fromY, long fromWidth, BYTE* fromSurf,
long toX, long toY, long toWidth, long toHeight, BYTE* toSurf, int maskRef)
{
BYTE* _fromSurf = fromSurf + (fromY * fromWidth + fromX);
BYTE* _toSurf = toSurf + (toY * toWidth + toX);
BYTE* endToSurf = (toWidth * toHeight) + toSurf;
for (long h = 0; h < height; h++) {
for (long w = 0; w < width; w++) {
if (_toSurf + w > endToSurf) return;
if (_toSurf >= toSurf && _fromSurf[w] != maskRef) _toSurf[w] = _fromSurf[w];
}
_fromSurf += fromWidth;
_toSurf += toWidth;
}
}
void DrawToSurface(long width, long height, long fromX, long fromY, long fromWidth, BYTE* fromSurf,
long toX, long toY, long toWidth, long toHeight, BYTE* toSurf)
{
BYTE* _fromSurf = fromSurf + (fromY * fromWidth + fromX);
BYTE* _toSurf = toSurf + (toY * toWidth + toX);
BYTE* endToSurf = (toWidth * toHeight) + toSurf;
for (long h = 0; h < height; h++) {
for (long w = 0; w < width; w++) {
if (_toSurf + w > endToSurf) return;
if (_toSurf >= toSurf) _toSurf[w] = _fromSurf[w];
}
_fromSurf += fromWidth;
_toSurf += toWidth;
}
}
//--------------------------------------------------------- //---------------------------------------------------------
// print text to surface // print text to surface
void __stdcall PrintText(char* displayText, BYTE colorIndex, DWORD xPos, DWORD yPos, DWORD txtWidth, DWORD toWidth, BYTE* toSurface) { void __stdcall PrintText(char* displayText, BYTE colorIndex, DWORD xPos, DWORD yPos, DWORD txtWidth, DWORD toWidth, BYTE* toSurface) {
@@ -1529,6 +1627,21 @@ void __stdcall PrintText(char* displayText, BYTE colorIndex, DWORD xPos, DWORD y
} }
} }
void __stdcall PrintTextFM(char* displayText, BYTE colorIndex, DWORD xPos, DWORD yPos, DWORD txtWidth, DWORD toWidth, BYTE* toSurface) {
DWORD posOffset = yPos * toWidth + xPos;
__asm {
xor eax, eax;
mov al, colorIndex;
mov edx, displayText;
push eax;
mov ebx, txtWidth;
mov eax, toSurface;
mov ecx, toWidth;
add eax, posOffset;
call FMtext_to_buf_;
}
}
//--------------------------------------------------------- //---------------------------------------------------------
//gets the height of the currently selected font //gets the height of the currently selected font
DWORD __stdcall GetTextHeight() { DWORD __stdcall GetTextHeight() {
@@ -1549,6 +1662,10 @@ DWORD __stdcall GetTextWidth(const char* TextMsg) {
} }
} }
DWORD __stdcall GetTextWidthFM(const char* TextMsg) {
return FMtextWidth(TextMsg); //get text width
}
//--------------------------------------------------------- //---------------------------------------------------------
//get width of Char for current font //get width of Char for current font
DWORD __stdcall GetCharWidth(char charVal) { DWORD __stdcall GetCharWidth(char charVal) {
@@ -1558,6 +1675,13 @@ DWORD __stdcall GetCharWidth(char charVal) {
} }
} }
DWORD __stdcall GetCharWidthFM(char charVal) {
__asm {
mov al, charVal;
call FMtext_char_width_;
}
}
//--------------------------------------------------------- //---------------------------------------------------------
//get maximum string length for current font - if all characters were maximum width //get maximum string length for current font - if all characters were maximum width
DWORD __stdcall GetMaxTextWidth(const char* TextMsg) { DWORD __stdcall GetMaxTextWidth(const char* TextMsg) {
+30
View File
@@ -262,10 +262,13 @@
#define _wmEncounterIconShow 0x672E48 #define _wmEncounterIconShow 0x672E48
#define _wmLastRndTime 0x51DEA0 #define _wmLastRndTime 0x51DEA0
#define _wmMaxMapNum 0x51DE10 #define _wmMaxMapNum 0x51DE10
#define _wmMsgFile 0x672FB0
#define _wmNumHorizontalTiles 0x51DDF4
#define _wmRndCursorFid 0x672E58 #define _wmRndCursorFid 0x672E58
#define _wmWorldOffsetX 0x51DE2C #define _wmWorldOffsetX 0x51DE2C
#define _wmWorldOffsetY 0x51DE30 #define _wmWorldOffsetY 0x51DE30
#define _wmYesNoStrs 0x51DD90 #define _wmYesNoStrs 0x51DD90
#define _world_subtile 0x672E14
#define _world_xpos 0x672E0C #define _world_xpos 0x672E0C
#define _world_ypos 0x672E10 #define _world_ypos 0x672E10
#define _WorldMapCurrArea 0x672E08 #define _WorldMapCurrArea 0x672E08
@@ -490,6 +493,8 @@ extern DWORD* ptr_wmAreaInfoList;
extern const DWORD* ptr_wmBkWin; extern const DWORD* ptr_wmBkWin;
extern BYTE** ptr_wmBkWinBuf; extern BYTE** ptr_wmBkWinBuf;
extern DWORD* ptr_wmLastRndTime; extern DWORD* ptr_wmLastRndTime;
extern MSGList* ptr_wmMsgFile;
extern DWORD* ptr_wmNumHorizontalTiles;
extern long* ptr_wmWorldOffsetX; extern long* ptr_wmWorldOffsetX;
extern long* ptr_wmWorldOffsetY; extern long* ptr_wmWorldOffsetY;
extern DWORD* ptr_world_xpos; extern DWORD* ptr_world_xpos;
@@ -621,6 +626,9 @@ extern const DWORD exec_script_proc_; // unsigned int aScriptID<eax>, int aProcI
extern const DWORD executeProcedure_; // <eax> - programPtr, <edx> - procNumber extern const DWORD executeProcedure_; // <eax> - programPtr, <edx> - procNumber
extern const DWORD fadeSystemPalette_; extern const DWORD fadeSystemPalette_;
extern const DWORD findVar_; extern const DWORD findVar_;
extern const DWORD FMtext_char_width_;
extern const DWORD FMtext_to_buf_;
extern const DWORD FMtext_width_;
extern const DWORD folder_print_line_; extern const DWORD folder_print_line_;
extern const DWORD fprintf_; extern const DWORD fprintf_;
extern const DWORD frame_ptr_; extern const DWORD frame_ptr_;
@@ -973,6 +981,7 @@ extern const DWORD windowGetBuffer_;
extern const DWORD windowHide_; extern const DWORD windowHide_;
extern const DWORD windowShow_; extern const DWORD windowShow_;
extern const DWORD windowWidth_; extern const DWORD windowWidth_;
extern const DWORD wmDrawCursorStopped_;
extern const DWORD wmFindCurSubTileFromPos_; extern const DWORD wmFindCurSubTileFromPos_;
extern const DWORD wmInterfaceRefresh_; extern const DWORD wmInterfaceRefresh_;
extern const DWORD wmInterfaceScrollTabsStart_; extern const DWORD wmInterfaceScrollTabsStart_;
@@ -981,6 +990,7 @@ extern const DWORD wmMarkSubTileRadiusVisited_;
extern const DWORD wmMatchAreaContainingMapIdx_; extern const DWORD wmMatchAreaContainingMapIdx_;
extern const DWORD wmPartyInitWalking_; extern const DWORD wmPartyInitWalking_;
extern const DWORD wmPartyWalkingStep_; extern const DWORD wmPartyWalkingStep_;
extern const DWORD wmRefreshInterfaceOverlay_;
extern const DWORD wmSubTileMarkRadiusVisited_; extern const DWORD wmSubTileMarkRadiusVisited_;
extern const DWORD wmWorldMapFunc_; extern const DWORD wmWorldMapFunc_;
extern const DWORD wmWorldMapLoadTempData_; extern const DWORD wmWorldMapLoadTempData_;
@@ -1189,6 +1199,7 @@ void __stdcall WinShow(DWORD winRef);
void __stdcall WinHide(DWORD winRef); void __stdcall WinHide(DWORD winRef);
BYTE* __stdcall WinGetBuf(DWORD winRef); BYTE* __stdcall WinGetBuf(DWORD winRef);
void __stdcall WinDraw(DWORD winRef); void __stdcall WinDraw(DWORD winRef);
void __stdcall WinDrawRect(DWORD winRef, RECT* rect);
void __stdcall WinDelete(DWORD winRef); void __stdcall WinDelete(DWORD winRef);
long __stdcall WindowWidth(); long __stdcall WindowWidth();
@@ -1263,12 +1274,18 @@ long __stdcall InvenUnwield(TGameObj* critter, long slot);
long __fastcall ItemAddForce(TGameObj* critter, TGameObj* item, long count); long __fastcall ItemAddForce(TGameObj* critter, TGameObj* item, long count);
long __fastcall MessageFind(DWORD* msgFile, long msgNumber, DWORD* outBuf);
long __fastcall MouseClickIn(long x, long y, long x_end, long y_end); long __fastcall MouseClickIn(long x, long y, long x_end, long y_end);
const char* __stdcall ArtGetName(long artFID); const char* __stdcall ArtGetName(long artFID);
long __stdcall LoadFrame(const char* filename, FrmFile** frmPtr); long __stdcall LoadFrame(const char* filename, FrmFile** frmPtr);
long __stdcall FMtextWidth(const char* text);
void __stdcall WmRefreshInterfaceOverlay(long isRedraw);
///////////////////////////////// ENGINE UTILS ///////////////////////////////// ///////////////////////////////// ENGINE UTILS /////////////////////////////////
// returns message string from given file or "Error" when not found // returns message string from given file or "Error" when not found
@@ -1300,17 +1317,30 @@ WINinfo* GetUIWindow(long winType);
void GetObjectsTileRadius(std::vector<TGameObj*> &objs, long sourceTile, long radius, long elev, long type); void GetObjectsTileRadius(std::vector<TGameObj*> &objs, long sourceTile, long radius, long elev, long type);
long wmGetCurrentTerrainType();
void SurfaceCopyToMem(long fromX, long fromY, long width, long height, long fromWidth, BYTE* fromSurface, BYTE* toMem);
void DrawToSurface(long toX, long toY, long width, long height, long toWidth, long toHeight, BYTE* toSurface, BYTE* fromMem);
void DrawToSurface(long width, long height, long fromX, long fromY, long fromWidth, BYTE* fromSurf, long toX, long toY, long toWidth, long toHeight, BYTE* toSurf, int maskRef);
void DrawToSurface(long width, long height, long fromX, long fromY, long fromWidth, BYTE* fromSurf, long toX, long toY, long toWidth, long toHeight, BYTE* toSurf);
// Print text to surface // Print text to surface
void __stdcall PrintText(char* displayText, BYTE colorIndex, DWORD xPos, DWORD yPos, DWORD txtWidth, DWORD toWidth, BYTE* toSurface); void __stdcall PrintText(char* displayText, BYTE colorIndex, DWORD xPos, DWORD yPos, DWORD txtWidth, DWORD toWidth, BYTE* toSurface);
void __stdcall PrintTextFM(char* displayText, BYTE colorIndex, DWORD xPos, DWORD yPos, DWORD txtWidth, DWORD toWidth, BYTE* toSurface);
// gets the height of the currently selected font // gets the height of the currently selected font
DWORD __stdcall GetTextHeight(); DWORD __stdcall GetTextHeight();
// gets the length of a string using the currently selected font // gets the length of a string using the currently selected font
DWORD __stdcall GetTextWidth(const char* textMsg); DWORD __stdcall GetTextWidth(const char* textMsg);
DWORD __stdcall GetTextWidthFM(const char* textMsg);
// get width of Char for current font // get width of Char for current font
DWORD __stdcall GetCharWidth(char charVal); DWORD __stdcall GetCharWidth(char charVal);
DWORD __stdcall GetCharWidthFM(char charVal);
// get maximum string length for current font - if all characters were maximum width // get maximum string length for current font - if all characters were maximum width
DWORD __stdcall GetMaxTextWidth(const char* textMsg); DWORD __stdcall GetMaxTextWidth(const char* textMsg);
+286 -3
View File
@@ -16,8 +16,12 @@
* 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 <array>
#include "main.h" #include "main.h"
#include "FalloutEngine.h" #include "FalloutEngine.h"
#include "Utils.h"
#include "Worldmap.h"
static long costAP = -1; static long costAP = -1;
static void __declspec(naked) intface_redraw_items_hack0() { static void __declspec(naked) intface_redraw_items_hack0() {
@@ -100,16 +104,250 @@ static void __declspec(naked) wmInterfaceInit_text_font_hook() {
} }
} }
// const because no expanded world map patch
static const long wmapWinWidth = 640;
static const long wmapWinHeight = 480;
static const long wmapViewPortWidth = 450;
static const long wmapViewPortHeight = 443;
///////////////////////// FALLOUT 1 WORLD MAP FEATURES /////////////////////////
static bool showTerrainType = false;
enum DotStyleDefault {
STYDEF_DotLen = 2,
STYDEF_SpaceLen = 2
};
enum TerrainHoverImage {
HVRIMG_width = 200,
HVRIMG_height = 15,
HVRIMG_size = HVRIMG_width * HVRIMG_height,
HVRIMG_x_shift = (HVRIMG_width / 4) + 25 // adjust x position
};
static std::array<unsigned char, HVRIMG_size> wmTmpBuffer;
static bool isHoveringHotspot = false;
static bool backImageIsCopy = false;
struct DotPosition {
long x;
long y;
};
static std::vector<DotPosition> dots;
static unsigned char colorDot = 0;
static long spaceLen = STYDEF_SpaceLen;
static long dotLen = STYDEF_DotLen;
static long dot_xpos = 0;
static long dot_ypos = 0;
static size_t terrainCount = 0;
static struct DotStyle {
long dotLen;
long spaceLen;
} *dotStyle = nullptr;
static void AddNewDot() {
dot_xpos = *ptr_world_xpos;
dot_ypos = *ptr_world_ypos;
long* terrain = *(long**)_world_subtile;
size_t id = (terrain) ? *terrain : 0;
// Reinitialize if current terrain has smaller values than previous
if (id < terrainCount) {
if (dotLen > dotStyle[id].dotLen) dotLen = dotStyle[id].dotLen;
if (spaceLen > dotStyle[id].spaceLen) spaceLen = dotStyle[id].spaceLen;
}
if (dotLen <= 0 && spaceLen) {
spaceLen--;
if (!spaceLen) { // set dot length
dotLen = (id < terrainCount) ? dotStyle[id].dotLen : STYDEF_DotLen;
};
return;
}
dotLen--;
spaceLen = (id < terrainCount) ? dotStyle[id].spaceLen : STYDEF_SpaceLen;
DotPosition dot;
dot.x = dot_xpos;
dot.y = dot_ypos;
dots.push_back(std::move(dot));
}
static void __declspec(naked) DrawingDots() {
long x_offset, y_offset;
__asm {
mov ebp, esp; // prolog
sub esp, __LOCAL_SIZE;
}
if (dot_xpos != *ptr_world_xpos || dot_ypos != *ptr_world_ypos) {
AddNewDot();
}
x_offset = 22 - *ptr_wmWorldOffsetX;
y_offset = 21 - *ptr_wmWorldOffsetY;
for (std::vector<DotPosition>::const_iterator it = dots.begin(); it != dots.end(); ++it) { // redraws all dots
if (it->x < *ptr_wmWorldOffsetX || it->y < *ptr_wmWorldOffsetY) continue; // the pixel is out of viewport
if (it->x > *ptr_wmWorldOffsetX + wmapViewPortWidth || it->y > *ptr_wmWorldOffsetY + wmapViewPortHeight) continue;
long wmPixelX = (it->x + x_offset);
long wmPixelY = (it->y + y_offset);
wmPixelY *= wmapWinWidth;
BYTE* wmWinBuf = *ptr_wmBkWinBuf;
BYTE* wmWinBuf_xy = (wmPixelY + wmPixelX) + wmWinBuf;
// put pixel to interface window buffer
if (wmWinBuf_xy > wmWinBuf) *wmWinBuf_xy = colorDot;
// TODO: fix dots for car travel
}
__asm {
mov esp, ebp; // epilog
retn;
}
}
static bool PrintHotspotText(long x, long y, bool backgroundCopy = false) {
long area = *ptr_WorldMapCurrArea;
char* text = (area != -1 || !showTerrainType) ? (char*)Wmap_GetCustomAreaTitle(area) : (char*)Wmap_GetCurrentTerrainName();
if (!text) return false;
if (backgroundCopy) { // copy background image to memory (size 200 x 15)
backImageIsCopy = true;
SurfaceCopyToMem(x - HVRIMG_x_shift, y, HVRIMG_width, HVRIMG_height, wmapWinWidth, *ptr_wmBkWinBuf, wmTmpBuffer.data());
}
long txtWidth = GetTextWidthFM(text);
if (txtWidth > HVRIMG_width) txtWidth = HVRIMG_width;
// offset text position
y += 4;
x += 25 - (txtWidth / 2);
// prevent printing text outside of viewport
/*if ((x + txtWidth) > wmapViewPortWidth - 20) {
txtWidth -= (x + txtWidth) - wmapViewPortWidth - 20;
} else if (x < 20) {
long x_cut = abs(20 - x);
long width = 0;
do {
width += GetCharWidthFM(*text++);
} while (width < x_cut);
x += x_cut;
}*/
PrintTextFM(text, 228, x, y, txtWidth, wmapWinWidth, *ptr_wmBkWinBuf); // shadow
PrintTextFM(text, 215, x - 1, y - 1, txtWidth, wmapWinWidth, *ptr_wmBkWinBuf);
if (backgroundCopy) WmRefreshInterfaceOverlay(0); // prevent printing text over the interface
return true;
}
static void __declspec(naked) wmInterfaceRefresh_hook() {
if (colorDot && *ptr_target_xpos != -1) {
if (*ptr_In_WorldMap) {
DrawingDots();
} else if (!*ptr_target_xpos && !*ptr_target_ypos) {
// player stops moving
dots.clear();
// Reinitialize on next AddNewDot
if (terrainCount)
dotLen = spaceLen = 99;
else {
dotLen = STYDEF_DotLen;
spaceLen = STYDEF_SpaceLen;
}
}
}
if (isHoveringHotspot && !*ptr_In_WorldMap) {
PrintHotspotText(*ptr_world_xpos - *ptr_wmWorldOffsetX, *ptr_world_ypos - *ptr_wmWorldOffsetY);
isHoveringHotspot = backImageIsCopy = false;
}
__asm jmp wmDrawCursorStopped_;
}
static void __fastcall wmDetectHotspotHover(long wmMouseX, long wmMouseY) {
if (!showTerrainType && Wmap_AreaTitlesIsEmpty()) return;
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 < 20 || wmMouseY < 20 || wmMouseX > wmapViewPortWidth + 15 || wmMouseY > wmapViewPortHeight + 20) == false) {
deltaX = abs((long)*ptr_world_xpos - (wmMouseX - deltaX + *ptr_wmWorldOffsetX));
deltaY = abs((long)*ptr_world_ypos - (wmMouseY - deltaY + *ptr_wmWorldOffsetY));
}
bool isHovered = isHoveringHotspot;
isHoveringHotspot = deltaX < 8 && deltaY < 6;
if (isHoveringHotspot != isHovered) { // if value has changed
// upper left corner
long y = *ptr_world_ypos - *ptr_wmWorldOffsetY;
long x = *ptr_world_xpos - *ptr_wmWorldOffsetX;
long x_offset = x - HVRIMG_x_shift;
if (!backImageIsCopy) {
if (!PrintHotspotText(x, y, true)) return;
} else {
// restore background image
DrawToSurface(x_offset, y, HVRIMG_width, HVRIMG_height, wmapWinWidth, wmapWinHeight, *ptr_wmBkWinBuf, wmTmpBuffer.data());
backImageIsCopy = false;
}
// redraw rectangle on worldmap interface
RECT rect;
rect.top = y;
rect.left = x_offset;
rect.right = x + HVRIMG_width;
rect.bottom = y + HVRIMG_height;
WinDrawRect(*ptr_wmBkWin, &rect);
}
}
static void __declspec(naked) wmWorldMap_hack() {
__asm {
cmp ds:[_In_WorldMap], 1; // player is moving
jne checkHover;
mov eax, dword ptr ds:[_wmWorldOffsetY]; // overwritten code
retn;
checkHover:
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;
mov eax, dword ptr ds:[_wmWorldOffsetY];
retn;
isScroll:
mov isHoveringHotspot, 0;
mov backImageIsCopy, 0;
mov eax, dword ptr ds:[_wmWorldOffsetY];
retn;
}
}
////////////////////////////////////////////////////////////////////////////////
static void __declspec(naked) wmInterfaceRefreshCarFuel_hack_empty() { static void __declspec(naked) wmInterfaceRefreshCarFuel_hack_empty() {
__asm { __asm {
mov byte ptr [eax - 1], 13; mov byte ptr [eax - 1], 13;
mov byte ptr [eax + 1], 13; mov byte ptr [eax + 1], 13;
add eax, 640; add eax, wmapWinWidth;
dec ebx; dec ebx;
mov byte ptr [eax], 14; mov byte ptr [eax], 14;
mov byte ptr [eax - 1], 15; mov byte ptr [eax - 1], 15;
mov byte ptr [eax + 1], 15; mov byte ptr [eax + 1], 15;
add eax, 640; add eax, wmapWinWidth;
retn; retn;
} }
} }
@@ -118,7 +356,7 @@ static void __declspec(naked) wmInterfaceRefreshCarFuel_hack() {
__asm { __asm {
mov byte ptr [eax - 1], 196; mov byte ptr [eax - 1], 196;
mov byte ptr [eax + 1], 196; mov byte ptr [eax + 1], 196;
add eax, 640; add eax, wmapWinWidth;
mov byte ptr [eax - 1], 200; mov byte ptr [eax - 1], 200;
mov byte ptr [eax + 1], 200; mov byte ptr [eax + 1], 200;
retn; retn;
@@ -156,6 +394,43 @@ static void WorldMapInterfacePatch() {
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
} }
// Fallout 1 features, travel markers and displaying terrain types or town titles
if (GetConfigInt("Interface", "WorldMapTravelMarkers", 0)) {
dlog("Applying world map travel markers patch.", DL_INIT);
int color = GetConfigInt("Interface", "TravelMarkerColor", 134); // color index in palette: R = 224, G = 0, B = 0
if (color > 228) color = 228; else if (color < 1) color = 1; // no palette animation colors
colorDot = color;
std::vector<std::string> dotList = GetConfigList("Interface", "TravelMarkerStyles", "", 512);
if (!dotList.empty()) {
terrainCount = dotList.size();
dotStyle = new DotStyle[terrainCount];
std::vector<std::string> pair;
for (size_t i = 0; i < terrainCount; i++) {
split(dotList[i], ':', std::back_inserter(pair), 2);
if (pair.size() >= 2) {
int len = atoi(pair[0].c_str());
if (len < 1) len = 1; else if (len > 10) len = 10;
dotStyle[i].dotLen = len;
len = atoi(pair[1].c_str());
if (len < 1) len = 1; else if (len > 10) len = 10;
dotStyle[i].spaceLen = len;
} else {
dotStyle[i].dotLen = STYDEF_DotLen;
dotStyle[i].spaceLen = STYDEF_SpaceLen;
}
pair.clear();
}
}
dots.reserve(512);
dlogr(" Done", DL_INIT);
}
showTerrainType = (GetConfigInt("Interface", "WorldMapTerrainInfo", 0) != 0);
HookCall(0x4C3C7E, wmInterfaceRefresh_hook); // when calling wmDrawCursorStopped_
MakeCall(0x4BFE84, wmWorldMap_hack);
// Car fuel gauge graphics patch // Car fuel gauge graphics patch
MakeCall(0x4C528A, wmInterfaceRefreshCarFuel_hack_empty); MakeCall(0x4C528A, wmInterfaceRefreshCarFuel_hack_empty);
MakeCall(0x4C529E, wmInterfaceRefreshCarFuel_hack); MakeCall(0x4C529E, wmInterfaceRefreshCarFuel_hack);
@@ -236,6 +511,10 @@ void InterfaceGmouseHandleHook() {
HookCall(0x44C018, gmouse_handle_event_hook); // replaces hack function from HRP HookCall(0x44C018, gmouse_handle_event_hook); // replaces hack function from HRP
} }
void Interface_OnGameLoad() {
dots.clear();
}
void InterfaceInit() { void InterfaceInit() {
DrawActionPointsNumber(); DrawActionPointsNumber();
WorldMapInterfacePatch(); WorldMapInterfacePatch();
@@ -247,3 +526,7 @@ void InterfaceInit() {
HookCall(0x44B737, gmouse_bk_process_hook); HookCall(0x44B737, gmouse_bk_process_hook);
// InterfaceGmouseHandleHook will be run before game initialization // InterfaceGmouseHandleHook will be run before game initialization
} }
void InterfaceExit() {
if (dotStyle) delete[] dotStyle;
}
+2
View File
@@ -1,4 +1,6 @@
#pragma once #pragma once
void InterfaceInit(); void InterfaceInit();
void InterfaceExit();
void InterfaceGmouseHandleHook(); void InterfaceGmouseHandleHook();
void Interface_OnGameLoad();
+2
View File
@@ -89,7 +89,9 @@ static void _stdcall ResetState(DWORD onLoad) {
ForceGraphicsRefresh(0); // disable refresh ForceGraphicsRefresh(0); // disable refresh
LoadOrder_OnGameLoad(); LoadOrder_OnGameLoad();
WipeSounds(); WipeSounds();
Interface_OnGameLoad();
RestoreObjUnjamAllLocks(); RestoreObjUnjamAllLocks();
Worldmap_OnGameLoad();
Stats_OnGameLoad(); Stats_OnGameLoad();
PerksReset(); PerksReset();
Combat_OnGameLoad(); Combat_OnGameLoad();
+2
View File
@@ -429,6 +429,8 @@ static const SfallOpcodeMetadata opcodeMetaArray[] = {
{sf_set_map_enter_position, "set_map_enter_position", {DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {sf_set_map_enter_position, "set_map_enter_position", {DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_INT}},
{sf_set_object_data, "set_object_data", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {sf_set_object_data, "set_object_data", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT, DATATYPE_MASK_INT}},
{sf_set_outline, "set_outline", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}}, {sf_set_outline, "set_outline", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
{sf_set_terrain_name, "set_terrain_name", {DATATYPE_MASK_INT, DATATYPE_MASK_INT, DATATYPE_MASK_STR}},
{sf_set_town_title, "set_town_title", {DATATYPE_MASK_INT, DATATYPE_MASK_STR}},
{sf_set_unique_id, "set_unique_id", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}}, {sf_set_unique_id, "set_unique_id", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
{sf_set_unjam_locks_time, "set_unjam_locks_time", {DATATYPE_MASK_INT}}, {sf_set_unjam_locks_time, "set_unjam_locks_time", {DATATYPE_MASK_INT}},
{sf_set_window_flag, "set_window_flag", {DATATYPE_MASK_INT | DATATYPE_MASK_STR, DATATYPE_MASK_INT, DATATYPE_MASK_INT}}, {sf_set_window_flag, "set_window_flag", {DATATYPE_MASK_INT | DATATYPE_MASK_STR, DATATYPE_MASK_INT, DATATYPE_MASK_INT}},
+2
View File
@@ -165,6 +165,8 @@ static const SfallMetarule metaruleArray[] = {
{"set_map_enter_position", sf_set_map_enter_position, 3, 3}, {"set_map_enter_position", sf_set_map_enter_position, 3, 3},
{"set_object_data", sf_set_object_data, 3, 3}, {"set_object_data", sf_set_object_data, 3, 3},
{"set_outline", sf_set_outline, 2, 2}, {"set_outline", sf_set_outline, 2, 2},
{"set_terrain_name", sf_set_terrain_name, 3, 3},
{"set_town_title", sf_set_town_title, 2, 2},
{"set_unique_id", sf_set_unique_id, 1, 2}, {"set_unique_id", sf_set_unique_id, 1, 2},
{"set_unjam_locks_time", sf_set_unjam_locks_time, 1, 1}, {"set_unjam_locks_time", sf_set_unjam_locks_time, 1, 1},
{"set_window_flag", sf_set_window_flag, 3, 3}, {"set_window_flag", sf_set_window_flag, 3, 3},
+8
View File
@@ -249,3 +249,11 @@ static void sf_get_map_enter_position() {
static void sf_tile_by_position() { static void sf_tile_by_position() {
opHandler.setReturn(TileNum(opHandler.arg(0).rawValue(), opHandler.arg(1).rawValue())); opHandler.setReturn(TileNum(opHandler.arg(0).rawValue(), opHandler.arg(1).rawValue()));
} }
static void sf_set_terrain_name() {
Wmap_SetTerrainTypeName(opHandler.arg(0).rawValue(), opHandler.arg(1).rawValue(), opHandler.arg(2).strValue());
}
static void sf_set_town_title() {
Wmap_SetCustomAreaTitle(opHandler.arg(0).rawValue(), opHandler.arg(1).strValue());
}
+56
View File
@@ -29,6 +29,9 @@ static DWORD AutomapPipboyList[AUTOMAP_MAX];
static DWORD ViewportX; static DWORD ViewportX;
static DWORD ViewportY; static DWORD ViewportY;
std::vector<std::pair<long, std::string>> wmTerrainTypeNames; // pair first: x + y * number of horizontal sub-tiles
std::vector<std::pair<long, std::string>> wmAreaHotSpotTitle;
static DWORD worldMapDelay; static DWORD worldMapDelay;
static DWORD worldMapTicks; static DWORD worldMapTicks;
@@ -442,6 +445,59 @@ DWORD GetAddedYears(bool isCheck) {
return (isCheck && !addYear) ? 0 : addedYears; return (isCheck && !addYear) ? 0 : addedYears;
} }
static const char* GetOverrideTerrainName(long x, long y) {
if (wmTerrainTypeNames.empty()) return nullptr;
long subTileID = x + y * (*ptr_wmNumHorizontalTiles * 7);
auto it = std::find_if(wmTerrainTypeNames.crbegin(), wmTerrainTypeNames.crend(),
[=](const std::pair<long, std::string> &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 Wmap_SetTerrainTypeName(long x, long y, const char* name) {
long subTileID = x + y * (*ptr_wmNumHorizontalTiles * 7);
wmTerrainTypeNames.push_back(std::make_pair(subTileID, name));
}
/*
// TODO: someone might need to know the name of a terrain type?
const char* Wmap_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* Wmap_GetCurrentTerrainName() {
const char* name = GetOverrideTerrainName(*ptr_world_xpos / 50, *ptr_world_ypos / 50);
return (name) ? name : GetMessageStr(ptr_wmMsgFile, 1000 + wmGetCurrentTerrainType());
}
bool Wmap_AreaTitlesIsEmpty() {
return wmAreaHotSpotTitle.empty();
}
void Wmap_SetCustomAreaTitle(long areaID, const char* msg) {
wmAreaHotSpotTitle.push_back(std::make_pair(areaID, msg));
}
const char* Wmap_GetCustomAreaTitle(long areaID) {
if (wmAreaHotSpotTitle.empty()) return nullptr;
auto it = std::find_if(wmAreaHotSpotTitle.crbegin(), wmAreaHotSpotTitle.crend(),
[=](const std::pair<long, std::string> &el)
{ return el.first == areaID; }
);
return (it != wmAreaHotSpotTitle.crend()) ? it->second.c_str() : nullptr;
}
void Worldmap_OnGameLoad() {
wmTerrainTypeNames.clear();
wmAreaHotSpotTitle.clear();
}
void WorldmapInit() { void WorldmapInit() {
PathfinderFixInit(); PathfinderFixInit();
StartingStatePatches(); StartingStatePatches();
+9
View File
@@ -19,8 +19,17 @@
#pragma once #pragma once
void WorldmapInit(); void WorldmapInit();
void Worldmap_OnGameLoad();
DWORD GetAddedYears(bool isCheck = true); DWORD GetAddedYears(bool isCheck = true);
void SetAddedYears(DWORD years); void SetAddedYears(DWORD years);
void Wmap_SetTerrainTypeName(long x, long y, const char* name);
//const char* Wmap_GetTerrainTypeName(long x, long y);
const char* Wmap_GetCurrentTerrainName();
bool Wmap_AreaTitlesIsEmpty();
const char* Wmap_GetCustomAreaTitle(long areaID);
void Wmap_SetCustomAreaTitle(long areaID, const char* msg);
void _stdcall SetMapMulti(float value); void _stdcall SetMapMulti(float value);
+1
View File
@@ -768,6 +768,7 @@ static void _stdcall OnExit() {
if (scriptDialog) delete[] scriptDialog; if (scriptDialog) delete[] scriptDialog;
GraphicsExit(); GraphicsExit();
MoviesExit(); MoviesExit();
InterfaceExit();
SpeedPatchExit(); SpeedPatchExit();
SkillsExit(); SkillsExit();
ReputationsExit(); ReputationsExit();