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")
SET(DFHACK_BUILD_32 1)
SET(DFHACK_BUILD_64 0)
set(DFHACK_SETARCH "i386")
ELSEIF("${DFHACK_BUILD_ARCH}" STREQUAL "64")
SET(DFHACK_BUILD_32 0)
SET(DFHACK_BUILD_64 1)
set(DFHACK_SETARCH "x86_64")
ADD_DEFINITIONS(-DDFHACK64)
ELSE()
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()
# set up versioning.
set(DF_VERSION "0.43.05")
SET(DFHACK_RELEASE "r2")
SET(DFHACK_PRERELEASE FALSE)
set(DF_VERSION "0.44.02")
SET(DFHACK_RELEASE "alpha1")
SET(DFHACK_PRERELEASE TRUE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
@ -334,6 +336,9 @@ IF(BUILD_LIBRARY)
install(FILES LICENSE.rst NEWS.rst DESTINATION ${DFHACK_USERDOC_DESTINATION})
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)
#build the plugins

@ -36,6 +36,54 @@ Changelog
.. contents::
: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
=================

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

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

@ -1966,6 +1966,18 @@ unless otherwise noted.
``listdir_recursive()`` returns the initial path and all components following it
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
------------
@ -3621,6 +3633,8 @@ Or with auto_gears::
auto_gears=true
}
.. _luasocket:
Luasocket
=========

@ -37,6 +37,26 @@ Development Changelog
.. contents::
: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
====================

@ -172,7 +172,7 @@ namespace DFHack
}
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);
}
@ -434,7 +434,7 @@ bool Console::init(bool)
{
d = new Private();
int hConHandle;
long lStdHandle;
intptr_t lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp;
DWORD oldMode, newMode;
@ -469,14 +469,14 @@ bool Console::init(bool)
// redirect unbuffered STDOUT to the console
d->console_out = GetStdHandle(STD_OUTPUT_HANDLE);
lStdHandle = (long)d->console_out;
lStdHandle = (intptr_t)d->console_out;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
d->dfout_C = _fdopen( hConHandle, "w" );
setvbuf( d->dfout_C, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console
d->console_in = GetStdHandle(STD_INPUT_HANDLE);
lStdHandle = (long)d->console_in;
lStdHandle = (intptr_t)d->console_in;
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" );
*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())
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 = [";
for (size_t i = 0; i < args.size(); i++)
rbcmd += "'" + args[i] + "', ";

@ -2429,6 +2429,23 @@ static const luaL_Reg dfhack_designations_funcs[] = {
{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 *****/
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, "filesystem", dfhack_filesystem_module, dfhack_filesystem_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);
}

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

@ -61,11 +61,14 @@ std::string stl_vsprintf(const char *fmt, va_list args) {
std::vector<char> buf;
buf.resize(4096);
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)
buf.resize(buf.size()*2);
else if (unsigned(rsz) > buf.size())
else if (unsigned(rsz) >= buf.size())
buf.resize(rsz+1);
else
return std::string(&buf[0], rsz);

@ -261,7 +261,7 @@ void ServerConnection::threadFn()
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))
{

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

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

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

@ -138,7 +138,7 @@ void buildings_onUpdate(color_ostream &out)
{
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) {
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)
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;
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->flags.bits.designated = true;
auto *link = world->job_list.next;
auto *link = world->jobs.list.next;
while (link)
{
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());
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 )
continue;
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());
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 )
continue;
nowJobs[link->item->id] = link->item;

@ -53,7 +53,7 @@ using namespace DFHack;
bool Filesystem::chdir (std::string path)
{
return !(bool)::chdir(path.c_str());
return ::chdir(path.c_str()) == 0;
}
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 |
S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
#endif
return !(bool)fail;
return fail == 0;
}
bool Filesystem::rmdir (std::string path)
@ -90,7 +90,7 @@ bool Filesystem::rmdir (std::string path)
#else
fail = ::rmdir(path.c_str());
#endif
return !(bool)fail;
return fail == 0;
}
#ifdef _WIN32
@ -116,13 +116,13 @@ _filetype mode2type (mode_t mode) {
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)
{
STAT_STRUCT info;
return (bool)Filesystem::stat(path, info);
return Filesystem::stat(path, info);
}
_filetype Filesystem::filetype (std::string path)

@ -48,12 +48,12 @@ using namespace DFHack;
#include "DataDefs.h"
#include "df/announcement_flags.h"
#include "df/announcements.h"
#include "df/assign_trade_status.h"
#include "df/building_civzonest.h"
#include "df/building_furnacest.h"
#include "df/building_trapst.h"
#include "df/building_workshopst.h"
#include "df/d_init.h"
#include "df/game_mode.h"
#include "df/general_ref.h"
#include "df/global_objects.h"
@ -108,7 +108,6 @@ using df::global::ui;
using df::global::world;
using df::global::selection_rect;
using df::global::ui_menu_width;
using df::global::ui_area_map_width;
using df::global::gamemode;
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_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))
{
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::unit *unit1, df::unit *unit2
) {
using df::global::announcements;
using df::global::d_init;
df::announcement_flags flags;
flags.bits.D_DISPLAY = flags.bits.A_DISPLAY = true;
if (is_valid_enum_item(type) && announcements)
flags = announcements->flags[type];
if (is_valid_enum_item(type) && d_init)
flags = d_init->announcements.flags[type];
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.menu_forced = false;
int menu_pos = (ui_menu_width ? *ui_menu_width : 2);
int area_pos = (ui_area_map_width ? *ui_area_map_width : 3);
int menu_pos = (ui_menu_width ? (*ui_menu_width)[0] : 2);
int area_pos = (ui_menu_width ? (*ui_menu_width)[1] : 3);
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)
{
menu_width = *df::global::ui_menu_width;
area_map_width = *df::global::ui_area_map_width;
menu_width = (*df::global::ui_menu_width)[0];
area_map_width = (*df::global::ui_menu_width)[1];
return true;
}
bool Gui::setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width)
{
*df::global::ui_menu_width = menu_width;
*df::global::ui_area_map_width = area_map_width;
(*df::global::ui_menu_width)[0] = menu_width;
(*df::global::ui_menu_width)[1] = area_map_width;
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->item = job;
linked_list_append(&world->job_list, job->list_link);
linked_list_append(&world->jobs.list, job->list_link);
return true;
} 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)
ins_pos = ins_pos->next;
@ -514,15 +514,15 @@ bool DFHack::Job::removePostings(df::job *job, bool remove_all)
bool removed = false;
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;
}
}
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)
{
@ -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));
df::job_list_link *link = world->job_list.next;
df::job_list_link *link = world->jobs.list.next;
for (; link; link = link->next)
{
int id = link->item->id;

@ -91,7 +91,7 @@ const char * DFHack::sa_feature(df::feature_type index)
return "Cavern";
case feature_type::magma_core_from_layer:
return "Magma sea";
case feature_type::feature_underworld_from_layer:
case feature_type::underworld_from_layer:
return "Underworld";
default:
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"
setarch_arch=$(cat hack/dfhack_setarch.txt || printf i386)
case "$1" in
-g | --gdb)
shift
@ -74,21 +76,21 @@ case "$1" in
;;
-h | --helgrind)
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=$?
;;
-v | --valgrind)
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=$?
;;
-c | --callgrind)
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=$?
;;
*)
setarch i386 -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@"
setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@"
ret=$?
;;
esac

@ -108,7 +108,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(deramp deramp.cpp)
DFHACK_PLUGIN(dig dig.cpp)
DFHACK_PLUGIN(digFlood digFlood.cpp)
# add_subdirectory(diggingInvaders)
add_subdirectory(diggingInvaders)
DFHACK_PLUGIN(dwarfvet dwarfvet.cpp)
DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(embark-tools embark-tools.cpp)
@ -128,7 +128,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(infiniteSky infiniteSky.cpp)
DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote)
DFHACK_PLUGIN(jobutils jobutils.cpp)
DFHACK_PLUGIN(labormanager labormanager.cpp)
add_subdirectory(labormanager)
DFHACK_PLUGIN(lair lair.cpp)
DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua)
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::setViewCoords(x,y,z);
return CR_OK;
}

@ -89,7 +89,7 @@ void onDig(color_ostream& out, void* ptr) {
return;
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 )
continue;

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

@ -2,6 +2,7 @@
#include "edgeCost.h"
#include "ColorText.h"
#include "modules/MapCache.h"
#include <unordered_map>
@ -9,5 +10,5 @@
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;
auto i1 = pointCost->find(p1);
auto i2 = pointCost->find(p2);
@ -598,7 +598,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
lastInvasionDigger = firstInvader->id;
lastInvasionJob = firstInvader->job.current_job ? firstInvader->job.current_job->id : -1;
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 )
continue;
df::job* job = link->item;

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

@ -93,6 +93,6 @@ struct PointHash {
}
};
cost_t getEdgeCost(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);
cost_t getEdgeCost(DFHack::color_ostream& out, df::coord pt1, df::coord pt2, 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::gamemode;
using df::global::ui_build_selector;
using df::global::ui_menu_width;
using df::global::ui_area_map_width;
using namespace DFHack::Gui;
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;
}
void add(ListEntry<T> &entry)
void add(const ListEntry<T> &entry)
{
list.push_back(entry);
if (entry.text.length() > max_item_width)

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

@ -146,15 +146,22 @@ static void json_array_to_bitfield(B & bits, Json::Value & arr)
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;
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;
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
&& blockFeatureGlobal.type == feature_type::feature_underworld_from_layer
&& blockFeatureGlobal.type == feature_type::underworld_from_layer
&& blockFeatureGlobal.main_material == 0) // stone
{
layerMats[blockFeatureGlobal.sub_material].add(global_z);

@ -118,6 +118,49 @@ enum TileDigDesignation
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
{
optional int32 x = 1;
@ -256,6 +299,7 @@ message MapBlock
repeated Item items = 26;
repeated bool tile_dig_designation_marker = 27;
repeated bool tile_dig_designation_auto = 28;
repeated int32 grass_percent = 29;
}
message MatPair {
@ -297,6 +341,12 @@ message MaterialList{
repeated MaterialDefinition material_list = 1;
}
message Hair
{
optional int32 length = 1;
optional HairStyle style = 2;
}
message BodySizeInfo
{
optional int32 size_cur = 1;
@ -313,6 +363,16 @@ message UnitAppearance
repeated int32 bp_modifiers = 2;
optional int32 size_modifier = 3;
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
@ -335,6 +395,8 @@ message UnitDefinition
optional UnitAppearance appearance = 16;
optional int32 profession_id = 17;
repeated string noble_positions = 18;
optional int32 rider_id = 19;
repeated InventoryItem inventory = 20;
}
message UnitList

@ -287,7 +287,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * remote_build)
{
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;
if (local_build->getType() == df::enums::building_type::Well)
{

@ -1,5 +1,5 @@
#include "df_version_int.h"
#define RFR_VERSION "0.17.0"
#define RFR_VERSION "0.18.0"
#include <cstdio>
#include <time.h>
@ -34,6 +34,7 @@
#include "df/army.h"
#include "df/army_flags.h"
#include "df/block_square_event_item_spatterst.h"
#include "df/block_square_event_grassst.h"
#endif
#include "df/block_square_event_material_spatterst.h"
#include "df/body_appearance_modifier.h"
@ -82,8 +83,10 @@
#include "df/site_realization_building_info_trenchesst.h"
#endif
#include "df/tissue.h"
#include "df/tissue_style_raw.h"
#include "df/ui.h"
#include "df/unit.h"
#include "df/unit_inventory_item.h"
#include "df/viewscreen_choose_start_sitest.h"
#include "df/world.h"
#include "df/world_data.h"
@ -104,6 +107,8 @@
#include "df/plant_tree_tile.h"
#endif
#include "df/unit_relationship_type.h"
#include "building_reader.h"
using namespace DFHack;
@ -1122,9 +1127,9 @@ void CopyDesignation(df::map_block * DfBlock, RemoteFortressReader::MapBlock * N
}
}
#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)
continue;
if (
@ -1179,7 +1184,11 @@ void CopyBuildings(DFCoord min, DFCoord max, RemoteFortressReader::MapBlock * Ne
{
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)
{
auto out_bld = NetBlock->add_buildings();
out_bld->set_index(bld->id);
continue;
}
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)
{
auto out_bld = NetBlock->add_buildings();
out_bld->set_index(bld->id);
continue;
}
auto out_bld = NetBlock->add_buildings();
CopyBuilding(i, out_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;
#if DF_VERSION_INT > 34011
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;
#else
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_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
}
}
@ -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->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;
}
@ -2670,7 +2738,7 @@ static command_result SendDigCommand(color_ostream &stream, const DigCommand *in
#if DF_VERSION_INT >= 43005
//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)
continue;

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

@ -36,8 +36,6 @@ REQUIRE_GLOBAL(enabler);
REQUIRE_GLOBAL(gametype);
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_area_map_width);
REQUIRE_GLOBAL(ui_menu_width);
REQUIRE_GLOBAL(window_x);
REQUIRE_GLOBAL(window_y);
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)
return false;
// 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;
// otherwise it's safe.
return true;

@ -1,9 +1,9 @@
module DFHack
class << self
# 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)
lastjob = world.job_list
lastjob = world.jobs.list
lastjob = lastjob.next while lastjob.next
joblink = JobListLink.cpp_new
joblink.prev = lastjob

@ -269,7 +269,7 @@ module DFHack
def dig(mode=:Default)
if mode == :Smooth
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
# 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)
@ -279,7 +279,7 @@ module DFHack
mapblock.flags.designated = true
end
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
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)
# compute screen 'map' size (tiles)
menuwidth = ui_menu_width
menuwidth = ui_menu_width[0]
# 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
w_w = gps.dimx - 2
w_h = gps.dimy - 2
case menuwidth
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
# center view

@ -43,7 +43,7 @@ command_result df_showmood (color_ostream &out, vector <string> & parameters)
CoreSuspender suspend;
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;
if ((job->job_type < job_type::StrangeMoodCrafter) || (job->job_type > job_type::StrangeMoodMechanics))

@ -69,7 +69,7 @@ public:
} else {
// Gather orders when the bookkeeper starts updating stockpile records,
// 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->job_type == job_type::UpdateStockpileRecords) {
found = true;

@ -465,8 +465,9 @@ int StockpileSerializer::other_mats_token ( const std::map<int, std::string> oth
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_barrels ( mPile->max_barrels );
mBuffer.set_use_links_only ( mPile->use_links_only );
mBuffer.set_unknown1 ( mPile->settings.unk1 );
mBuffer.set_allow_inorganic ( mPile->settings.allow_inorganic );

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

@ -429,15 +429,15 @@ public:
static int fix_job_postings (color_ostream *out, bool dry_run)
{
int count = 0;
df::job_list_link *link = &world->job_list;
df::job_list_link *link = &world->jobs.list;
while (link)
{
df::job *job = link->item;
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)
{
++count;
@ -673,7 +673,7 @@ static void check_lost_jobs(color_ostream &out, int ticks)
ProtectedJob::cur_tick_idx++;
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)
{
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)
{
df::job_list_link *p = world->job_list.next;
df::job_list_link *p = world->jobs.list.next;
for (; p; p = p->next)
{
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_menu_width);
REQUIRE_GLOBAL(ui_area_map_width);
using namespace DFHack::Gui;
@ -3926,8 +3925,8 @@ public:
return;
int left_margin = gps->dimx - 30;
int8_t a = *ui_menu_width;
int8_t b = *ui_area_map_width;
int8_t a = (*ui_menu_width)[0];
int8_t b = (*ui_menu_width)[1];
if ((a == 1 && b > 1) || (a == 2 && b == 2))
left_margin -= 24;

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