Updated map view code

This commit is contained in:
NovaRain
2021-11-08 10:24:59 +08:00
parent a543cd934c
commit f75214056e
8 changed files with 279 additions and 73 deletions
+27 -18
View File
@@ -1,20 +1,20 @@
/*
* sfall
* Copyright (C) 2008-2016 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
* sfall
* Copyright (C) 2008-2016 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "FunctionOffsets.h"
#include "VariableOffsets.h"
@@ -155,9 +155,18 @@ void __declspec(naked) interpretError(const char* fmt, ...) {
}
long __fastcall tile_num(long x, long y) {
__asm push ebx; // don't delete (bug in tile_num_)
__asm xor ebx, ebx; // don't delete (bug in tile_num_)
WRAP_WATCOM_FCALL2(tile_num_, x, y);
__asm pop ebx;
}
void __fastcall square_xy(long x, long y, long* outSX, long* outSY) {
__asm {
xor ebx, ebx; // don't delete (bug in square_xy_)
mov eax, ecx;
push outSY;
mov ecx, outSX;
call fo::funcoffs::square_xy_;
}
}
GameObject* __fastcall obj_blocking_at_wrapper(GameObject* obj, DWORD tile, DWORD elevation, void* func) {
+18 -16
View File
@@ -1,20 +1,20 @@
/*
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
@@ -54,6 +54,8 @@ void __declspec() interpretError(const char* fmt, ...);
long __fastcall tile_num(long x, long y);
void __fastcall square_xy(long x, long y, long* outSX, long* outSY);
GameObject* __fastcall obj_blocking_at_wrapper(GameObject* obj, DWORD tile, DWORD elevation, void* func);
// Creates a button on a given window
+1
View File
@@ -60,6 +60,7 @@ WRAP_WATCOM_FFUNC4(long, register_object_run_to_object, fo::GameObject*, source,
WRAP_WATCOM_FFUNC3(long, register_object_play_sfx, fo::GameObject*, object, const char*, sfxName, long, delay)
WRAP_WATCOM_FFUNC3(long, scr_get_local_var, long, sid, long, varId, long*, value)
WRAP_WATCOM_FFUNC3(long, scr_set_local_var, long, sid, long, varId, long, value)
WRAP_WATCOM_FFUNC3(long, square_coord, long, square, long*, outX, long*, outY)
WRAP_WATCOM_FFUNC6(long, text_object_create, fo::GameObject*, object, const char*, text, long, font, long, colorText, long, colorOutline, fo::BoundRect*, rect)
WRAP_WATCOM_FFUNC3(long, tile_coord, long, tile, long*, outX, long*, outY) // the fourth argument of the function is not used
WRAP_WATCOM_FFUNC3(long, tile_num_in_direction, long, tile, long, rotation, long, distance)
+22 -13
View File
@@ -57,6 +57,8 @@ bool HRP::CheckExternalPatch() {
}
void HRP::init() {
//SafeWrite16(0x4B2EA8, 0x9090); // _show_grid
if (!hrpIsEnabled && IniReader::GetIntDefaultConfig("Main", "HiResMode", 1) == 0) return; // vanilla game mode
SCR_WIDTH = IniReader::GetInt("Main", "SCR_WIDTH", 640, f2ResIni);
@@ -93,8 +95,8 @@ void HRP::init() {
std::string x = trim(IniReader::GetString("MAPS", "SCROLL_DIST_X", "480", 16, f2ResIni));
std::string y = trim(IniReader::GetString("MAPS", "SCROLL_DIST_Y", "400", 16, f2ResIni));
ViewMap::SCROLL_DIST_X = (x == "HALF_SCRN") ? (SCR_WIDTH / 2) + 32 : std::atol(x.c_str());
ViewMap::SCROLL_DIST_Y = (y == "HALF_SCRN") ? (SCR_HEIGHT / 2) + 24 : std::atol(y.c_str());
ViewMap::SCROLL_DIST_X = (!x.compare(0, 9, "HALF_SCRN")) ? (SCR_WIDTH / 2) + 32 : std::atol(x.c_str());
ViewMap::SCROLL_DIST_Y = (!y.compare(0, 9, "HALF_SCRN")) ? (SCR_HEIGHT / 2) + 24 : std::atol(y.c_str());
ViewMap::IGNORE_PLAYER_SCROLL_LIMITS = (IniReader::GetInt("MAPS", "IGNORE_PLAYER_SCROLL_LIMITS", 0, f2ResIni) != 0);
ViewMap::IGNORE_MAP_EDGES = (IniReader::GetInt("MAPS", "IGNORE_MAP_EDGES", 0, f2ResIni) != 0);
@@ -106,20 +108,27 @@ void HRP::init() {
IniReader::GetString("Main", "f2_res_patches", "data", MAX_PATH, f2ResIni)
);
// Inject hacks
/* Inject hacks */
SafeWrite32(0x482E30, FO_VAR_mapEntranceTileNum); // map_load_file_ (_tile_center_tile to _mapEntranceTileNum)
// Set the resolution for GNW95_init_mode_ex_
SafeWrite32(0x4CAD6B, SCR_WIDTH); // 640
SafeWrite32(0x4CAD66, SCR_HEIGHT); // 480
if (SCR_WIDTH != 640 || SCR_HEIGHT != 480) {
// Set the resolution for GNW95_init_mode_ex_
SafeWrite32(0x4CAD6B, SCR_WIDTH); // 640
SafeWrite32(0x4CAD66, SCR_HEIGHT); // 480
// Set the resolution for the overlapping temporary black window when loading/starting the game
// main_load_new_
SafeWrite32(0x480D6C, SCR_HEIGHT);
SafeWrite32(0x480D84, SCR_WIDTH);
// gnw_main_
SafeWrite32(0x480AFA, SCR_HEIGHT); // -100 for ifacebar?
SafeWrite32(0x480B04, SCR_WIDTH);
// Set the resolution for the overlapping temporary black window when loading/starting the game
// main_load_new_
SafeWrite32(0x480D6C, SCR_HEIGHT);
SafeWrite32(0x480D84, SCR_WIDTH);
// gnw_main_
SafeWrite32(0x480AFA, SCR_HEIGHT); // -100 for ifacebar?
SafeWrite32(0x480B04, SCR_WIDTH);
// LoadGame_
SafeWrite32(0x47C6E0, SCR_HEIGHT);
SafeWrite32(0x47C6E5, SCR_WIDTH);
SafeWrite32(0x47C703, SCR_WIDTH);
SafeWrite32(0x47C70D, SCR_HEIGHT);
}
// Inits
SplashScreen::init();
+11 -11
View File
@@ -16,15 +16,15 @@ namespace sfall
{
static EdgeBorder::Edge* MapEdgeData;
// reference
EdgeBorder::Edge* currentMapEdge;
EdgeBorder::Edge* EdgeBorder::CurrentMapEdge() { return currentMapEdge; }
static EdgeBorder::Edge* currentMapEdge; // reference
static long edgeVersion; // 0 - version 1 (obsolete), 1 - version 2 (current)
bool isLoadingMapEdge;
bool isDefaultSetEdge;
static bool isDefaultSetEdge;
//bool isLoadingMapEdge;
long EdgeBorder::EdgeVersion() { return edgeVersion; }
EdgeBorder::Edge* EdgeBorder::CurrentMapEdge() { return currentMapEdge; }
// Implementation from HRP by Mash
static void CalcEdgeData(EdgeBorder::Edge* edgeData, long w, long h) {
@@ -67,7 +67,7 @@ static void CalcEdgeData(EdgeBorder::Edge* edgeData, long w, long h) {
long rectH = (edgeData->borderRect.bottom - edgeData->borderRect.top) / 2;
long _rectH = rectH;
if (rectH % 24) {
rectH -= rectH % 24; // truncate
rectH -= rectH % 24;
_rectH = rectH + 24;
}
if (rectH < h) {
@@ -78,7 +78,6 @@ static void CalcEdgeData(EdgeBorder::Edge* edgeData, long w, long h) {
edgeData->borderRect.bottom -= h;
}
// borderRect: right is less than left
if ((edgeData->borderRect.left < edgeData->borderRect.right) || (edgeData->borderRect.left - edgeData->borderRect.right) == 32) {
edgeData->borderRect.left = edgeData->borderRect.right;
}
@@ -197,6 +196,7 @@ static fo::DbFile* LoadMapEdgeFileSub(char* mapName) {
if (getValue != mapLevel) break; // next level
EdgeBorder::Edge *edge = new EdgeBorder::Edge;
edge->prevEdgeData = edgeData;
edge->nextEdgeData = nullptr;
edge->squareRect = edgeData->squareRect; // rect copy
edgeData->nextEdgeData = edge;
@@ -303,8 +303,8 @@ long EdgeBorder::CheckBorder(long tile) {
long x, y;
ViewMap::GetTileCoordOffset(tile, x, y);
if (x > currentMapEdge->borderRect.left || x < currentMapEdge->borderRect.right ||
y > currentMapEdge->borderRect.bottom || y < currentMapEdge->borderRect.top)
if (x > currentMapEdge->borderRect.left || x < currentMapEdge->borderRect.right ||
y < currentMapEdge->borderRect.top || y > currentMapEdge->borderRect.bottom)
{
return 0; // block
}
+5 -2
View File
@@ -12,8 +12,8 @@ namespace sfall
class EdgeBorder {
public:
struct Edge {
POINT center; // x/y center of current map screen?
RECT borderRect;
POINT center; // x/y center of current map screen?
RECT borderRect; // right is less than left
RECT rect_2;
RECT tileRect;
RECT squareRect;
@@ -36,7 +36,10 @@ public:
};
static void init();
static Edge* CurrentMapEdge();
static long EdgeVersion();
static long GetCenterTile(long tile, long mapLevel);
static long CheckBorder(long tile);
};
+8 -6
View File
@@ -19,7 +19,7 @@ static RECT mapVisibleArea;
// Returns -1 if the scrRect is not in the rectangle of inRect (same as rect_inside_bound_)
static __inline long rect_inside_bound(RECT* srcRect, RECT* inRect, RECT* outRect) {
*outRect = *srcRect; // srcRect copy to outRect
if (srcRect != outRect) *outRect = *srcRect; // srcRect copy to outRect
if (inRect->right < srcRect->left ||
inRect->left > srcRect->right ||
@@ -111,7 +111,7 @@ static long __fastcall rect_inside_bound_clip(RECT* srcRect, RECT* inRect, RECT*
if (ViewMap::EDGE_CLIPPING_ON) {
if (CheckRect(outRect)) { // when do you need the fill below?
long height = outRect->bottom - outRect->top + 1;
long height = (outRect->bottom - outRect->top) + 1;
if (height > 0) {
long width = (outRect->right - outRect->left) + 1;
if (width > 0) {
@@ -139,7 +139,7 @@ static void __declspec(naked) refresh_game_hook_rect_inside_bound() {
static long __fastcall rect_inside_bound_scroll_clip(RECT* srcRect, RECT* inRect, RECT* outRect) {
long height = (srcRect->bottom - srcRect->top) + 1;
if (height > 0) {
long width = srcRect->right - srcRect->left + 1;
long width = (srcRect->right - srcRect->left) + 1;
if (width > 0) {
ClearRect(width, height, srcRect);
}
@@ -159,9 +159,10 @@ static void __declspec(naked) map_scroll_refresh_game_hook_rect_inside_bound() {
}
static long __fastcall MouseCheckArea(long x, long y) {
if (x < (mapVisibleArea.left) || x > (mapVisibleArea.right) || y < mapVisibleArea.top || y >= mapVisibleArea.bottom) {
if (!ViewMap::EDGE_CLIPPING_ON) return 0;
if (x < mapVisibleArea.left || x > mapVisibleArea.right || y < mapVisibleArea.top || y >= mapVisibleArea.bottom) {
if (fo::func::win_get_top_win(x, y) == fo::var::getInt(FO_VAR_display_win)) {
return -7;
return 40000;
}
}
return 0;
@@ -186,7 +187,8 @@ check:
jnz set;
retn;
set:
mov ebx, eax;
mov ebx, -7;
//mov ecx, 3;
retn;
}
}
+187 -7
View File
@@ -17,6 +17,10 @@
namespace sfall
{
const long grid_width = 200; // _grid_width
const long square_width = 100;
const long square_length = 100;
static Rectangle obj_on_screen_rect;
long ViewMap::SCROLL_DIST_X;
@@ -39,15 +43,15 @@ void ViewMap::GetCoordFromOffset(long &inOutX, long &inOutY) {
}
void ViewMap::GetTileCoord(long tile, long &outX, long &outY) {
int x = tile % 200; // tile % _grid_width // 20100%200 = 100
int y = (tile / 200) + (x / 2); // tile / _grid_width + x / 2 // 20100/200 = 100+(100/2) = y:150 ???
int x = tile % grid_width; // 20100%200 = 100
int y = (tile / grid_width) + (x / 2); // 20100/200 = 100+(100/2) = y:150 ???
outY = y;
outX = (2 * x) - y; // 2*100 = 200-150 = x:50 ???
}
void ViewMap::GetTileCoordOffset(long tile, long &outX, long &outY) {
int x = tile % 200; // tile % _grid_width // 20100%200 = 100
int y = (tile / 200) + (x / 2); // tile / _grid_width + x / 2 // 20100/200 = 100+(100/2) = y:150 ???
int x = tile % grid_width; // 20100%200 = 100
int y = (tile / grid_width) + (x / 2); // 20100/200 = 100+(100/2) = y:150 ???
y &= 0xFFFFFFFE; // even to down
x = (2 * x) + 200 - y; // 2*100 = 200+200-150 = x:250 ???
@@ -112,8 +116,8 @@ static long __fastcall tile_set_center(long tile, long modeFlags) {
fo::var::setInt(FO_VAR_tile_center_tile) = tile;
long tile_y = tile / 200; // _grid_width
long tile_x = 200 - (tile % 200) - 1;
long tile_y = tile / grid_width;
long tile_x = 200 - (tile % grid_width) - 1;
if (tile_x & 1) {
tile_x--;
@@ -155,11 +159,178 @@ static void __declspec(naked) tile_set_center_hack_replacement() {
static void __declspec(naked) tile_scroll_to_hack_replacement() {
__asm {
//mov edx, 3; // modeFlags is always 2
mov edx, 3; // modeFlags is always 2
jmp tile_set_center_hack_replacement;
}
}
static long __fastcall square_rect_render_floor(long y, long id, long x) {
if (x < 0 || x >= square_width || y < 0 || y >= square_length) return -1;
auto edge = EdgeBorder::CurrentMapEdge();
if (EdgeBorder::EdgeVersion() && (x > edge->squareRect.left || x < edge->squareRect.right || y > edge->squareRect.bottom || y < edge->squareRect.top)) {
return 1;
}
return id;
}
static void __declspec(naked) square_render_floor_hook_art_id() {
__asm {
mov ecx, [esp + 0x24 + 4];
push esi;
call square_rect_render_floor;
test eax, eax;
js skipDraw; // -1
mov edx, eax;
xor ecx, ecx;
mov eax, 4;
jmp fo::funcoffs::art_id_;
skipDraw:
mov [esp], 0x4B2AD4;
retn 4;
}
}
static long __fastcall square_rect_render_roof(long y, long id, long x) {
if (x < 0 || x >= square_width || y < 0 || y >= square_length) return -1;
auto edge = EdgeBorder::CurrentMapEdge();
if (EdgeBorder::EdgeVersion() && (x > (edge->squareRect.left + 2) || x < (edge->squareRect.right + 2) ||
y > (edge->squareRect.bottom + 3) || y < (edge->squareRect.top + 3)))
{
return -1;
}
return id;
}
static void __declspec(naked) square_render_roof_hook_art_id() {
using namespace fo;
__asm {
mov ecx, [esp + 0x20 + 4];
push edi;
call square_rect_render_roof;
test eax, eax;
js skipDraw; // -1
mov edx, eax;
xor ecx, ecx;
mov eax, OBJ_TYPE_TILE;
jmp fo::funcoffs::art_id_;
skipDraw:
mov eax, esi;
retn 4;
}
}
static void __declspec(naked) square_roof_intersect_hook_art_id() {
using namespace fo;
__asm {
mov ecx, [esp + 0x8 + 4];
push [esp + 0x4 + 4];
call square_rect_render_roof;
test eax, eax;
js skipDraw; // -1
mov edx, eax;
xor ecx, ecx;
mov eax, OBJ_TYPE_TILE;
jmp fo::funcoffs::art_id_;
skipDraw:
xor eax, eax;
mov [esp], 0x4B2C05;
retn 4;
}
}
static void __fastcall square_obj_render(fo::BoundRect* rect, long tag) {
if (EdgeBorder::EdgeVersion() == 0) return;
long x0, y0, x1, y1, x2, y2, x3, y3;
fo::func::square_xy(rect->x, rect->offy, &x0, &y0);
fo::func::square_xy(rect->x, rect->y, &x1, &y1);
fo::func::square_xy(rect->offx, rect->y, &x2, &y2);
fo::func::square_xy(rect->offx, rect->offy, &x3, &y3);
if (++x0 > square_width) x0 = square_width - 1;
if (--x2 < 0) x2 = 0;
if (--y1 < 0) y1 = 0;
if (++y3 > square_length) y3 = square_length - 1;
if (y1 >= y3 || x2 >= x0) return; // top >= bottom / left >= right
long Y = y1;
long sY = square_width * Y;
auto edge = EdgeBorder::CurrentMapEdge();
do {
long X = x2;
do {
if (X > edge->squareRect.left && ((edge->field_48 >> 24) & 1) == tag ||
Y < edge->squareRect.top && ((edge->field_48 >> 16) & 1) == tag ||
X < edge->squareRect.right && ((edge->field_48 >> 8) & 1) == tag ||
Y > edge->squareRect.bottom && (edge->field_48 & 1) == tag)
{
long s_x, s_y;
fo::func::square_coord(X + sY, &s_x, &s_y);
__asm {
mov ecx, rect;
mov ebx, s_y;
mov edx, s_x;
mov eax, 0x4000001; // tile fid
call fo::funcoffs::floor_draw_;
}
}
} while (++X < x0);
sY += square_width;
} while (++Y < y3); // y < bottom
}
static void __declspec(naked) obj_render_pre_roof_hack_0() {
__asm {
lea ecx, [esp + 4];
mov edx, 0;
call square_obj_render;
mov edi, [esp + 0x2C + 4];
test edi, edi;
retn;
}
}
static void __declspec(naked) obj_render_pre_roof_hack_1() {
__asm {
lea ecx, [esp + 4];
mov edx, 1;
call square_obj_render;
pop eax; // ret addr
add esp, 0x44;
pop ebp;
pop edi;
jmp eax;
}
}
// An odd solution to the problem from HRP 3.06 (4.1.8 uses a different solution)
static void __declspec(naked) obj_render_pre_roof_hack() {
__asm {
mov ebx, [eax];
lea eax, [edx + ebx];
cmp eax, 40000; // _grid_size
jge capMax;
cmp eax, 0;
jl capMin;
retn;
capMax:
mov eax, 39999;
retn;
capMin:
xor eax, eax;
retn;
}
}
void ViewMap::init() {
if (SCROLL_DIST_X <= 0) SCROLL_DIST_X = 480;
else if (SCROLL_DIST_X < 320) SCROLL_DIST_X = 320;
@@ -170,6 +341,15 @@ void ViewMap::init() {
MakeJump(fo::funcoffs::tile_set_center_, tile_set_center_hack_replacement); // 0x4B12F8
MakeJump(fo::funcoffs::tile_scroll_to_, tile_scroll_to_hack_replacement); // 0x4B3924
HookCall(0x4B2AC0, square_render_floor_hook_art_id);
HookCall(0x4B2261, square_render_roof_hook_art_id);
HookCall(0x4B2BF7, square_roof_intersect_hook_art_id); // need to test object_under_mouse_
MakeCall(0x489730, obj_render_pre_roof_hack_0, 1);
MakeCall(0x4897E3, obj_render_pre_roof_hack_1);
// Fix
MakeCall(0x489665, obj_render_pre_roof_hack); // find the bug
obj_on_screen_rect.width = HRP::ScreenWidth();
obj_on_screen_rect.height = HRP::ScreenHeight(); // maybe take into account the interface bar and be: height - 100?
SafeWrite32(0x45C886, (DWORD)&obj_on_screen_rect); // replace rectangle in op_obj_on_screen_