Merge branch 'master' of git://github.com/peterix/dfhack

develop
Quietust 2012-05-18 22:21:55 -05:00
commit a47c2ecbda
20 changed files with 474 additions and 87 deletions

@ -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)``
@ -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++.

@ -935,7 +935,7 @@ a lua list containing them.</p>
<h3><a class="toc-backref" href="#id16">Units module</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.units.getPosition(unit)</tt></p>
<p>Returns true <em>x,y,z</em> of the unit; may be not equal to unit.pos if caged.</p>
<p>Returns true <em>x,y,z</em> of the unit, or <em>nil</em> if invalid; may be not equal to unit.pos if caged.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getContainer(unit)</tt></p>
<p>Returns the container (cage) item or <em>nil</em>.</p>
@ -982,7 +982,7 @@ or raws. The <tt class="docutils literal">ignore_noble</tt> boolean disables the
<h3><a class="toc-backref" href="#id17">Items module</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.items.getPosition(item)</tt></p>
<p>Returns true <em>x,y,z</em> of the item; may be not equal to item.pos if in inventory.</p>
<p>Returns true <em>x,y,z</em> of the item, or <em>nil</em> if invalid; may be not equal to item.pos if in inventory.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.getGeneralRef(item, type)</tt></p>
<p>Searches for a general_ref with the given type.</p>
@ -1265,6 +1265,12 @@ and cannot be queued until it is loaded again.
Returns the timer id, or <em>nil</em> if unsuccessful due to
world being unloaded.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.timeout_active(id[,new_callback])</span></tt></p>
<p>Returns the active callback with the given id, or <em>nil</em>
if inactive or nil id. If called with 2 arguments, replaces
the current callback with the given value, if still active.
Using <tt class="docutils literal">timeout_active(id,nil)</tt> cancels the timer.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.onStateChange.foo = function(code)</tt></p>
<p>Event. Receives the same codes as plugin_onstatechange in C++.</p>
</li>

@ -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.
@ -1017,7 +1018,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 +1044,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 +1059,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 +1072,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 +1114,34 @@ 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);
// process timers in lua
Lua::Core::onUpdate(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);
}
// FIXME: needs to terminate the IO threads and properly dismantle all the machinery involved.
int Core::Shutdown ( void )
{
@ -1180,6 +1206,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:

@ -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 }
};

@ -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<int,int>(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<int,int> &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<int,int> &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);
}

@ -28,6 +28,7 @@ distribution.
#include <stdint.h>
#include <vector>
#include <string>
#include "Core.h"
#include "PluginManager.h"
#include "Hooks.h"
#include <stdio.h>

@ -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!

@ -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

@ -31,6 +31,8 @@ distribution.
#include <string>
#include <vector>
#include "Core.h"
#include "RemoteClient.h"
typedef struct lua_State lua_State;
@ -65,16 +67,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*);

@ -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);
}
}

@ -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. ]]

@ -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;
@ -86,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();
@ -289,6 +342,10 @@ bool Buildings::getCorrectSize(df::coord2d &size, df::coord2d &center,
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 +649,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 +944,11 @@ bool Buildings::constructWithFilters(df::building *bld, std::vector<df::job_item
if (items[i]->quantity < 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;
@ -891,6 +958,8 @@ bool Buildings::constructWithFilters(df::building *bld, std::vector<df::job_item
bld->mat_index = items[i]->mat_index;
}
buildings_do_onupdate = true;
createDesign(bld, rough);
return true;
}
@ -954,3 +1023,4 @@ bool Buildings::deconstruct(df::building *bld)
return true;
}

@ -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<int32_t>);
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;

@ -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,8 @@ 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;
using namespace df::enums;
@ -512,9 +515,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 +538,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 +647,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 +661,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;
}
@ -652,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<df::general_ref_building_holderst>();
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;
}

@ -49,6 +49,7 @@ using namespace std;
#include "df/world.h"
#include "df/ui.h"
#include "df/job.h"
#include "df/unit_inventory_item.h"
#include "df/unit_soul.h"
#include "df/nemesis_record.h"
@ -215,24 +216,18 @@ void Units::CopyCreature(df::unit * source, t_unit & furball)
}
}
*/
/*
furball.current_job.occupationPtr = p->readDWord (addr_cr + offs.current_job_offset);
if(furball.current_job.occupationPtr)
{
furball.current_job.active = true;
furball.current_job.jobType = p->readByte (furball.current_job.occupationPtr + offs.job_type_offset );
furball.current_job.jobId = p->readWord (furball.current_job.occupationPtr + offs.job_id_offset);
}
else
if(source->job.current_job == NULL)
{
furball.current_job.active = false;
}
*/
// no jobs for now...
else
{
furball.current_job.active = false;
furball.current_job.active = true;
furball.current_job.jobType = source->job.current_job->job_type;
furball.current_job.jobId = source->job.current_job->id;
}
}
int32_t Units::FindIndexById(int32_t creature_id)
{
return df::unit::binsearch_index(world->units.all, creature_id);

@ -1 +1 @@
Subproject commit b20eba4170a2b7f52e465849e8853c3ecc978a8e
Subproject commit f004804fd655efcb4bf9ea31bd95ae4f759937b4

@ -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
@ -452,8 +457,9 @@ static const struct labor_default default_labor_infos[] = {
/* POTTERY */ {AUTOMATIC, false, 1, 200, 0},
/* GLAZING */ {AUTOMATIC, false, 1, 200, 0},
/* PRESSING */ {AUTOMATIC, false, 1, 200, 0},
/* BEEKEEPING */ {AUTOMATIC, false, 1, 200, 0},
/* WAX_WORKING */ {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},
/* PUSH_HAUL_VEHICLES */ {HAULERS, false, 1, 200, 0}
};
static const int responsibility_penalties[] = {
@ -886,8 +892,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]++;
@ -1261,7 +1272,7 @@ command_result autolabor (color_ostream &out, std::vector <std::string> & 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;
}

@ -1 +1 @@
Subproject commit 07e832b9d2b1862dc831c872a559d5704d3ad13e
Subproject commit 37a823541538023b9f3d0d1e8039cf32851de68d

@ -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)

@ -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