diff --git a/LUA_API.rst b/LUA_API.rst
index a7dab21b0..542034f40 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -764,10 +764,20 @@ Gui module
Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.
+* ``dfhack.gui.showZoomAnnouncement(type,pos,text,color[,is_bright])``
+
+ Like above, but also specifies a position you can zoom to from the announcement menu.
+
* ``dfhack.gui.showPopupAnnouncement(text,color[,is_bright])``
Pops up a titan-style modal announcement window.
+* ``dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright])``
+
+ Uses the type to look up options from announcements.txt, and calls the
+ above operations accordingly. If enabled, pauses and zooms to position.
+
+
Job module
----------
@@ -959,6 +969,10 @@ Maps module
Returns a map block object for given x,y,z in local block coordinates.
+* ``dfhack.maps.isValidTilePos(coords)``, or isValidTilePos(x,y,z)``
+
+ Checks if the given df::coord or x,y,z in local tile coordinates are valid.
+
* ``dfhack.maps.getTileBlock(coords)``, or ``getTileBlock(x,y,z)``
Returns a map block object for given df::coord or x,y,z in local tile coordinates.
@@ -971,6 +985,11 @@ Maps module
Enables updates for liquid flow or temperature, unless already active.
+* ``dfhack.maps.spawnFlow(pos,type,mat_type,mat_index,dimension)``
+
+ Spawns a new flow (i.e. steam/mist/dust/etc) at the given pos, and with
+ the given parameters. Returns it, or *nil* if unsuccessful.
+
* ``dfhack.maps.getGlobalInitFeature(index)``
Returns the global feature object with the given index.
diff --git a/Lua API.html b/Lua API.html
index b9f09cf96..63a4c8547 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -1019,9 +1019,16 @@ the container itself.
Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.
+dfhack.gui.showZoomAnnouncement(type,pos,text,color[,is_bright])
+Like above, but also specifies a position you can zoom to from the announcement menu.
+
dfhack.gui.showPopupAnnouncement(text,color[,is_bright])
Pops up a titan-style modal announcement window.
+dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright])
+Uses the type to look up options from announcements.txt, and calls the
+above operations accordingly. If enabled, pauses and zooms to position.
+
@@ -1177,6 +1184,9 @@ Returns
false in case of error.
dfhack.maps.getBlock(x,y,z)
Returns a map block object for given x,y,z in local block coordinates.
+
dfhack.maps.isValidTilePos(coords), or isValidTilePos(x,y,z)``
+Checks if the given df::coord or x,y,z in local tile coordinates are valid.
+
dfhack.maps.getTileBlock(coords), or getTileBlock(x,y,z)
Returns a map block object for given df::coord or x,y,z in local tile coordinates.
@@ -1186,6 +1196,10 @@ Returns
false in case of error.
dfhack.maps.enableBlockUpdates(block[,flow,temperature])
Enables updates for liquid flow or temperature, unless already active.
+
dfhack.maps.spawnFlow(pos,type,mat_type,mat_index,dimension)
+Spawns a new flow (i.e. steam/mist/dust/etc) at the given pos, and with
+the given parameters. Returns it, or nil if unsuccessful.
+
dfhack.maps.getGlobalInitFeature(index)
Returns the global feature object with the given index.
diff --git a/dfhack.init-example b/dfhack.init-example
index d3a28b9b0..9ee5ecc46 100644
--- a/dfhack.init-example
+++ b/dfhack.init-example
@@ -61,3 +61,6 @@ tweak stable-cursor
# stop military from considering training as 'patrol duty'
tweak patrol-duty
+
+# display creature weight in build plate menu as ??K, instead of (???df: Max
+tweak readable-build-plate
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 6dfb2f354..4e57b113f 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -78,6 +78,7 @@ distribution.
#include "df/burrow.h"
#include "df/building_civzonest.h"
#include "df/region_map_entry.h"
+#include "df/flow_info.h"
#include
#include
@@ -756,7 +757,9 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getSelectedUnit),
WRAPM(Gui, getSelectedItem),
WRAPM(Gui, showAnnouncement),
+ WRAPM(Gui, showZoomAnnouncement),
WRAPM(Gui, showPopupAnnouncement),
+ WRAPM(Gui, showAutoAnnouncement),
{ NULL, NULL }
};
@@ -912,9 +915,17 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
WRAPM(Maps, getGlobalInitFeature),
WRAPM(Maps, getLocalInitFeature),
WRAPM(Maps, canWalkBetween),
+ WRAPM(Maps, spawnFlow),
{ NULL, NULL }
};
+static int maps_isValidTilePos(lua_State *L)
+{
+ auto pos = CheckCoordXYZ(L, 1, true);
+ lua_pushboolean(L, Maps::isValidTilePos(pos));
+ return 1;
+}
+
static int maps_getTileBlock(lua_State *L)
{
auto pos = CheckCoordXYZ(L, 1, true);
@@ -936,6 +947,7 @@ static int maps_getTileBiomeRgn(lua_State *L)
}
static const luaL_Reg dfhack_maps_funcs[] = {
+ { "isValidTilePos", maps_isValidTilePos },
{ "getTileBlock", maps_getTileBlock },
{ "getRegionBiome", maps_getRegionBiome },
{ "getTileBiomeRgn", maps_getTileBiomeRgn },
diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h
index 58f222419..97e8bd422 100644
--- a/library/include/modules/Gui.h
+++ b/library/include/modules/Gui.h
@@ -32,6 +32,7 @@ distribution.
#include "DataDefs.h"
#include "df/init.h"
#include "df/ui.h"
+#include "df/announcement_type.h"
namespace df {
struct viewscreen;
@@ -92,14 +93,32 @@ namespace DFHack
// Show a plain announcement, or a titan-style popup message
DFHACK_EXPORT void showAnnouncement(std::string message, int color = 7, bool bright = true);
+ DFHACK_EXPORT void showZoomAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true);
DFHACK_EXPORT void showPopupAnnouncement(std::string message, int color = 7, bool bright = true);
+ // Show an announcement with effects determined by announcements.txt
+ DFHACK_EXPORT void showAutoAnnouncement(df::announcement_type type, df::coord pos, std::string message, int color = 7, bool bright = true);
+
/*
* Cursor and window coords
*/
DFHACK_EXPORT df::coord getViewportPos();
DFHACK_EXPORT df::coord getCursorPos();
+ static const int AREA_MAP_WIDTH = 23;
+ static const int MENU_WIDTH = 30;
+
+ struct DwarfmodeDims {
+ int map_x1, map_x2, menu_x1, menu_x2, area_x1, area_x2;
+ int y1, y2;
+ bool menu_on, area_on, menu_forced;
+ };
+
+ DFHACK_EXPORT DwarfmodeDims getDwarfmodeViewDims();
+
+ DFHACK_EXPORT void resetDwarfmodeView(bool pause = false);
+ DFHACK_EXPORT bool revealInDwarfmodeMap(df::coord pos, bool center = false);
+
DFHACK_EXPORT bool getViewCoords (int32_t &x, int32_t &y, int32_t &z);
DFHACK_EXPORT bool setViewCoords (const int32_t x, const int32_t y, const int32_t z);
diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h
index e6e9682eb..984cf16cf 100644
--- a/library/include/modules/Maps.h
+++ b/library/include/modules/Maps.h
@@ -50,6 +50,7 @@ distribution.
#include "df/tile_dig_designation.h"
#include "df/tile_traffic.h"
#include "df/feature_init.h"
+#include "df/flow_type.h"
/**
* \defgroup grp_maps Maps module and its types
@@ -232,6 +233,9 @@ extern DFHACK_EXPORT void getSize(uint32_t& x, uint32_t& y, uint32_t& z);
/// get the position of the map on world map
extern DFHACK_EXPORT void getPosition(int32_t& x, int32_t& y, int32_t& z);
+extern DFHACK_EXPORT bool isValidTilePos(int32_t x, int32_t y, int32_t z);
+inline bool isValidTilePos(df::coord pos) { return isValidTilePos(pos.x, pos.y, pos.z); }
+
/**
* Get the map block or NULL if block is not valid
*/
@@ -272,6 +276,8 @@ inline df::coord2d getTileBiomeRgn(df::coord pos) {
// Enables per-frame updates for liquid flow and/or temperature.
DFHACK_EXPORT void enableBlockUpdates(df::map_block *blk, bool flow = false, bool temperature = false);
+DFHACK_EXPORT df::flow_info *spawnFlow(df::coord pos, df::flow_type type, int mat_type = 0, int mat_index = -1, int density = 100);
+
/// sorts the block event vector into multiple vectors by type
/// mineral veins, what's under ice, blood smears and mud
extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block,
diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp
index 0f28860bf..1ea4bf687 100644
--- a/library/modules/Gui.cpp
+++ b/library/modules/Gui.cpp
@@ -43,6 +43,7 @@ using namespace DFHack;
#include "modules/Job.h"
#include "modules/Screen.h"
+#include "modules/Maps.h"
#include "DataDefs.h"
#include "df/world.h"
@@ -81,6 +82,8 @@ using namespace DFHack;
#include "df/graphic.h"
#include "df/layer_object_listst.h"
#include "df/assign_trade_status.h"
+#include "df/announcement_flags.h"
+#include "df/announcements.h"
using namespace df::enums;
using df::global::gview;
@@ -88,6 +91,9 @@ using df::global::init;
using df::global::gps;
using df::global::ui;
using df::global::world;
+using df::global::selection_rect;
+using df::global::ui_menu_width;
+using df::global::ui_area_map_width;
static df::layer_object_listst *getLayerList(df::viewscreen_layerst *layer, int idx)
{
@@ -921,8 +927,9 @@ df::item *Gui::getSelectedItem(color_ostream &out, bool quiet)
//
-void Gui::showAnnouncement(std::string message, int color, bool bright)
-{
+static void doShowAnnouncement(
+ df::announcement_type type, df::coord pos, std::string message, int color, bool bright
+) {
using df::global::world;
using df::global::cur_year;
using df::global::cur_year_tick;
@@ -948,6 +955,9 @@ void Gui::showAnnouncement(std::string message, int color, bool bright)
{
df::report *new_rep = new df::report();
+ new_rep->type = type;
+ new_rep->pos = pos;
+
new_rep->color = color;
new_rep->bright = bright;
new_rep->year = year;
@@ -969,7 +979,17 @@ void Gui::showAnnouncement(std::string message, int color, bool bright)
world->status.announcements.push_back(new_rep);
world->status.display_timer = 2000;
}
+}
+
+void Gui::showAnnouncement(std::string message, int color, bool bright)
+{
+ doShowAnnouncement(df::announcement_type(0), df::coord(), message, color, bright);
+}
+void Gui::showZoomAnnouncement(
+ df::announcement_type type, df::coord pos, std::string message, int color, bool bright
+) {
+ doShowAnnouncement(type, pos, message, color, bright);
}
void Gui::showPopupAnnouncement(std::string message, int color, bool bright)
@@ -983,6 +1003,29 @@ void Gui::showPopupAnnouncement(std::string message, int color, bool bright)
world->status.popups.push_back(popup);
}
+void Gui::showAutoAnnouncement(
+ df::announcement_type type, df::coord pos, std::string message, int color, bool bright
+) {
+ using df::global::announcements;
+
+ df::announcement_flags flags;
+ if (is_valid_enum_item(type) && announcements)
+ flags = announcements->flags[type];
+
+ doShowAnnouncement(type, pos, message, color, bright);
+
+ if (flags.bits.DO_MEGA || flags.bits.PAUSE || flags.bits.RECENTER)
+ {
+ resetDwarfmodeView(flags.bits.DO_MEGA || flags.bits.PAUSE);
+
+ if (flags.bits.RECENTER && pos.isValid())
+ revealInDwarfmodeMap(pos, true);
+ }
+
+ if (flags.bits.DO_MEGA)
+ showPopupAnnouncement(message, color, bright);
+}
+
df::viewscreen *Gui::getCurViewscreen(bool skip_dismissed)
{
df::viewscreen * ws = &gview->view;
@@ -1015,6 +1058,110 @@ df::coord Gui::getCursorPos()
return df::coord(cursor->x, cursor->y, cursor->z);
}
+Gui::DwarfmodeDims Gui::getDwarfmodeViewDims()
+{
+ DwarfmodeDims dims;
+
+ auto ws = Screen::getWindowSize();
+ dims.y1 = 1;
+ dims.y2 = ws.y-2;
+ dims.map_x1 = 1;
+ dims.map_x2 = ws.x-2;
+ dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1;
+ dims.menu_forced = false;
+
+ int menu_pos = (ui_menu_width ? *ui_menu_width : 2);
+ int area_pos = (ui_area_map_width ? *ui_area_map_width : 3);
+
+ if (ui && ui->main.mode && menu_pos >= area_pos)
+ {
+ dims.menu_forced = true;
+ menu_pos = area_pos-1;
+ }
+
+ dims.area_on = (area_pos < 3);
+ dims.menu_on = (menu_pos < area_pos);
+
+ if (dims.menu_on)
+ {
+ dims.menu_x2 = ws.x - 2;
+ dims.menu_x1 = dims.menu_x2 - Gui::MENU_WIDTH + 1;
+ if (menu_pos == 1)
+ dims.menu_x1 -= Gui::AREA_MAP_WIDTH + 1;
+ dims.map_x2 = dims.menu_x1 - 2;
+ }
+ if (dims.area_on)
+ {
+ dims.area_x2 = ws.x-2;
+ dims.area_x1 = dims.area_x2 - Gui::AREA_MAP_WIDTH + 1;
+ if (dims.menu_on)
+ dims.menu_x2 = dims.area_x1 - 2;
+ else
+ dims.map_x2 = dims.area_x1 - 2;
+ }
+
+ return dims;
+}
+
+void Gui::resetDwarfmodeView(bool pause)
+{
+ using df::global::cursor;
+
+ if (ui)
+ {
+ ui->follow_unit = -1;
+ ui->follow_item = -1;
+ ui->main.mode = ui_sidebar_mode::Default;
+ }
+
+ if (selection_rect)
+ {
+ selection_rect->start_x = -30000;
+ selection_rect->end_x = -30000;
+ }
+
+ if (cursor)
+ cursor->x = cursor->y = cursor->z = -30000;
+
+ if (pause && df::global::pause_state)
+ *df::global::pause_state = true;
+}
+
+bool Gui::revealInDwarfmodeMap(df::coord pos, bool center)
+{
+ using df::global::window_x;
+ using df::global::window_y;
+ using df::global::window_z;
+
+ if (!window_x || !window_y || !window_z || !world)
+ return false;
+ if (!Maps::isValidTilePos(pos))
+ return false;
+
+ auto dims = getDwarfmodeViewDims();
+ int w = dims.map_x2 - dims.map_x1 + 1;
+ int h = dims.y2 - dims.y1 + 1;
+
+ *window_z = pos.z;
+
+ if (center)
+ {
+ *window_x = pos.x - w/2;
+ *window_y = pos.y - h/2;
+ }
+ else
+ {
+ while (*window_x + w < pos.x+5) *window_x += 10;
+ while (*window_y + h < pos.y+5) *window_y += 10;
+ while (*window_x + 5 > pos.x) *window_x -= 10;
+ while (*window_y + 5 > pos.y) *window_y -= 10;
+ }
+
+ *window_x = std::max(0, std::min(*window_x, world->map.x_count-w));
+ *window_y = std::max(0, std::min(*window_y, world->map.y_count-h));
+ return true;
+}
+
bool Gui::getViewCoords (int32_t &x, int32_t &y, int32_t &z)
{
x = *df::global::window_x;
diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp
index 4107680b0..305f1296d 100644
--- a/library/modules/Maps.cpp
+++ b/library/modules/Maps.cpp
@@ -58,6 +58,7 @@ using namespace std;
#include "df/block_square_event_grassst.h"
#include "df/z_level_flags.h"
#include "df/region_map_entry.h"
+#include "df/flow_info.h"
using namespace DFHack;
using namespace df::enums;
@@ -138,13 +139,20 @@ df::map_block *Maps::getBlock (int32_t blockx, int32_t blocky, int32_t blockz)
return world->map.block_index[blockx][blocky][blockz];
}
-df::map_block *Maps::getTileBlock (int32_t x, int32_t y, int32_t z)
+bool Maps::isValidTilePos(int32_t x, int32_t y, int32_t z)
{
if (!IsValid())
- return NULL;
+ return false;
if ((x < 0) || (y < 0) || (z < 0))
- return NULL;
+ return false;
if ((x >= world->map.x_count) || (y >= world->map.y_count) || (z >= world->map.z_count))
+ return false;
+ return true;
+}
+
+df::map_block *Maps::getTileBlock (int32_t x, int32_t y, int32_t z)
+{
+ if (!isValidTilePos(x,y,z))
return NULL;
return world->map.block_index[x >> 4][y >> 4][z];
}
@@ -204,6 +212,26 @@ void Maps::enableBlockUpdates(df::map_block *blk, bool flow, bool temperature)
}
}
+df::flow_info *Maps::spawnFlow(df::coord pos, df::flow_type type, int mat_type, int mat_index, int density)
+{
+ using df::global::flows;
+
+ auto block = getTileBlock(pos);
+ if (!flows || !block)
+ return NULL;
+
+ auto flow = new df::flow_info();
+ flow->type = type;
+ flow->mat_type = mat_type;
+ flow->mat_index = mat_index;
+ flow->density = std::min(100, density);
+ flow->pos = pos;
+
+ block->flows.push_back(flow);
+ flows->push_back(flow);
+ return flow;
+}
+
df::feature_init *Maps::getGlobalInitFeature(int32_t index)
{
auto data = world->world_data;
diff --git a/plugins/tweak.cpp b/plugins/tweak.cpp
index fa99f39e5..9853f7f95 100644
--- a/plugins/tweak.cpp
+++ b/plugins/tweak.cpp
@@ -211,9 +211,6 @@ struct patrol_duty_hook : df::squad_order_trainst
IMPLEMENT_VMETHOD_INTERPOSE(patrol_duty_hook, isPatrol);
-static const int AREA_MAP_WIDTH = 23;
-static const int MENU_WIDTH = 30;
-
struct readable_build_plate_hook : df::viewscreen_dwarfmodest
{
typedef df::viewscreen_dwarfmodest interpose_base;
@@ -228,10 +225,8 @@ struct readable_build_plate_hook : df::viewscreen_dwarfmodest
ui_build_selector->building_subtype == trap_type::PressurePlate &&
ui_build_selector->plate_info.flags.bits.units)
{
- auto wsize = Screen::getWindowSize();
- int x = wsize.x - MENU_WIDTH - 1;
- if (*ui_menu_width == 1 || *ui_area_map_width == 2)
- x -= AREA_MAP_WIDTH + 1;
+ auto dims = Gui::getDwarfmodeViewDims();
+ int x = dims.menu_x1;
Screen::Pen pen(' ',COLOR_WHITE);