Merge pull request #1 from DFHack/develop

Develop
develop
PatrikLundell 2017-12-13 11:24:28 +01:00 committed by GitHub
commit 88be4b2b6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 1534 additions and 1059 deletions

@ -81,9 +81,11 @@ ENDIF()
IF("${DFHACK_BUILD_ARCH}" STREQUAL "32") IF("${DFHACK_BUILD_ARCH}" STREQUAL "32")
SET(DFHACK_BUILD_32 1) SET(DFHACK_BUILD_32 1)
SET(DFHACK_BUILD_64 0) SET(DFHACK_BUILD_64 0)
set(DFHACK_SETARCH "i386")
ELSEIF("${DFHACK_BUILD_ARCH}" STREQUAL "64") ELSEIF("${DFHACK_BUILD_ARCH}" STREQUAL "64")
SET(DFHACK_BUILD_32 0) SET(DFHACK_BUILD_32 0)
SET(DFHACK_BUILD_64 1) SET(DFHACK_BUILD_64 1)
set(DFHACK_SETARCH "x86_64")
ADD_DEFINITIONS(-DDFHACK64) ADD_DEFINITIONS(-DDFHACK64)
ELSE() ELSE()
MESSAGE(SEND_ERROR "Invalid build architecture (should be 32/64): ${DFHACK_BUILD_ARCH}") MESSAGE(SEND_ERROR "Invalid build architecture (should be 32/64): ${DFHACK_BUILD_ARCH}")
@ -138,9 +140,9 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac
endif() endif()
# set up versioning. # set up versioning.
set(DF_VERSION "0.43.05") set(DF_VERSION "0.44.02")
SET(DFHACK_RELEASE "r2") SET(DFHACK_RELEASE "alpha1")
SET(DFHACK_PRERELEASE FALSE) SET(DFHACK_PRERELEASE TRUE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
@ -334,6 +336,9 @@ IF(BUILD_LIBRARY)
install(FILES LICENSE.rst NEWS.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) install(FILES LICENSE.rst NEWS.rst DESTINATION ${DFHACK_USERDOC_DESTINATION})
endif() endif()
file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH})
install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}")
install(DIRECTORY dfhack-config/ DESTINATION dfhack-config/default) install(DIRECTORY dfhack-config/ DESTINATION dfhack-config/default)
#build the plugins #build the plugins

@ -36,6 +36,54 @@ Changelog
.. contents:: .. contents::
:depth: 2 :depth: 2
DFHack future
=============
Lua
---
- Added a new ``dfhack.console`` API
DFHack 0.43.05-r3
=================
Internals
---------
- Fixed an uncommon crash that could occur when printing text to the console
- Added lots of previously-missing DF classes
- More names for fields: https://github.com/DFHack/df-structures/compare/0.43.05-r2...0.43.05
Fixes
-----
- Linux: fixed argument to ``setarch`` in the ``dfhack`` launcher script
- Ruby: fixed an error that occurred when the DF path contained an apostrophe
- `diggingInvaders` now compiles again and is included
- `labormanager`:
- stopped waiting for on-duty military dwarves with minor injuries to obtain care
- stopped waiting for meetings when participant(s) are dead
- fixed a crash for dwarves with no cultural identity
- `luasocket`: fixed ``receive()`` with a byte count
- `orders`: fixed an error when importing orders with material categories
- `siren`: fixed an error
- `stockpiles`: fixed serialization of barrel and bin counts
- `view-item-info`: fixed a ``CHEESE_MAT``-related error
Misc Improvements
-----------------
- `devel/export-dt-ini`: added more offsets for new DT versions
- `digfort`: added support for changing z-levels
- `exportlegends`: suppressed ABSTRACT_BUILDING warning
- `gui/dfstatus`: excluded logs in constructions
- `labormanager`:
- stopped assigning woodcutting jobs to elves
- "recover wounded" jobs now weighted based on altruism
- `remotefortressreader`: added support for buildings, grass, riders, and
hair/beard styles
DFHack 0.43.05-r2 DFHack 0.43.05-r2
================= =================

@ -1 +1 @@
Subproject commit d1565a3b711514048477e11bc04f60f6218af37f Subproject commit 0f0ad78c4fd429caacd0694b5c868dbeacea16b6

@ -26,6 +26,7 @@ Caldfir caldfir
Carter Bray Qartar Carter Bray Qartar
Chris Dombroski cdombroski Chris Dombroski cdombroski
Clayton Hughes Clayton Hughes
Clément Vuchener cvuchener
David Corbett dscorbett David Corbett dscorbett
David Seguin dseguin David Seguin dseguin
Deon Deon
@ -78,10 +79,12 @@ Nick Rart nickrart comestible
Nikolay Amiantov abbradar Nikolay Amiantov abbradar
nocico nocico nocico nocico
Omniclasm Omniclasm
OwnageIsMagic OwnageIsMagic
Patrik Lundell PatrikLundell Patrik Lundell PatrikLundell
Paul Fenwick pjf Paul Fenwick pjf
PeridexisErrant PeridexisErrant PeridexisErrant PeridexisErrant
Petr Mrázek peterix Petr Mrázek peterix
Pfhreak Pfhreak
potato potato
Priit Laes plaes Priit Laes plaes
Putnam Putnam3145 Putnam Putnam3145
@ -124,6 +127,7 @@ Travis Hoppe thoppe orthographic-pedant
txtsd txtsd txtsd txtsd
U-glouglou\\simon U-glouglou\\simon
Valentin Ochs Cat-Ion Valentin Ochs Cat-Ion
ViTuRaS ViTuRaS
Vjek Vjek
Warmist warmist Warmist warmist
Wes Malone wesQ3 Wes Malone wesQ3

@ -1966,6 +1966,18 @@ unless otherwise noted.
``listdir_recursive()`` returns the initial path and all components following it ``listdir_recursive()`` returns the initial path and all components following it
for each entry. for each entry.
Console API
-----------
* ``dfhack.console.clear()``
Clears the console; equivalent to the ``cls`` built-in command.
* ``dfhack.console.flush()``
Flushes all output to the console. This can be useful when printing text that
does not end in a newline but should still be displayed.
Internal API Internal API
------------ ------------
@ -3621,6 +3633,8 @@ Or with auto_gears::
auto_gears=true auto_gears=true
} }
.. _luasocket:
Luasocket Luasocket
========= =========

@ -37,6 +37,26 @@ Development Changelog
.. contents:: .. contents::
:depth: 2 :depth: 2
DFHack 0.44.02-alpha1
=====================
Fixes
-----
- Fixed a crash that could occur if a symbol table in symbols.xml had no content
- The Lua API can now wrap functions with 12 or 13 parameters
Structures
----------
- The ``ui_menu_width`` global is now a 2-byte array; the second item is the
former ``ui_area_map_width`` global, which is now removed
- The former ``announcements`` global is now a field in ``d_init``
- ``world`` fields formerly beginning with ``job_`` are now fields of
``world.jobs``, e.g. ``world.job_list`` is now ``world.jobs.list``
API Changes
-----------
- Lua: Added a new ``dfhack.console`` API
DFHack 0.43.05-beta2 DFHack 0.43.05-beta2
==================== ====================

@ -172,7 +172,7 @@ namespace DFHack
} }
void gotoxy(int x, int y) void gotoxy(int x, int y)
{ {
COORD coord = {x-1, y-1}; // Windows uses 0-based coordinates COORD coord = {(SHORT)(x-1), (SHORT)(y-1)}; // Windows uses 0-based coordinates
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
} }
@ -434,7 +434,7 @@ bool Console::init(bool)
{ {
d = new Private(); d = new Private();
int hConHandle; int hConHandle;
long lStdHandle; intptr_t lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo; CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp; FILE *fp;
DWORD oldMode, newMode; DWORD oldMode, newMode;
@ -469,14 +469,14 @@ bool Console::init(bool)
// redirect unbuffered STDOUT to the console // redirect unbuffered STDOUT to the console
d->console_out = GetStdHandle(STD_OUTPUT_HANDLE); d->console_out = GetStdHandle(STD_OUTPUT_HANDLE);
lStdHandle = (long)d->console_out; lStdHandle = (intptr_t)d->console_out;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
d->dfout_C = _fdopen( hConHandle, "w" ); d->dfout_C = _fdopen( hConHandle, "w" );
setvbuf( d->dfout_C, NULL, _IONBF, 0 ); setvbuf( d->dfout_C, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console // redirect unbuffered STDIN to the console
d->console_in = GetStdHandle(STD_INPUT_HANDLE); d->console_in = GetStdHandle(STD_INPUT_HANDLE);
lStdHandle = (long)d->console_in; lStdHandle = (intptr_t)d->console_in;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" ); fp = _fdopen( hConHandle, "r" );
*stdin = *fp; *stdin = *fp;

@ -388,6 +388,15 @@ static command_result runRubyScript(color_ostream &out, PluginManager *plug_mgr,
if (!plug_mgr->ruby || !plug_mgr->ruby->is_enabled()) if (!plug_mgr->ruby || !plug_mgr->ruby->is_enabled())
return CR_FAILURE; return CR_FAILURE;
// ugly temporary patch for https://github.com/DFHack/dfhack/issues/1146
string cwd = Filesystem::getcwd();
if (filename.find(cwd) == 0)
{
filename = filename.substr(cwd.size());
while (!filename.empty() && (filename[0] == '/' || filename[0] == '\\'))
filename = filename.substr(1);
}
std::string rbcmd = "$script_args = ["; std::string rbcmd = "$script_args = [";
for (size_t i = 0; i < args.size(); i++) for (size_t i = 0; i < args.size(); i++)
rbcmd += "'" + args[i] + "', "; rbcmd += "'" + args[i] + "', ";

@ -2429,6 +2429,23 @@ static const luaL_Reg dfhack_designations_funcs[] = {
{NULL, NULL} {NULL, NULL}
}; };
/***** Console module *****/
namespace console {
void clear() {
Core::getInstance().getConsole().clear();
}
void flush() {
Core::getInstance().getConsole() << std::flush;
}
}
static const LuaWrapper::FunctionReg dfhack_console_module[] = {
WRAPM(console, clear),
WRAPM(console, flush),
{ NULL, NULL }
};
/***** Internal module *****/ /***** Internal module *****/
static void *checkaddr(lua_State *L, int idx, bool allow_null = false) static void *checkaddr(lua_State *L, int idx, bool allow_null = false)
@ -2964,5 +2981,6 @@ void OpenDFHackApi(lua_State *state)
OpenModule(state, "screen", dfhack_screen_module, dfhack_screen_funcs); OpenModule(state, "screen", dfhack_screen_module, dfhack_screen_funcs);
OpenModule(state, "filesystem", dfhack_filesystem_module, dfhack_filesystem_funcs); OpenModule(state, "filesystem", dfhack_filesystem_module, dfhack_filesystem_funcs);
OpenModule(state, "designations", dfhack_designations_module, dfhack_designations_funcs); OpenModule(state, "designations", dfhack_designations_module, dfhack_designations_funcs);
OpenModule(state, "console", dfhack_console_module);
OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs); OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs);
} }

@ -1190,9 +1190,8 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo
continue; continue;
case struct_field_info::POINTER: case struct_field_info::POINTER:
// Skip class-typed pointers within unions // Skip class-typed pointers within unions and other bad pointers
if ((fields[i].count & 2) != 0 && fields[i].type && if ((fields[i].count & 2) != 0 && fields[i].type)
fields[i].type->type() == IDTYPE_CLASS)
add_to_enum = false; add_to_enum = false;
break; break;

@ -61,11 +61,14 @@ std::string stl_vsprintf(const char *fmt, va_list args) {
std::vector<char> buf; std::vector<char> buf;
buf.resize(4096); buf.resize(4096);
for (;;) { for (;;) {
int rsz = vsnprintf(&buf[0], buf.size(), fmt, args); va_list args2;
va_copy(args2, args);
int rsz = vsnprintf(&buf[0], buf.size(), fmt, args2);
va_end(args2);
if (rsz < 0) if (rsz < 0)
buf.resize(buf.size()*2); buf.resize(buf.size()*2);
else if (unsigned(rsz) > buf.size()) else if (unsigned(rsz) >= buf.size())
buf.resize(rsz+1); buf.resize(rsz+1);
else else
return std::string(&buf[0], rsz); return std::string(&buf[0], rsz);

@ -261,7 +261,7 @@ void ServerConnection::threadFn()
break; break;
} }
std::auto_ptr<uint8_t> buf(new uint8_t[header.size]); std::unique_ptr<uint8_t[]> buf(new uint8_t[header.size]);
if (!readFullBuffer(socket, buf.get(), header.size)) if (!readFullBuffer(socket, buf.get(), header.size))
{ {

@ -116,6 +116,10 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
// process additional entries // process additional entries
//cout << "Entry " << cstr_version << " " << cstr_os << endl; //cout << "Entry " << cstr_version << " " << cstr_os << endl;
if (!entry->FirstChildElement()) {
cerr << "Empty symbol table: " << entry->Attribute("name") << endl;
return;
}
pMemEntry = entry->FirstChildElement()->ToElement(); pMemEntry = entry->FirstChildElement()->ToElement();
for(;pMemEntry;pMemEntry=pMemEntry->NextSiblingElement()) for(;pMemEntry;pMemEntry=pMemEntry->NextSiblingElement())
{ {

@ -221,6 +221,29 @@ INSTANTIATE_WRAPPERS(11, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11),
LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11);) LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11);)
#undef FW_TARGS #undef FW_TARGS
#define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10, class A11, class A12
INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12))
INSTANTIATE_WRAPPERS(12, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12),
(OSTREAM_ARG,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12),
(vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12),
(out,vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12),
LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4);
LOAD_ARG(A5); LOAD_ARG(A6); LOAD_ARG(A7); LOAD_ARG(A8);
LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11); LOAD_ARG(A12);)
#undef FW_TARGS
#define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10, class A11, class A12, class A13
INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13))
INSTANTIATE_WRAPPERS(13, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13),
(OSTREAM_ARG,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13),
(vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12,vA13),
(out,vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12,vA13),
LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4);
LOAD_ARG(A5); LOAD_ARG(A6); LOAD_ARG(A7); LOAD_ARG(A8);
LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11); LOAD_ARG(A12);
LOAD_ARG(A13);)
#undef FW_TARGS
#undef FW_TARGSC #undef FW_TARGSC
#undef INSTANTIATE_WRAPPERS #undef INSTANTIATE_WRAPPERS
#undef INSTANTIATE_WRAPPERS2 #undef INSTANTIATE_WRAPPERS2

@ -58,6 +58,8 @@ distribution.
#pragma warning( disable: 4482) #pragma warning( disable: 4482)
// nonstandard extension used: 'extern' before template explicit instantiation // nonstandard extension used: 'extern' before template explicit instantiation
#pragma warning( disable: 4231) #pragma warning( disable: 4231)
// ignore warnings about putting a vector index into an int
#pragma warning( disable: 4267)
#endif #endif
#endif #endif

@ -18,8 +18,8 @@ refreshSidebar = dfhack.gui.refreshSidebar
function getPanelLayout() function getPanelLayout()
local dims = dfhack.gui.getDwarfmodeViewDims() local dims = dfhack.gui.getDwarfmodeViewDims()
local area_pos = df.global.ui_area_map_width local area_pos = df.global.ui_menu_width[1]
local menu_pos = df.global.ui_menu_width local menu_pos = df.global.ui_menu_width[0]
if dims.menu_forced then if dims.menu_forced then
menu_pos = area_pos - 1 menu_pos = area_pos - 1

@ -138,7 +138,7 @@ void buildings_onUpdate(color_ostream &out)
{ {
buildings_do_onupdate = false; buildings_do_onupdate = false;
df::job_list_link *link = world->job_list.next; df::job_list_link *link = world->jobs.list.next;
for (; link; link = link->next) { for (; link; link = link->next) {
df::job *job = link->item; df::job *job = link->item;

@ -66,7 +66,7 @@ bool Designations::isPlantMarked(const df::plant *plant)
if (block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig == tile_dig_designation::Default) if (block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig == tile_dig_designation::Default)
return true; return true;
for (auto *link = world->job_list.next; link; link = link->next) for (auto *link = world->jobs.list.next; link; link = link->next)
{ {
df::job *job = link->item; df::job *job = link->item;
if (!job) if (!job)
@ -128,7 +128,7 @@ bool Designations::unmarkPlant(const df::plant *plant)
block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig = tile_dig_designation::No; block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig = tile_dig_designation::No;
block->flags.bits.designated = true; block->flags.bits.designated = true;
auto *link = world->job_list.next; auto *link = world->jobs.list.next;
while (link) while (link)
{ {
auto *next = link->next; auto *next = link->next;

@ -381,7 +381,7 @@ static void manageJobInitiatedEvent(color_ostream& out) {
} }
multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_INITIATED].begin(), handlers[EventType::JOB_INITIATED].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_INITIATED].begin(), handlers[EventType::JOB_INITIATED].end());
for ( df::job_list_link* link = &df::global::world->job_list; link != NULL; link = link->next ) { for ( df::job_list_link* link = &df::global::world->jobs.list; link != NULL; link = link->next ) {
if ( link->item == NULL ) if ( link->item == NULL )
continue; continue;
if ( link->item->id <= lastJobId ) if ( link->item->id <= lastJobId )
@ -411,7 +411,7 @@ static void manageJobCompletedEvent(color_ostream& out) {
multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_COMPLETED].begin(), handlers[EventType::JOB_COMPLETED].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::JOB_COMPLETED].begin(), handlers[EventType::JOB_COMPLETED].end());
map<int32_t, df::job*> nowJobs; map<int32_t, df::job*> nowJobs;
for ( df::job_list_link* link = &df::global::world->job_list; link != NULL; link = link->next ) { for ( df::job_list_link* link = &df::global::world->jobs.list; link != NULL; link = link->next ) {
if ( link->item == NULL ) if ( link->item == NULL )
continue; continue;
nowJobs[link->item->id] = link->item; nowJobs[link->item->id] = link->item;

@ -53,7 +53,7 @@ using namespace DFHack;
bool Filesystem::chdir (std::string path) bool Filesystem::chdir (std::string path)
{ {
return !(bool)::chdir(path.c_str()); return ::chdir(path.c_str()) == 0;
} }
std::string Filesystem::getcwd () std::string Filesystem::getcwd ()
@ -79,7 +79,7 @@ bool Filesystem::mkdir (std::string path)
fail = ::mkdir(path.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | fail = ::mkdir(path.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH); S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
#endif #endif
return !(bool)fail; return fail == 0;
} }
bool Filesystem::rmdir (std::string path) bool Filesystem::rmdir (std::string path)
@ -90,7 +90,7 @@ bool Filesystem::rmdir (std::string path)
#else #else
fail = ::rmdir(path.c_str()); fail = ::rmdir(path.c_str());
#endif #endif
return !(bool)fail; return fail == 0;
} }
#ifdef _WIN32 #ifdef _WIN32
@ -116,13 +116,13 @@ _filetype mode2type (mode_t mode) {
bool Filesystem::stat (std::string path, STAT_STRUCT &info) bool Filesystem::stat (std::string path, STAT_STRUCT &info)
{ {
return !(bool)(STAT_FUNC(path.c_str(), &info)); return (STAT_FUNC(path.c_str(), &info)) == 0;
} }
bool Filesystem::exists (std::string path) bool Filesystem::exists (std::string path)
{ {
STAT_STRUCT info; STAT_STRUCT info;
return (bool)Filesystem::stat(path, info); return Filesystem::stat(path, info);
} }
_filetype Filesystem::filetype (std::string path) _filetype Filesystem::filetype (std::string path)

@ -48,12 +48,12 @@ using namespace DFHack;
#include "DataDefs.h" #include "DataDefs.h"
#include "df/announcement_flags.h" #include "df/announcement_flags.h"
#include "df/announcements.h"
#include "df/assign_trade_status.h" #include "df/assign_trade_status.h"
#include "df/building_civzonest.h" #include "df/building_civzonest.h"
#include "df/building_furnacest.h" #include "df/building_furnacest.h"
#include "df/building_trapst.h" #include "df/building_trapst.h"
#include "df/building_workshopst.h" #include "df/building_workshopst.h"
#include "df/d_init.h"
#include "df/game_mode.h" #include "df/game_mode.h"
#include "df/general_ref.h" #include "df/general_ref.h"
#include "df/global_objects.h" #include "df/global_objects.h"
@ -108,7 +108,6 @@ using df::global::ui;
using df::global::world; using df::global::world;
using df::global::selection_rect; using df::global::selection_rect;
using df::global::ui_menu_width; using df::global::ui_menu_width;
using df::global::ui_area_map_width;
using df::global::gamemode; using df::global::gamemode;
static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx) static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx)
@ -990,6 +989,18 @@ df::item *Gui::getAnyItem(df::viewscreen *top)
using df::global::ui_building_item_cursor; using df::global::ui_building_item_cursor;
using df::global::ui_sidebar_menus; using df::global::ui_sidebar_menus;
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_textviewerst, top))
{
// return the main item if the parent screen is a viewscreen_itemst
if (VIRTUAL_CAST_VAR(parent_screen, df::viewscreen_itemst, screen->parent))
return parent_screen->item;
if (screen->parent)
return getAnyItem(screen->parent);
return NULL;
}
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top)) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top))
{ {
df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos); df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos);
@ -1416,13 +1427,13 @@ void Gui::showAutoAnnouncement(
df::announcement_type type, df::coord pos, std::string message, int color, bool bright, df::announcement_type type, df::coord pos, std::string message, int color, bool bright,
df::unit *unit1, df::unit *unit2 df::unit *unit1, df::unit *unit2
) { ) {
using df::global::announcements; using df::global::d_init;
df::announcement_flags flags; df::announcement_flags flags;
flags.bits.D_DISPLAY = flags.bits.A_DISPLAY = true; flags.bits.D_DISPLAY = flags.bits.A_DISPLAY = true;
if (is_valid_enum_item(type) && announcements) if (is_valid_enum_item(type) && d_init)
flags = announcements->flags[type]; flags = d_init->announcements.flags[type];
int id = makeAnnouncement(type, flags, pos, message, color, bright); int id = makeAnnouncement(type, flags, pos, message, color, bright);
@ -1496,8 +1507,8 @@ Gui::DwarfmodeDims getDwarfmodeViewDims_default()
dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1; dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1;
dims.menu_forced = false; dims.menu_forced = false;
int menu_pos = (ui_menu_width ? *ui_menu_width : 2); int menu_pos = (ui_menu_width ? (*ui_menu_width)[0] : 2);
int area_pos = (ui_area_map_width ? *ui_area_map_width : 3); int area_pos = (ui_menu_width ? (*ui_menu_width)[1] : 3);
if (ui && ui->main.mode && menu_pos >= area_pos) if (ui && ui->main.mode && menu_pos >= area_pos)
{ {
@ -1703,14 +1714,14 @@ bool Gui::getWindowSize (int32_t &width, int32_t &height)
bool Gui::getMenuWidth(uint8_t &menu_width, uint8_t &area_map_width) bool Gui::getMenuWidth(uint8_t &menu_width, uint8_t &area_map_width)
{ {
menu_width = *df::global::ui_menu_width; menu_width = (*df::global::ui_menu_width)[0];
area_map_width = *df::global::ui_area_map_width; area_map_width = (*df::global::ui_menu_width)[1];
return true; return true;
} }
bool Gui::setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width) bool Gui::setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width)
{ {
*df::global::ui_menu_width = menu_width; (*df::global::ui_menu_width)[0] = menu_width;
*df::global::ui_area_map_width = area_map_width; (*df::global::ui_menu_width)[1] = area_map_width;
return true; return true;
} }

@ -490,10 +490,10 @@ bool DFHack::Job::linkIntoWorld(df::job *job, bool new_id)
job->list_link = new df::job_list_link(); job->list_link = new df::job_list_link();
job->list_link->item = job; job->list_link->item = job;
linked_list_append(&world->job_list, job->list_link); linked_list_append(&world->jobs.list, job->list_link);
return true; return true;
} else { } else {
df::job_list_link *ins_pos = &world->job_list; df::job_list_link *ins_pos = &world->jobs.list;
while (ins_pos->next && ins_pos->next->item->id < job->id) while (ins_pos->next && ins_pos->next->item->id < job->id)
ins_pos = ins_pos->next; ins_pos = ins_pos->next;
@ -514,15 +514,15 @@ bool DFHack::Job::removePostings(df::job *job, bool remove_all)
bool removed = false; bool removed = false;
if (!remove_all) if (!remove_all)
{ {
if (job->posting_index >= 0 && job->posting_index < world->job_postings.size()) if (job->posting_index >= 0 && job->posting_index < world->jobs.postings.size())
{ {
world->job_postings[job->posting_index]->flags.bits.dead = true; world->jobs.postings[job->posting_index]->flags.bits.dead = true;
removed = true; removed = true;
} }
} }
else else
{ {
for (auto it = world->job_postings.begin(); it != world->job_postings.end(); ++it) for (auto it = world->jobs.postings.begin(); it != world->jobs.postings.end(); ++it)
{ {
if ((**it).job == job) if ((**it).job == job)
{ {
@ -553,7 +553,7 @@ bool DFHack::Job::listNewlyCreated(std::vector<df::job*> *pvec, int *id_var)
pvec->reserve(std::min(20,cur_id - old_id)); pvec->reserve(std::min(20,cur_id - old_id));
df::job_list_link *link = world->job_list.next; df::job_list_link *link = world->jobs.list.next;
for (; link; link = link->next) for (; link; link = link->next)
{ {
int id = link->item->id; int id = link->item->id;

@ -91,7 +91,7 @@ const char * DFHack::sa_feature(df::feature_type index)
return "Cavern"; return "Cavern";
case feature_type::magma_core_from_layer: case feature_type::magma_core_from_layer:
return "Magma sea"; return "Magma sea";
case feature_type::feature_underworld_from_layer: case feature_type::underworld_from_layer:
return "Underworld"; return "Underworld";
default: default:
return "Unknown/Error"; return "Unknown/Error";

@ -1 +1 @@
Subproject commit 3322beb2e7f4b28ff8e573e9bec738c77026b8e9 Subproject commit e2e256066cc4a5c427172d9d27db25b7823e4e86

@ -63,6 +63,8 @@ export LD_LIBRARY_PATH="./hack/libs:./hack:$LD_LIBRARY_PATH"
PRELOAD_LIB="${PRELOAD_LIB:+$PRELOAD_LIB:}./hack/libdfhack.so" PRELOAD_LIB="${PRELOAD_LIB:+$PRELOAD_LIB:}./hack/libdfhack.so"
setarch_arch=$(cat hack/dfhack_setarch.txt || printf i386)
case "$1" in case "$1" in
-g | --gdb) -g | --gdb)
shift shift
@ -74,21 +76,21 @@ case "$1" in
;; ;;
-h | --helgrind) -h | --helgrind)
shift shift
LD_PRELOAD="$PRELOAD_LIB" setarch i386 -R valgrind $DF_HELGRIND_OPTS --tool=helgrind --log-file=helgrind.log ./libs/Dwarf_Fortress "$@" LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_HELGRIND_OPTS --tool=helgrind --log-file=helgrind.log ./libs/Dwarf_Fortress "$@"
ret=$? ret=$?
;; ;;
-v | --valgrind) -v | --valgrind)
shift shift
LD_PRELOAD="$PRELOAD_LIB" setarch i386 -R valgrind $DF_VALGRIND_OPTS --log-file=valgrind.log ./libs/Dwarf_Fortress "$@" LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_VALGRIND_OPTS --log-file=valgrind.log ./libs/Dwarf_Fortress "$@"
ret=$? ret=$?
;; ;;
-c | --callgrind) -c | --callgrind)
shift shift
LD_PRELOAD="$PRELOAD_LIB" setarch i386 -R valgrind $DF_CALLGRIND_OPTS --tool=callgrind --separate-threads=yes --dump-instr=yes --instr-atstart=no --log-file=callgrind.log ./libs/Dwarf_Fortress "$@" LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_CALLGRIND_OPTS --tool=callgrind --separate-threads=yes --dump-instr=yes --instr-atstart=no --log-file=callgrind.log ./libs/Dwarf_Fortress "$@"
ret=$? ret=$?
;; ;;
*) *)
setarch i386 -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@"
ret=$? ret=$?
;; ;;
esac esac

@ -108,7 +108,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(deramp deramp.cpp) DFHACK_PLUGIN(deramp deramp.cpp)
DFHACK_PLUGIN(dig dig.cpp) DFHACK_PLUGIN(dig dig.cpp)
DFHACK_PLUGIN(digFlood digFlood.cpp) DFHACK_PLUGIN(digFlood digFlood.cpp)
# add_subdirectory(diggingInvaders) add_subdirectory(diggingInvaders)
DFHACK_PLUGIN(dwarfvet dwarfvet.cpp) DFHACK_PLUGIN(dwarfvet dwarfvet.cpp)
DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(embark-tools embark-tools.cpp) DFHACK_PLUGIN(embark-tools embark-tools.cpp)
@ -128,7 +128,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp)
DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote)
DFHACK_PLUGIN(jobutils jobutils.cpp) DFHACK_PLUGIN(jobutils jobutils.cpp)
DFHACK_PLUGIN(labormanager labormanager.cpp) add_subdirectory(labormanager)
DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(lair lair.cpp)
DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua)
DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread)

@ -77,5 +77,6 @@ command_result df_gzoom (color_ostream &out, std::vector<std::string> & paramete
Gui::setCursorCoords(x,y,z); Gui::setCursorCoords(x,y,z);
} }
Gui::setViewCoords(x,y,z); Gui::setViewCoords(x,y,z);
return CR_OK;
} }

@ -89,7 +89,7 @@ void onDig(color_ostream& out, void* ptr) {
return; return;
set<df::coord> jobLocations; set<df::coord> jobLocations;
for ( df::job_list_link* link = &world->job_list; link != NULL; link = link->next ) { for ( df::job_list_link* link = &world->jobs.list; link != NULL; link = link->next ) {
if ( link->item == NULL ) if ( link->item == NULL )
continue; continue;

@ -20,6 +20,7 @@
#include "df/item_type.h" #include "df/item_type.h"
#include "df/item_weaponst.h" #include "df/item_weaponst.h"
#include "df/job.h" #include "df/job.h"
#include "df/job_list_link.h"
#include "df/job_skill.h" #include "df/job_skill.h"
#include "df/job_type.h" #include "df/job_type.h"
#include "df/reaction_product_itemst.h" #include "df/reaction_product_itemst.h"
@ -27,8 +28,11 @@
#include "df/ui.h" #include "df/ui.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/unit_inventory_item.h" #include "df/unit_inventory_item.h"
#include "df/world.h"
#include "df/world_site.h" #include "df/world_site.h"
using namespace DFHack;
void getRidOfOldJob(df::unit* unit) { void getRidOfOldJob(df::unit* unit) {
if ( unit->job.current_job == NULL ) { if ( unit->job.current_job == NULL ) {
return; return;

@ -2,6 +2,7 @@
#include "edgeCost.h" #include "edgeCost.h"
#include "ColorText.h"
#include "modules/MapCache.h" #include "modules/MapCache.h"
#include <unordered_map> #include <unordered_map>
@ -9,5 +10,5 @@
using namespace std; using namespace std;
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache, DigAbilities& abilities); int32_t assignJob(DFHack::color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache, DigAbilities& abilities);

@ -199,7 +199,7 @@ public:
} }
int32_t operator()(df::coord p1, df::coord p2) { int32_t operator()(df::coord p1, df::coord p2) const {
if ( p1 == p2 ) return 0; if ( p1 == p2 ) return 0;
auto i1 = pointCost->find(p1); auto i1 = pointCost->find(p1);
auto i2 = pointCost->find(p2); auto i2 = pointCost->find(p2);
@ -598,7 +598,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
lastInvasionDigger = firstInvader->id; lastInvasionDigger = firstInvader->id;
lastInvasionJob = firstInvader->job.current_job ? firstInvader->job.current_job->id : -1; lastInvasionJob = firstInvader->job.current_job ? firstInvader->job.current_job->id : -1;
invaderJobs.erase(lastInvasionJob); invaderJobs.erase(lastInvasionJob);
for ( df::job_list_link* link = &world->job_list; link != NULL; link = link->next ) { for ( df::job_list_link* link = &world->jobs.list; link != NULL; link = link->next ) {
if ( link->item == NULL ) if ( link->item == NULL )
continue; continue;
df::job* job = link->item; df::job* job = link->item;

@ -19,6 +19,8 @@
#include <iostream> #include <iostream>
using namespace DFHack;
/* /*
cost_t costWeight[] = { cost_t costWeight[] = {
//Distance //Distance

@ -93,6 +93,6 @@ struct PointHash {
} }
}; };
cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2, DigAbilities& abilities); cost_t getEdgeCost(DFHack::color_ostream& out, df::coord pt1, df::coord pt2, DigAbilities& abilities);
std::vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax, DigAbilities& abilities); std::vector<Edge>* getEdgeSet(DFHack::color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax, DigAbilities& abilities);

@ -57,8 +57,6 @@ using df::global::ui;
using df::global::world; using df::global::world;
using df::global::gamemode; using df::global::gamemode;
using df::global::ui_build_selector; using df::global::ui_build_selector;
using df::global::ui_menu_width;
using df::global::ui_area_map_width;
using namespace DFHack::Gui; using namespace DFHack::Gui;
using Screen::Pen; using Screen::Pen;

@ -0,0 +1,34 @@
PROJECT (labormanager)
# A list of source files
SET(PROJECT_SRCS
labormanager.cpp
joblabormapper.cpp
)
# A list of headers
SET(PROJECT_HDRS
labormanager.h
joblabormapper.h
)
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE)
# mash them together (headers are marked as headers and nothing will try to compile them)
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
#linux
IF(UNIX)
add_definitions(-DLINUX_BUILD)
SET(PROJECT_LIBS
# add any extra linux libs here
${PROJECT_LIBS}
)
# windows
ELSE(UNIX)
SET(PROJECT_LIBS
# add any extra linux libs here
${PROJECT_LIBS}
$(NOINHERIT)
)
ENDIF(UNIX)
# this makes sure all the stuff is put in proper places and linked to dfhack
DFHACK_PLUGIN(labormanager ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS})

@ -0,0 +1,920 @@
/*a
* This file contains the logic to attempt to intuit the labor required for
* a given job. This is way more complicated than it should be, but I have
* not figured out how to make it simpler.
*
* Usage:
* Instantiate an instance of the JobLaborMapper class
* Call the find_job_labor method of that class instance,
* passing the job as the only argument, to determine the labor for that job
* When done, destroy the instance
*
* The class should allow you to create multiple instances, although there is
* little benefit to doing so. jlfuncs are not reused across instances.
*
*/
#include "DataDefs.h"
#include "MiscUtils.h"
#include "modules/Materials.h"
#include <df/building.h>
#include <df/building_actual.h>
#include <df/building_def.h>
#include <df/building_design.h>
#include <df/building_furnacest.h>
#include <df/building_type.h>
#include <df/building_workshopst.h>
#include <df/furnace_type.h>
#include <df/general_ref.h>
#include <df/general_ref_building_holderst.h>
#include <df/general_ref_contains_itemst.h>
#include <df/item.h>
#include <df/item_type.h>
#include <df/job.h>
#include <df/job_item.h>
#include <df/job_item_ref.h>
#include <df/material_flags.h>
#include <df/reaction.h>
#include <df/unit_labor.h>
#include <df/world.h>
#include <vector>
#include <set>
using namespace std;
using std::string;
using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::ui;
using df::global::world;
#include "labormanager.h"
#include "joblabormapper.h"
static df::unit_labor hauling_labor_map[] =
{
df::unit_labor::HAUL_ITEM, /* BAR */
df::unit_labor::HAUL_STONE, /* SMALLGEM */
df::unit_labor::HAUL_ITEM, /* BLOCKS */
df::unit_labor::HAUL_STONE, /* ROUGH */
df::unit_labor::HAUL_STONE, /* BOULDER */
df::unit_labor::HAUL_WOOD, /* WOOD */
df::unit_labor::HAUL_FURNITURE, /* DOOR */
df::unit_labor::HAUL_FURNITURE, /* FLOODGATE */
df::unit_labor::HAUL_FURNITURE, /* BED */
df::unit_labor::HAUL_FURNITURE, /* CHAIR */
df::unit_labor::HAUL_ITEM, /* CHAIN */
df::unit_labor::HAUL_ITEM, /* FLASK */
df::unit_labor::HAUL_ITEM, /* GOBLET */
df::unit_labor::HAUL_ITEM, /* INSTRUMENT */
df::unit_labor::HAUL_ITEM, /* TOY */
df::unit_labor::HAUL_FURNITURE, /* WINDOW */
df::unit_labor::HAUL_ANIMALS, /* CAGE */
df::unit_labor::HAUL_ITEM, /* BARREL */
df::unit_labor::HAUL_ITEM, /* BUCKET */
df::unit_labor::HAUL_ANIMALS, /* ANIMALTRAP */
df::unit_labor::HAUL_FURNITURE, /* TABLE */
df::unit_labor::HAUL_FURNITURE, /* COFFIN */
df::unit_labor::HAUL_FURNITURE, /* STATUE */
df::unit_labor::HAUL_REFUSE, /* CORPSE */
df::unit_labor::HAUL_ITEM, /* WEAPON */
df::unit_labor::HAUL_ITEM, /* ARMOR */
df::unit_labor::HAUL_ITEM, /* SHOES */
df::unit_labor::HAUL_ITEM, /* SHIELD */
df::unit_labor::HAUL_ITEM, /* HELM */
df::unit_labor::HAUL_ITEM, /* GLOVES */
df::unit_labor::HAUL_FURNITURE, /* BOX */
df::unit_labor::HAUL_ITEM, /* BIN */
df::unit_labor::HAUL_FURNITURE, /* ARMORSTAND */
df::unit_labor::HAUL_FURNITURE, /* WEAPONRACK */
df::unit_labor::HAUL_FURNITURE, /* CABINET */
df::unit_labor::HAUL_ITEM, /* FIGURINE */
df::unit_labor::HAUL_ITEM, /* AMULET */
df::unit_labor::HAUL_ITEM, /* SCEPTER */
df::unit_labor::HAUL_ITEM, /* AMMO */
df::unit_labor::HAUL_ITEM, /* CROWN */
df::unit_labor::HAUL_ITEM, /* RING */
df::unit_labor::HAUL_ITEM, /* EARRING */
df::unit_labor::HAUL_ITEM, /* BRACELET */
df::unit_labor::HAUL_ITEM, /* GEM */
df::unit_labor::HAUL_FURNITURE, /* ANVIL */
df::unit_labor::HAUL_REFUSE, /* CORPSEPIECE */
df::unit_labor::HAUL_REFUSE, /* REMAINS */
df::unit_labor::HAUL_FOOD, /* MEAT */
df::unit_labor::HAUL_FOOD, /* FISH */
df::unit_labor::HAUL_FOOD, /* FISH_RAW */
df::unit_labor::HAUL_REFUSE, /* VERMIN */
df::unit_labor::HAUL_ITEM, /* PET */
df::unit_labor::HAUL_ITEM, /* SEEDS */
df::unit_labor::HAUL_FOOD, /* PLANT */
df::unit_labor::HAUL_ITEM, /* SKIN_TANNED */
df::unit_labor::HAUL_FOOD, /* LEAVES */
df::unit_labor::HAUL_ITEM, /* THREAD */
df::unit_labor::HAUL_ITEM, /* CLOTH */
df::unit_labor::HAUL_ITEM, /* TOTEM */
df::unit_labor::HAUL_ITEM, /* PANTS */
df::unit_labor::HAUL_ITEM, /* BACKPACK */
df::unit_labor::HAUL_ITEM, /* QUIVER */
df::unit_labor::HAUL_FURNITURE, /* CATAPULTPARTS */
df::unit_labor::HAUL_FURNITURE, /* BALLISTAPARTS */
df::unit_labor::HAUL_FURNITURE, /* SIEGEAMMO */
df::unit_labor::HAUL_FURNITURE, /* BALLISTAARROWHEAD */
df::unit_labor::HAUL_FURNITURE, /* TRAPPARTS */
df::unit_labor::HAUL_FURNITURE, /* TRAPCOMP */
df::unit_labor::HAUL_FOOD, /* DRINK */
df::unit_labor::HAUL_FOOD, /* POWDER_MISC */
df::unit_labor::HAUL_FOOD, /* CHEESE */
df::unit_labor::HAUL_FOOD, /* FOOD */
df::unit_labor::HAUL_FOOD, /* LIQUID_MISC */
df::unit_labor::HAUL_ITEM, /* COIN */
df::unit_labor::HAUL_FOOD, /* GLOB */
df::unit_labor::HAUL_STONE, /* ROCK */
df::unit_labor::HAUL_FURNITURE, /* PIPE_SECTION */
df::unit_labor::HAUL_FURNITURE, /* HATCH_COVER */
df::unit_labor::HAUL_FURNITURE, /* GRATE */
df::unit_labor::HAUL_FURNITURE, /* QUERN */
df::unit_labor::HAUL_FURNITURE, /* MILLSTONE */
df::unit_labor::HAUL_ITEM, /* SPLINT */
df::unit_labor::HAUL_ITEM, /* CRUTCH */
df::unit_labor::HAUL_FURNITURE, /* TRACTION_BENCH */
df::unit_labor::HAUL_ITEM, /* ORTHOPEDIC_CAST */
df::unit_labor::HAUL_ITEM, /* TOOL */
df::unit_labor::HAUL_FURNITURE, /* SLAB */
df::unit_labor::HAUL_FOOD, /* EGG */
df::unit_labor::HAUL_ITEM, /* BOOK */
};
static df::unit_labor workshop_build_labor[] =
{
/* Carpenters */ df::unit_labor::CARPENTER,
/* Farmers */ df::unit_labor::PROCESS_PLANT,
/* Masons */ df::unit_labor::MASON,
/* Craftsdwarfs */ df::unit_labor::STONE_CRAFT,
/* Jewelers */ df::unit_labor::CUT_GEM,
/* MetalsmithsForge */ df::unit_labor::METAL_CRAFT,
/* MagmaForge */ df::unit_labor::METAL_CRAFT,
/* Bowyers */ df::unit_labor::BOWYER,
/* Mechanics */ df::unit_labor::MECHANIC,
/* Siege */ df::unit_labor::SIEGECRAFT,
/* Butchers */ df::unit_labor::BUTCHER,
/* Leatherworks */ df::unit_labor::LEATHER,
/* Tanners */ df::unit_labor::TANNER,
/* Clothiers */ df::unit_labor::CLOTHESMAKER,
/* Fishery */ df::unit_labor::CLEAN_FISH,
/* Still */ df::unit_labor::BREWER,
/* Loom */ df::unit_labor::WEAVER,
/* Quern */ df::unit_labor::MILLER,
/* Kennels */ df::unit_labor::ANIMALTRAIN,
/* Kitchen */ df::unit_labor::COOK,
/* Ashery */ df::unit_labor::LYE_MAKING,
/* Dyers */ df::unit_labor::DYER,
/* Millstone */ df::unit_labor::MILLER,
/* Custom */ df::unit_labor::NONE,
/* Tool */ df::unit_labor::NONE
};
static df::building* get_building_from_job(df::job* j)
{
for (auto r = j->general_refs.begin(); r != j->general_refs.end(); r++)
{
if ((*r)->getType() == df::general_ref_type::BUILDING_HOLDER)
{
int32_t id = ((df::general_ref_building_holderst*)(*r))->building_id;
df::building* bld = binsearch_in_vector(world->buildings.all, id);
return bld;
}
}
return 0;
}
static df::unit_labor construction_build_labor(df::building_actual* b)
{
if (b->getType() == df::building_type::RoadPaved)
return df::unit_labor::BUILD_ROAD;
// Find last item in building with use mode appropriate to the building's constructions state
// For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block
// For wells 0 mechanism, 1 rope, 2 bucket, 3 block
// Trade depots and bridges use the last one too
// Must check use mode b/c buildings may have items in them that are not part of the building
df::item* i = 0;
for (auto p = b->contained_items.begin(); p != b->contained_items.end(); p++)
if (b->construction_stage > 0 && (*p)->use_mode == 2 ||
b->construction_stage == 0 && (*p)->use_mode == 0)
i = (*p)->item;
MaterialInfo matinfo;
if (i && matinfo.decode(i))
{
if (matinfo.material->flags.is_set(df::material_flags::IS_METAL))
return df::unit_labor::METAL_CRAFT;
if (matinfo.material->flags.is_set(df::material_flags::WOOD))
return df::unit_labor::CARPENTER;
}
return df::unit_labor::MASON;
}
class jlfunc
{
public:
virtual df::unit_labor get_labor(df::job* j) = 0;
};
class jlfunc_const : public jlfunc
{
private:
df::unit_labor labor;
public:
df::unit_labor get_labor(df::job* j)
{
return labor;
}
jlfunc_const(df::unit_labor l) : labor(l) {};
};
class jlfunc_hauling : public jlfunc
{
public:
df::unit_labor get_labor(df::job* j)
{
df::item* item = 0;
if (j->job_type == df::job_type::StoreItemInStockpile && j->item_subtype != -1)
return (df::unit_labor) j->item_subtype;
for (auto i = j->items.begin(); i != j->items.end(); i++)
{
if ((*i)->role == 7)
{
item = (*i)->item;
break;
}
}
if (item && item->flags.bits.container)
{
for (auto a = item->general_refs.begin(); a != item->general_refs.end(); a++)
{
if ((*a)->getType() == df::general_ref_type::CONTAINS_ITEM)
{
int item_id = ((df::general_ref_contains_itemst *) (*a))->item_id;
item = binsearch_in_vector(world->items.all, item_id);
break;
}
}
}
df::unit_labor l = item ? hauling_labor_map[item->getType()] : df::unit_labor::HAUL_ITEM;
if (item && l == df::unit_labor::HAUL_REFUSE && item->flags.bits.dead_dwarf)
l = df::unit_labor::HAUL_BODY;
return l;
}
jlfunc_hauling() {};
};
class jlfunc_construct_bld : public jlfunc
{
public:
df::unit_labor get_labor(df::job* j)
{
if (j->flags.bits.item_lost)
return df::unit_labor::NONE;
df::building* bld = get_building_from_job(j);
switch (bld->getType())
{
case df::building_type::Hive:
return df::unit_labor::BEEKEEPING;
case df::building_type::Workshop:
{
df::building_workshopst* ws = (df::building_workshopst*) bld;
if (ws->design && !ws->design->flags.bits.designed)
return df::unit_labor::ARCHITECT;
if (ws->type == df::workshop_type::Custom)
{
df::building_def* def = df::building_def::find(ws->custom_type);
return def->build_labors[0];
}
else
return workshop_build_labor[ws->type];
}
break;
case df::building_type::Construction:
return df::unit_labor::BUILD_CONSTRUCTION;
case df::building_type::Furnace:
case df::building_type::TradeDepot:
case df::building_type::Bridge:
case df::building_type::ArcheryTarget:
case df::building_type::WaterWheel:
case df::building_type::RoadPaved:
case df::building_type::Well:
case df::building_type::ScrewPump:
case df::building_type::Wagon:
case df::building_type::Shop:
case df::building_type::Support:
case df::building_type::Windmill:
{
df::building_actual* b = (df::building_actual*) bld;
if (b->design && !b->design->flags.bits.designed)
return df::unit_labor::ARCHITECT;
return construction_build_labor(b);
}
break;
case df::building_type::FarmPlot:
return df::unit_labor::PLANT;
case df::building_type::Chair:
case df::building_type::Bed:
case df::building_type::Table:
case df::building_type::Coffin:
case df::building_type::Door:
case df::building_type::Floodgate:
case df::building_type::Box:
case df::building_type::Weaponrack:
case df::building_type::Armorstand:
case df::building_type::Cabinet:
case df::building_type::Statue:
case df::building_type::WindowGlass:
case df::building_type::WindowGem:
case df::building_type::Cage:
case df::building_type::NestBox:
case df::building_type::TractionBench:
case df::building_type::Slab:
case df::building_type::Chain:
case df::building_type::GrateFloor:
case df::building_type::Hatch:
case df::building_type::BarsFloor:
case df::building_type::BarsVertical:
case df::building_type::GrateWall:
case df::building_type::Bookcase:
case df::building_type::Instrument:
return df::unit_labor::HAUL_FURNITURE;
case df::building_type::Trap:
case df::building_type::GearAssembly:
case df::building_type::AxleHorizontal:
case df::building_type::AxleVertical:
case df::building_type::Rollers:
return df::unit_labor::MECHANIC;
case df::building_type::AnimalTrap:
return df::unit_labor::TRAPPER;
case df::building_type::Civzone:
case df::building_type::Nest:
case df::building_type::Stockpile:
case df::building_type::Weapon:
return df::unit_labor::NONE;
case df::building_type::SiegeEngine:
return df::unit_labor::SIEGECRAFT;
case df::building_type::RoadDirt:
return df::unit_labor::BUILD_ROAD;
}
debug("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n",
ENUM_KEY_STR(building_type, bld->getType()).c_str());
debug_pause();
return df::unit_labor::NONE;
}
jlfunc_construct_bld() {}
};
class jlfunc_destroy_bld : public jlfunc
{
public:
df::unit_labor get_labor(df::job* j)
{
df::building* bld = get_building_from_job(j);
df::building_type type = bld->getType();
switch (bld->getType())
{
case df::building_type::Hive:
return df::unit_labor::BEEKEEPING;
case df::building_type::Workshop:
{
df::building_workshopst* ws = (df::building_workshopst*) bld;
if (ws->type == df::workshop_type::Custom)
{
df::building_def* def = df::building_def::find(ws->custom_type);
return def->build_labors[0];
}
else
return workshop_build_labor[ws->type];
}
break;
case df::building_type::Construction:
return df::unit_labor::REMOVE_CONSTRUCTION;
case df::building_type::Furnace:
case df::building_type::TradeDepot:
case df::building_type::Wagon:
case df::building_type::Bridge:
case df::building_type::ScrewPump:
case df::building_type::ArcheryTarget:
case df::building_type::RoadPaved:
case df::building_type::Shop:
case df::building_type::Support:
case df::building_type::WaterWheel:
case df::building_type::Well:
case df::building_type::Windmill:
{
auto b = (df::building_actual*) bld;
return construction_build_labor(b);
}
break;
case df::building_type::FarmPlot:
return df::unit_labor::PLANT;
case df::building_type::Trap:
case df::building_type::AxleHorizontal:
case df::building_type::AxleVertical:
case df::building_type::GearAssembly:
case df::building_type::Rollers:
return df::unit_labor::MECHANIC;
case df::building_type::Chair:
case df::building_type::Bed:
case df::building_type::Table:
case df::building_type::Coffin:
case df::building_type::Door:
case df::building_type::Floodgate:
case df::building_type::Box:
case df::building_type::Weaponrack:
case df::building_type::Armorstand:
case df::building_type::Cabinet:
case df::building_type::Statue:
case df::building_type::WindowGlass:
case df::building_type::WindowGem:
case df::building_type::Cage:
case df::building_type::NestBox:
case df::building_type::TractionBench:
case df::building_type::Slab:
case df::building_type::Chain:
case df::building_type::Hatch:
case df::building_type::BarsFloor:
case df::building_type::BarsVertical:
case df::building_type::GrateFloor:
case df::building_type::GrateWall:
case df::building_type::Bookcase:
case df::building_type::Instrument:
return df::unit_labor::HAUL_FURNITURE;
case df::building_type::AnimalTrap:
return df::unit_labor::TRAPPER;
case df::building_type::Civzone:
case df::building_type::Nest:
case df::building_type::RoadDirt:
case df::building_type::Stockpile:
case df::building_type::Weapon:
return df::unit_labor::NONE;
case df::building_type::SiegeEngine:
return df::unit_labor::SIEGECRAFT;
}
debug("LABORMANAGER: Cannot deduce labor for destroy building job of type %s\n",
ENUM_KEY_STR(building_type, bld->getType()).c_str());
debug_pause();
return df::unit_labor::NONE;
}
jlfunc_destroy_bld() {}
};
class jlfunc_make : public jlfunc
{
private:
df::unit_labor metaltype;
public:
df::unit_labor get_labor(df::job* j)
{
df::building* bld = get_building_from_job(j);
if (bld->getType() == df::building_type::Workshop)
{
df::workshop_type type = ((df::building_workshopst*)(bld))->type;
switch (type)
{
case df::workshop_type::Craftsdwarfs:
{
df::item_type jobitem = j->job_items[0]->item_type;
switch (jobitem)
{
case df::item_type::BOULDER:
return df::unit_labor::STONE_CRAFT;
case df::item_type::NONE:
if (j->material_category.bits.bone ||
j->material_category.bits.horn ||
j->material_category.bits.tooth ||
j->material_category.bits.shell)
return df::unit_labor::BONE_CARVE;
else
{
debug("LABORMANAGER: Cannot deduce labor for make crafts job (not bone)\n");
debug_pause();
return df::unit_labor::NONE;
}
case df::item_type::WOOD:
return df::unit_labor::WOOD_CRAFT;
case df::item_type::CLOTH:
return df::unit_labor::CLOTHESMAKER;
case df::item_type::SKIN_TANNED:
return df::unit_labor::LEATHER;
default:
debug("LABORMANAGER: Cannot deduce labor for make crafts job, item type %s\n",
ENUM_KEY_STR(item_type, jobitem).c_str());
debug_pause();
return df::unit_labor::NONE;
}
}
case df::workshop_type::Masons:
return df::unit_labor::MASON;
case df::workshop_type::Carpenters:
return df::unit_labor::CARPENTER;
case df::workshop_type::Leatherworks:
return df::unit_labor::LEATHER;
case df::workshop_type::Clothiers:
return df::unit_labor::CLOTHESMAKER;
case df::workshop_type::Bowyers:
return df::unit_labor::BOWYER;
case df::workshop_type::MagmaForge:
case df::workshop_type::MetalsmithsForge:
return metaltype;
default:
debug("LABORMANAGER: Cannot deduce labor for make job, workshop type %s\n",
ENUM_KEY_STR(workshop_type, type).c_str());
debug_pause();
return df::unit_labor::NONE;
}
}
else if (bld->getType() == df::building_type::Furnace)
{
df::furnace_type type = ((df::building_furnacest*)(bld))->type;
switch (type)
{
case df::furnace_type::MagmaGlassFurnace:
case df::furnace_type::GlassFurnace:
return df::unit_labor::GLASSMAKER;
default:
debug("LABORMANAGER: Cannot deduce labor for make job, furnace type %s\n",
ENUM_KEY_STR(furnace_type, type).c_str());
debug_pause();
return df::unit_labor::NONE;
}
}
debug("LABORMANAGER: Cannot deduce labor for make job, building type %s\n",
ENUM_KEY_STR(building_type, bld->getType()).c_str());
debug_pause();
return df::unit_labor::NONE;
}
jlfunc_make(df::unit_labor mt) : metaltype(mt) {}
};
class jlfunc_custom : public jlfunc
{
public:
df::unit_labor get_labor(df::job* j)
{
for (auto r = world->raws.reactions.begin(); r != world->raws.reactions.end(); r++)
{
if ((*r)->code == j->reaction_name)
{
df::job_skill skill = (*r)->skill;
df::unit_labor labor = ENUM_ATTR(job_skill, labor, skill);
return labor;
}
}
return df::unit_labor::NONE;
}
jlfunc_custom() {}
};
jlfunc* JobLaborMapper::jlf_const(df::unit_labor l) {
jlfunc* jlf;
if (jlf_cache.count(l) == 0)
{
jlf = new jlfunc_const(l);
jlf_cache[l] = jlf;
}
else
jlf = jlf_cache[l];
return jlf;
}
JobLaborMapper::~JobLaborMapper()
{
std::set<jlfunc*> log;
for (auto i = jlf_cache.begin(); i != jlf_cache.end(); i++)
{
if (!log.count(i->second))
{
log.insert(i->second);
delete i->second;
}
i->second = 0;
}
FOR_ENUM_ITEMS(job_type, j)
{
if (j < 0)
continue;
jlfunc* p = job_to_labor_table[j];
if (!log.count(p))
{
log.insert(p);
delete p;
}
job_to_labor_table[j] = 0;
}
}
JobLaborMapper::JobLaborMapper()
{
jlfunc* jlf_hauling = new jlfunc_hauling();
jlfunc* jlf_make_furniture = new jlfunc_make(df::unit_labor::FORGE_FURNITURE);
jlfunc* jlf_make_object = new jlfunc_make(df::unit_labor::METAL_CRAFT);
jlfunc* jlf_make_armor = new jlfunc_make(df::unit_labor::FORGE_ARMOR);
jlfunc* jlf_make_weapon = new jlfunc_make(df::unit_labor::FORGE_WEAPON);
jlfunc* jlf_no_labor = jlf_const(df::unit_labor::NONE);
job_to_labor_table[df::job_type::CarveFortification] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::DetailWall] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::DetailFloor] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::Dig] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveUpwardStaircase] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveDownwardStaircase] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveUpDownStaircase] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::CarveRamp] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::DigChannel] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::FellTree] = jlf_const(df::unit_labor::CUTWOOD);
job_to_labor_table[df::job_type::GatherPlants] = jlf_const(df::unit_labor::HERBALIST);
job_to_labor_table[df::job_type::RemoveConstruction] = jlf_const(df::unit_labor::REMOVE_CONSTRUCTION);
job_to_labor_table[df::job_type::CollectWebs] = jlf_const(df::unit_labor::WEAVER);
job_to_labor_table[df::job_type::BringItemToDepot] = jlf_const(df::unit_labor::HAUL_TRADE);
job_to_labor_table[df::job_type::BringItemToShop] = jlf_no_labor;
job_to_labor_table[df::job_type::Eat] = jlf_no_labor;
job_to_labor_table[df::job_type::GetProvisions] = jlf_no_labor;
job_to_labor_table[df::job_type::Drink] = jlf_no_labor;
job_to_labor_table[df::job_type::Drink2] = jlf_no_labor;
job_to_labor_table[df::job_type::FillWaterskin] = jlf_no_labor;
job_to_labor_table[df::job_type::FillWaterskin2] = jlf_no_labor;
job_to_labor_table[df::job_type::Sleep] = jlf_no_labor;
job_to_labor_table[df::job_type::CollectSand] = jlf_const(df::unit_labor::HAUL_ITEM);
job_to_labor_table[df::job_type::Fish] = jlf_const(df::unit_labor::FISH);
job_to_labor_table[df::job_type::Hunt] = jlf_const(df::unit_labor::HUNT);
job_to_labor_table[df::job_type::HuntVermin] = jlf_no_labor;
job_to_labor_table[df::job_type::Kidnap] = jlf_no_labor;
job_to_labor_table[df::job_type::BeatCriminal] = jlf_no_labor;
job_to_labor_table[df::job_type::StartingFistFight] = jlf_no_labor;
job_to_labor_table[df::job_type::CollectTaxes] = jlf_no_labor;
job_to_labor_table[df::job_type::GuardTaxCollector] = jlf_no_labor;
job_to_labor_table[df::job_type::CatchLiveLandAnimal] = jlf_const(df::unit_labor::HUNT);
job_to_labor_table[df::job_type::CatchLiveFish] = jlf_const(df::unit_labor::FISH);
job_to_labor_table[df::job_type::ReturnKill] = jlf_no_labor;
job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor;
job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor;
job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY);
job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling;
job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling;
job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling;
job_to_labor_table[df::job_type::StoreItemInBin] = jlf_hauling;
job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor;
job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor;
job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor;
job_to_labor_table[df::job_type::GoShopping] = jlf_no_labor;
job_to_labor_table[df::job_type::GoShopping2] = jlf_no_labor;
job_to_labor_table[df::job_type::Clean] = jlf_const(df::unit_labor::CLEAN);
job_to_labor_table[df::job_type::Rest] = jlf_no_labor;
job_to_labor_table[df::job_type::PickupEquipment] = jlf_no_labor;
job_to_labor_table[df::job_type::DumpItem] = jlf_const(df::unit_labor::HAUL_REFUSE);
job_to_labor_table[df::job_type::StrangeMoodCrafter] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodJeweller] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodForge] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodMagmaForge] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodBrooding] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodFell] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodCarpenter] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodMason] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodBowyer] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodTanner] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodWeaver] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodGlassmaker] = jlf_no_labor;
job_to_labor_table[df::job_type::StrangeMoodMechanics] = jlf_no_labor;
job_to_labor_table[df::job_type::ConstructBuilding] = new jlfunc_construct_bld();
job_to_labor_table[df::job_type::ConstructDoor] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructFloodgate] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructBed] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructThrone] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCoffin] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructTable] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructChest] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructBin] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructArmorStand] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructWeaponRack] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCabinet] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructStatue] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructBlocks] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeRawGlass] = jlf_const(df::unit_labor::GLASSMAKER);
job_to_labor_table[df::job_type::MakeCrafts] = jlf_make_object; job_to_labor_table[df::job_type::MintCoins] = jlf_const(df::unit_labor::METAL_CRAFT);
job_to_labor_table[df::job_type::CutGems] = jlf_const(df::unit_labor::CUT_GEM);
job_to_labor_table[df::job_type::CutGlass] = jlf_const(df::unit_labor::CUT_GEM);
job_to_labor_table[df::job_type::EncrustWithGems] = jlf_const(df::unit_labor::ENCRUST_GEM);
job_to_labor_table[df::job_type::EncrustWithGlass] = jlf_const(df::unit_labor::ENCRUST_GEM);
job_to_labor_table[df::job_type::DestroyBuilding] = new jlfunc_destroy_bld();
job_to_labor_table[df::job_type::SmeltOre] = jlf_const(df::unit_labor::SMELT);
job_to_labor_table[df::job_type::MeltMetalObject] = jlf_const(df::unit_labor::SMELT);
job_to_labor_table[df::job_type::ExtractMetalStrands] = jlf_const(df::unit_labor::EXTRACT_STRAND);
job_to_labor_table[df::job_type::PlantSeeds] = jlf_const(df::unit_labor::PLANT);
job_to_labor_table[df::job_type::HarvestPlants] = jlf_const(df::unit_labor::PLANT);
job_to_labor_table[df::job_type::TrainHuntingAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::TrainWarAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::MakeWeapon] = jlf_make_weapon;
job_to_labor_table[df::job_type::ForgeAnvil] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCatapultParts] = jlf_const(df::unit_labor::SIEGECRAFT);
job_to_labor_table[df::job_type::ConstructBallistaParts] = jlf_const(df::unit_labor::SIEGECRAFT);
job_to_labor_table[df::job_type::MakeArmor] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeHelm] = jlf_make_armor;
job_to_labor_table[df::job_type::MakePants] = jlf_make_armor;
job_to_labor_table[df::job_type::StudWith] = jlf_make_object;
job_to_labor_table[df::job_type::ButcherAnimal] = jlf_const(df::unit_labor::BUTCHER);
job_to_labor_table[df::job_type::PrepareRawFish] = jlf_const(df::unit_labor::CLEAN_FISH);
job_to_labor_table[df::job_type::MillPlants] = jlf_const(df::unit_labor::MILLER);
job_to_labor_table[df::job_type::BaitTrap] = jlf_const(df::unit_labor::TRAPPER);
job_to_labor_table[df::job_type::MilkCreature] = jlf_const(df::unit_labor::MILK);
job_to_labor_table[df::job_type::MakeCheese] = jlf_const(df::unit_labor::MAKE_CHEESE);
job_to_labor_table[df::job_type::ProcessPlants] = jlf_const(df::unit_labor::PROCESS_PLANT);
job_to_labor_table[df::job_type::ProcessPlantsVial] = jlf_const(df::unit_labor::PROCESS_PLANT);
job_to_labor_table[df::job_type::ProcessPlantsBarrel] = jlf_const(df::unit_labor::PROCESS_PLANT);
job_to_labor_table[df::job_type::PrepareMeal] = jlf_const(df::unit_labor::COOK);
job_to_labor_table[df::job_type::WeaveCloth] = jlf_const(df::unit_labor::WEAVER);
job_to_labor_table[df::job_type::MakeGloves] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeShoes] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeShield] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeCage] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeChain] = jlf_make_object;
job_to_labor_table[df::job_type::MakeFlask] = jlf_make_object;
job_to_labor_table[df::job_type::MakeGoblet] = jlf_make_object;
job_to_labor_table[df::job_type::MakeToy] = jlf_make_object;
job_to_labor_table[df::job_type::MakeAnimalTrap] = jlf_const(df::unit_labor::TRAPPER);
job_to_labor_table[df::job_type::MakeBarrel] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeBucket] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeWindow] = jlf_make_furniture;
job_to_labor_table[df::job_type::MakeTotem] = jlf_const(df::unit_labor::BONE_CARVE);
job_to_labor_table[df::job_type::MakeAmmo] = jlf_make_weapon;
job_to_labor_table[df::job_type::DecorateWith] = jlf_make_object;
job_to_labor_table[df::job_type::MakeBackpack] = jlf_make_object;
job_to_labor_table[df::job_type::MakeQuiver] = jlf_make_armor;
job_to_labor_table[df::job_type::MakeBallistaArrowHead] = jlf_make_weapon;
job_to_labor_table[df::job_type::AssembleSiegeAmmo] = jlf_const(df::unit_labor::SIEGECRAFT);
job_to_labor_table[df::job_type::LoadCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::LoadBallista] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::FireCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::FireBallista] = jlf_const(df::unit_labor::SIEGEOPERATE);
job_to_labor_table[df::job_type::ConstructMechanisms] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::MakeTrapComponent] = jlf_make_weapon;
job_to_labor_table[df::job_type::LoadCageTrap] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::LoadStoneTrap] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::LoadWeaponTrap] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::CleanTrap] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::CastSpell] = jlf_no_labor;
job_to_labor_table[df::job_type::LinkBuildingToTrigger] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::PullLever] = jlf_const(df::unit_labor::PULL_LEVER);
job_to_labor_table[df::job_type::ExtractFromPlants] = jlf_const(df::unit_labor::HERBALIST);
job_to_labor_table[df::job_type::ExtractFromRawFish] = jlf_const(df::unit_labor::DISSECT_FISH);
job_to_labor_table[df::job_type::ExtractFromLandAnimal] = jlf_const(df::unit_labor::DISSECT_VERMIN);
job_to_labor_table[df::job_type::TameVermin] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::TameAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::ChainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS);
job_to_labor_table[df::job_type::UnchainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS);
job_to_labor_table[df::job_type::UnchainPet] = jlf_no_labor;
job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS);
job_to_labor_table[df::job_type::ReleasePet] = jlf_no_labor;
job_to_labor_table[df::job_type::ReleaseSmallCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::HandleSmallCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS);
job_to_labor_table[df::job_type::CageLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS);
job_to_labor_table[df::job_type::CageSmallCreature] = jlf_no_labor;
job_to_labor_table[df::job_type::RecoverWounded] = jlf_const(df::unit_labor::RECOVER_WOUNDED);
job_to_labor_table[df::job_type::DiagnosePatient] = jlf_const(df::unit_labor::DIAGNOSE);
job_to_labor_table[df::job_type::ImmobilizeBreak] = jlf_const(df::unit_labor::BONE_SETTING);
job_to_labor_table[df::job_type::DressWound] = jlf_const(df::unit_labor::DRESSING_WOUNDS);
job_to_labor_table[df::job_type::CleanPatient] = jlf_const(df::unit_labor::DRESSING_WOUNDS);
job_to_labor_table[df::job_type::Surgery] = jlf_const(df::unit_labor::SURGERY);
job_to_labor_table[df::job_type::Suture] = jlf_const(df::unit_labor::SUTURING);
job_to_labor_table[df::job_type::SetBone] = jlf_const(df::unit_labor::BONE_SETTING);
job_to_labor_table[df::job_type::PlaceInTraction] = jlf_const(df::unit_labor::BONE_SETTING);
job_to_labor_table[df::job_type::DrainAquarium] = jlf_no_labor;
job_to_labor_table[df::job_type::FillAquarium] = jlf_no_labor;
job_to_labor_table[df::job_type::FillPond] = jlf_no_labor;
job_to_labor_table[df::job_type::GiveWater] = jlf_const(df::unit_labor::FEED_WATER_CIVILIANS);
job_to_labor_table[df::job_type::GiveFood] = jlf_const(df::unit_labor::FEED_WATER_CIVILIANS);
job_to_labor_table[df::job_type::GiveWater2] = jlf_no_labor;
job_to_labor_table[df::job_type::GiveFood2] = jlf_no_labor;
job_to_labor_table[df::job_type::RecoverPet] = jlf_no_labor;
job_to_labor_table[df::job_type::PitLargeAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS);
job_to_labor_table[df::job_type::PitSmallAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::SlaughterAnimal] = jlf_const(df::unit_labor::BUTCHER);
job_to_labor_table[df::job_type::MakeCharcoal] = jlf_const(df::unit_labor::BURN_WOOD);
job_to_labor_table[df::job_type::MakeAsh] = jlf_const(df::unit_labor::BURN_WOOD);
job_to_labor_table[df::job_type::MakeLye] = jlf_const(df::unit_labor::LYE_MAKING);
job_to_labor_table[df::job_type::MakePotashFromLye] = jlf_const(df::unit_labor::POTASH_MAKING);
job_to_labor_table[df::job_type::FertilizeField] = jlf_const(df::unit_labor::PLANT);
job_to_labor_table[df::job_type::MakePotashFromAsh] = jlf_const(df::unit_labor::POTASH_MAKING);
job_to_labor_table[df::job_type::DyeThread] = jlf_const(df::unit_labor::DYER);
job_to_labor_table[df::job_type::DyeCloth] = jlf_const(df::unit_labor::DYER);
job_to_labor_table[df::job_type::SewImage] = jlf_make_object;
job_to_labor_table[df::job_type::MakePipeSection] = jlf_make_furniture;
job_to_labor_table[df::job_type::OperatePump] = jlf_const(df::unit_labor::OPERATE_PUMP);
job_to_labor_table[df::job_type::ManageWorkOrders] = jlf_no_labor;
job_to_labor_table[df::job_type::UpdateStockpileRecords] = jlf_no_labor;
job_to_labor_table[df::job_type::TradeAtDepot] = jlf_no_labor;
job_to_labor_table[df::job_type::ConstructHatchCover] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructGrate] = jlf_make_furniture;
job_to_labor_table[df::job_type::RemoveStairs] = jlf_const(df::unit_labor::MINE);
job_to_labor_table[df::job_type::ConstructQuern] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructMillstone] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructSplint] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructCrutch] = jlf_make_furniture;
job_to_labor_table[df::job_type::ConstructTractionBench] = jlf_const(df::unit_labor::MECHANIC);
job_to_labor_table[df::job_type::CleanSelf] = jlf_no_labor;
job_to_labor_table[df::job_type::BringCrutch] = jlf_const(df::unit_labor::BONE_SETTING);
job_to_labor_table[df::job_type::ApplyCast] = jlf_const(df::unit_labor::BONE_SETTING);
job_to_labor_table[df::job_type::CustomReaction] = new jlfunc_custom();
job_to_labor_table[df::job_type::ConstructSlab] = jlf_make_furniture;
job_to_labor_table[df::job_type::EngraveSlab] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::ShearCreature] = jlf_const(df::unit_labor::SHEARER);
job_to_labor_table[df::job_type::SpinThread] = jlf_const(df::unit_labor::SPINNER);
job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS);
job_to_labor_table[df::job_type::PenSmallAnimal] = jlf_no_labor;
job_to_labor_table[df::job_type::MakeTool] = jlf_make_object;
job_to_labor_table[df::job_type::CollectClay] = jlf_const(df::unit_labor::POTTERY);
job_to_labor_table[df::job_type::InstallColonyInHive] = jlf_const(df::unit_labor::BEEKEEPING);
job_to_labor_table[df::job_type::CollectHiveProducts] = jlf_const(df::unit_labor::BEEKEEPING);
job_to_labor_table[df::job_type::CauseTrouble] = jlf_no_labor;
job_to_labor_table[df::job_type::DrinkBlood] = jlf_no_labor;
job_to_labor_table[df::job_type::ReportCrime] = jlf_no_labor;
job_to_labor_table[df::job_type::ExecuteCriminal] = jlf_no_labor;
job_to_labor_table[df::job_type::TrainAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN);
job_to_labor_table[df::job_type::CarveTrack] = jlf_const(df::unit_labor::DETAIL);
job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES);
job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES);
job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_hauling;
job_to_labor_table[df::job_type::GeldAnimal] = jlf_const(df::unit_labor::GELD);
job_to_labor_table[df::job_type::MakeFigurine] = jlf_make_object;
job_to_labor_table[df::job_type::MakeAmulet] = jlf_make_object;
job_to_labor_table[df::job_type::MakeScepter] = jlf_make_object;
job_to_labor_table[df::job_type::MakeCrown] = jlf_make_object;
job_to_labor_table[df::job_type::MakeRing] = jlf_make_object;
job_to_labor_table[df::job_type::MakeEarring] = jlf_make_object;
job_to_labor_table[df::job_type::MakeBracelet] = jlf_make_object;
job_to_labor_table[df::job_type::MakeGem] = jlf_make_object;
job_to_labor_table[df::job_type::StoreItemInLocation] = jlf_no_labor; // StoreItemInLocation
};
df::unit_labor JobLaborMapper::find_job_labor(df::job* j)
{
if (j->job_type == df::job_type::CustomReaction)
{
for (auto r = world->raws.reactions.begin(); r != world->raws.reactions.end(); r++)
{
if ((*r)->code == j->reaction_name)
{
df::job_skill skill = (*r)->skill;
return ENUM_ATTR(job_skill, labor, skill);
}
}
return df::unit_labor::NONE;
}
df::unit_labor labor;
if (job_to_labor_table.count(j->job_type) == 0)
{
debug("LABORMANAGER: job has no job to labor table entry: %s (%d)\n", ENUM_KEY_STR(job_type, j->job_type).c_str(), j->job_type);
debug_pause();
labor = df::unit_labor::NONE;
}
else {
labor = job_to_labor_table[j->job_type]->get_labor(j);
}
return labor;
}
/* End of labor deducer */

@ -0,0 +1,32 @@
#pragma once
#include <map>
#include <Core.h>
using namespace DFHack;
using namespace df::enums;
#include "df/job.h"
#include "df/job_type.h"
#include "df/unit_labor.h"
class jlfunc;
class JobLaborMapper {
private:
std::map<df::job_type, jlfunc*> job_to_labor_table;
std::map<df::unit_labor, jlfunc*> jlf_cache;
jlfunc* jlf_const(df::unit_labor l);
public:
~JobLaborMapper();
JobLaborMapper();
df::unit_labor find_job_labor(df::job* j);
};

@ -0,0 +1,4 @@
#pragma once
void debug(const char* fmt, ...);
void debug_pause();

@ -70,7 +70,7 @@ public:
display_max_rows = gps->dimy - 4 - bottom_margin; display_max_rows = gps->dimy - 4 - bottom_margin;
} }
void add(ListEntry<T> &entry) void add(const ListEntry<T> &entry)
{ {
list.push_back(entry); list.push_back(entry);
if (entry.text.length() > max_item_width) if (entry.text.length() > max_item_width)

@ -47,7 +47,7 @@ function client:receive( pattern )
local pattern=pattern or "*l" local pattern=pattern or "*l"
local bytes=-1 local bytes=-1
if type(pattern)== number then if type(pattern)== 'number' then
bytes=pattern bytes=pattern
end end

@ -146,15 +146,22 @@ static void json_array_to_bitfield(B & bits, Json::Value & arr)
return; return;
} }
for (Json::ArrayIndex i = arr.size() - 1; i != 0; i--) for (Json::ArrayIndex i = arr.size(); i != 0; i--)
{ {
if (!arr[i - 1].isString())
{
continue;
}
std::string str(arr[i - 1].asString());
int current; int current;
if (get_bitfield_field(&current, bits, arr[i].asString())) if (get_bitfield_field(&current, bits, str))
{ {
if (!current && set_bitfield_field(&bits, arr[i].asString(), 1)) if (!current && set_bitfield_field(&bits, str, 1))
{ {
Json::Value removed; Json::Value removed;
arr.removeIndex(i, &removed); arr.removeIndex(i - 1, &removed);
} }
} }
} }

@ -721,7 +721,7 @@ command_result prospector (color_ostream &con, vector <string> & parameters)
} }
if (showSlade && blockFeatureGlobal.type != -1 && des.bits.feature_global if (showSlade && blockFeatureGlobal.type != -1 && des.bits.feature_global
&& blockFeatureGlobal.type == feature_type::feature_underworld_from_layer && blockFeatureGlobal.type == feature_type::underworld_from_layer
&& blockFeatureGlobal.main_material == 0) // stone && blockFeatureGlobal.main_material == 0) // stone
{ {
layerMats[blockFeatureGlobal.sub_material].add(global_z); layerMats[blockFeatureGlobal.sub_material].add(global_z);

@ -118,6 +118,49 @@ enum TileDigDesignation
UP_STAIR_DIG = 6; UP_STAIR_DIG = 6;
} }
enum HairStyle
{
UNKEMPT = -1;
NEATLY_COMBED = 0;
BRAIDED = 1;
DOUBLE_BRAID = 2;
PONY_TAILS = 3;
CLEAN_SHAVEN = 4;
}
enum InventoryMode
{
Hauled = 0;
/**
* also shield, crutch
*/
Weapon = 1;
/**
* quiver
*/
Worn = 2;
Piercing = 3;
/**
* attached to clothing
*/
Flask = 4;
/**
* e.g. bandage
*/
WrappedAround = 5;
StuckIn = 6;
/**
* string descr like Worn
*/
InMouth = 7;
/**
* Left shoulder, right shoulder, or head, selected randomly using pet_seed
*/
Pet = 8;
SewnInto = 9;
Strapped = 10;
}
message Coord message Coord
{ {
optional int32 x = 1; optional int32 x = 1;
@ -256,6 +299,7 @@ message MapBlock
repeated Item items = 26; repeated Item items = 26;
repeated bool tile_dig_designation_marker = 27; repeated bool tile_dig_designation_marker = 27;
repeated bool tile_dig_designation_auto = 28; repeated bool tile_dig_designation_auto = 28;
repeated int32 grass_percent = 29;
} }
message MatPair { message MatPair {
@ -297,6 +341,12 @@ message MaterialList{
repeated MaterialDefinition material_list = 1; repeated MaterialDefinition material_list = 1;
} }
message Hair
{
optional int32 length = 1;
optional HairStyle style = 2;
}
message BodySizeInfo message BodySizeInfo
{ {
optional int32 size_cur = 1; optional int32 size_cur = 1;
@ -313,6 +363,16 @@ message UnitAppearance
repeated int32 bp_modifiers = 2; repeated int32 bp_modifiers = 2;
optional int32 size_modifier = 3; optional int32 size_modifier = 3;
repeated int32 colors = 4; repeated int32 colors = 4;
optional Hair hair = 5;
optional Hair beard = 6;
optional Hair moustache = 7;
optional Hair sideburns = 8;
}
message InventoryItem
{
optional InventoryMode mode = 1;
optional Item item = 2;
} }
message UnitDefinition message UnitDefinition
@ -335,6 +395,8 @@ message UnitDefinition
optional UnitAppearance appearance = 16; optional UnitAppearance appearance = 16;
optional int32 profession_id = 17; optional int32 profession_id = 17;
repeated string noble_positions = 18; repeated string noble_positions = 18;
optional int32 rider_id = 19;
repeated InventoryItem inventory = 20;
} }
message UnitList message UnitList

@ -287,7 +287,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * remote_build) void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * remote_build)
{ {
df::building * local_build = df::global::world->buildings.all[buildingIndex]; df::building * local_build = df::global::world->buildings.all[buildingIndex];
remote_build->set_index(buildingIndex); remote_build->set_index(local_build->id);
int minZ = local_build->z; int minZ = local_build->z;
if (local_build->getType() == df::enums::building_type::Well) if (local_build->getType() == df::enums::building_type::Well)
{ {

@ -1,5 +1,5 @@
#include "df_version_int.h" #include "df_version_int.h"
#define RFR_VERSION "0.17.0" #define RFR_VERSION "0.18.0"
#include <cstdio> #include <cstdio>
#include <time.h> #include <time.h>
@ -34,6 +34,7 @@
#include "df/army.h" #include "df/army.h"
#include "df/army_flags.h" #include "df/army_flags.h"
#include "df/block_square_event_item_spatterst.h" #include "df/block_square_event_item_spatterst.h"
#include "df/block_square_event_grassst.h"
#endif #endif
#include "df/block_square_event_material_spatterst.h" #include "df/block_square_event_material_spatterst.h"
#include "df/body_appearance_modifier.h" #include "df/body_appearance_modifier.h"
@ -82,8 +83,10 @@
#include "df/site_realization_building_info_trenchesst.h" #include "df/site_realization_building_info_trenchesst.h"
#endif #endif
#include "df/tissue.h" #include "df/tissue.h"
#include "df/tissue_style_raw.h"
#include "df/ui.h" #include "df/ui.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/unit_inventory_item.h"
#include "df/viewscreen_choose_start_sitest.h" #include "df/viewscreen_choose_start_sitest.h"
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h" #include "df/world_data.h"
@ -104,6 +107,8 @@
#include "df/plant_tree_tile.h" #include "df/plant_tree_tile.h"
#endif #endif
#include "df/unit_relationship_type.h"
#include "building_reader.h" #include "building_reader.h"
using namespace DFHack; using namespace DFHack;
@ -1122,9 +1127,9 @@ void CopyDesignation(df::map_block * DfBlock, RemoteFortressReader::MapBlock * N
} }
} }
#if DF_VERSION_INT > 34011 #if DF_VERSION_INT > 34011
for (int i = 0; i < world->job_postings.size(); i++) for (int i = 0; i < world->jobs.postings.size(); i++)
{ {
auto job = world->job_postings[i]->job; auto job = world->jobs.postings[i]->job;
if (job == nullptr) if (job == nullptr)
continue; continue;
if ( if (
@ -1179,7 +1184,11 @@ void CopyBuildings(DFCoord min, DFCoord max, RemoteFortressReader::MapBlock * Ne
{ {
df::building * bld = df::global::world->buildings.all[i]; df::building * bld = df::global::world->buildings.all[i];
if (bld->x1 >= max.x || bld->y1 >= max.y || bld->x2 < min.x || bld->y2 < min.y) if (bld->x1 >= max.x || bld->y1 >= max.y || bld->x2 < min.x || bld->y2 < min.y)
{
auto out_bld = NetBlock->add_buildings();
out_bld->set_index(bld->id);
continue; continue;
}
int z2 = bld->z; int z2 = bld->z;
@ -1192,7 +1201,11 @@ void CopyBuildings(DFCoord min, DFCoord max, RemoteFortressReader::MapBlock * Ne
} }
} }
if (bld->z < min.z || z2 >= max.z) if (bld->z < min.z || z2 >= max.z)
{
auto out_bld = NetBlock->add_buildings();
out_bld->set_index(bld->id);
continue; continue;
}
auto out_bld = NetBlock->add_buildings(); auto out_bld = NetBlock->add_buildings();
CopyBuilding(i, out_bld); CopyBuilding(i, out_bld);
df::building_actual* actualBuilding = virtual_cast<df::building_actual>(bld); df::building_actual* actualBuilding = virtual_cast<df::building_actual>(bld);
@ -1216,7 +1229,8 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB
std::vector<df::block_square_event_material_spatterst *> materials; std::vector<df::block_square_event_material_spatterst *> materials;
#if DF_VERSION_INT > 34011 #if DF_VERSION_INT > 34011
std::vector<df::block_square_event_item_spatterst *> items; std::vector<df::block_square_event_item_spatterst *> items;
if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL, NULL, &items)) std::vector<df::block_square_event_grassst *> grasses;
if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, &grasses, NULL, NULL, &items))
return; return;
#else #else
if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL)) if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL))
@ -1249,6 +1263,14 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB
send_item->set_mat_type(item->item_type); send_item->set_mat_type(item->item_type);
send_item->set_mat_index(item->item_subtype); send_item->set_mat_index(item->item_subtype);
} }
int grassPercent = 0;
for (int i = 0; i < grasses.size(); i++)
{
auto grass = grasses[i];
if (grass->amount[xx][yy] > grassPercent)
grassPercent = grass->amount[xx][yy];
}
NetBlock->add_grass_percent(grassPercent);
#endif #endif
} }
} }
@ -1556,6 +1578,52 @@ static command_result GetUnitList(color_ostream &stream, const EmptyMessage *in,
send_unit->add_noble_positions(noble_positon.position->code); send_unit->add_noble_positions(noble_positon.position->code);
} }
} }
send_unit->set_rider_id(unit->relationship_ids[df::unit_relationship_type::RiderMount]);
auto creatureRaw = world->raws.creatures.all[unit->race];
auto casteRaw = creatureRaw->caste[unit->caste];
for (int j = 0; j < unit->appearance.tissue_style_type.size(); j++)
{
auto type = unit->appearance.tissue_style_type[j];
if (type < 0)
continue;
int style_raw_index = binsearch_index(casteRaw->tissue_styles, &df::tissue_style_raw::id, type);
auto styleRaw = casteRaw->tissue_styles[style_raw_index];
if (styleRaw->token == "HAIR")
{
auto send_style = appearance->mutable_hair();
send_style->set_length(unit->appearance.tissue_length[j]);
send_style->set_style((HairStyle)unit->appearance.tissue_style[j]);
}
else if (styleRaw->token == "BEARD")
{
auto send_style = appearance->mutable_beard();
send_style->set_length(unit->appearance.tissue_length[j]);
send_style->set_style((HairStyle)unit->appearance.tissue_style[j]);
}
else if (styleRaw->token == "MOUSTACHE")
{
auto send_style = appearance->mutable_moustache();
send_style->set_length(unit->appearance.tissue_length[j]);
send_style->set_style((HairStyle)unit->appearance.tissue_style[j]);
}
else if (styleRaw->token == "SIDEBURNS")
{
auto send_style = appearance->mutable_sideburns();
send_style->set_length(unit->appearance.tissue_length[j]);
send_style->set_style((HairStyle)unit->appearance.tissue_style[j]);
}
}
for (int j = 0; j < unit->inventory.size(); j++)
{
auto inventory_item = unit->inventory[j];
auto sent_item = send_unit->add_inventory();
sent_item->set_mode((InventoryMode)inventory_item->mode);
CopyItem(sent_item->mutable_item(), inventory_item->item);
}
} }
return CR_OK; return CR_OK;
} }
@ -2670,7 +2738,7 @@ static command_result SendDigCommand(color_ostream &stream, const DigCommand *in
#if DF_VERSION_INT >= 43005 #if DF_VERSION_INT >= 43005
//remove and job postings related. //remove and job postings related.
for (df::job_list_link * listing = &(world->job_list); listing != NULL; listing = listing->next) for (df::job_list_link * listing = &(world->jobs.list); listing != NULL; listing = listing->next)
{ {
if (listing->item == NULL) if (listing->item == NULL)
continue; continue;

@ -88,8 +88,8 @@ rect2d getMapViewport()
int menu_x1=area_x2-MENU_WIDTH-1; int menu_x1=area_x2-MENU_WIDTH-1;
int view_rb=w-1; int view_rb=w-1;
int area_pos=*df::global::ui_area_map_width; int area_pos=(*df::global::ui_menu_width)[1];
int menu_pos=*df::global::ui_menu_width; int menu_pos=(*df::global::ui_menu_width)[0];
if(area_pos<3) if(area_pos<3)
{ {
view_rb=area_x2; view_rb=area_x2;

@ -36,8 +36,6 @@ REQUIRE_GLOBAL(enabler);
REQUIRE_GLOBAL(gametype); REQUIRE_GLOBAL(gametype);
REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_area_map_width);
REQUIRE_GLOBAL(ui_menu_width);
REQUIRE_GLOBAL(window_x); REQUIRE_GLOBAL(window_x);
REQUIRE_GLOBAL(window_y); REQUIRE_GLOBAL(window_y);
REQUIRE_GLOBAL(window_z); REQUIRE_GLOBAL(window_z);

@ -44,7 +44,7 @@ bool isSafe(df::coord c)
if (local_feature.type == feature_type::deep_special_tube || local_feature.type == feature_type::deep_surface_portal) if (local_feature.type == feature_type::deep_special_tube || local_feature.type == feature_type::deep_surface_portal)
return false; return false;
// And Hell *is* Hell. // And Hell *is* Hell.
if (global_feature.type == feature_type::feature_underworld_from_layer) if (global_feature.type == feature_type::underworld_from_layer)
return false; return false;
// otherwise it's safe. // otherwise it's safe.
return true; return true;

@ -1,9 +1,9 @@
module DFHack module DFHack
class << self class << self
# link a job to the world # link a job to the world
# allocate & set job.id, allocate a JobListLink, link to job & world.job_list # allocate & set job.id, allocate a JobListLink, link to job & world.jobs.list
def job_link(job) def job_link(job)
lastjob = world.job_list lastjob = world.jobs.list
lastjob = lastjob.next while lastjob.next lastjob = lastjob.next while lastjob.next
joblink = JobListLink.cpp_new joblink = JobListLink.cpp_new
joblink.prev = lastjob joblink.prev = lastjob

@ -269,7 +269,7 @@ module DFHack
def dig(mode=:Default) def dig(mode=:Default)
if mode == :Smooth if mode == :Smooth
if (tilemat == :STONE or tilemat == :MINERAL) and caption !~ /smooth|pillar|fortification/i and # XXX caption.. if (tilemat == :STONE or tilemat == :MINERAL) and caption !~ /smooth|pillar|fortification/i and # XXX caption..
designation.smooth == 0 and (designation.hidden or not df.world.job_list.find { |j| designation.smooth == 0 and (designation.hidden or not df.world.jobs.list.find { |j|
# the game removes 'smooth' designation as soon as it assigns a job, if we # the game removes 'smooth' designation as soon as it assigns a job, if we
# re-set it the game may queue another :DetailWall that will carve a fortification # re-set it the game may queue another :DetailWall that will carve a fortification
(j.job_type == :DetailWall or j.job_type == :DetailFloor) and df.same_pos?(j, self) (j.job_type == :DetailWall or j.job_type == :DetailFloor) and df.same_pos?(j, self)
@ -279,7 +279,7 @@ module DFHack
mapblock.flags.designated = true mapblock.flags.designated = true
end end
else else
return if mode != :No and designation.dig == :No and not designation.hidden and df.world.job_list.find { |j| return if mode != :No and designation.dig == :No and not designation.hidden and df.world.jobs.list.find { |j|
# someone already enroute to dig here, avoid 'Inappropriate dig square' spam # someone already enroute to dig here, avoid 'Inappropriate dig square' spam
JobType::Type[j.job_type] == :Digging and df.same_pos?(j, self) JobType::Type[j.job_type] == :Digging and df.same_pos?(j, self)
} }

@ -15,15 +15,15 @@ module DFHack
x, y, z = x.x, x.y, x.z if x.respond_to?(:x) x, y, z = x.x, x.y, x.z if x.respond_to?(:x)
# compute screen 'map' size (tiles) # compute screen 'map' size (tiles)
menuwidth = ui_menu_width menuwidth = ui_menu_width[0]
# ui_menu_width shows only the 'tab' status # ui_menu_width shows only the 'tab' status
menuwidth = 1 if menuwidth == 2 and ui_area_map_width == 2 and cursor.x != -30000 menuwidth = 1 if menuwidth == 2 and ui_menu_width[1] == 2 and cursor.x != -30000
menuwidth = 2 if menuwidth == 3 and cursor.x != -30000 menuwidth = 2 if menuwidth == 3 and cursor.x != -30000
w_w = gps.dimx - 2 w_w = gps.dimx - 2
w_h = gps.dimy - 2 w_h = gps.dimy - 2
case menuwidth case menuwidth
when 1; w_w -= 55 when 1; w_w -= 55
when 2; w_w -= (ui_area_map_width == 2 ? 24 : 31) when 2; w_w -= (ui_menu_width[1] == 2 ? 24 : 31)
end end
# center view # center view

@ -43,7 +43,7 @@ command_result df_showmood (color_ostream &out, vector <string> & parameters)
CoreSuspender suspend; CoreSuspender suspend;
bool found = false; bool found = false;
for (df::job_list_link *cur = world->job_list.next; cur != NULL; cur = cur->next) for (df::job_list_link *cur = world->jobs.list.next; cur != NULL; cur = cur->next)
{ {
df::job *job = cur->item; df::job *job = cur->item;
if ((job->job_type < job_type::StrangeMoodCrafter) || (job->job_type > job_type::StrangeMoodMechanics)) if ((job->job_type < job_type::StrangeMoodCrafter) || (job->job_type > job_type::StrangeMoodMechanics))

@ -69,7 +69,7 @@ public:
} else { } else {
// Gather orders when the bookkeeper starts updating stockpile records, // Gather orders when the bookkeeper starts updating stockpile records,
// and enqueue them when the job is done. // and enqueue them when the job is done.
for (df::job_list_link* link = &world->job_list; link != NULL; link = link->next) { for (df::job_list_link* link = &world->jobs.list; link != NULL; link = link->next) {
if (link->item == NULL) continue; if (link->item == NULL) continue;
if (link->item->job_type == job_type::UpdateStockpileRecords) { if (link->item->job_type == job_type::UpdateStockpileRecords) {
found = true; found = true;

@ -465,8 +465,9 @@ int StockpileSerializer::other_mats_token ( const std::map<int, std::string> oth
void StockpileSerializer::write_general() void StockpileSerializer::write_general()
{ {
mBuffer.set_max_bins ( mPile->max_barrels ); mBuffer.set_max_bins ( mPile->max_bins );
mBuffer.set_max_wheelbarrows ( mPile->max_wheelbarrows ); mBuffer.set_max_wheelbarrows ( mPile->max_wheelbarrows );
mBuffer.set_max_barrels ( mPile->max_barrels );
mBuffer.set_use_links_only ( mPile->use_links_only ); mBuffer.set_use_links_only ( mPile->use_links_only );
mBuffer.set_unknown1 ( mPile->settings.unk1 ); mBuffer.set_unknown1 ( mPile->settings.unk1 );
mBuffer.set_allow_inorganic ( mPile->settings.allow_inorganic ); mBuffer.set_allow_inorganic ( mPile->settings.allow_inorganic );

@ -117,13 +117,12 @@ DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(enabler); REQUIRE_GLOBAL(enabler);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_area_map_width);
REQUIRE_GLOBAL(ui_build_selector); REQUIRE_GLOBAL(ui_build_selector);
REQUIRE_GLOBAL(ui_building_in_assign); REQUIRE_GLOBAL(ui_building_in_assign);
REQUIRE_GLOBAL(ui_building_in_resize); REQUIRE_GLOBAL(ui_building_in_resize);
REQUIRE_GLOBAL(ui_building_item_cursor); REQUIRE_GLOBAL(ui_building_item_cursor);
REQUIRE_GLOBAL(ui_menu_width);
REQUIRE_GLOBAL(ui_look_cursor); REQUIRE_GLOBAL(ui_look_cursor);
REQUIRE_GLOBAL(ui_menu_width);
REQUIRE_GLOBAL(ui_sidebar_menus); REQUIRE_GLOBAL(ui_sidebar_menus);
REQUIRE_GLOBAL(ui_unit_view_mode); REQUIRE_GLOBAL(ui_unit_view_mode);
REQUIRE_GLOBAL(ui_workshop_in_add); REQUIRE_GLOBAL(ui_workshop_in_add);

@ -429,15 +429,15 @@ public:
static int fix_job_postings (color_ostream *out, bool dry_run) static int fix_job_postings (color_ostream *out, bool dry_run)
{ {
int count = 0; int count = 0;
df::job_list_link *link = &world->job_list; df::job_list_link *link = &world->jobs.list;
while (link) while (link)
{ {
df::job *job = link->item; df::job *job = link->item;
if (job) if (job)
{ {
for (size_t i = 0; i < world->job_postings.size(); ++i) for (size_t i = 0; i < world->jobs.postings.size(); ++i)
{ {
df::world::T_job_postings *posting = world->job_postings[i]; df::job_handler::T_postings *posting = world->jobs.postings[i];
if (posting->job == job && i != job->posting_index && !posting->flags.bits.dead) if (posting->job == job && i != job->posting_index && !posting->flags.bits.dead)
{ {
++count; ++count;
@ -673,7 +673,7 @@ static void check_lost_jobs(color_ostream &out, int ticks)
ProtectedJob::cur_tick_idx++; ProtectedJob::cur_tick_idx++;
if (ticks < 0) ticks = 0; if (ticks < 0) ticks = 0;
df::job_list_link *p = world->job_list.next; df::job_list_link *p = world->jobs.list.next;
for (; p; p = p->next) for (; p; p = p->next)
{ {
df::job *job = p->item; df::job *job = p->item;
@ -707,7 +707,7 @@ static void check_lost_jobs(color_ostream &out, int ticks)
static void update_job_data(color_ostream &out) static void update_job_data(color_ostream &out)
{ {
df::job_list_link *p = world->job_list.next; df::job_list_link *p = world->jobs.list.next;
for (; p; p = p->next) for (; p; p = p->next)
{ {
ProtectedJob *pj = get_known(p->item->id); ProtectedJob *pj = get_known(p->item->id);

@ -108,7 +108,6 @@ REQUIRE_GLOBAL(ui_building_assign_items);
REQUIRE_GLOBAL(ui_building_in_assign); REQUIRE_GLOBAL(ui_building_in_assign);
REQUIRE_GLOBAL(ui_menu_width); REQUIRE_GLOBAL(ui_menu_width);
REQUIRE_GLOBAL(ui_area_map_width);
using namespace DFHack::Gui; using namespace DFHack::Gui;
@ -3926,8 +3925,8 @@ public:
return; return;
int left_margin = gps->dimx - 30; int left_margin = gps->dimx - 30;
int8_t a = *ui_menu_width; int8_t a = (*ui_menu_width)[0];
int8_t b = *ui_area_map_width; int8_t b = (*ui_menu_width)[1];
if ((a == 1 && b > 1) || (a == 2 && b == 2)) if ((a == 1 && b > 1) || (a == 2 && b == 2))
left_margin -= 24; left_margin -= 24;

@ -1 +1 @@
Subproject commit 3baa24fec93461218b5b658de94884ebff0a0b23 Subproject commit 252a5adbf1a5cae45cf7e623d3c5ce6f3aa1195d