From efdb709284d393938db6b60185ee3898cb068954 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 17 May 2012 00:19:29 +0400
Subject: [PATCH 1/5] Support creating rollers and stops with
dfhack.buildings.constructBuilding.
---
library/lua/dfhack/buildings.lua | 18 ++++++++++++++++--
library/modules/Buildings.cpp | 17 ++++++++++++++++-
library/xml | 2 +-
3 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/library/lua/dfhack/buildings.lua b/library/lua/dfhack/buildings.lua
index ad82da89a..af9ad2605 100644
--- a/library/lua/dfhack/buildings.lua
+++ b/library/lua/dfhack/buildings.lua
@@ -178,7 +178,20 @@ local building_inputs = {
},
[df.building_type.Slab] = { { item_type=df.item_type.SLAB } },
[df.building_type.NestBox] = { { has_tool_use=df.tool_uses.NEST_BOX, item_type=df.item_type.TOOL } },
- [df.building_type.Hive] = { { has_tool_use=df.tool_uses.HIVE, item_type=df.item_type.TOOL } }
+ [df.building_type.Hive] = { { has_tool_use=df.tool_uses.HIVE, item_type=df.item_type.TOOL } },
+ [df.building_type.Rollers] = {
+ {
+ name='mechanism',
+ item_type=df.item_type.TRAPPARTS,
+ quantity=-1,
+ vector_id=df.job_item_vector_id.TRAPPARTS
+ },
+ {
+ name='chain',
+ item_type=df.item_type.CHAIN,
+ vector_id=df.job_item_vector_id.CHAIN
+ }
+ }
}
--[[ Furnace building input material table. ]]
@@ -318,7 +331,8 @@ local trap_inputs = {
item_type=df.item_type.TRAPPARTS,
vector_id=df.job_item_vector_id.TRAPPARTS
}
- }
+ },
+ [df.trap_type.TrackStop] = { { flags2={ building_material=true, non_economic=true } } }
}
--[[ Functions for lookup in tables. ]]
diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp
index 65cf009f3..d2b3e3527 100644
--- a/library/modules/Buildings.cpp
+++ b/library/modules/Buildings.cpp
@@ -66,6 +66,7 @@ using namespace DFHack;
#include "df/building_screw_pumpst.h"
#include "df/building_water_wheelst.h"
#include "df/building_wellst.h"
+#include "df/building_rollersst.h"
using namespace df::enums;
using df::global::ui;
@@ -289,6 +290,10 @@ bool Buildings::getCorrectSize(df::coord2d &size, df::coord2d ¢er,
makeOneDim(size, center, direction);
return true;
+ case Rollers:
+ makeOneDim(size, center, (direction&1) == 0);
+ return true;
+
case WaterWheel:
size = df::coord2d(3,3);
makeOneDim(size, center, direction);
@@ -592,6 +597,12 @@ bool Buildings::setSize(df::building *bld, df::coord2d size, int direction)
obj->direction = (df::screw_pump_direction)direction;
break;
}
+ case Rollers:
+ {
+ auto obj = (df::building_rollersst*)bld;
+ obj->direction = (df::screw_pump_direction)direction;
+ break;
+ }
case Bridge:
{
auto obj = (df::building_bridgest*)bld;
@@ -881,7 +892,11 @@ bool Buildings::constructWithFilters(df::building *bld, std::vectorquantity < 0)
items[i]->quantity = computeMaterialAmount(bld);
- job->job_items.push_back(items[i]);
+ /* The game picks up explicitly listed items in reverse
+ * order, but processes filters straight. This reverses
+ * the order of filters so as to produce the same final
+ * contained_items ordering as the normal ui way. */
+ vector_insert_at(job->job_items, 0, items[i]);
if (items[i]->item_type == item_type::BOULDER)
rough = true;
diff --git a/library/xml b/library/xml
index 92dbeb626..b0d8e71dc 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit 92dbeb6267a24a35babe3d5326801f2e8cfd22e1
+Subproject commit b0d8e71dc9f6e697409bd999801097acdc57fcd8
From 2c0024adc91491b6d687f3b56d6a5779a3391e59 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 17 May 2012 19:56:55 +0400
Subject: [PATCH 2/5] Make Items::getPosition exactly match the DF original in
behavior.
---
LUA_API.rst | 4 ++--
Lua API.html | 4 ++--
library/modules/Items.cpp | 34 +++++++++++++++++++++++++++++-----
3 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index bd2d33cb0..9ecd2e55e 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -693,7 +693,7 @@ Units module
* ``dfhack.units.getPosition(unit)``
- Returns true *x,y,z* of the unit; may be not equal to unit.pos if caged.
+ Returns true *x,y,z* of the unit, or *nil* if invalid; may be not equal to unit.pos if caged.
* ``dfhack.units.getContainer(unit)``
@@ -752,7 +752,7 @@ Items module
* ``dfhack.items.getPosition(item)``
- Returns true *x,y,z* of the item; may be not equal to item.pos if in inventory.
+ Returns true *x,y,z* of the item, or *nil* if invalid; may be not equal to item.pos if in inventory.
* ``dfhack.items.getGeneralRef(item, type)``
diff --git a/Lua API.html b/Lua API.html
index d44d82bab..7ce777c42 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -935,7 +935,7 @@ a lua list containing them.
dfhack.units.getPosition(unit)
-Returns true x,y,z of the unit; may be not equal to unit.pos if caged.
+Returns true x,y,z of the unit, or nil if invalid; may be not equal to unit.pos if caged.
dfhack.units.getContainer(unit)
Returns the container (cage) item or nil.
@@ -982,7 +982,7 @@ or raws. The ignore_noble boolean disables the
dfhack.items.getPosition(item)
-Returns true x,y,z of the item; may be not equal to item.pos if in inventory.
+Returns true x,y,z of the item, or nil if invalid; may be not equal to item.pos if in inventory.
dfhack.items.getGeneralRef(item, type)
Searches for a general_ref with the given type.
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index f1d495bf1..335d7d8fc 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -69,6 +69,7 @@ using namespace std;
#include "df/general_ref_unit_itemownerst.h"
#include "df/general_ref_contains_itemst.h"
#include "df/general_ref_contained_in_itemst.h"
+#include "df/vermin.h"
using namespace DFHack;
using namespace df::enums;
@@ -512,9 +513,12 @@ df::coord Items::getPosition(df::item *item)
{
CHECK_NULL_POINTER(item);
- if (item->flags.bits.in_inventory ||
- item->flags.bits.in_chest ||
- item->flags.bits.in_building)
+ /* Function reverse-engineered from DF code. */
+
+ if (item->flags.bits.removed)
+ return df::coord();
+
+ if (item->flags.bits.in_inventory)
{
for (size_t i = 0; i < item->itemrefs.size(); i++)
{
@@ -532,15 +536,31 @@ df::coord Items::getPosition(df::item *item)
return Units::getPosition(unit);
break;
- case general_ref_type::BUILDING_HOLDER:
+ /*case general_ref_type::BUILDING_HOLDER:
if (auto bld = ref->getBuilding())
return df::coord(bld->centerx, bld->centery, bld->z);
+ break;*/
+
+ default:
break;
+ }
+ }
+
+ for (size_t i = 0; i < item->specific_refs.size(); i++)
+ {
+ df::specific_ref *ref = item->specific_refs[i];
+
+ switch (ref->type)
+ {
+ case specific_ref_type::VERMIN_ESCAPED_PET:
+ return ref->vermin->pos;
default:
break;
}
}
+
+ return df::coord();
}
return item->pos;
@@ -625,6 +645,10 @@ bool DFHack::Items::moveToContainer(MapExtras::MapCache &mc, df::item *item, df:
CHECK_NULL_POINTER(item);
CHECK_NULL_POINTER(container);
+ auto cpos = getPosition(container);
+ if (!cpos.isValid())
+ return false;
+
if (!detachItem(mc, item))
return false;
@@ -635,7 +659,7 @@ bool DFHack::Items::moveToContainer(MapExtras::MapCache &mc, df::item *item, df:
{
delete ref1; delete ref2;
Core::printerr("Could not allocate container refs.\n");
- putOnGround(mc, item, getPosition(container));
+ putOnGround(mc, item, cpos);
return false;
}
From e9ef9b87b575b4746e2090556c192237c95f508a Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 17 May 2012 20:04:09 +0400
Subject: [PATCH 3/5] Add central locations for onUpdate and onStateChange
handling in core.
---
library/Core.cpp | 35 ++++++++++++++++++++++-----------
library/PluginManager.cpp | 2 --
library/include/Core.h | 14 +++++++++++++
library/include/PluginManager.h | 10 ----------
4 files changed, 38 insertions(+), 23 deletions(-)
diff --git a/library/Core.cpp b/library/Core.cpp
index 7f08f402f..1d2a76026 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -1017,7 +1017,7 @@ int Core::Update()
Lua::Core::Reset(out, "DF code execution");
if (first_update)
- plug_mgr->OnStateChange(out, SC_CORE_INITIALIZED);
+ onStateChange(out, SC_CORE_INITIALIZED);
// detect if the game was loaded or unloaded in the meantime
void *new_wdata = NULL;
@@ -1043,11 +1043,11 @@ int Core::Update()
// and if the world is going away, we report the map change first
if(had_map)
- plug_mgr->OnStateChange(out, SC_MAP_UNLOADED);
+ onStateChange(out, SC_MAP_UNLOADED);
// and if the world is appearing, we report map change after that
- plug_mgr->OnStateChange(out, new_wdata ? SC_WORLD_LOADED : SC_WORLD_UNLOADED);
+ onStateChange(out, new_wdata ? SC_WORLD_LOADED : SC_WORLD_UNLOADED);
if(isMapLoaded())
- plug_mgr->OnStateChange(out, SC_MAP_LOADED);
+ onStateChange(out, SC_MAP_LOADED);
}
// otherwise just check for map change...
else if (new_mapdata != last_local_map_ptr)
@@ -1058,7 +1058,7 @@ int Core::Update()
if (isMapLoaded() != had_map)
{
getWorld()->ClearPersistentCache();
- plug_mgr->OnStateChange(out, new_mapdata ? SC_MAP_LOADED : SC_MAP_UNLOADED);
+ onStateChange(out, new_mapdata ? SC_MAP_LOADED : SC_MAP_UNLOADED);
}
}
@@ -1071,15 +1071,12 @@ int Core::Update()
if (screen != top_viewscreen)
{
top_viewscreen = screen;
- plug_mgr->OnStateChange(out, SC_VIEWSCREEN_CHANGED);
+ onStateChange(out, SC_VIEWSCREEN_CHANGED);
}
}
- // notify all the plugins that a game tick is finished
- plug_mgr->OnUpdate(out);
-
- // process timers in lua
- Lua::Core::onUpdate(out);
+ // Execute per-frame handlers
+ onUpdate(out);
// Release the fake suspend lock
{
@@ -1116,6 +1113,22 @@ int Core::Update()
return 0;
};
+void Core::onUpdate(color_ostream &out)
+{
+ // notify all the plugins that a game tick is finished
+ plug_mgr->OnUpdate(out);
+
+ // process timers in lua
+ Lua::Core::onUpdate(out);
+}
+
+void Core::onStateChange(color_ostream &out, state_change_event event)
+{
+ plug_mgr->OnStateChange(out, event);
+
+ Lua::Core::onStateChange(out, event);
+}
+
// FIXME: needs to terminate the IO threads and properly dismantle all the machinery involved.
int Core::Shutdown ( void )
{
diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp
index 320e8dec8..ae8cc755f 100644
--- a/library/PluginManager.cpp
+++ b/library/PluginManager.cpp
@@ -609,8 +609,6 @@ void PluginManager::OnStateChange(color_ostream &out, state_change_event event)
{
all_plugins[i]->on_state_change(out, event);
}
-
- Lua::Core::onStateChange(out, event);
}
// FIXME: doesn't check name collisions!
diff --git a/library/include/Core.h b/library/include/Core.h
index fe83715cf..7da633cca 100644
--- a/library/include/Core.h
+++ b/library/include/Core.h
@@ -68,6 +68,17 @@ namespace DFHack
class df_window;
}
+ enum state_change_event
+ {
+ SC_WORLD_LOADED = 0,
+ SC_WORLD_UNLOADED = 1,
+ SC_MAP_LOADED = 2,
+ SC_MAP_UNLOADED = 3,
+ SC_VIEWSCREEN_CHANGED = 4,
+ SC_CORE_INITIALIZED = 5,
+ SC_BEGIN_UNLOAD = 6
+ };
+
// Core is a singleton. Why? Because it is closely tied to SDL calls. It tracks the global state of DF.
// There should never be more than one instance
// Better than tracking some weird variables all over the place.
@@ -162,6 +173,9 @@ namespace DFHack
int SDL_Event(SDL::Event* event);
bool ncurses_wgetch(int in, int & out);
+ void onUpdate(color_ostream &out);
+ void onStateChange(color_ostream &out, state_change_event event);
+
Core(Core const&); // Don't Implement
void operator=(Core const&); // Don't implement
diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h
index 7f98bf422..02974f36b 100644
--- a/library/include/PluginManager.h
+++ b/library/include/PluginManager.h
@@ -65,16 +65,6 @@ namespace DFHack
// Close a plugin library
void ClosePlugin (DFLibrary * plugin);
- enum state_change_event
- {
- SC_WORLD_LOADED = 0,
- SC_WORLD_UNLOADED = 1,
- SC_MAP_LOADED = 2,
- SC_MAP_UNLOADED = 3,
- SC_VIEWSCREEN_CHANGED = 4,
- SC_CORE_INITIALIZED = 5,
- SC_BEGIN_UNLOAD = 6
- };
struct DFHACK_EXPORT CommandReg {
const char *name;
int (*command)(lua_State*);
From f37f708b37bf21ded2ca99fac6db3facd7a05fcf Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 17 May 2012 20:38:27 +0400
Subject: [PATCH 4/5] Add a workaround for Planepacked bug in buildings
constructed via API.
Buildings hanging in the air cause constructWithFilters to
exhibit the same behavior as a moody dwarf in a burrow excluding
the workshop, i.e. endlessly collecting the same type of reagent.
http://www.bay12games.com/dwarves/mantisbt/view.php?id=1416
The workaround monitors jobs and reclassifies the reagents on the fly.
---
library/Core.cpp | 13 +++++++++
library/modules/Buildings.cpp | 55 +++++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
diff --git a/library/Core.cpp b/library/Core.cpp
index 1d2a76026..e8c43b7f5 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -71,6 +71,7 @@ using namespace DFHack;
using namespace tthread;
using namespace df::enums;
using df::global::init;
+using df::global::world;
// FIXME: A lot of code in one file, all doing different things... there's something fishy about it.
@@ -1113,8 +1114,18 @@ int Core::Update()
return 0;
};
+extern bool buildings_do_onupdate;
+void buildings_onStateChange(color_ostream &out, state_change_event event);
+void buildings_onUpdate(color_ostream &out);
+
+static int buildings_timer = 0;
+
void Core::onUpdate(color_ostream &out)
{
+ // convert building reagents
+ if (buildings_do_onupdate && (++buildings_timer & 1))
+ buildings_onUpdate(out);
+
// notify all the plugins that a game tick is finished
plug_mgr->OnUpdate(out);
@@ -1124,6 +1135,8 @@ void Core::onUpdate(color_ostream &out)
void Core::onStateChange(color_ostream &out, state_change_event event)
{
+ buildings_onStateChange(out, event);
+
plug_mgr->OnStateChange(out, event);
Lua::Core::onStateChange(out, event);
diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp
index d2b3e3527..e0afc56ed 100644
--- a/library/modules/Buildings.cpp
+++ b/library/modules/Buildings.cpp
@@ -87,6 +87,58 @@ static uint8_t *getExtentTile(df::building_extents &extent, df::coord2d tile)
return &extent.extents[dx + dy*extent.width];
}
+/*
+ * A monitor to work around this bug, in its application to buildings:
+ *
+ * http://www.bay12games.com/dwarves/mantisbt/view.php?id=1416
+ */
+bool buildings_do_onupdate = false;
+
+void buildings_onStateChange(color_ostream &out, state_change_event event)
+{
+ switch (event) {
+ case SC_MAP_LOADED:
+ buildings_do_onupdate = true;
+ break;
+ case SC_MAP_UNLOADED:
+ buildings_do_onupdate = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void buildings_onUpdate(color_ostream &out)
+{
+ buildings_do_onupdate = false;
+
+ df::job_list_link *link = world->job_list.next;
+ for (; link; link = link->next) {
+ df::job *job = link->item;
+
+ if (job->job_type != job_type::ConstructBuilding)
+ continue;
+ if (job->job_items.empty())
+ continue;
+
+ buildings_do_onupdate = true;
+
+ for (size_t i = 0; i < job->items.size(); i++)
+ {
+ df::job_item_ref *iref = job->items[i];
+ if (iref->role != df::job_item_ref::Reagent)
+ continue;
+ df::job_item *item = vector_get(job->job_items, iref->job_item_idx);
+ if (!item)
+ continue;
+ // Convert Reagent to Hauled, while decrementing quantity
+ item->quantity = std::max(0, item->quantity-1);
+ iref->role = df::job_item_ref::Hauled;
+ iref->job_item_idx = -1;
+ }
+ }
+}
+
uint32_t Buildings::getNumBuildings()
{
return world->buildings.all.size();
@@ -906,6 +958,8 @@ bool Buildings::constructWithFilters(df::building *bld, std::vectormat_index = items[i]->mat_index;
}
+ buildings_do_onupdate = true;
+
createDesign(bld, rough);
return true;
}
@@ -969,3 +1023,4 @@ bool Buildings::deconstruct(df::building *bld)
return true;
}
+
From 52426f9035c54fdfcd38992259c94a65de160ed8 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 17 May 2012 20:41:41 +0400
Subject: [PATCH 5/5] Track xml
---
library/xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/library/xml b/library/xml
index b0d8e71dc..ab102b93f 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit b0d8e71dc9f6e697409bd999801097acdc57fcd8
+Subproject commit ab102b93fca9b1ae8b5fbfc3ae5a9ee06ee60811