dfhack.maps.canWalkBetween(pos1, pos2)
Checks if a dwarf may be able to walk between the two tiles,
using a pathfinding cache maintained by the game. Note that
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 1baa4045d..529bdd077 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -94,6 +94,26 @@ void Lua::Push(lua_State *state, const Units::NoblePosition &pos)
lua_setfield(state, -2, "position");
}
+void Lua::Push(lua_State *state, df::coord pos)
+{
+ lua_createtable(state, 0, 3);
+ lua_pushinteger(state, pos.x);
+ lua_setfield(state, -2, "x");
+ lua_pushinteger(state, pos.y);
+ lua_setfield(state, -2, "y");
+ lua_pushinteger(state, pos.z);
+ lua_setfield(state, -2, "z");
+}
+
+void Lua::Push(lua_State *state, df::coord2d pos)
+{
+ lua_createtable(state, 0, 2);
+ lua_pushinteger(state, pos.x);
+ lua_setfield(state, -2, "x");
+ lua_pushinteger(state, pos.y);
+ lua_setfield(state, -2, "y");
+}
+
int Lua::PushPosXYZ(lua_State *state, df::coord pos)
{
if (!pos.isValid())
@@ -110,6 +130,21 @@ int Lua::PushPosXYZ(lua_State *state, df::coord pos)
}
}
+int Lua::PushPosXY(lua_State *state, df::coord2d pos)
+{
+ if (!pos.isValid())
+ {
+ lua_pushnil(state);
+ return 1;
+ }
+ else
+ {
+ lua_pushinteger(state, pos.x);
+ lua_pushinteger(state, pos.y);
+ return 2;
+ }
+}
+
static df::coord2d CheckCoordXY(lua_State *state, int base, bool vararg = false)
{
df::coord2d p;
@@ -754,7 +789,6 @@ static const luaL_Reg dfhack_items_funcs[] = {
static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock),
- WRAPM(Maps, getRegionBiome),
WRAPM(Maps, enableBlockUpdates),
WRAPM(Maps, getGlobalInitFeature),
WRAPM(Maps, getLocalInitFeature),
@@ -769,8 +803,24 @@ static int maps_getTileBlock(lua_State *L)
return 1;
}
+static int maps_getRegionBiome(lua_State *L)
+{
+ auto pos = CheckCoordXY(L, 1, true);
+ Lua::PushDFObject(L, Maps::getRegionBiome(pos));
+ return 1;
+}
+
+static int maps_getTileBiomeRgn(lua_State *L)
+{
+ auto pos = CheckCoordXYZ(L, 1, true);
+ Lua::PushPosXY(L, Maps::getTileBiomeRgn(pos));
+ return 1;
+}
+
static const luaL_Reg dfhack_maps_funcs[] = {
{ "getTileBlock", maps_getTileBlock },
+ { "getRegionBiome", maps_getRegionBiome },
+ { "getTileBiomeRgn", maps_getTileBiomeRgn },
{ NULL, NULL }
};
diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h
index a52db2572..d3c7a65d2 100644
--- a/library/include/LuaTools.h
+++ b/library/include/LuaTools.h
@@ -264,11 +264,14 @@ namespace DFHack {namespace Lua {
inline void Push(lua_State *state, bool value) {
lua_pushboolean(state, value);
}
+ inline void Push(lua_State *state, const char *str) {
+ lua_pushstring(state, str);
+ }
inline void Push(lua_State *state, const std::string &str) {
lua_pushlstring(state, str.data(), str.size());
}
- inline void Push(lua_State *state, df::coord &obj) { PushDFObject(state, &obj); }
- inline void Push(lua_State *state, df::coord2d &obj) { PushDFObject(state, &obj); }
+ DFHACK_EXPORT void Push(lua_State *state, df::coord obj);
+ DFHACK_EXPORT void Push(lua_State *state, df::coord2d obj);
void Push(lua_State *state, const Units::NoblePosition &pos);
template inline void Push(lua_State *state, T *ptr) {
PushDFObject(state, ptr);
@@ -293,6 +296,7 @@ namespace DFHack {namespace Lua {
}
DFHACK_EXPORT int PushPosXYZ(lua_State *state, df::coord pos);
+ DFHACK_EXPORT int PushPosXY(lua_State *state, df::coord2d pos);
DFHACK_EXPORT bool IsCoreContext(lua_State *state);
diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h
index c6dc7c404..e63eef733 100644
--- a/library/include/modules/Maps.h
+++ b/library/include/modules/Maps.h
@@ -255,8 +255,20 @@ inline df::tile_occupancy *getTileOccupancy(df::coord pos) {
return getTileOccupancy(pos.x, pos.y, pos.z);
}
+/**
+ * Returns biome info about the specified world region.
+ */
DFHACK_EXPORT df::world_data::T_region_map *getRegionBiome(df::coord2d rgn_pos);
+/**
+ * Returns biome world region coordinates for the given tile within given block.
+ */
+DFHACK_EXPORT df::coord2d getBlockTileBiomeRgn(df::map_block *block, df::coord2d pos);
+
+inline df::coord2d getTileBiomeRgn(df::coord pos) {
+ return getBlockTileBiomeRgn(getTileBlock(pos), pos);
+}
+
// Enables per-frame updates for liquid flow and/or temperature.
DFHACK_EXPORT void enableBlockUpdates(df::map_block *blk, bool flow = false, bool temperature = false);
diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua
index c0ba64375..926600c0f 100644
--- a/library/lua/dfhack.lua
+++ b/library/lua/dfhack.lua
@@ -111,9 +111,11 @@ function copyall(table)
end
function pos2xyz(pos)
- local x = pos.x
- if x and x ~= -30000 then
- return x, pos.y, pos.z
+ if pos then
+ local x = pos.x
+ if x and x ~= -30000 then
+ return x, pos.y, pos.z
+ end
end
end
diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp
index a8b7945d1..3160af75e 100644
--- a/library/modules/Maps.cpp
+++ b/library/modules/Maps.cpp
@@ -369,6 +369,39 @@ bool Maps::RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square
return false;
}
+static df::coord2d biome_offsets[9] = {
+ df::coord2d(-1,-1), df::coord2d(0,-1), df::coord2d(1,-1),
+ df::coord2d(-1,0), df::coord2d(0,0), df::coord2d(1,0),
+ df::coord2d(-1,1), df::coord2d(0,1), df::coord2d(1,1)
+};
+
+inline df::coord2d getBiomeRgnPos(df::coord2d base, int idx)
+{
+ auto r = base + biome_offsets[idx];
+
+ int world_width = world->world_data->world_width;
+ int world_height = world->world_data->world_height;
+
+ return df::coord2d(clip_range(r.x,0,world_width-1),clip_range(r.y,0,world_height-1));
+}
+
+df::coord2d Maps::getBlockTileBiomeRgn(df::map_block *block, df::coord2d pos)
+{
+ if (!block || !world->world_data)
+ return df::coord2d();
+
+ auto des = MapExtras::index_tile(block->designation,pos);
+ unsigned idx = des.bits.biome;
+ if (idx < 9)
+ {
+ idx = block->region_offset[idx];
+ if (idx < 9)
+ return getBiomeRgnPos(block->region_pos, idx);
+ }
+
+ return df::coord2d();
+}
+
/*
* Layer geology
*/
@@ -386,20 +419,14 @@ bool Maps::ReadGeology(vector > *layer_mats, vector
(*geoidx)[i] = df::coord2d(-30000,-30000);
}
- int world_width = world->world_data->world_width;
- int world_height = world->world_data->world_height;
+ // regionX is in embark squares
+ // regionX/16 is in 16x16 embark square regions
+ df::coord2d map_region(world->map.region_x / 16, world->map.region_y / 16);
// iterate over 8 surrounding regions + local region
for (int i = eNorthWest; i < eBiomeCount; i++)
{
- // check against worldmap boundaries, fix if needed
- // regionX is in embark squares
- // regionX/16 is in 16x16 embark square regions
- // i provides -1 .. +1 offset from the current region
- int bioRX = world->map.region_x / 16 + ((i % 3) - 1);
- int bioRY = world->map.region_y / 16 + ((i / 3) - 1);
-
- df::coord2d rgn_pos(clip_range(bioRX,0,world_width-1),clip_range(bioRY,0,world_height-1));
+ df::coord2d rgn_pos = getBiomeRgnPos(map_region, i);
(*geoidx)[i] = rgn_pos;
From 642a625586b9d40440bd3ce05d827f707ccce5ac Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 13 May 2012 18:39:00 +0400
Subject: [PATCH 09/27] Support custom buildings in
dfhack.buildings.getFiltersByType.
Also document it and constructBuilding in Lua API docs.
---
LUA_API.rst | 74 ++++++++++++++++++++++++++++++++
Lua API.html | 63 +++++++++++++++++++++++++++
library/lua/dfhack/buildings.lua | 65 ++++++++++++++++++++++++----
library/lua/utils.lua | 62 ++++++++++++++++++++++++++
scripts/devel/list-filters.lua | 58 ++++++++-----------------
5 files changed, 273 insertions(+), 49 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index bb1ef803e..c42785278 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -971,6 +971,80 @@ Low-level building creation functions;
More high-level functions are implemented in lua and can be loaded by
``require('dfhack.buildings')``. See ``hack/lua/dfhack/buildings.lua``.
+Among them are:
+
+* ``dfhack.buildings.getFiltersByType(argtable,type,subtype,custom)``
+
+ Returns a sequence of lua structures, describing input item filters
+ suitable for the specified building type, or *nil* if unknown or invalid.
+ The returned sequence is suitable for use as the ``job_items`` argument
+ of ``constructWithFilters``.
+ Uses tables defined in ``buildings.lua``.
+
+ Argtable members ``material`` (the default name), ``bucket``, ``barrel``,
+ ``chain``, ``mechanism``, ``screw``, ``pipe``, ``anvil``, ``weapon`` are used to
+ augment the basic attributes with more detailed information if the
+ building has input items with the matching name (see the tables for naming details).
+ Note that it is impossible to *override* any properties this way, only supply those that
+ are not mentioned otherwise; one exception is that flags2.non_economic
+ is automatically cleared if an explicit material is specified.
+
+* ``dfhack.buildings.constructBuilding{...}``
+
+ Creates a building in one call, using options contained
+ in the argument table. Returns the building, or *nil, error*.
+
+ **NOTE:** Despite the name, unless the building is abstract,
+ the function creates it in an 'unconstructed' stage, with
+ a queued in-game job that will actually construct it. I.e.
+ the function replicates programmatically what can be done
+ through the construct building menu in the game ui, except
+ that it does less environment constraint checking.
+
+ The following options can be used:
+
+ - ``pos = coordinates``, or ``x = ..., y = ..., z = ...``
+
+ Mandatory. Specifies the left upper corner of the building.
+
+ - ``type = df.building_type.FOO, subtype = ..., custom = ...``
+
+ Mandatory. Specifies the type of the building. Obviously, subtype
+ and custom are only expected if the type requires them.
+
+ - ``fields = { ... }``
+
+ Initializes fields of the building object after creation with ``df.assign``.
+
+ - ``width = ..., height = ..., direction = ...``
+
+ Sets size and orientation of the building. If it is
+ fixed-size, specified dimensions are ignored.
+
+ - ``full_rectangle = true``
+
+ For buildings like stockpiles or farm plots that can normally
+ accomodate individual tile exclusion, forces an error if any
+ tiles within the specified width*height are obstructed.
+
+ - ``items = { item, item ... }``, or ``filters = { {...}, {...}... }``
+
+ Specifies explicit items or item filters to use in construction.
+ It is the job of the user to ensure they are correct for the building type.
+
+ - ``abstract = true``
+
+ Specifies that the building is abstract and does not require construction.
+ Required for stockpiles and civzones; an error otherwise.
+
+ - ``material = {...}, mechanism = {...}, ...``
+
+ If none of ``items``, ``filter``, or ``abstract`` is used,
+ the function uses ``getFiltersByType`` to compute the input
+ item filters, and passes the argument table through. If no filters
+ can be determined this way, ``constructBuilding`` throws an error.
+
+
Constructions module
--------------------
diff --git a/Lua API.html b/Lua API.html
index 3e023ebd3..ed2e9f6a9 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -1163,6 +1163,69 @@ Returns true if the building was destroyed and deallocated immediately.
More high-level functions are implemented in lua and can be loaded by
require('dfhack.buildings'). See hack/lua/dfhack/buildings.lua.
+Among them are:
+
+dfhack.buildings.getFiltersByType(argtable,type,subtype,custom)
+Returns a sequence of lua structures, describing input item filters
+suitable for the specified building type, or nil if unknown or invalid.
+The returned sequence is suitable for use as the job_items argument
+of constructWithFilters.
+Uses tables defined in buildings.lua.
+Argtable members material (the default name), bucket, barrel,
+chain, mechanism, screw, pipe, anvil, weapon are used to
+augment the basic attributes with more detailed information if the
+building has input items with the matching name (see the tables for naming details).
+Note that it is impossible to override any properties this way, only supply those that
+are not mentioned otherwise; one exception is that flags2.non_economic
+is automatically cleared if an explicit material is specified.
+
+dfhack.buildings.constructBuilding{...}
+Creates a building in one call, using options contained
+in the argument table. Returns the building, or nil, error.
+NOTE: Despite the name, unless the building is abstract,
+the function creates it in an 'unconstructed' stage, with
+a queued in-game job that will actually construct it. I.e.
+the function replicates programmatically what can be done
+through the construct building menu in the game ui, except
+that it does less environment constraint checking.
+The following options can be used:
+
+pos = coordinates, or x = ..., y = ..., z = ...
+Mandatory. Specifies the left upper corner of the building.
+
+type = df.building_type.FOO, subtype = ..., custom = ...
+Mandatory. Specifies the type of the building. Obviously, subtype
+and custom are only expected if the type requires them.
+
+fields = { ... }
+Initializes fields of the building object after creation with df.assign.
+
+width = ..., height = ..., direction = ...
+Sets size and orientation of the building. If it is
+fixed-size, specified dimensions are ignored.
+
+full_rectangle = true
+For buildings like stockpiles or farm plots that can normally
+accomodate individual tile exclusion, forces an error if any
+tiles within the specified width*height are obstructed.
+
+items = { item, item ... }, or filters = { {...}, {...}... }
+Specifies explicit items or item filters to use in construction.
+It is the job of the user to ensure they are correct for the building type.
+
+abstract = true
+Specifies that the building is abstract and does not require construction.
+Required for stockpiles and civzones; an error otherwise.
+
+material = {...}, mechanism = {...}, ...
+If none of items, filter, or abstract is used,
+the function uses getFiltersByType to compute the input
+item filters, and passes the argument table through. If no filters
+can be determined this way, constructBuilding throws an error.
+
+
+
+
diff --git a/library/lua/dfhack/buildings.lua b/library/lua/dfhack/buildings.lua
index eb0a6a5b5..ad82da89a 100644
--- a/library/lua/dfhack/buildings.lua
+++ b/library/lua/dfhack/buildings.lua
@@ -4,7 +4,32 @@ local buildings = dfhack.buildings
local utils = require 'utils'
---[[ Building input material tables. ]]
+-- Uninteresting values for filter attributes when reading them from DF memory.
+-- Differs from the actual defaults of the job_item constructor in allow_artifact.
+
+buildings.input_filter_defaults = {
+ item_type = -1,
+ item_subtype = -1,
+ mat_type = -1,
+ mat_index = -1,
+ flags1 = {},
+ -- Instead of noting those that allow artifacts, mark those that forbid them.
+ -- Leaves actually enabling artifacts to the discretion of the API user,
+ -- which is the right thing because unlike the game UI these filters are
+ -- used in a way that does not give the user a chance to choose manually.
+ flags2 = { allow_artifact = true },
+ flags3 = {},
+ flags4 = 0,
+ flags5 = 0,
+ reaction_class = '',
+ has_material_reaction_product = '',
+ metal_ore = -1,
+ min_dimension = -1,
+ has_tool_use = -1,
+ quantity = 1
+}
+
+--[[ Building input material table. ]]
local building_inputs = {
[df.building_type.Chair] = { { item_type=df.item_type.CHAIR, vector_id=df.job_item_vector_id.CHAIR } },
@@ -12,7 +37,6 @@ local building_inputs = {
[df.building_type.Table] = { { item_type=df.item_type.TABLE, vector_id=df.job_item_vector_id.TABLE } },
[df.building_type.Coffin] = { { item_type=df.item_type.COFFIN, vector_id=df.job_item_vector_id.COFFIN } },
[df.building_type.FarmPlot] = { },
- [df.building_type.Furnace] = { { flags2={ building_material=true, fire_safe=true, non_economic=true } } },
[df.building_type.TradeDepot] = { { flags2={ building_material=true, non_economic=true }, quantity=3 } },
[df.building_type.Door] = { { item_type=df.item_type.DOOR, vector_id=df.job_item_vector_id.DOOR } },
[df.building_type.Floodgate] = {
@@ -40,7 +64,6 @@ local building_inputs = {
vector_id=df.job_item_vector_id.ARMORSTAND
}
},
- [df.building_type.Workshop] = { { flags2={ building_material=true, non_economic=true } } },
[df.building_type.Cabinet] = {
{ item_type=df.item_type.CABINET, vector_id=df.job_item_vector_id.CABINET }
},
@@ -89,7 +112,7 @@ local building_inputs = {
[df.building_type.ArcheryTarget] = { { flags2={ building_material=true, non_economic=true } } },
[df.building_type.Chain] = { { item_type=df.item_type.CHAIN, vector_id=df.job_item_vector_id.CHAIN } },
[df.building_type.Cage] = { { item_type=df.item_type.CAGE, vector_id=df.job_item_vector_id.CAGE } },
- [df.building_type.Weapon] = { { vector_id=df.job_item_vector_id.ANY_SPIKE } },
+ [df.building_type.Weapon] = { { name='weapon', vector_id=df.job_item_vector_id.ANY_SPIKE } },
[df.building_type.ScrewPump] = {
{
item_type=df.item_type.BLOCKS,
@@ -158,6 +181,8 @@ local building_inputs = {
[df.building_type.Hive] = { { has_tool_use=df.tool_uses.HIVE, item_type=df.item_type.TOOL } }
}
+--[[ Furnace building input material table. ]]
+
local furnace_inputs = {
[df.furnace_type.WoodFurnace] = { { flags2={ building_material=true, fire_safe=true, non_economic=true } } },
[df.furnace_type.Smelter] = { { flags2={ building_material=true, fire_safe=true, non_economic=true } } },
@@ -168,6 +193,8 @@ local furnace_inputs = {
[df.furnace_type.MagmaKiln] = { { flags2={ building_material=true, magma_safe=true, non_economic=true } } }
}
+--[[ Workshop building input material table. ]]
+
local workshop_inputs = {
[df.workshop_type.Carpenters] = { { flags2={ building_material=true, non_economic=true } } },
[df.workshop_type.Farmers] = { { flags2={ building_material=true, non_economic=true } } },
@@ -250,6 +277,8 @@ local workshop_inputs = {
}
}
+--[[ Trap building input material table. ]]
+
local trap_inputs = {
[df.trap_type.StoneFallTrap] = {
{
@@ -264,7 +293,10 @@ local trap_inputs = {
item_type=df.item_type.TRAPPARTS,
vector_id=df.job_item_vector_id.TRAPPARTS
},
- { vector_id=df.job_item_vector_id.ANY_WEAPON }
+ {
+ name='weapon',
+ vector_id=df.job_item_vector_id.ANY_WEAPON
+ }
},
[df.trap_type.Lever] = {
{
@@ -289,11 +321,28 @@ local trap_inputs = {
}
}
+--[[ Functions for lookup in tables. ]]
+
+local function get_custom_inputs(custom)
+ local defn = df.building_def.find(custom)
+ if defn ~= nil then
+ return utils.clone_with_default(defn.build_items, buildings.input_filter_defaults)
+ end
+end
+
local function get_inputs_by_type(type,subtype,custom)
if type == df.building_type.Workshop then
- return workshop_inputs[subtype]
+ if subtype == df.workshop_type.Custom then
+ return get_custom_inputs(custom)
+ else
+ return workshop_inputs[subtype]
+ end
elseif type == df.building_type.Furnace then
- return furnace_inputs[subtype]
+ if subtype == df.furnace_type.Custom then
+ return get_custom_inputs(custom)
+ else
+ return furnace_inputs[subtype]
+ end
elseif type == df.building_type.Trap then
return trap_inputs[subtype]
else
@@ -357,7 +406,7 @@ end
-- Materials:
items = { item, item ... },
-- OR
- filter = { { ... }, { ... }... }
+ filters = { { ... }, { ... }... }
-- OR
abstract = true
-- OR
diff --git a/library/lua/utils.lua b/library/lua/utils.lua
index 96ab2b190..e67801f4f 100644
--- a/library/lua/utils.lua
+++ b/library/lua/utils.lua
@@ -221,6 +221,68 @@ function clone(obj,deep)
end
end
+local function get_default(default,key,base)
+ if type(default) == 'table' then
+ local dv = default[key]
+ if dv == nil then
+ dv = default._default
+ end
+ if dv == nil then
+ dv = base
+ end
+ return dv
+ else
+ return default
+ end
+end
+
+-- Copy the object as lua data structures, skipping values matching defaults.
+function clone_with_default(obj,default,force)
+ local rv = nil
+ local function setrv(k,v)
+ if v ~= nil then
+ if rv == nil then
+ rv = {}
+ end
+ rv[k] = v
+ end
+ end
+ if default == nil then
+ return nil
+ elseif type(obj) == 'table' then
+ for k,v in pairs(obj) do
+ setrv(k, clone_with_default(v, get_default(default,k)))
+ end
+ elseif df.isvalid(obj) == 'ref' then
+ local kind = obj._kind
+ if kind == 'primitive' then
+ return clone_with_default(obj.value,default,force)
+ elseif kind == 'bitfield' then
+ for k,v in pairs(obj) do
+ setrv(k, clone_with_default(v, get_default(default,k,false)))
+ end
+ elseif kind == 'container' then
+ for k,v in ipairs(obj) do
+ setrv(k+1, clone_with_default(v, default, true))
+ end
+ else -- struct
+ for k,v in pairs(obj) do
+ setrv(k, clone_with_default(v, get_default(default,k)))
+ end
+ end
+ elseif obj == default and not force then
+ return nil
+ elseif obj == nil then
+ return NULL
+ else
+ return obj
+ end
+ if force and rv == nil then
+ rv = {}
+ end
+ return rv
+end
+
-- Sort a vector or lua table
function sort_vector(vector,field,cmp)
local fcmp = compare_field(field,cmp)
diff --git a/scripts/devel/list-filters.lua b/scripts/devel/list-filters.lua
index 69fb57164..87b9f24b1 100644
--- a/scripts/devel/list-filters.lua
+++ b/scripts/devel/list-filters.lua
@@ -1,43 +1,29 @@
-- List input items for the building currently being built.
+--
+-- This is where the filters in lua/dfhack/buildings.lua come from.
local dumper = require 'dumper'
+local utils = require 'utils'
+local buildings = require 'dfhack.buildings'
-local function copy_flags(tgt,src,name)
- local val = src[name]
- if val.whole == 0 then
- return
- end
- local out = {}
- tgt[name] = out
- for k,v in pairs(val) do
- if v then
- out[k] = v
- end
- end
-end
-
-local function copy_value(tgt,src,name,defval)
- if src[name] ~= defval then
- tgt[name] = src[name]
- end
-end
-local function copy_enum(tgt,src,name,defval,ename,enum)
- if src[name] ~= defval then
- tgt[name] = ename..'.'..enum[src[name]]
+local function name_enum(tgt,name,ename,enum)
+ if tgt[name] ~= nil then
+ tgt[name] = ename..'.'..enum[tgt[name]]
end
end
local lookup = {}
+local items = df.global.world.items
for i=df.job_item_vector_id._first_item,df.job_item_vector_id._last_item do
local id = df.job_item_vector_id.attrs[i].other
local ptr
if id == df.items_other_id.ANY then
- ptr = df.global.world.items.all
+ ptr = items.all
elseif id == df.items_other_id.BAD then
- ptr = df.global.world.items.bad
+ ptr = items.bad
else
- ptr = df.global.world.items.other[id]
+ ptr = items.other[id]
end
if ptr then
local _,addr = df.sizeof(ptr)
@@ -46,23 +32,12 @@ for i=df.job_item_vector_id._first_item,df.job_item_vector_id._last_item do
end
local function clone_filter(src,quantity)
- local tgt = {}
- src.flags2.allow_artifact = false
+ local tgt = utils.clone_with_default(src, buildings.input_filter_defaults, true)
if quantity ~= 1 then
tgt.quantity = quantity
end
- copy_enum(tgt, src, 'item_type', -1, 'df.item_type', df.item_type)
- copy_value(tgt, src, 'item_subtype', -1)
- copy_value(tgt, src, 'mat_type', -1)
- copy_value(tgt, src, 'mat_index', -1)
- copy_flags(tgt, src, 'flags1')
- copy_flags(tgt, src, 'flags2')
- copy_flags(tgt, src, 'flags3')
- copy_value(tgt, src, 'reaction_class', '')
- copy_value(tgt, src, 'has_material_reaction_product', '')
- copy_value(tgt, src, 'metal_ore', -1)
- copy_value(tgt, src, 'min_dimension', -1)
- copy_enum(tgt, src, 'has_tool_use', -1, 'df.tool_uses', df.tool_uses)
+ name_enum(tgt, 'item_type', 'df.item_type', df.item_type)
+ name_enum(tgt, 'has_tool_use', 'df.tool_uses', df.tool_uses)
local ptr = src.item_vector
if ptr and ptr ~= df.global.world.items.other[0] then
local _,addr = df.sizeof(ptr)
@@ -78,8 +53,9 @@ local function dump(name)
end
local fmt = dumper.DataDumper(out,name,false,1,4)
- local out = string.gsub(fmt, '"', '')
- print(out)
+ fmt = string.gsub(fmt, '"(df%.[^"]+)"','%1')
+ fmt = string.gsub(fmt, '%s+$', '')
+ print(fmt)
end
local itype = df.global.ui_build_selector.building_type
From e078c75737c51039b3e44f4e8540eb2de4f012db Mon Sep 17 00:00:00 2001
From: Kelly Martin
Date: Mon, 14 May 2012 13:44:03 -0500
Subject: [PATCH 10/27] Track submodules
---
library/xml | 2 +-
plugins/stonesense | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/library/xml b/library/xml
index b20eba417..dc6e5b4b1 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit b20eba4170a2b7f52e465849e8853c3ecc978a8e
+Subproject commit dc6e5b4b16a5ba3a099d8d063807312ceb6a13d3
diff --git a/plugins/stonesense b/plugins/stonesense
index 07e832b9d..15e3b726c 160000
--- a/plugins/stonesense
+++ b/plugins/stonesense
@@ -1 +1 @@
-Subproject commit 07e832b9d2b1862dc831c872a559d5704d3ad13e
+Subproject commit 15e3b726c3e68d2985aecd95d2a33bf4550caaa1
From d4f98065683dfc9521ac0d86c27b8491027a980e Mon Sep 17 00:00:00 2001
From: Kelly Martin
Date: Mon, 14 May 2012 17:30:21 -0500
Subject: [PATCH 11/27] Track library
---
library/xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/library/xml b/library/xml
index dc6e5b4b1..8a9a76b9d 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit dc6e5b4b16a5ba3a099d8d063807312ceb6a13d3
+Subproject commit 8a9a76b9d0459992a62bf054a6df98483a3b14eb
From 27cc2dc92cc7c2c5221a3e3234e8aadca343555e Mon Sep 17 00:00:00 2001
From: Kelly Martin
Date: Mon, 14 May 2012 21:54:11 -0500
Subject: [PATCH 12/27] Add dwarf state table entries for the new jobs from
.34.7 and .34.8. Also add a warning message for a dwarf who is doing an
unknown job (instead of just reading random nonsense from off the end of the
dwarf_states array).
This code is backward-compatible (the extra job entries will simply be unused in pre-.8).
---
plugins/autolabor.cpp | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp
index cd3232e64..5a588cdde 100644
--- a/plugins/autolabor.cpp
+++ b/plugins/autolabor.cpp
@@ -348,7 +348,12 @@ static const dwarf_state dwarf_states[] = {
OTHER /* CauseTrouble */,
OTHER /* DrinkBlood */,
OTHER /* ReportCrime */,
- OTHER /* ExecuteCriminal */
+ OTHER /* ExecuteCriminal */,
+ BUSY /* TrainAnimal */,
+ BUSY /* CarveTrack */,
+ BUSY /* PushTrackVehicle */,
+ BUSY /* PlaceTrackVehicle */,
+ BUSY /* StoreItemInVehicle */
};
struct labor_info
@@ -886,8 +891,13 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
assert(job >= 0);
assert(job < ARRAY_COUNT(dwarf_states));
*/
-
- dwarf_info[dwarf].state = dwarf_states[job];
+ if (job >= 0 && job < ARRAY_COUNT(dwarf_states))
+ dwarf_info[dwarf].state = dwarf_states[job];
+ else
+ {
+ out.print("Dwarf %i \"%s\" has unknown job %i\n", dwarf, dwarfs[dwarf]->name.first_name.c_str(), job);
+ dwarf_info[dwarf].state = OTHER;
+ }
}
state_count[dwarf_info[dwarf].state]++;
From e77c9dc730fdd94423319b744fb4162bd36e8377 Mon Sep 17 00:00:00 2001
From: Kelly Martin
Date: Tue, 15 May 2012 13:42:48 -0500
Subject: [PATCH 13/27] Add new PUSH_HAUL_VEHICLES labor to autolabor.
This commit will only work with 0.34.08 (or later).
---
library/xml | 2 +-
plugins/autolabor.cpp | 5 +++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/library/xml b/library/xml
index 8a9a76b9d..92dbeb626 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit 8a9a76b9d0459992a62bf054a6df98483a3b14eb
+Subproject commit 92dbeb6267a24a35babe3d5326801f2e8cfd22e1
diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp
index 5a588cdde..d89ddd7c6 100644
--- a/plugins/autolabor.cpp
+++ b/plugins/autolabor.cpp
@@ -458,7 +458,8 @@ static const struct labor_default default_labor_infos[] = {
/* GLAZING */ {AUTOMATIC, false, 1, 200, 0},
/* PRESSING */ {AUTOMATIC, false, 1, 200, 0},
/* BEEKEEPING */ {AUTOMATIC, false, 1, 1, 0}, // reduce risk of stuck beekeepers (see http://www.bay12games.com/dwarves/mantisbt/view.php?id=3981)
- /* WAX_WORKING */ {AUTOMATIC, false, 1, 200, 0},
+ /* WAX_WORKING */ {AUTOMATIC, false, 1, 200, 0},
+ /* PUSH_HAUL_VEHICLES */ {HAULERS, false, 1, 200, 0}
};
static const int responsibility_penalties[] = {
@@ -1271,7 +1272,7 @@ command_result autolabor (color_ostream &out, std::vector & parame
if (labor == df::enums::unit_labor::NONE)
{
- out.printerr("Could not find labor %s.", parameters[0].c_str());
+ out.printerr("Could not find labor %s.\n", parameters[0].c_str());
return CR_WRONG_USAGE;
}
From dbd39af58a1eea630b6e390375517acb79b179f2 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Wed, 16 May 2012 17:06:08 +0400
Subject: [PATCH 14/27] Support testing and modifying pending timeout
callbacks.
---
LUA_API.rst | 7 ++++
Lua API.html | 6 +++
library/LuaTools.cpp | 91 +++++++++++++++++++++++++++++---------------
3 files changed, 73 insertions(+), 31 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index c42785278..bd2d33cb0 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -1087,6 +1087,13 @@ Core context specific functions:
Returns the timer id, or *nil* if unsuccessful due to
world being unloaded.
+* ``dfhack.timeout_active(id[,new_callback])``
+
+ Returns the active callback with the given id, or *nil*
+ if inactive or nil id. If called with 2 arguments, replaces
+ the current callback with the given value, if still active.
+ Using ``timeout_active(id,nil)`` cancels the timer.
+
* ``dfhack.onStateChange.foo = function(code)``
Event. Receives the same codes as plugin_onstatechange in C++.
diff --git a/Lua API.html b/Lua API.html
index ed2e9f6a9..d44d82bab 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -1265,6 +1265,12 @@ and cannot be queued until it is loaded again.
Returns the timer id, or nil if unsuccessful due to
world being unloaded.
+dfhack.timeout_active(id[,new_callback])
+Returns the active callback with the given id, or nil
+if inactive or nil id. If called with 2 arguments, replaces
+the current callback with the given value, if still active.
+Using timeout_active(id,nil) cancels the timer.
+
dfhack.onStateChange.foo = function(code)
Event. Receives the same codes as plugin_onstatechange in C++.
diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp
index 794cb52a6..f794f6b41 100644
--- a/library/LuaTools.cpp
+++ b/library/LuaTools.cpp
@@ -1429,6 +1429,7 @@ int dfhack_timeout(lua_State *L)
using df::global::world;
using df::global::enabler;
+ // Parse arguments
lua_Number time = luaL_checknumber(L, 1);
int mode = luaL_checkoption(L, 2, NULL, timeout_modes);
luaL_checktype(L, 3, LUA_TFUNCTION);
@@ -1440,6 +1441,7 @@ int dfhack_timeout(lua_State *L)
return 1;
}
+ // Compute timeout value
switch (mode)
{
case 2:
@@ -1454,12 +1456,13 @@ int dfhack_timeout(lua_State *L)
default:;
}
- int id = next_timeout_id++;
int delta = time;
if (delta <= 0)
luaL_error(L, "Invalid timeout: %d", delta);
+ // Queue the timeout
+ int id = next_timeout_id++;
if (mode)
tick_timers.insert(std::pair(world->frame_counter+delta, id));
else
@@ -1473,20 +1476,44 @@ int dfhack_timeout(lua_State *L)
return 1;
}
-static void cancel_tick_timers()
+int dfhack_timeout_active(lua_State *L)
+{
+ int id = luaL_optint(L, 1, -1);
+ bool set_cb = (lua_gettop(L) >= 2);
+ lua_settop(L, 2);
+ if (!lua_isnil(L, 2))
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ if (id < 0)
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
+ lua_rawgeti(L, 3, id);
+ if (set_cb && !lua_isnil(L, -1))
+ {
+ lua_pushvalue(L, 2);
+ lua_rawseti(L, 3, id);
+ }
+ return 1;
+}
+
+static void cancel_timers(std::multimap &timers)
{
using Lua::Core::State;
Lua::StackUnwinder frame(State);
lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
- for (auto it = tick_timers.begin(); it != tick_timers.end(); ++it)
+ for (auto it = timers.begin(); it != timers.end(); ++it)
{
lua_pushnil(State);
lua_rawseti(State, frame[1], it->second);
}
- tick_timers.clear();
+ timers.clear();
}
void DFHack::Lua::Core::onStateChange(color_ostream &out, int code) {
@@ -1496,7 +1523,7 @@ void DFHack::Lua::Core::onStateChange(color_ostream &out, int code) {
{
case SC_MAP_UNLOADED:
case SC_WORLD_UNLOADED:
- cancel_tick_timers();
+ cancel_timers(tick_timers);
break;
default:;
@@ -1506,40 +1533,40 @@ void DFHack::Lua::Core::onStateChange(color_ostream &out, int code) {
Lua::InvokeEvent(out, State, (void*)onStateChange, 1);
}
-void DFHack::Lua::Core::onUpdate(color_ostream &out)
+static void run_timers(color_ostream &out, lua_State *L,
+ std::multimap &timers, int table, int bound)
{
- using df::global::world;
-
- Lua::StackUnwinder frame(State);
- lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
-
- frame_idx++;
-
- while (!frame_timers.empty() &&
- frame_timers.begin()->first <= frame_idx)
+ while (!timers.empty() && timers.begin()->first <= bound)
{
- int id = frame_timers.begin()->second;
- frame_timers.erase(frame_timers.begin());
+ int id = timers.begin()->second;
+ timers.erase(timers.begin());
- lua_rawgeti(State, frame[1], id);
- lua_pushnil(State);
- lua_rawseti(State, frame[1], id);
+ lua_rawgeti(L, table, id);
+
+ if (lua_isnil(L, -1))
+ lua_pop(L, 1);
+ else
+ {
+ lua_pushnil(L);
+ lua_rawseti(L, table, id);
- Lua::SafeCall(out, State, 0, 0);
+ Lua::SafeCall(out, L, 0, 0);
+ }
}
+}
- while (!tick_timers.empty() &&
- tick_timers.begin()->first <= world->frame_counter)
- {
- int id = tick_timers.begin()->second;
- tick_timers.erase(tick_timers.begin());
+void DFHack::Lua::Core::onUpdate(color_ostream &out)
+{
+ using df::global::world;
- lua_rawgeti(State, frame[1], id);
- lua_pushnil(State);
- lua_rawseti(State, frame[1], id);
+ if (frame_timers.empty() && tick_timers.empty())
+ return;
- Lua::SafeCall(out, State, 0, 0);
- }
+ Lua::StackUnwinder frame(State);
+ lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN);
+
+ run_timers(out, State, frame_timers, frame[1], ++frame_idx);
+ run_timers(out, State, tick_timers, frame[1], world->frame_counter);
}
void DFHack::Lua::Core::Init(color_ostream &out)
@@ -1562,6 +1589,8 @@ void DFHack::Lua::Core::Init(color_ostream &out)
lua_pushcfunction(State, dfhack_timeout);
lua_setfield(State, -2, "timeout");
+ lua_pushcfunction(State, dfhack_timeout_active);
+ lua_setfield(State, -2, "timeout_active");
lua_pop(State, 1);
}
From 8185eec95c82ea5acb4f49144e6aab2306bf7cd8 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Wed, 16 May 2012 17:46:44 +0400
Subject: [PATCH 15/27] Add two more development related lua scripts.
---
scripts/devel/cmptiles.lua | 42 ++++++++++++++++++
scripts/devel/watch-minecarts.lua | 74 +++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+)
create mode 100644 scripts/devel/cmptiles.lua
create mode 100644 scripts/devel/watch-minecarts.lua
diff --git a/scripts/devel/cmptiles.lua b/scripts/devel/cmptiles.lua
new file mode 100644
index 000000000..8421038eb
--- /dev/null
+++ b/scripts/devel/cmptiles.lua
@@ -0,0 +1,42 @@
+-- Lists and/or compares two tiletype material groups.
+-- Usage: devel/cmptiles material1 [material2]
+
+local nmat1,nmat2=...
+local mat1 = df.tiletype_material[nmat1]
+local mat2 = df.tiletype_material[nmat2]
+
+local tmat1 = {}
+local tmat2 = {}
+
+local attrs = df.tiletype.attrs
+
+for i=df.tiletype._first_item,df.tiletype._last_item do
+ local shape = df.tiletype_shape[attrs[i].shape] or ''
+ local variant = df.tiletype_variant[attrs[i].variant] or ''
+ local special = df.tiletype_special[attrs[i].special] or ''
+ local direction = attrs[i].direction or ''
+ local code = shape..':'..variant..':'..special..':'..direction
+
+ if attrs[i].material == mat1 then
+ tmat1[code] = true
+ end
+ if attrs[i].material == mat2 then
+ tmat2[code] = true
+ end
+end
+
+local function list_diff(n, t1, t2)
+ local lst = {}
+ for k,v in pairs(t1) do
+ if not t2[k] then
+ lst[#lst+1] = k
+ end
+ end
+ table.sort(lst)
+ for k,v in ipairs(lst) do
+ print(n, v)
+ end
+end
+
+list_diff(nmat1,tmat1,tmat2)
+list_diff(nmat2,tmat2,tmat1)
diff --git a/scripts/devel/watch-minecarts.lua b/scripts/devel/watch-minecarts.lua
new file mode 100644
index 000000000..166004d85
--- /dev/null
+++ b/scripts/devel/watch-minecarts.lua
@@ -0,0 +1,74 @@
+-- Logs minecart coordinates and speeds to console.
+
+last_stats = last_stats or {}
+
+function compare_one(vehicle)
+ local last = last_stats[vehicle.id]
+ local item = df.item.find(vehicle.item_id)
+ local ipos = item.pos
+ local new = {
+ ipos.x*100000 + vehicle.offset_x, vehicle.speed_x,
+ ipos.y*100000 + vehicle.offset_y, vehicle.speed_y,
+ ipos.z*100000 + vehicle.offset_z, vehicle.speed_z
+ }
+
+ if (last == nil) or item.flags.on_ground then
+ local delta = { vehicle.id }
+ local show = (last == nil)
+
+ for i=1,6 do
+ local rv = 0
+ if last then
+ rv = last[i]
+ end
+ delta[i*2] = new[i]/100000
+ local dv = new[i] - rv
+ delta[i*2+1] = dv/100000
+ if dv ~= 0 then
+ show = true
+ end
+ end
+
+ if show then
+ print(table.unpack(delta))
+ end
+ end
+
+ last_stats[vehicle.id] = new
+end
+
+function compare_all()
+ local seen = {}
+ for _,v in ipairs(df.global.world.vehicles.all) do
+ seen[v.id] = true
+ compare_one(v)
+ end
+ for k,v in pairs(last_stats) do
+ if not seen[k] then
+ print(k,'DEAD')
+ end
+ end
+end
+
+function start_timer()
+ if not dfhack.timeout_active(timeout_id) then
+ timeout_id = dfhack.timeout(1, 'ticks', function()
+ compare_all()
+ start_timer()
+ end);
+ if not timeout_id then
+ dfhack.printerr('Could not start timer in watch-minecarts')
+ end
+ end
+end
+
+compare_all()
+
+local cmd = ...
+
+if cmd == 'start' then
+ start_timer()
+elseif cmd == 'stop' then
+ dfhack.timeout_active(timeout_id, nil)
+end
+
From 68c5d9b86c2a252f87f53804c3af94881c4ae39e Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Wed, 16 May 2012 18:10:07 +0400
Subject: [PATCH 16/27] Stop Shift-Enter from being handled as if it was
Shift-M.
---
library/Core.cpp | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/library/Core.cpp b/library/Core.cpp
index d7e4435ce..7f08f402f 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -1180,6 +1180,18 @@ int Core::UnicodeAwareSym(const SDL::KeyboardEvent& ke)
if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym;
if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym;
+ // These keys are mapped to the same control codes as Ctrl-?
+ switch (ke.ksym.sym) {
+ case SDL::K_RETURN:
+ case SDL::K_KP_ENTER:
+ case SDL::K_TAB:
+ case SDL::K_ESCAPE:
+ case SDL::K_DELETE:
+ return ke.ksym.sym;
+ default:
+ break;
+ }
+
int unicode = ke.ksym.unicode;
// convert Ctrl characters to their 0x40-0x5F counterparts:
From cba3f8d61d66e27de2ea7ec9e2f4d51d3706087b Mon Sep 17 00:00:00 2001
From: Kelly Martin
Date: Wed, 16 May 2012 11:28:21 -0500
Subject: [PATCH 17/27] Track xml
---
library/xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 efdb709284d393938db6b60185ee3898cb068954 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 17 May 2012 00:19:29 +0400
Subject: [PATCH 18/27] 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 19/27] 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 20/27] 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 21/27] 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 22/27] 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
From 3f542b4df10d8ff7df6151ee4eee2707134c696c Mon Sep 17 00:00:00 2001
From: Kelly Martin
Date: Fri, 18 May 2012 07:40:05 -0500
Subject: [PATCH 23/27] Update merge
---
library/xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/library/xml b/library/xml
index ab102b93f..3c8269225 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit ab102b93fca9b1ae8b5fbfc3ae5a9ee06ee60811
+Subproject commit 3c8269225b1a68fd8803b7b7160d547247449789
From 48185568e9a9370f843fb28f1ff53335639b92d6 Mon Sep 17 00:00:00 2001
From: Warmist
Date: Fri, 18 May 2012 16:05:29 +0300
Subject: [PATCH 24/27] Added df::Items::moveToBuilding. Moved item from ground
to building, usefull for museum forts (placing items on tables)
---
library/LuaApi.cpp | 7 +++++++
library/include/modules/Items.h | 4 +++-
library/modules/Items.cpp | 33 +++++++++++++++++++++++++++++++++
3 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 529bdd077..d4c3b157d 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -755,6 +755,12 @@ static bool items_moveToContainer(df::item *item, df::item *container)
return Items::moveToContainer(mc, item, container);
}
+static bool items_moveToBuilding(df::item *item, df::building_actual *building, int use_mode)
+{
+ MapExtras::MapCache mc;
+ return Items::moveToBuilding(mc, item, building,use_mode);
+}
+
static const LuaWrapper::FunctionReg dfhack_items_module[] = {
WRAPM(Items, getGeneralRef),
WRAPM(Items, getSpecificRef),
@@ -763,6 +769,7 @@ static const LuaWrapper::FunctionReg dfhack_items_module[] = {
WRAPM(Items, getContainer),
WRAPN(moveToGround, items_moveToGround),
WRAPN(moveToContainer, items_moveToContainer),
+ WRAPN(moveToBuilding, items_moveToBuilding),
{ NULL, NULL }
};
diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h
index 8353d24c3..54db8e6ca 100644
--- a/library/include/modules/Items.h
+++ b/library/include/modules/Items.h
@@ -37,6 +37,7 @@ distribution.
#include "df/item_type.h"
#include "df/general_ref.h"
#include "df/specific_ref.h"
+#include "df/building_actual.h"
namespace df
{
@@ -147,5 +148,6 @@ DFHACK_EXPORT df::coord getPosition(df::item *item);
DFHACK_EXPORT bool moveToGround(MapExtras::MapCache &mc, df::item *item, df::coord pos);
DFHACK_EXPORT bool moveToContainer(MapExtras::MapCache &mc, df::item *item, df::item *container);
+DFHACK_EXPORT bool moveToBuilding(MapExtras::MapCache &mc, df::item *item, df::building_actual *building,int16_t use_mode);
+}
}
-}
\ No newline at end of file
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index 335d7d8fc..a18ba60cb 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -48,6 +48,7 @@ using namespace std;
#include "df/world.h"
#include "df/item.h"
#include "df/building.h"
+#include "df/building_actual.h"
#include "df/tool_uses.h"
#include "df/itemdef_weaponst.h"
#include "df/itemdef_trapcompst.h"
@@ -69,6 +70,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/general_ref_building_holderst.h"
#include "df/vermin.h"
using namespace DFHack;
@@ -676,3 +678,34 @@ bool DFHack::Items::moveToContainer(MapExtras::MapCache &mc, df::item *item, df:
return true;
}
+DFHACK_EXPORT bool DFHack::Items::moveToBuilding(MapExtras::MapCache &mc, df::item *item, df::building_actual *building,int16_t use_mode)
+{
+ CHECK_NULL_POINTER(item);
+ CHECK_NULL_POINTER(building);
+
+ auto ref = df::allocate();
+ if(!ref)
+ {
+ delete ref;
+ Core::printerr("Could not allocate building holder refs.\n");
+ return false;
+ }
+ if (!detachItem(mc, item))
+ {
+ delete ref;
+ return false;
+ }
+ item->pos.x=building->centerx;
+ item->pos.y=building->centery;
+ item->pos.z=building->z;
+ item->flags.bits.in_building=true;
+
+ ref->building_id=building->id;
+ item->itemrefs.push_back(ref);
+
+ auto con=new df::building_actual::T_contained_items;
+ con->item=item;
+ con->use_mode=use_mode;
+ building->contained_items.push_back(con);
+ return true;
+}
From 51ad697bf504754890f75f0aa4c527db546c7767 Mon Sep 17 00:00:00 2001
From: Kelly Martin
Date: Fri, 18 May 2012 08:25:25 -0500
Subject: [PATCH 25/27] Fix unresolved symbol reference in Windows platform.
---
library/PlugLoad-windows.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/library/PlugLoad-windows.cpp b/library/PlugLoad-windows.cpp
index f9a75df97..714960e64 100644
--- a/library/PlugLoad-windows.cpp
+++ b/library/PlugLoad-windows.cpp
@@ -28,6 +28,7 @@ distribution.
#include
#include
#include
+#include "Core.h"
#include "PluginManager.h"
#include "Hooks.h"
#include
From 3c44e22760b6cead3b42194097c24700b314683a Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Fri, 18 May 2012 17:54:05 +0400
Subject: [PATCH 26/27] Support trade viewscreens in Items::getSelectedItem.
---
library/include/PluginManager.h | 2 ++
library/modules/Gui.cpp | 30 ++++++++++++++++++++++++++++++
library/xml | 2 +-
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h
index 02974f36b..31633dfe2 100644
--- a/library/include/PluginManager.h
+++ b/library/include/PluginManager.h
@@ -31,6 +31,8 @@ distribution.
#include
#include
+#include "Core.h"
+
#include "RemoteClient.h"
typedef struct lua_State lua_State;
diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp
index 2d9402fca..461921391 100644
--- a/library/modules/Gui.cpp
+++ b/library/modules/Gui.cpp
@@ -54,7 +54,9 @@ using namespace DFHack;
#include "df/viewscreen_layer_workshop_profilest.h"
#include "df/viewscreen_layer_noblelistst.h"
#include "df/viewscreen_layer_overall_healthst.h"
+#include "df/viewscreen_layer_assigntradest.h"
#include "df/viewscreen_petst.h"
+#include "df/viewscreen_tradegoodsst.h"
#include "df/ui_unit_view_mode.h"
#include "df/ui_sidebar_menus.h"
#include "df/ui_look_list.h"
@@ -69,6 +71,7 @@ using namespace DFHack;
#include "df/interfacest.h"
#include "df/graphic.h"
#include "df/layer_object_listst.h"
+#include "df/assign_trade_status.h"
using namespace df::enums;
using df::global::gview;
@@ -420,6 +423,33 @@ static df::item *getAnyItem(df::viewscreen *top)
return ref ? ref->getItem() : NULL;
}
+ if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_assigntradest, top))
+ {
+ auto list1 = getLayerList(screen, 0);
+ auto list2 = getLayerList(screen, 1);
+ if (!list1 || !list2 || !list2->bright)
+ return NULL;
+
+ int list_idx = vector_get(screen->visible_lists, list1->cursor, (int16_t)-1);
+ unsigned num_lists = sizeof(screen->lists)/sizeof(std::vector);
+ if (unsigned(list_idx) >= num_lists)
+ return NULL;
+
+ int idx = vector_get(screen->lists[list_idx], list2->cursor, -1);
+ if (auto info = vector_get(screen->info, idx))
+ return info->item;
+
+ return NULL;
+ }
+
+ if (VIRTUAL_CAST_VAR(screen, df::viewscreen_tradegoodsst, top))
+ {
+ if (screen->in_right_pane)
+ return vector_get(screen->broker_items, screen->broker_cursor);
+ else
+ return vector_get(screen->trader_items, screen->trader_cursor);
+ }
+
if (!Gui::dwarfmode_hotkey(top))
return NULL;
diff --git a/library/xml b/library/xml
index 3c8269225..f004804fd 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit 3c8269225b1a68fd8803b7b7160d547247449789
+Subproject commit f004804fd655efcb4bf9ea31bd95ae4f759937b4
From e2f39368b17bbc9d6b380faed7ceb52b1bd8eb2d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Mr=C3=A1zek?=
Date: Fri, 18 May 2012 17:43:22 +0200
Subject: [PATCH 27/27] Sync submodules
---
plugins/stonesense | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/stonesense b/plugins/stonesense
index 15e3b726c..37a823541 160000
--- a/plugins/stonesense
+++ b/plugins/stonesense
@@ -1 +1 @@
-Subproject commit 15e3b726c3e68d2985aecd95d2a33bf4550caaa1
+Subproject commit 37a823541538023b9f3d0d1e8039cf32851de68d