Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add paintTileMapPort to support world map tile painting (Develop) #4767

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions library/LuaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2861,6 +2861,34 @@ static int screen_readTile(lua_State *L)
return 1;
}

static int screen_paintTileMapPort(lua_State *L)
{
Pen pen;
Lua::CheckPen(L, &pen, 1);
int x = luaL_checkint(L, 2);
int y = luaL_checkint(L, 3);
if (lua_gettop(L) >= 4 && !lua_isnil(L, 4))
{
if (lua_type(L, 4) == LUA_TSTRING)
pen.ch = lua_tostring(L, 4)[0];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if it's a zero-length string?

Copy link
Member

@lethosor lethosor Jul 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will still be safe, since the string is null-terminated, but it will set pen.ch to 0, which may or may not be what you want.

else
pen.ch = luaL_checkint(L, 4);
}
if (lua_gettop(L) >= 5 && !lua_isnil(L, 5))
pen.tile = luaL_checkint(L, 5);
lua_pushboolean(L, Screen::paintTileMapPort(pen, x, y));
return 1;
}

static int screen_readTileMapPort(lua_State *L)
{
int x = luaL_checkint(L, 1);
int y = luaL_checkint(L, 2);
Pen pen = Screen::readTileMapPort(x, y);
Lua::Push(L, pen);
return 1;
}

static int screen_paintString(lua_State *L)
{
Pen pen;
Expand Down Expand Up @@ -3048,6 +3076,8 @@ static const luaL_Reg dfhack_screen_funcs[] = {
{ "getWindowSize", screen_getWindowSize },
{ "paintTile", screen_paintTile },
{ "readTile", screen_readTile },
{ "paintTileMapPort", screen_paintTileMapPort },
{ "readTileMapPort", screen_readTileMapPort },
Comment on lines +3079 to +3080
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs docs in Lua API.rst

{ "paintString", screen_paintString },
{ "fillRect", screen_fillRect },
{ "findGraphicsTile", screen_findGraphicsTile },
Expand Down
7 changes: 7 additions & 0 deletions library/include/modules/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ distribution.

#include "df/viewscreen.h"
#include "df/graphic_viewportst.h"
#include "df/graphic_map_portst.h"

#include <set>
#include <memory>
Expand Down Expand Up @@ -203,6 +204,12 @@ namespace DFHack
/// Retrieves one screen tile from the buffer
DFHACK_EXPORT Pen readTile(int x, int y, bool map = false, int32_t * df::graphic_viewportst::*texpos_field = NULL);

/// Paint one world map tile with the given pen
DFHACK_EXPORT bool paintTileMapPort(const Pen &pen, int x, int y, int32_t * df::graphic_map_portst::*texpos_field = NULL);

/// Retrieves one world map tile from the buffer
DFHACK_EXPORT Pen readTileMapPort(int x, int y, int32_t * df::graphic_map_portst::*texpos_field = NULL);

/// Paint a string onto the screen. Ignores ch and tile of pen.
DFHACK_EXPORT bool paintString(const Pen &pen, int x, int y, const std::string &text, bool map = false);

Expand Down
143 changes: 131 additions & 12 deletions library/modules/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,8 @@ static bool doSetTile_map(const Pen &pen, int x, int y, int32_t * df::graphic_vi
return true;
}

static bool doSetTile_default(const Pen &pen, int x, int y, bool map, int32_t * df::graphic_viewportst::*texpos_field)
static bool doSetTile_char(const Pen &pen, int x, int y, bool use_graphics)
{
bool use_graphics = Screen::inGraphicsMode();

if (map && use_graphics)
return doSetTile_map(pen, x, y, texpos_field);

if (x < 0 || x >= gps->dimx || y < 0 || y >= gps->dimy)
return false;

Expand Down Expand Up @@ -227,6 +222,16 @@ static bool doSetTile_default(const Pen &pen, int x, int y, bool map, int32_t *
return true;
}

static bool doSetTile_default(const Pen &pen, int x, int y, bool map, int32_t * df::graphic_viewportst::*texpos_field)
{
bool use_graphics = Screen::inGraphicsMode();

if (map && use_graphics)
return doSetTile_map(pen, x, y, texpos_field);

return doSetTile_char(pen, x, y, use_graphics);
}

GUI_HOOK_DEFINE(Screen::Hooks::set_tile, doSetTile_default);
static bool doSetTile(const Pen &pen, int x, int y, bool map, int32_t * df::graphic_viewportst::*texpos_field = NULL)
{
Expand Down Expand Up @@ -287,12 +292,7 @@ static uint8_t to_16_bit_color(uint8_t *rgb) {
return 0;
}

static Pen doGetTile_default(int x, int y, bool map, int32_t * df::graphic_viewportst::*texpos_field = NULL) {
bool use_graphics = Screen::inGraphicsMode();

if (map && use_graphics)
return doGetTile_map(x, y, texpos_field);

static Pen doGetTile_char(int x, int y, bool use_graphics) {
if (x < 0 || x >= gps->dimx || y < 0 || y >= gps->dimy)
return Pen(0, 0, 0, -1);

Expand Down Expand Up @@ -352,6 +352,14 @@ static Pen doGetTile_default(int x, int y, bool map, int32_t * df::graphic_viewp
return ret;
}

static Pen doGetTile_default(int x, int y, bool map, int32_t * df::graphic_viewportst::*texpos_field = NULL) {
bool use_graphics = Screen::inGraphicsMode();

if (map && use_graphics)
return doGetTile_map(x, y, texpos_field);
return doGetTile_char(x, y, use_graphics);
}

GUI_HOOK_DEFINE(Screen::Hooks::get_tile, doGetTile_default);
static Pen doGetTile(int x, int y, bool map, int32_t * df::graphic_viewportst::*texpos_field = NULL)
{
Expand All @@ -365,6 +373,117 @@ Pen Screen::readTile(int x, int y, bool map, int32_t * df::graphic_viewportst::*
return doGetTile(x, y, map, texpos_field);
}

static bool doSetTile_map_port(const Pen &pen, int x, int y, int32_t * df::graphic_map_portst::*texpos_field) {
auto &vp = gps->main_map_port;
if (!texpos_field)
texpos_field = &df::graphic_map_portst::screentexpos_interface;

if (x < 0 || x >= vp->dim_x || y < 0 || y >= vp->dim_y)
return false;

size_t max_index = vp->dim_y * vp->dim_x - 1;
size_t index = (y * vp->dim_x) + x;

if (index > max_index)
return false;

long texpos = pen.tile;
if (!texpos && pen.ch)
texpos = init->font.large_font_texpos[(uint8_t)pen.ch];
(vp->*texpos_field)[index] = texpos;
return true;
}

static bool doSetTile_map_port_default(const Pen &pen, int x, int y, int32_t * df::graphic_map_portst::*texpos_field) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of doSetTile_default() is to enable GuiHooks - it's the default implementation called if no hooks are defined. Since you don't appear to be worried about GuiHooks for your new functions (which is probably fine), you can likely drop the _default functions.

Also, I would opt for consistent capitalization within function names, e.g. doSetTileMapPort or doSetMapPortTile. The _default suffix is a special case for GuiHooks, to indicate we're defining "our" default implementation of a function that could be overridden.

bool use_graphics = Screen::inGraphicsMode();

if (use_graphics)
return doSetTile_map_port(pen, x, y, texpos_field);

return doSetTile_char(pen, x, y, use_graphics);
}

bool Screen::paintTileMapPort(const Pen &pen, int x, int y, int32_t * df::graphic_map_portst::*texpos_field)
{
if (!gps || !pen.valid()) return false;

doSetTile_map_port_default(pen, x, y, texpos_field);
return true;
}

static Pen doGetTile_map_port(int x, int y, int32_t * df::graphic_map_portst::*texpos_field) {
auto &vp = gps->main_map_port;

if (x < 0 || x >= vp->dim_x || y < 0 || y >= vp->dim_y)
return Pen(0, 0, 0, -1);

size_t max_index = vp->dim_x * vp->dim_y - 1;
size_t index = (x * vp->dim_y) + y;

if (index < 0 || index > max_index)
return Pen(0, 0, 0, -1);

int tile = 0;
if (!texpos_field) {
if (tile == 0)
tile = vp->screentexpos_base[index];
if (tile == 0)
tile = vp->screentexpos_detail[index];
if (tile == 0)
tile = vp->screentexpos_tunnel[index];
if (tile == 0)
tile = vp->screentexpos_river[index];
if (tile == 0)
tile = vp->screentexpos_road[index];
if (tile == 0)
tile = vp->screentexpos_site[index];
if (tile == 0)
tile = vp->screentexpos_army[index];
if (tile == 0)
tile = vp->screentexpos_interface[index];
Comment on lines +442 to +443
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be checked first since it is the "default" layer

if (tile == 0)
tile = vp->screentexpos_detail_to_n[index];
if (tile == 0)
tile = vp->screentexpos_detail_to_s[index];
if (tile == 0)
tile = vp->screentexpos_detail_to_w[index];
if (tile == 0)
tile = vp->screentexpos_detail_to_e[index];
if (tile == 0)
tile = vp->screentexpos_detail_to_nw[index];
if (tile == 0)
tile = vp->screentexpos_detail_to_ne[index];
if (tile == 0)
tile = vp->screentexpos_detail_to_sw[index];
if (tile == 0)
tile = vp->screentexpos_detail_to_se[index];
if (tile == 0)
tile = vp->screentexpos_site_to_s[index];
} else {
tile = (vp->*texpos_field)[index];
}

char ch = 0;
uint8_t fg = 0;
uint8_t bg = 0;
return Pen(ch, fg, bg, tile, false);
}

static Pen doGetTile_map_port_default(int x, int y, int32_t * df::graphic_map_portst::*texpos_field = NULL) {
bool use_graphics = Screen::inGraphicsMode();

if (use_graphics)
return doGetTile_map_port(x, y, texpos_field);
return doGetTile_char(x, y, use_graphics);
}

Pen Screen::readTileMapPort(int x, int y, int32_t * df::graphic_map_portst::*texpos_field)
{
if (!gps) return Pen(0,0,0,-1);

return doGetTile_map_port_default(x, y, texpos_field);
}

bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text, bool map)
{
auto dim = getWindowSize();
Expand Down
Loading