Merge remote-tracking branch 'angavrilov/master' into 0.34.11-r4

Conflicts:
	NEWS
	library/xml
	plugins/CMakeLists.txt
	plugins/autoSyndrome.cpp
develop
expwnent 2013-10-19 20:19:29 -04:00
commit 57fc0f3e89
71 changed files with 2136 additions and 209 deletions

@ -104,9 +104,9 @@ OPTION(BUILD_PLUGINS "Build the plugins." ON)
# enable C++11 features # enable C++11 features
IF(UNIX) IF(UNIX)
add_definitions(-DLINUX_BUILD) add_definitions(-DLINUX_BUILD)
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -Wall -Wno-unused-variable") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g -Wall -Wno-unused-variable")
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic -std=c++0x") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -m32 -march=i686 -mtune=generic -std=c++0x")
SET(CMAKE_C_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -m32 -march=i686 -mtune=generic")
ELSEIF(MSVC) ELSEIF(MSVC)
# for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP")

@ -717,6 +717,57 @@ Functions:
Checks if the material matches job_material_category or job_item. Checks if the material matches job_material_category or job_item.
Accept dfhack_material_category auto-assign table. Accept dfhack_material_category auto-assign table.
Random number generation
------------------------
* ``dfhack.random.new([seed[,perturb_count]])``
Creates a new random number generator object. Without any
arguments, the object is initialized using current time.
Otherwise, the seed must be either a non-negative integer,
or a list of such integers. The second argument may specify
the number of additional randomization steps performed to
improve the initial state.
* ``rng:init([seed[,perturb_count]])``
Re-initializes an already existing random number generator object.
* ``rng:random([limit])``
Returns a random integer. If ``limit`` is specified, the value
is in the range [0, limit); otherwise it uses the whole 32-bit
unsigned integer range.
* ``rng:drandom()``
Returns a random floating-point number in the range [0,1).
* ``rng:drandom0()``
Returns a random floating-point number in the range (0,1).
* ``rng:drandom1()``
Returns a random floating-point number in the range [0,1].
* ``rng:unitrandom()``
Returns a random floating-point number in the range [-1,1].
* ``rng:unitvector([size])``
Returns multiple values that form a random vector of length 1,
uniformly distributed over the corresponding sphere surface.
The default size is 3.
* ``fn = rng:perlin([dim]); fn(x[,y[,z]])``
Returns a closure that computes a classical Perlin noise function
of dimension *dim*, initialized from this random generator.
Dimension may be 1, 2 or 3 (default).
C++ function wrappers C++ function wrappers
===================== =====================

@ -11,10 +11,12 @@ DFHack future
- multicmd: run a sequence of dfhack commands, separated by ';' - multicmd: run a sequence of dfhack commands, separated by ';'
- autobutcher: A GUI front-end for the autobutcher plugin. - autobutcher: A GUI front-end for the autobutcher plugin.
- invasionNow: trigger an invasion, or many - invasionNow: trigger an invasion, or many
- startdwarf: change the number of dwarves for a new embark
Misc improvements: Misc improvements:
- exterminate: renamed from slayrace, add help message, add butcher mode - exterminate: renamed from slayrace, add help message, add butcher mode
- ruby: add df.dfhack_run "somecommand" - ruby: add df.dfhack_run "somecommand"
- magmasource: rename to source, allow water/magma sources/drains - magmasource: rename to 'source', allow water/magma sources/drains
- core: fix SC_WORLD_(UN)LOADED event for arena mode
- autoSyndrome: - autoSyndrome:
disable by default disable by default
reorganized special tags reorganized special tags
@ -23,6 +25,8 @@ DFHack future
- syndromeTrigger: replaces and extends trueTransformation. Can trigger things when syndromes are added for any reason. - syndromeTrigger: replaces and extends trueTransformation. Can trigger things when syndromes are added for any reason.
- fastdwarf: fixed bug involving fastdwarf and teledwarf being on at the same time - fastdwarf: fixed bug involving fastdwarf and teledwarf being on at the same time
- workNow: can optionally look for jobs when jobs are completed - workNow: can optionally look for jobs when jobs are completed
New tweaks:
- hive-crash: Prevent crash if bees die in a hive with ungathered products (bug 6368).
New plugins: New plugins:
- buildingplan: Place furniture before it's built - buildingplan: Place furniture before it's built
- outsideOnly: make raw-specified buildings impossible to build inside - outsideOnly: make raw-specified buildings impossible to build inside

@ -209,6 +209,25 @@ or is a prefix ending at a '/' boundary would be considered for execution, i.e.
for context ``foo/bar/baz``, possible matches are any of ``@foo/bar/baz``, ``@foo/bar``, for context ``foo/bar/baz``, possible matches are any of ``@foo/bar/baz``, ``@foo/bar``,
``@foo`` or none. ``@foo`` or none.
Enabling plugins
================
Many plugins can be in a distinct enabled or disabled state. Some of
them activate and deactivate automatically depending on the contents
of the world raws. Others store their state in world data. However a
number of them have to be enabled globally, and the init file is the
right place to do it.
Most of such plugins support the built-in ``enable`` and ``disable``
commands. Calling them at any time without arguments prints a list
of enabled and disabled plugins, and shows whether that can be changed
through the same commands.
To enable or disable plugins that support this, use their names as
arguments for the command::
enable manipulator search
======== ========
Commands Commands
@ -1279,6 +1298,9 @@ Subcommands that persist until disabled or DF quit:
(i.e. the more units you have, the slower it becomes), and making (i.e. the more units you have, the slower it becomes), and making
the units spar more. the units spar more.
:hive-crash: The hive code crashes if there are ungathered products in a hive without bees (bug 6368).
This tweak prevents it by auto-gathering the products if this happens.
fix-armory fix-armory
---------- ----------

@ -147,8 +147,27 @@ tweak military-color-assigned
# remove inverse dependency of squad training speed on unit list size and use more sparring # remove inverse dependency of squad training speed on unit list size and use more sparring
tweak military-training tweak military-training
# enable autoSyndrome # prevent crash if bees die in a hive with ungathered products by insta-gathering them
autoSyndrome enable tweak hive-crash
###########################
# Globally acting plugins #
###########################
# Dwarf Manipulator (simple in-game Dwarf Therapist replacement)
enable manipulator
# Search tool in various screens (by falconne)
enable search
# Improved build material selection interface (by falconne)
enable automaterial
# Other interface improvement tools
#enable dwarfmonitor mousequery autotrade buildingplan resume zone
# Auto Syndrome
#autoSyndrome enable
########### ###########
# Scripts # # Scripts #

@ -120,6 +120,7 @@ include/modules/Maps.h
include/modules/MapCache.h include/modules/MapCache.h
include/modules/Materials.h include/modules/Materials.h
include/modules/Notes.h include/modules/Notes.h
include/modules/Random.h
include/modules/Screen.h include/modules/Screen.h
include/modules/Translation.h include/modules/Translation.h
include/modules/Vermin.h include/modules/Vermin.h
@ -142,6 +143,7 @@ modules/kitchen.cpp
modules/Maps.cpp modules/Maps.cpp
modules/Materials.cpp modules/Materials.cpp
modules/Notes.cpp modules/Notes.cpp
modules/Random.cpp
modules/Screen.cpp modules/Screen.cpp
modules/Translation.cpp modules/Translation.cpp
modules/Vermin.cpp modules/Vermin.cpp
@ -362,7 +364,7 @@ if(BUILD_DEVEL)
# without the '/', the directory itself is installed # without the '/', the directory itself is installed
install(DIRECTORY include/ install(DIRECTORY include/
DESTINATION ${DFHACK_INCLUDES_DESTINATION} DESTINATION ${DFHACK_INCLUDES_DESTINATION}
FILES_MATCHING PATTERN "*.h" ) #linux: include FILES_MATCHING PATTERN "*.h" PATTERN "*.inc" ) #linux: include
# Building the docs # Building the docs
IF(BUILD_DOXYGEN) IF(BUILD_DOXYGEN)
add_subdirectory (doc) add_subdirectory (doc)

@ -259,7 +259,7 @@ static void listScripts(PluginManager *plug_mgr, std::map<string,string> &pset,
pset[prefix + files[i].substr(0, files[i].size()-4)] = help; pset[prefix + files[i].substr(0, files[i].size()-4)] = help;
} }
else if (plug_mgr->eval_ruby && hasEnding(files[i], ".rb")) else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && hasEnding(files[i], ".rb"))
{ {
std::string help = getScriptHelp(path + files[i], "# "); std::string help = getScriptHelp(path + files[i], "# ");
@ -312,6 +312,9 @@ static command_result runLuaScript(color_ostream &out, std::string name, vector<
static command_result runRubyScript(color_ostream &out, PluginManager *plug_mgr, std::string name, vector<string> &args) static command_result runRubyScript(color_ostream &out, PluginManager *plug_mgr, std::string name, vector<string> &args)
{ {
if (!plug_mgr->ruby || !plug_mgr->ruby->is_enabled())
return CR_FAILURE;
std::string rbcmd = "$script_args = ["; std::string rbcmd = "$script_args = [";
for (size_t i = 0; i < args.size(); i++) for (size_t i = 0; i < args.size(); i++)
rbcmd += "'" + args[i] + "', "; rbcmd += "'" + args[i] + "', ";
@ -319,7 +322,7 @@ static command_result runRubyScript(color_ostream &out, PluginManager *plug_mgr,
rbcmd += "catch(:script_finished) { load './hack/scripts/" + name + ".rb' }"; rbcmd += "catch(:script_finished) { load './hack/scripts/" + name + ".rb' }";
return plug_mgr->eval_ruby(out, rbcmd.c_str()); return plug_mgr->ruby->eval_ruby(out, rbcmd.c_str());
} }
command_result Core::runCommand(color_ostream &out, const std::string &command) command_result Core::runCommand(color_ostream &out, const std::string &command)
@ -450,7 +453,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
con.print("%s: %s\n", parts[0].c_str(), help.c_str()); con.print("%s: %s\n", parts[0].c_str(), help.c_str());
return CR_OK; return CR_OK;
} }
if (plug_mgr->eval_ruby && fileExists(filename + ".rb")) if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && fileExists(filename + ".rb"))
{ {
string help = getScriptHelp(filename + ".rb", "# "); string help = getScriptHelp(filename + ".rb", "# ");
con.print("%s: %s\n", parts[0].c_str(), help.c_str()); con.print("%s: %s\n", parts[0].c_str(), help.c_str());
@ -544,6 +547,56 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
} }
} }
} }
else if( first == "enable" || first == "disable" )
{
CoreSuspender suspend;
bool enable = (first == "enable");
if(parts.size())
{
command_result res = CR_OK;
for (size_t i = 0; i < parts.size(); i++)
{
Plugin * plug = plug_mgr->getPluginByName(parts[i]);
if(!plug)
{
res = CR_NOT_FOUND;
con.printerr("No such plugin: %s\n", parts[i].c_str());
}
else if (!plug->can_set_enabled())
{
res = CR_NOT_IMPLEMENTED;
con.printerr("Cannot %s plugin: %s\n", first.c_str(), parts[i].c_str());
}
else
{
res = plug->set_enabled(con, enable);
if (res != CR_OK || plug->is_enabled() != enable)
con.printerr("Could not %s plugin: %s\n", first.c_str(), parts[i].c_str());
}
}
return res;
}
else
{
for(size_t i = 0; i < plug_mgr->size();i++)
{
Plugin * plug = (plug_mgr->operator[](i));
if (!plug->can_be_enabled()) continue;
con.print(
"%20s\t%-3s%s\n",
(plug->getName()+":").c_str(),
plug->is_enabled() ? "on" : "off",
plug->can_set_enabled() ? "" : " (controlled elsewhere)"
);
}
}
}
else if(first == "ls" || first == "dir") else if(first == "ls" || first == "dir")
{ {
bool all = false; bool all = false;
@ -584,6 +637,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
" load PLUGIN|all - Load a plugin by name or load all possible plugins.\n" " load PLUGIN|all - Load a plugin by name or load all possible plugins.\n"
" unload PLUGIN|all - Unload a plugin or all loaded plugins.\n" " unload PLUGIN|all - Unload a plugin or all loaded plugins.\n"
" reload PLUGIN|all - Reload a plugin or all loaded plugins.\n" " reload PLUGIN|all - Reload a plugin or all loaded plugins.\n"
" enable/disable PLUGIN - Enable or disable a plugin if supported.\n"
"\n" "\n"
"plugins:\n" "plugins:\n"
); );
@ -716,7 +770,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
if (fileExists(filename + ".lua")) if (fileExists(filename + ".lua"))
res = runLuaScript(con, first, parts); res = runLuaScript(con, first, parts);
else if (plug_mgr->eval_ruby && fileExists(filename + ".rb")) else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && fileExists(filename + ".rb"))
res = runRubyScript(con, plug_mgr, first, parts); res = runRubyScript(con, plug_mgr, first, parts);
else if (try_autocomplete(con, first, completed)) else if (try_autocomplete(con, first, completed))
return CR_NOT_IMPLEMENTED;// runCommand(con, completed, parts); return CR_NOT_IMPLEMENTED;// runCommand(con, completed, parts);
@ -1160,7 +1214,8 @@ void Core::doUpdate(color_ostream &out, bool first_update)
{ {
df::world_data *wdata = df::global::world->world_data; df::world_data *wdata = df::global::world->world_data;
// when the game is unloaded, world_data isn't deleted, but its contents are // when the game is unloaded, world_data isn't deleted, but its contents are
if (wdata && !wdata->sites.empty()) // regions work to detect arena too
if (wdata && !wdata->regions.empty())
new_wdata = wdata; new_wdata = wdata;
new_mapdata = df::global::world->map.block_index; new_mapdata = df::global::world->map.block_index;
} }

@ -51,6 +51,7 @@ distribution.
#include "modules/Burrows.h" #include "modules/Burrows.h"
#include "modules/Buildings.h" #include "modules/Buildings.h"
#include "modules/Constructions.h" #include "modules/Constructions.h"
#include "modules/Random.h"
#include "LuaWrapper.h" #include "LuaWrapper.h"
#include "LuaTools.h" #include "LuaTools.h"
@ -92,6 +93,10 @@ using namespace DFHack;
using namespace DFHack::LuaWrapper; using namespace DFHack::LuaWrapper;
using Screen::Pen; using Screen::Pen;
using Random::MersenneRNG;
using Random::PerlinNoise1D;
using Random::PerlinNoise2D;
using Random::PerlinNoise3D;
void dfhack_printerr(lua_State *S, const std::string &str); void dfhack_printerr(lua_State *S, const std::string &str);
@ -739,12 +744,10 @@ void Lua::Push(lua_State *L, const Screen::Pen &info)
return; return;
} }
void *pdata = lua_newuserdata(L, sizeof(Pen)); new (L) Pen(info);
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_PEN_TOKEN); lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_PEN_TOKEN);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
new (pdata) Pen(info);
} }
static Pen *check_pen_native(lua_State *L, int index) static Pen *check_pen_native(lua_State *L, int index)
@ -1035,6 +1038,200 @@ static void OpenPen(lua_State *state)
lua_pop(state, 1); lua_pop(state, 1);
} }
/********************
* Random generator *
********************/
static int DFHACK_RANDOM_TOKEN = 0;
static MersenneRNG *check_random_native(lua_State *L, int index)
{
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_RANDOM_TOKEN);
if (!lua_getmetatable(L, index) || !lua_rawequal(L, -1, -2))
luaL_argerror(L, index, "not a random generator object");
lua_pop(L, 2);
return (MersenneRNG*)lua_touserdata(L, index);
}
static int dfhack_random_init(lua_State *L)
{
lua_settop(L, 3);
MersenneRNG *prng = check_random_native(L, 1);
if (lua_isnil(L, 2))
prng->init();
else
{
std::vector<uint32_t> data;
int tcnt = luaL_optint(L, 3, 1);
if (lua_isnumber(L, 2))
data.push_back(lua_tounsigned(L, 2));
else if (lua_istable(L, 2))
{
int cnt = lua_rawlen(L, 2);
if (cnt <= 0)
luaL_argerror(L, 2, "empty list in dfhack.random.init");
for (int i = 1; i <= cnt; i++)
{
lua_rawgeti(L, 2, i);
if (!lua_isnumber(L, -1))
luaL_argerror(L, 2, "not a number in dfhack.random.init argument");
data.push_back(lua_tounsigned(L, -1));
lua_pop(L, 1);
}
}
else
luaL_argerror(L, 2, "dfhack.random.init argument not number or table");
prng->init(data.data(), data.size(), tcnt);
}
lua_settop(L, 1);
return 1;
}
static int dfhack_random_new(lua_State *L)
{
new (L) MersenneRNG();
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_RANDOM_TOKEN);
lua_setmetatable(L, -2);
lua_insert(L, 1);
return dfhack_random_init(L);
}
static int dfhack_random_random(lua_State *L)
{
MersenneRNG *prng = check_random_native(L, 1);
lua_settop(L, 2);
if (lua_gettop(L) < 2 || lua_isnil(L, 2))
lua_pushunsigned(L, prng->random());
else
lua_pushunsigned(L, prng->random(luaL_optunsigned(L, 2, 0)));
return 1;
}
static int dfhack_random_drandom(lua_State *L)
{
lua_pushnumber(L, check_random_native(L, 1)->drandom());
return 1;
}
static int dfhack_random_drandom0(lua_State *L)
{
lua_pushnumber(L, check_random_native(L, 1)->drandom0());
return 1;
}
static int dfhack_random_drandom1(lua_State *L)
{
lua_pushnumber(L, check_random_native(L, 1)->drandom1());
return 1;
}
static int dfhack_random_unitrandom(lua_State *L)
{
lua_pushnumber(L, check_random_native(L, 1)->unitrandom());
return 1;
}
static int dfhack_random_unitvector(lua_State *L)
{
MersenneRNG *prng = check_random_native(L, 1);
int size = luaL_optint(L, 2, 3);
if (size <= 0 || size > 32)
luaL_argerror(L, 2, "vector size must be positive");
luaL_checkstack(L, size, "not enough stack in dfhack.random.unitvector");
std::vector<double> buf(size);
prng->unitvector(buf.data(), size);
for (int i = 0; i < size; i++)
lua_pushnumber(L, buf[i]);
return size;
}
static int eval_perlin_1(lua_State *L)
{
auto &gen = *(PerlinNoise1D<float>*)lua_touserdata(L, lua_upvalueindex(1));
lua_pushnumber(L, gen(luaL_checknumber(L, 1)));
return 1;
}
static int eval_perlin_2(lua_State *L)
{
auto &gen = *(PerlinNoise2D<float>*)lua_touserdata(L, lua_upvalueindex(1));
lua_pushnumber(L, gen(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
return 1;
}
static int eval_perlin_3(lua_State *L)
{
auto &gen = *(PerlinNoise3D<float>*)lua_touserdata(L, lua_upvalueindex(1));
lua_pushnumber(L, gen(luaL_checknumber(L, 1), luaL_checknumber(L, 2), luaL_checknumber(L, 3)));
return 1;
}
static int dfhack_random_perlin(lua_State *L)
{
MersenneRNG *prng = check_random_native(L, 1);
int size = luaL_optint(L, 2, 3);
switch (size)
{
case 1: {
auto pdata = new (L) PerlinNoise1D<float>();
pdata->init(*prng);
lua_pushcclosure(L, eval_perlin_1, 1);
break;
}
case 2: {
auto pdata = new (L) PerlinNoise2D<float>();
pdata->init(*prng);
lua_pushcclosure(L, eval_perlin_2, 1);
break;
}
case 3: {
auto pdata = new (L) PerlinNoise3D<float>();
pdata->init(*prng);
lua_pushcclosure(L, eval_perlin_3, 1);
break;
}
default:
luaL_argerror(L, 2, "perlin noise dimension must be 1, 2 or 3");
}
return 1;
}
static const luaL_Reg dfhack_random_funcs[] = {
{ "new", dfhack_random_new },
{ "init", dfhack_random_init },
{ "random", dfhack_random_random },
{ "drandom", dfhack_random_drandom },
{ "drandom0", dfhack_random_drandom0 },
{ "drandom1", dfhack_random_drandom1 },
{ "unitrandom", dfhack_random_unitrandom },
{ "unitvector", dfhack_random_unitvector },
{ "perlin", dfhack_random_perlin },
{ NULL, NULL }
};
static void OpenRandom(lua_State *state)
{
luaL_getsubtable(state, lua_gettop(state), "random");
lua_dup(state);
lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_RANDOM_TOKEN);
luaL_setfuncs(state, dfhack_random_funcs, 0);
lua_pop(state, 1);
}
/************************ /************************
* Wrappers for C++ API * * Wrappers for C++ API *
************************/ ************************/
@ -2023,6 +2220,7 @@ void OpenDFHackApi(lua_State *state)
OpenPersistent(state); OpenPersistent(state);
OpenMatinfo(state); OpenMatinfo(state);
OpenPen(state); OpenPen(state);
OpenRandom(state);
LuaWrapper::SetFunctionWrappers(state, dfhack_module); LuaWrapper::SetFunctionWrappers(state, dfhack_module);
OpenModule(state, "gui", dfhack_gui_module); OpenModule(state, "gui", dfhack_gui_module);

@ -172,6 +172,8 @@ Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _f
plugin_onupdate = 0; plugin_onupdate = 0;
plugin_onstatechange = 0; plugin_onstatechange = 0;
plugin_rpcconnect = 0; plugin_rpcconnect = 0;
plugin_enable = 0;
plugin_is_enabled = 0;
state = PS_UNLOADED; state = PS_UNLOADED;
access = new RefLock(); access = new RefLock();
} }
@ -245,6 +247,8 @@ bool Plugin::load(color_ostream &con)
plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown"); plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown");
plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange"); plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange");
plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect"); plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect");
plugin_enable = (command_result (*)(color_ostream &,bool)) LookupPlugin(plug, "plugin_enable");
plugin_is_enabled = (bool*) LookupPlugin(plug, "plugin_is_enabled");
plugin_eval_ruby = (command_result (*)(color_ostream &, const char*)) LookupPlugin(plug, "plugin_eval_ruby"); plugin_eval_ruby = (command_result (*)(color_ostream &, const char*)) LookupPlugin(plug, "plugin_eval_ruby");
index_lua(plug); index_lua(plug);
this->name = *plug_name; this->name = *plug_name;
@ -254,11 +258,15 @@ bool Plugin::load(color_ostream &con)
{ {
state = PS_LOADED; state = PS_LOADED;
parent->registerCommands(this); parent->registerCommands(this);
if ((plugin_onupdate || plugin_enable) && !plugin_is_enabled)
con.printerr("Plugin %s has no enabled var!\n", name.c_str());
return true; return true;
} }
else else
{ {
con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str()); con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str());
plugin_is_enabled = 0;
plugin_onupdate = 0;
reset_lua(); reset_lua();
ClosePlugin(plugin_lib); ClosePlugin(plugin_lib);
state = PS_BROKEN; state = PS_BROKEN;
@ -294,6 +302,8 @@ bool Plugin::unload(color_ostream &con)
if(plugin_shutdown) if(plugin_shutdown)
cr = plugin_shutdown(con); cr = plugin_shutdown(con);
// cleanup... // cleanup...
plugin_is_enabled = 0;
plugin_onupdate = 0;
reset_lua(); reset_lua();
parent->unregisterCommands(this); parent->unregisterCommands(this);
commands.clear(); commands.clear();
@ -408,6 +418,12 @@ bool Plugin::can_invoke_hotkey(const std::string & command, df::viewscreen *top
command_result Plugin::on_update(color_ostream &out) command_result Plugin::on_update(color_ostream &out)
{ {
// Check things that are implicitly protected by the suspend lock
if (!plugin_onupdate)
return CR_NOT_IMPLEMENTED;
if (plugin_is_enabled && !*plugin_is_enabled)
return CR_OK;
// Grab mutex and call the thing
command_result cr = CR_NOT_IMPLEMENTED; command_result cr = CR_NOT_IMPLEMENTED;
access->lock_add(); access->lock_add();
if(state == PS_LOADED && plugin_onupdate) if(state == PS_LOADED && plugin_onupdate)
@ -419,6 +435,21 @@ command_result Plugin::on_update(color_ostream &out)
return cr; return cr;
} }
command_result Plugin::set_enabled(color_ostream &out, bool enable)
{
command_result cr = CR_NOT_IMPLEMENTED;
access->lock_add();
if(state == PS_LOADED && plugin_is_enabled && plugin_enable)
{
cr = plugin_enable(out, enable);
if (cr == CR_OK && enable != is_enabled())
cr = CR_FAILURE;
}
access->lock_sub();
return cr;
}
command_result Plugin::on_state_change(color_ostream &out, state_change_event event) command_result Plugin::on_state_change(color_ostream &out, state_change_event event)
{ {
command_result cr = CR_NOT_IMPLEMENTED; command_result cr = CR_NOT_IMPLEMENTED;
@ -524,6 +555,37 @@ void Plugin::reset_lua()
} }
} }
int Plugin::lua_is_enabled(lua_State *state)
{
auto obj = (Plugin*)lua_touserdata(state, lua_upvalueindex(1));
RefAutoinc lock(obj->access);
if (obj->state == PS_LOADED && obj->plugin_is_enabled)
lua_pushboolean(state, obj->is_enabled());
else
lua_pushnil(state);
return 1;
}
int Plugin::lua_set_enabled(lua_State *state)
{
lua_settop(state, 1);
bool val = lua_toboolean(state, 1);
auto obj = (Plugin*)lua_touserdata(state, lua_upvalueindex(1));
RefAutoinc lock(obj->access);
color_ostream *out = Lua::GetOutput(state);
if (obj->state == PS_LOADED && obj->plugin_enable)
lua_pushboolean(state, obj->set_enabled(*out, val) == CR_OK);
else
luaL_error(state, "plugin %s unloaded, cannot enable or disable", obj->name.c_str());
return 1;
}
int Plugin::lua_cmd_wrapper(lua_State *state) int Plugin::lua_cmd_wrapper(lua_State *state)
{ {
auto cmd = (LuaCommand*)lua_touserdata(state, lua_upvalueindex(1)); auto cmd = (LuaCommand*)lua_touserdata(state, lua_upvalueindex(1));
@ -561,6 +623,19 @@ void Plugin::open_lua(lua_State *state, int table)
RefAutolock lock(access); RefAutolock lock(access);
if (plugin_is_enabled)
{
lua_pushlightuserdata(state, this);
lua_pushcclosure(state, lua_is_enabled, 1);
lua_setfield(state, table, "isEnabled");
}
if (plugin_enable)
{
lua_pushlightuserdata(state, this);
lua_pushcclosure(state, lua_set_enabled, 1);
lua_setfield(state, table, "setEnabled");
}
for (auto it = lua_commands.begin(); it != lua_commands.end(); ++it) for (auto it = lua_commands.begin(); it != lua_commands.end(); ++it)
{ {
lua_pushlightuserdata(state, it->second); lua_pushlightuserdata(state, it->second);
@ -604,7 +679,7 @@ void Plugin::push_function(lua_State *state, LuaFunction *fn)
PluginManager::PluginManager(Core * core) PluginManager::PluginManager(Core * core)
{ {
cmdlist_mutex = new mutex(); cmdlist_mutex = new mutex();
eval_ruby = NULL; ruby = NULL;
} }
PluginManager::~PluginManager() PluginManager::~PluginManager()
@ -699,7 +774,7 @@ void PluginManager::registerCommands( Plugin * p )
belongs[cmds[i].name] = p; belongs[cmds[i].name] = p;
} }
if (p->plugin_eval_ruby) if (p->plugin_eval_ruby)
eval_ruby = p->plugin_eval_ruby; ruby = p;
cmdlist_mutex->unlock(); cmdlist_mutex->unlock();
} }
@ -713,6 +788,6 @@ void PluginManager::unregisterCommands( Plugin * p )
belongs.erase(cmds[i].name); belongs.erase(cmds[i].name);
} }
if (p->plugin_eval_ruby) if (p->plugin_eval_ruby)
eval_ruby = NULL; ruby = NULL;
cmdlist_mutex->unlock(); cmdlist_mutex->unlock();
} }

@ -288,9 +288,9 @@ void VMethodInterposeLinkBase::set_chain(void *chain)
addr_to_method_pointer_(chain_mptr, chain); addr_to_method_pointer_(chain_mptr, chain);
} }
VMethodInterposeLinkBase::VMethodInterposeLinkBase(virtual_identity *host, int vmethod_idx, void *interpose_method, void *chain_mptr, int priority) VMethodInterposeLinkBase::VMethodInterposeLinkBase(virtual_identity *host, int vmethod_idx, void *interpose_method, void *chain_mptr, int priority, const char *name)
: host(host), vmethod_idx(vmethod_idx), interpose_method(interpose_method), : host(host), vmethod_idx(vmethod_idx), interpose_method(interpose_method),
chain_mptr(chain_mptr), priority(priority), chain_mptr(chain_mptr), priority(priority), name_str(name),
applied(false), saved_chain(NULL), next(NULL), prev(NULL) applied(false), saved_chain(NULL), next(NULL), prev(NULL)
{ {
if (vmethod_idx < 0 || interpose_method == NULL) if (vmethod_idx < 0 || interpose_method == NULL)
@ -303,8 +303,8 @@ VMethodInterposeLinkBase::VMethodInterposeLinkBase(virtual_identity *host, int v
* - interpose_method comes from method_pointer_to_addr_ * - interpose_method comes from method_pointer_to_addr_
*/ */
fprintf(stderr, "Bad VMethodInterposeLinkBase arguments: %d %08x\n", fprintf(stderr, "Bad VMethodInterposeLinkBase arguments: %d %08x (%s)\n",
vmethod_idx, unsigned(interpose_method)); vmethod_idx, unsigned(interpose_method), name_str);
fflush(stderr); fflush(stderr);
abort(); abort();
} }

@ -29,15 +29,24 @@ distribution.
#ifndef DFHACK_EXPORT #ifndef DFHACK_EXPORT
#define DFHACK_EXPORT __attribute__ ((visibility("default"))) #define DFHACK_EXPORT __attribute__ ((visibility("default")))
#endif #endif
#ifndef DFHACK_IMPORT
#define DFHACK_IMPORT DFHACK_EXPORT
#endif
#else #else
#ifdef BUILD_DFHACK_LIB #ifdef BUILD_DFHACK_LIB
#ifndef DFHACK_EXPORT #ifndef DFHACK_EXPORT
#define DFHACK_EXPORT __declspec(dllexport) #define DFHACK_EXPORT __declspec(dllexport)
#endif #endif
#ifndef DFHACK_IMPORT
#define DFHACK_IMPORT
#endif
#else #else
#ifndef DFHACK_EXPORT #ifndef DFHACK_EXPORT
#define DFHACK_EXPORT __declspec(dllimport) #define DFHACK_EXPORT __declspec(dllimport)
#endif #endif
#ifndef DFHACK_IMPORT
#define DFHACK_IMPORT DFHACK_EXPORT
#endif
#endif #endif
#endif #endif

@ -34,6 +34,11 @@ distribution.
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
/// Allocate a new user data object and push it on the stack
inline void *operator new (std::size_t size, lua_State *L) {
return lua_newuserdata(L, size);
}
namespace DFHack { namespace DFHack {
class function_identity_base; class function_identity_base;
struct MaterialInfo; struct MaterialInfo;

@ -144,6 +144,11 @@ namespace DFHack
bool unload(color_ostream &out); bool unload(color_ostream &out);
bool reload(color_ostream &out); bool reload(color_ostream &out);
bool can_be_enabled() { return plugin_is_enabled != 0; }
bool is_enabled() { return plugin_is_enabled && *plugin_is_enabled; }
bool can_set_enabled() { return plugin_is_enabled != 0 && plugin_enable; }
command_result set_enabled(color_ostream &out, bool enable);
command_result invoke(color_ostream &out, const std::string & command, std::vector <std::string> & parameters); command_result invoke(color_ostream &out, const std::string & command, std::vector <std::string> & parameters);
bool can_invoke_hotkey(const std::string & command, df::viewscreen *top ); bool can_invoke_hotkey(const std::string & command, df::viewscreen *top );
plugin_state getState () const; plugin_state getState () const;
@ -165,6 +170,12 @@ namespace DFHack
void open_lua(lua_State *state, int table); void open_lua(lua_State *state, int table);
command_result eval_ruby(color_ostream &out, const char* cmd) {
if (!plugin_eval_ruby || !is_enabled())
return CR_FAILURE;
return plugin_eval_ruby(out, cmd);
}
private: private:
RefLock * access; RefLock * access;
std::vector <PluginCommand> commands; std::vector <PluginCommand> commands;
@ -184,17 +195,22 @@ namespace DFHack
static int lua_fun_wrapper(lua_State *state); static int lua_fun_wrapper(lua_State *state);
void push_function(lua_State *state, LuaFunction *fn); void push_function(lua_State *state, LuaFunction *fn);
static int lua_is_enabled(lua_State *state);
static int lua_set_enabled(lua_State *state);
struct LuaEvent; struct LuaEvent;
std::map<std::string, LuaEvent*> lua_events; std::map<std::string, LuaEvent*> lua_events;
void index_lua(DFLibrary *lib); void index_lua(DFLibrary *lib);
void reset_lua(); void reset_lua();
bool *plugin_is_enabled;
command_result (*plugin_init)(color_ostream &, std::vector <PluginCommand> &); command_result (*plugin_init)(color_ostream &, std::vector <PluginCommand> &);
command_result (*plugin_status)(color_ostream &, std::string &); command_result (*plugin_status)(color_ostream &, std::string &);
command_result (*plugin_shutdown)(color_ostream &); command_result (*plugin_shutdown)(color_ostream &);
command_result (*plugin_onupdate)(color_ostream &); command_result (*plugin_onupdate)(color_ostream &);
command_result (*plugin_onstatechange)(color_ostream &, state_change_event); command_result (*plugin_onstatechange)(color_ostream &, state_change_event);
command_result (*plugin_enable)(color_ostream &, bool);
RPCService* (*plugin_rpcconnect)(color_ostream &); RPCService* (*plugin_rpcconnect)(color_ostream &);
command_result (*plugin_eval_ruby)(color_ostream &, const char*); command_result (*plugin_eval_ruby)(color_ostream &, const char*);
}; };
@ -226,7 +242,7 @@ namespace DFHack
{ {
return all_plugins.size(); return all_plugins.size();
} }
command_result (*eval_ruby)(color_ostream &, const char*); Plugin *ruby;
// DATA // DATA
private: private:
tthread::mutex * cmdlist_mutex; tthread::mutex * cmdlist_mutex;
@ -250,6 +266,10 @@ namespace DFHack
DFhackDataExport const char * name = plugin_name;\ DFhackDataExport const char * name = plugin_name;\
DFhackDataExport Plugin *plugin_self = NULL; DFhackDataExport Plugin *plugin_self = NULL;
#define DFHACK_PLUGIN_IS_ENABLED(varname) \
DFhackDataExport bool plugin_is_enabled = false; \
bool &varname = plugin_is_enabled;
#define DFHACK_PLUGIN_LUA_COMMANDS \ #define DFHACK_PLUGIN_LUA_COMMANDS \
DFhackCExport const DFHack::CommandReg plugin_lua_commands[] = DFhackCExport const DFHack::CommandReg plugin_lua_commands[] =
#define DFHACK_PLUGIN_LUA_FUNCTIONS \ #define DFHACK_PLUGIN_LUA_FUNCTIONS \

@ -56,6 +56,8 @@ distribution.
#pragma warning( disable: 4018) #pragma warning( disable: 4018)
// nonstandard extension used: enum 'df::whatever::etc' used in qualified name // nonstandard extension used: enum 'df::whatever::etc' used in qualified name
#pragma warning( disable: 4482) #pragma warning( disable: 4482)
// nonstandard extension used: 'extern' before template explicit instantiation
#pragma warning( disable: 4231)
#endif #endif
#endif #endif

@ -141,7 +141,7 @@ namespace DFHack
#define IMPLEMENT_VMETHOD_INTERPOSE_PRIO(class,name,priority) \ #define IMPLEMENT_VMETHOD_INTERPOSE_PRIO(class,name,priority) \
DFHack::VMethodInterposeLink<class::interpose_base,class::interpose_ptr_##name> \ DFHack::VMethodInterposeLink<class::interpose_base,class::interpose_ptr_##name> \
class::interpose_##name(&class::interpose_base::name, &class::interpose_fn_##name, priority); class::interpose_##name(&class::interpose_base::name, &class::interpose_fn_##name, priority, #class"::"#name);
#define IMPLEMENT_VMETHOD_INTERPOSE(class,name) IMPLEMENT_VMETHOD_INTERPOSE_PRIO(class,name,0) #define IMPLEMENT_VMETHOD_INTERPOSE(class,name) IMPLEMENT_VMETHOD_INTERPOSE_PRIO(class,name,0)
@ -161,6 +161,7 @@ namespace DFHack
void *interpose_method; // Pointer to the code of the interposing method void *interpose_method; // Pointer to the code of the interposing method
void *chain_mptr; // Pointer to the chain field in the subclass below void *chain_mptr; // Pointer to the chain field in the subclass below
int priority; // Higher priority hooks are called earlier int priority; // Higher priority hooks are called earlier
const char *name_str; // Name of the hook
bool applied; // True if this hook is currently applied bool applied; // True if this hook is currently applied
void *saved_chain; // Pointer to the code of the original vmethod or next hook void *saved_chain; // Pointer to the code of the original vmethod or next hook
@ -179,12 +180,14 @@ namespace DFHack
VMethodInterposeLinkBase *get_first_interpose(virtual_identity *id); VMethodInterposeLinkBase *get_first_interpose(virtual_identity *id);
bool find_child_hosts(virtual_identity *cur, void *vmptr); bool find_child_hosts(virtual_identity *cur, void *vmptr);
public: public:
VMethodInterposeLinkBase(virtual_identity *host, int vmethod_idx, void *interpose_method, void *chain_mptr, int priority); VMethodInterposeLinkBase(virtual_identity *host, int vmethod_idx, void *interpose_method, void *chain_mptr, int priority, const char *name);
~VMethodInterposeLinkBase(); ~VMethodInterposeLinkBase();
bool is_applied() { return applied; } bool is_applied() { return applied; }
bool apply(bool enable = true); bool apply(bool enable = true);
void remove(); void remove();
const char *name() { return name_str; }
}; };
template<class Base, class Ptr> template<class Base, class Ptr>
@ -198,13 +201,13 @@ namespace DFHack
operator Ptr () { return chain; } operator Ptr () { return chain; }
template<class Ptr2> template<class Ptr2>
VMethodInterposeLink(Ptr target, Ptr2 src, int priority) VMethodInterposeLink(Ptr target, Ptr2 src, int priority, const char *name)
: VMethodInterposeLinkBase( : VMethodInterposeLinkBase(
&Base::_identity, &Base::_identity,
vmethod_pointer_to_idx(target), vmethod_pointer_to_idx(target),
method_pointer_to_addr(src), method_pointer_to_addr(src),
&chain, &chain,
priority priority, name
) )
{ src = target; /* check compatibility */ } { src = target; /* check compatibility */ }
}; };

@ -0,0 +1,130 @@
#pragma once
namespace DFHack {
namespace Random {
/*
* A good explanation:
* http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html
*/
// Interpolation functions
template<class T>
inline T s_curve(T t)
{
// Classical function
//return t * t * (3 - 2*t);
// 2002 version from http://mrl.nyu.edu/~perlin/paper445.pdf
return t * t * t * (t * (t * 6 - 15) + 10);
}
template<class T>
inline T lerp(T s, T a, T b)
{
return a + s * (b-a);
}
// Dot product of VSIZE vectors pointed by pa, pb
template<class T, unsigned i>
struct DotProduct {
static inline T eval(T *pa, T *pb);
};
template<class T>
struct DotProduct<T,0> {
static inline T eval(T *pa, T *pb) { return pa[0]*pb[0]; }
};
template<class T, unsigned i>
inline T DotProduct<T,i>::eval(T *pa, T *pb) {
return DotProduct<T,i-1>::eval(pa, pb) + pa[i]*pb[i];
}
// Templates used to force unrolling and inlining of the loops
template<class T, unsigned VSIZE, unsigned BITS, class IDXT>
template<unsigned mask>
struct PerlinNoise<T,VSIZE,BITS,IDXT>::Impl<mask,-1> {
typedef typename PerlinNoise<T,VSIZE,BITS,IDXT>::Temp Temp;
static inline void setup(PerlinNoise<T,VSIZE,BITS,IDXT> *, const T *, Temp *) {}
static inline T eval(PerlinNoise<T,VSIZE,BITS,IDXT> *self, Temp *pt, unsigned idx, T *pq);
};
// Initialization of the temporaries from input coordinates
template<class T, unsigned VSIZE, unsigned BITS, class IDXT>
template<unsigned mask, int i>
inline void PerlinNoise<T,VSIZE,BITS,IDXT>::Impl<mask,i>::setup(
PerlinNoise<T,VSIZE,BITS,IDXT> *self, const T *pv, Temp *pt
) {
Impl<mask,i-1>::setup(self, pv, pt);
T t = std::floor(pv[i]);
pt[i].s = s_curve(pt[i].r0 = pv[i] - t);
unsigned b = unsigned(int32_t(t));
pt[i].b0 = self->idxmap[i][b & mask];
pt[i].b1 = self->idxmap[i][(b+1) & mask];
}
// Main recursion. Uses tables from self and pt.
// Recursion changes current index idx, and current offset vector pq.
template<class T, unsigned VSIZE, unsigned BITS, class IDXT>
template<unsigned mask>
inline T PerlinNoise<T,VSIZE,BITS,IDXT>::Impl<mask, -1>::eval(
PerlinNoise<T,VSIZE,BITS,IDXT> *self, Temp *pt, unsigned idx, T *pq
) {
return DotProduct<T,VSIZE-1>::eval(pq, self->gradients[idx]);
}
template<class T, unsigned VSIZE, unsigned BITS, class IDXT>
template<unsigned mask, int i>
inline T PerlinNoise<T,VSIZE,BITS,IDXT>::Impl<mask,i>::eval(
PerlinNoise<T,VSIZE,BITS,IDXT> *self, Temp *pt, unsigned idx, T *pq
) {
pq[i] = pt[i].r0;
T u = Impl<mask,i-1>::eval(self, pt, idx ^ pt[i].b0, pq);
pq[i] -= 1;
T v = Impl<mask,i-1>::eval(self, pt, idx ^ pt[i].b1, pq);
return lerp(pt[i].s, u, v);
}
// Actual methods of the object
template<class T, unsigned VSIZE, unsigned BITS, class IDXT>
void PerlinNoise<T,VSIZE,BITS,IDXT>::init(MersenneRNG &rng)
{
STATIC_ASSERT(VSIZE > 0 && BITS <= 8*sizeof(IDXT));
// Random unit gradient vectors
for (unsigned i = 0; i < TSIZE; i++)
rng.unitvector(gradients[i], VSIZE);
// Random permutation tables
for (unsigned j = 0; j < VSIZE; j++)
{
for (unsigned i = 0; i < TSIZE; i++)
idxmap[j][i] = i;
rng.permute(idxmap[j], TSIZE);
}
}
template<class T, unsigned VSIZE, unsigned BITS, class IDXT>
T PerlinNoise<T,VSIZE,BITS,IDXT>::eval(const T coords[VSIZE])
{
// Precomputed properties from the coordinates
Temp tmp[VSIZE];
// Temporary used to build the current offset vector
T q[VSIZE];
Impl<TSIZE-1,VSIZE-1>::setup(this, coords, tmp);
return Impl<TSIZE-1,VSIZE-1>::eval(this, tmp, 0, q);
}
}} // namespace

@ -0,0 +1,179 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#ifndef CL_MOD_RANDOM
#define CL_MOD_RANDOM
/**
* \defgroup grp_random Random: Random number and noise generation
* @ingroup grp_modules
*/
#include "Export.h"
#include "Module.h"
#include "Types.h"
#include "DataDefs.h"
namespace DFHack
{
namespace Random
{
class DFHACK_EXPORT MersenneRNG
{
static const unsigned MT_LEN = 624;
unsigned mt_index;
uint32_t mt_buffer[MT_LEN];
void twist();
void prefill(unsigned step, int twist_cnt);
public:
/* No constructor or destructor - safe to treat as data */
void init(const uint32_t *pseed, unsigned cnt, int twist_cnt = 1);
void init(); // uses time
void init(uint32_t seed, int twist_cnt = 1) { init(&seed, 1, twist_cnt); }
// [0, 2^32)
uint32_t random() {
if (mt_index >= MT_LEN) twist();
return mt_buffer[mt_index++];
}
// [0, limit)
uint32_t random(uint32_t limit) {
return uint32_t(uint64_t(random())*limit >> 32);
}
// (0, 1)
double drandom0() {
return (double(random())+1)/4294967297.0;
}
// [0, 1)
double drandom() {
return double(random())/4294967296.0;
}
// [0, 1]
double drandom1() {
return double(random())/4294967295.0;
}
// [-1, 1]
double unitrandom() {
return drandom1()*2.0 - 1.0;
}
// Two exact replicas of functions in DF code
int32_t df_trandom(uint32_t max=2147483647LU);
int32_t df_loadtrandom(uint32_t max=2147483647LU);
template<class T>
void unitvector(T *p, int size);
template<class T>
void permute(T *p, int size) {
while(size > 1)
{
int j = random(size--);
T c = p[j]; p[j] = p[size]; p[size] = c;
}
}
};
#ifndef DFHACK_RANDOM_CPP
extern template void MersenneRNG::unitvector<float>(float *p, int size);
extern template void MersenneRNG::unitvector<double>(double *p, int size);
#endif
/*
* Classical Perlin noise function in template form.
* http://mrl.nyu.edu/~perlin/doc/oscar.html#noise
*
* Using an improved hash function from:
* http://www.cs.utah.edu/~aek/research/noise.pdf
*/
template<class T, unsigned VSIZE, unsigned BITS = 8, class IDXT = uint8_t>
class PerlinNoise
{
// Size of randomness tables
static const unsigned TSIZE = 1<<BITS;
T gradients[TSIZE][VSIZE];
IDXT idxmap[VSIZE][TSIZE];
// Templates used to unwind and inline recursion and loops
struct Temp {
T r0, s;
unsigned b0, b1;
};
template<unsigned mask, int i>
struct Impl {
static inline void setup(PerlinNoise<T,VSIZE,BITS,IDXT> *self, const T *pv, Temp *pt);
static inline T eval(PerlinNoise<T,VSIZE,BITS,IDXT> *self, Temp *pt, unsigned idx, T *pq);
};
public:
/* No constructor or destructor - safe to treat as data */
void init(MersenneRNG &rng);
T eval(const T coords[VSIZE]);
};
#ifndef DFHACK_RANDOM_CPP
extern template class DFHACK_IMPORT PerlinNoise<float, 1>;
extern template class DFHACK_IMPORT PerlinNoise<float, 2>;
extern template class DFHACK_IMPORT PerlinNoise<float, 3>;
#endif
template<class T, unsigned BITS = 8, class IDXT = uint8_t>
class PerlinNoise1D : public PerlinNoise<T, 1, BITS, IDXT>
{
public:
T operator() (T x) { return this->eval(&x); }
};
template<class T, unsigned BITS = 8, class IDXT = uint8_t>
class PerlinNoise2D : public PerlinNoise<T, 2, BITS, IDXT>
{
public:
T operator() (T x, T y) {
T tmp[2] = { x, y };
return this->eval(tmp);
}
};
template<class T, unsigned BITS = 8, class IDXT = uint8_t>
class PerlinNoise3D : public PerlinNoise<T, 3, BITS, IDXT>
{
public:
T operator() (T x, T y, T z) {
T tmp[3] = { x, y, z };
return this->eval(tmp);
}
};
}
}
#endif

@ -220,6 +220,12 @@ function dfhack.matinfo:__tostring()
return "<material "..self.type..":"..self.index.." "..self:getToken()..">" return "<material "..self.type..":"..self.index.." "..self:getToken()..">"
end end
dfhack.random.__index = dfhack.random
function dfhack.random:__tostring()
return "<random generator>"
end
function dfhack.maps.getSize() function dfhack.maps.getSize()
local map = df.global.world.map local map = df.global.world.map
return map.x_count_block, map.y_count_block, map.z_count_block return map.x_count_block, map.y_count_block, map.z_count_block

@ -151,7 +151,7 @@ bool DFHack::operator== (const df::job &a, const df::job &b)
CHECK_NULL_POINTER(&a); CHECK_NULL_POINTER(&a);
CHECK_NULL_POINTER(&b); CHECK_NULL_POINTER(&b);
if (!(CMP(job_type) && CMP(unk2) && if (!(CMP(job_type) && CMP(job_subtype) &&
CMP(mat_type) && CMP(mat_index) && CMP(mat_type) && CMP(mat_index) &&
CMP(item_subtype) && CMP(item_category.whole) && CMP(item_subtype) && CMP(item_category.whole) &&
CMP(hist_figure_id) && CMP(material_category.whole) && CMP(hist_figure_id) && CMP(material_category.whole) &&

@ -0,0 +1,156 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include <string>
#include <vector>
#include <map>
using namespace std;
#define DFHACK_RANDOM_CPP
#include "modules/Random.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Types.h"
#include "ModuleFactory.h"
#include "Core.h"
#include "Error.h"
#include "VTableInterpose.h"
#include <cmath>
using namespace DFHack;
using namespace df::enums;
using namespace DFHack::Random;
//public domain RNG stuff by Michael Brundage
//modified to be compatible with the version in DF
#define MT_IA 397
#define MT_IB (MT_LEN - MT_IA)
#define UPPER_MASK 0x80000000
#define LOWER_MASK 0x7FFFFFFF
#define MATRIX_A 0x9908B0DF
#define TWIST(b,i,j) ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK)
#define MAGIC(s) (((s)&1)*MATRIX_A)
void MersenneRNG::twist()
{
uint32_t *b = mt_buffer;
uint32_t s;
unsigned i;
i = 0;
for (; i < MT_IB; i++) {
s = TWIST(b, i, i+1);
b[i] = b[i + MT_IA] ^ (s >> 1) ^ MAGIC(s);
}
for (; i < MT_LEN-1; i++) {
s = TWIST(b, i, i+1);
b[i] = b[i - MT_IB] ^ (s >> 1) ^ MAGIC(s);
}
s = TWIST(b, MT_LEN-1, 0);
b[MT_LEN-1] = b[MT_IA-1] ^ (s >> 1) ^ MAGIC(s);
mt_index = 0;
}
void MersenneRNG::prefill(unsigned step, int twist_cnt)
{
for(unsigned i=step;i<MT_LEN;i++)
{
//2010: better init line from wikipedia, ultimate source unknown
mt_buffer[i]=1812433253UL * (mt_buffer[i-step] ^ (mt_buffer[i-step]>>30)) + i;
}
mt_index = 0;
for(int j=0;j<twist_cnt;j++)
twist();
}
void MersenneRNG::init()
{
init(Core::getInstance().p->getTickCount(), 20);
}
void MersenneRNG::init(const uint32_t *pseed, unsigned cnt, int twist_cnt)
{
memcpy(mt_buffer, pseed, cnt*sizeof(uint32_t));
prefill(cnt, twist_cnt);
}
int32_t MersenneRNG::df_trandom(uint32_t max)
{
if(max<=1)return 0;
uint32_t seed=random();
seed=seed%2147483647LU;
seed=seed/((2147483647LU/max)+1);
return((int32_t)seed);
}
int32_t MersenneRNG::df_loadtrandom(uint32_t max)
{
uint32_t seed=random();
seed=seed%max;
return((int32_t)seed);
}
template<class T>
void MersenneRNG::unitvector(T *p, int size)
{
for (;;)
{
T rsqr = 0;
for (int i = 0; i < size; i++)
{
p[i] = (T)unitrandom();
rsqr += p[i]*p[i];
}
if (rsqr > 0 && rsqr <= 1)
{
rsqr = std::sqrt(rsqr);
for (int i = 0; i < size; i++)
p[i] /= rsqr;
break;
}
}
}
template void MersenneRNG::unitvector<float>(float *p, int size);
template void MersenneRNG::unitvector<double>(double *p, int size);
#include "modules/PerlinNoise.inc"
template class DFHACK_EXPORT PerlinNoise<float, 1>;
template class DFHACK_EXPORT PerlinNoise<float, 2>;
template class DFHACK_EXPORT PerlinNoise<float, 3>;

@ -66,6 +66,7 @@ using namespace std;
#include "df/game_mode.h" #include "df/game_mode.h"
#include "df/unit_misc_trait.h" #include "df/unit_misc_trait.h"
#include "df/unit_skill.h" #include "df/unit_skill.h"
#include "df/curse_attr_change.h"
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
@ -1208,12 +1209,10 @@ int Units::computeMovementSpeed(df::unit *unit)
if (unsigned(unit->counters.webbed-1) <= 8) if (unsigned(unit->counters.webbed-1) <= 8)
speed += unit->counters.webbed*100; speed += unit->counters.webbed*100;
// Muscle weight vs vascular tissue (?) // Muscle and fat weight vs expected size
auto &attr_tissue = unit->body.physical_attr_tissues; auto &s_info = unit->body.size_info;
int muscle = attr_tissue[STRENGTH]; speed = std::max(speed*3/4, std::min(speed*3/2, int(int64_t(speed)*s_info.size_cur/s_info.size_base)));
int blood = attr_tissue[AGILITY];
speed = std::max(speed*3/4, std::min(speed*3/2, int(int64_t(speed)*muscle/blood)));
// Attributes // Attributes
@ -1243,7 +1242,7 @@ int Units::computeMovementSpeed(df::unit *unit)
// Inventory encumberance // Inventory encumberance
int total_weight = calcInventoryWeight(unit); int total_weight = calcInventoryWeight(unit);
int free_weight = std::max(1, muscle/10 + strength_attr*3); int free_weight = std::max(1, s_info.size_cur/10 + strength_attr*3);
if (free_weight < total_weight) if (free_weight < total_weight)
{ {

@ -1 +1 @@
Subproject commit 20ecaa0393df1ea111861d67c789aaaa56a37c58 Subproject commit e62d498e68e3a87929b144220d03e691016f7aae

@ -158,6 +158,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(autotrade autotrade.cpp) DFHACK_PLUGIN(autotrade autotrade.cpp)
DFHACK_PLUGIN(stocks stocks.cpp) DFHACK_PLUGIN(stocks stocks.cpp)
DFHACK_PLUGIN(treefarm treefarm.cpp) DFHACK_PLUGIN(treefarm treefarm.cpp)
DFHACK_PLUGIN(cleanconst cleanconst.cpp)
endif() endif()

@ -48,6 +48,7 @@ using df::global::ui;
typedef df::reaction_product_item_improvementst improvement_product; typedef df::reaction_product_item_improvementst improvement_product;
DFHACK_PLUGIN("add-spatter"); DFHACK_PLUGIN("add-spatter");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
struct ReagentSource { struct ReagentSource {
int idx; int idx;
@ -378,7 +379,7 @@ static bool find_reactions(color_ostream &out)
parse_product(out, out_prod.back(), it->second.react, itprod); parse_product(out, out_prod.back(), it->second.react, itprod);
} }
for (size_t i = 0; i < prod.size(); i++) for (size_t i = 0; i < out_prod.size(); i++)
{ {
if (out_prod[i].isValid()) if (out_prod[i].isValid())
products[out_prod[i].product] = &out_prod[i]; products[out_prod[i].product] = &out_prod[i];
@ -390,6 +391,7 @@ static bool find_reactions(color_ostream &out)
static void enable_hooks(bool enable) static void enable_hooks(bool enable)
{ {
is_enabled = enable;
INTERPOSE_HOOK(item_hook, isImprovable).apply(enable); INTERPOSE_HOOK(item_hook, isImprovable).apply(enable);
INTERPOSE_HOOK(product_hook, produce).apply(enable); INTERPOSE_HOOK(product_hook, produce).apply(enable);
} }

@ -99,7 +99,7 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap); df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap);
static bool in_transient_swap = false; DFHACK_PLUGIN_IS_ENABLED(in_transient_swap);
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{ {

@ -39,12 +39,11 @@
using namespace std; using namespace std;
using namespace DFHack; using namespace DFHack;
static bool enabled = false;
namespace ResetPolicy { namespace ResetPolicy {
typedef enum {DoNothing, ResetDuration, AddDuration, NewInstance} ResetPolicy; typedef enum {DoNothing, ResetDuration, AddDuration, NewInstance} ResetPolicy;
} }
DFHACK_PLUGIN_IS_ENABLED(enabled);
DFHACK_PLUGIN("autoSyndrome"); DFHACK_PLUGIN("autoSyndrome");
command_result autoSyndrome(color_ostream& out, vector<string>& parameters); command_result autoSyndrome(color_ostream& out, vector<string>& parameters);
@ -75,35 +74,44 @@ DFhackCExport command_result plugin_shutdown(color_ostream& out) {
return CR_OK; return CR_OK;
}*/ }*/
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
if (enabled == enable)
return CR_OK;
enabled = enable;
if ( enabled ) {
EventManager::EventHandler handle(processJob, 0);
EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, handle, plugin_self);
} else {
EventManager::unregisterAll(plugin_self);
}
return CR_OK;
}
command_result autoSyndrome(color_ostream& out, vector<string>& parameters) { command_result autoSyndrome(color_ostream& out, vector<string>& parameters) {
if ( parameters.size() > 1 ) if ( parameters.size() > 1 )
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
bool wasEnabled = enabled; bool enable = false;
if ( parameters.size() == 1 ) { if ( parameters.size() == 1 ) {
if ( parameters[0] == "enable" ) { if ( parameters[0] == "enable" ) {
enabled = true; enable = true;
} else if ( parameters[0] == "disable" ) { } else if ( parameters[0] == "disable" ) {
enabled = false; enable = false;
} else { } else {
int32_t a = atoi(parameters[0].c_str()); int32_t a = atoi(parameters[0].c_str());
if ( a < 0 || a > 1 ) if ( a < 0 || a > 1 )
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
enabled = (bool)a; enable = (bool)a;
} }
} }
out.print("autoSyndrome is %s\n", enabled ? "enabled" : "disabled"); out.print("autoSyndrome is %s\n", enabled ? "enabled" : "disabled");
if ( enabled == wasEnabled ) return plugin_enable(out, enable);
return CR_OK;
EventManager::unregisterAll(plugin_self);
if ( enabled ) {
EventManager::EventHandler handle(processJob, 0);
EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, handle, plugin_self);
}
return CR_OK;
} }
bool maybeApply(color_ostream& out, df::syndrome* syndrome, int32_t workerId, df::unit* unit, ResetPolicy::ResetPolicy policy) { bool maybeApply(color_ostream& out, df::syndrome* syndrome, int32_t workerId, df::unit* unit, ResetPolicy::ResetPolicy policy) {

@ -125,7 +125,7 @@ static command_result autodump_main(color_ostream &out, vector <string> & parame
{ {
if (!Gui::getCursorCoords(cx,cy,cz)) if (!Gui::getCursorCoords(cx,cy,cz))
{ {
out.printerr("Cursor position not found. Please enabled the cursor.\n"); out.printerr("Cursor position not found. Please enable the cursor.\n");
return CR_FAILURE; return CR_FAILURE;
} }
pos_cursor = DFCoord(cx,cy,cz); pos_cursor = DFCoord(cx,cy,cz);

@ -76,7 +76,7 @@ using df::global::world;
* (mining, hunting, and woodcutting) need to be handled carefully to minimize churn. * (mining, hunting, and woodcutting) need to be handled carefully to minimize churn.
*/ */
static int enable_autolabor = 0; DFHACK_PLUGIN_IS_ENABLED(enable_autolabor);
static bool print_debug = 0; static bool print_debug = 0;
@ -535,6 +535,7 @@ static void setOptionEnabled(ConfigFlags flag, bool on)
static void cleanup_state() static void cleanup_state()
{ {
enable_autolabor = false;
labor_infos.clear(); labor_infos.clear();
} }
@ -1297,6 +1298,27 @@ void print_labor (df::unit_labor labor, color_ostream &out)
} }
} }
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable )
{
if (!Core::getInstance().isWorldLoaded()) {
out.printerr("World is not loaded: please load a game first.\n");
return CR_FAILURE;
}
if (enable && !enable_autolabor)
{
enable_plugin(out);
}
else if(!enable && enable_autolabor)
{
enable_autolabor = false;
setOptionEnabled(CF_ENABLED, false);
out << "Autolabor is disabled." << endl;
}
return CR_OK;
}
command_result autolabor (color_ostream &out, std::vector <std::string> & parameters) command_result autolabor (color_ostream &out, std::vector <std::string> & parameters)
{ {
@ -1312,19 +1334,8 @@ command_result autolabor (color_ostream &out, std::vector <std::string> & parame
parameters[0] == "1" || parameters[0] == "disable")) parameters[0] == "1" || parameters[0] == "disable"))
{ {
bool enable = (parameters[0] == "1" || parameters[0] == "enable"); bool enable = (parameters[0] == "1" || parameters[0] == "enable");
if (enable && !enable_autolabor)
{
enable_plugin(out);
}
else if(!enable && enable_autolabor)
{
enable_autolabor = false;
setOptionEnabled(CF_ENABLED, false);
out << "The plugin is disabled." << endl; return plugin_enable(out, enable);
}
return CR_OK;
} }
else if (parameters.size() == 2 && parameters[0] == "haulpct") else if (parameters.size() == 2 && parameters[0] == "haulpct")
{ {

@ -1179,11 +1179,27 @@ color_ostream_proxy console_out(Core::getInstance().getConsole());
IMPLEMENT_VMETHOD_INTERPOSE(jobutils_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(jobutils_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(jobutils_hook, render); IMPLEMENT_VMETHOD_INTERPOSE(jobutils_hook, render);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable)
{ {
if (!gps || !INTERPOSE_HOOK(jobutils_hook, feed).apply() || !INTERPOSE_HOOK(jobutils_hook, render).apply()) if (!gps)
out.printerr("Could not insert jobutils hooks!\n"); return CR_FAILURE;
if (enable != is_enabled)
{
if (!INTERPOSE_HOOK(jobutils_hook, feed).apply(enable) ||
!INTERPOSE_HOOK(jobutils_hook, render).apply(enable))
return CR_FAILURE;
is_enabled = enable;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
hotkeys[construction_type::Wall] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_WALL; hotkeys[construction_type::Wall] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_WALL;
hotkeys[construction_type::Floor] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_FLOOR; hotkeys[construction_type::Floor] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_FLOOR;
hotkeys[construction_type::Ramp] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_RAMP; hotkeys[construction_type::Ramp] = df::interface_key::HOTKEY_BUILDING_CONSTRUCTION_RAMP;

@ -583,7 +583,6 @@ static command_result autotrade_cmd(color_ostream &out, vector <string> & parame
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{ {
switch (event) switch (event)
@ -600,11 +599,30 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{ {
if (!gps || !INTERPOSE_HOOK(trade_hook, feed).apply() || !INTERPOSE_HOOK(trade_hook, render).apply()) if (!gps)
out.printerr("Could not insert autotrade hooks!\n"); return CR_FAILURE;
if (enable != is_enabled)
{
depot_info.reset();
monitor.reset();
if (!INTERPOSE_HOOK(trade_hook, feed).apply(enable) ||
!INTERPOSE_HOOK(trade_hook, render).apply(enable))
return CR_FAILURE;
is_enabled = enable;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back( commands.push_back(
PluginCommand( PluginCommand(
"autotrade", "Automatically send items in marked stockpiles to trade depot, when trading is possible.", "autotrade", "Automatically send items in marked stockpiles to trade depot, when trading is possible.",

@ -92,6 +92,8 @@ static void debug(const string &msg)
* Material Choice Screen * Material Choice Screen
*/ */
static string material_to_string_fn(MaterialInfo m) { return m.toString(); }
struct ItemFilter struct ItemFilter
{ {
df::dfhack_material_category mat_mask; df::dfhack_material_category mat_mask;
@ -114,8 +116,10 @@ struct ItemFilter
bool matches(MaterialInfo &material) const bool matches(MaterialInfo &material) const
{ {
return any_of(materials.begin(), materials.end(), for (auto it = materials.begin(); it != materials.end(); ++it)
[&] (const MaterialInfo &m) { return material.matches(m); }); if (material.matches(*it))
return true;
return false;
} }
bool matches(df::item *item) bool matches(df::item *item)
@ -137,8 +141,7 @@ struct ItemFilter
{ {
vector<string> descriptions; vector<string> descriptions;
transform_(materials, descriptions, transform_(materials, descriptions, material_to_string_fn);
[] (MaterialInfo m) { return m.toString(); });
if (descriptions.size() == 0) if (descriptions.size() == 0)
bitfield_to_string(&descriptions, mat_mask); bitfield_to_string(&descriptions, mat_mask);
@ -157,8 +160,8 @@ struct ItemFilter
str.append("/"); str.append("/");
if (materials.size() > 0) if (materials.size() > 0)
{ {
for_each_(materials, for (size_t i = 0; i < materials.size(); i++)
[&] (MaterialInfo &m) { str.append(m.getToken() + ","); }); str.append(materials[i].getToken() + ",");
if (str[str.size()-1] == ',') if (str[str.size()-1] == ',')
str.resize(str.size () - 1); str.resize(str.size () - 1);
@ -217,6 +220,7 @@ private:
bool valid; bool valid;
}; };
static MaterialInfo &material_info_identity_fn(MaterialInfo &m) { return m; }
class ViewscreenChooseMaterial : public dfhack_viewscreen class ViewscreenChooseMaterial : public dfhack_viewscreen
{ {
@ -284,13 +288,12 @@ public:
// Category masks // Category masks
auto masks = masks_column.getSelectedElems(); auto masks = masks_column.getSelectedElems();
for_each_(masks, for (auto it = masks.begin(); it != masks.end(); ++it)
[&] (df::dfhack_material_category &m) { filter->mat_mask.whole |= m.whole; }); filter->mat_mask.whole |= it->whole;
// Specific materials // Specific materials
auto materials = materials_column.getSelectedElems(); auto materials = materials_column.getSelectedElems();
transform_(materials, filter->materials, transform_(materials, filter->materials, material_info_identity_fn);
[] (MaterialInfo &m) { return m; });
Screen::dismiss(this); Screen::dismiss(this);
} }
@ -465,6 +468,7 @@ private:
} }
}; };
static void delete_item_fn(df::job_item *x) { delete x; }
// START Planning // START Planning
class PlannedBuilding class PlannedBuilding
@ -555,7 +559,7 @@ public:
auto job = building->jobs[0]; auto job = building->jobs[0];
for_each_(job->job_items, [] (df::job_item *x) { delete x; }); for_each_(job->job_items, delete_item_fn);
job->job_items.clear(); job->job_items.clear();
job->flags.bits.suspend = false; job->flags.bits.suspend = false;
@ -613,9 +617,10 @@ private:
ItemFilter filter; ItemFilter filter;
}; };
static map<df::building_type, bool> planmode_enabled, saved_planmodes; static map<df::building_type, bool> planmode_enabled, saved_planmodes;
static void enable_quickfort_fn(pair<const df::building_type, bool>& pair) { pair.second = true; }
class Planner class Planner
{ {
public: public:
@ -804,8 +809,7 @@ public:
void enableQuickfortMode() void enableQuickfortMode()
{ {
saved_planmodes = planmode_enabled; saved_planmodes = planmode_enabled;
for_each_(planmode_enabled, for_each_(planmode_enabled, enable_quickfort_fn);
[] (pair<const df::building_type, bool>& pair) { pair.second = true; } );
quickfort_mode = true; quickfort_mode = true;
} }
@ -1093,8 +1097,8 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest
OutputHotkeyString(x, y, "Material Filter:", "m", true, left_margin); OutputHotkeyString(x, y, "Material Filter:", "m", true, left_margin);
auto filter_descriptions = filter->getMaterialFilterAsVector(); auto filter_descriptions = filter->getMaterialFilterAsVector();
for_each_(filter_descriptions, for (auto it = filter_descriptions.begin(); it != filter_descriptions.end(); ++it)
[&](string d) { OutputString(COLOR_BROWN, x, y, " *" + d, true, left_margin); }); OutputString(COLOR_BROWN, x, y, " *" + *it, true, left_margin);
} }
else else
{ {
@ -1121,8 +1125,8 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest
OutputString(COLOR_BROWN, x, y, "Materials:", true, left_margin); OutputString(COLOR_BROWN, x, y, "Materials:", true, left_margin);
auto filters = filter->getMaterialFilterAsVector(); auto filters = filter->getMaterialFilterAsVector();
for_each_(filters, for (auto it = filters.begin(); it != filters.end(); ++it)
[&](string d) { OutputString(COLOR_BLUE, x, y, "*" + d, true, left_margin); }); OutputString(COLOR_BLUE, x, y, "*" + *it, true, left_margin);
} }
else else
{ {
@ -1153,12 +1157,29 @@ static command_result buildingplan_cmd(color_ostream &out, vector <string> & par
return CR_OK; return CR_OK;
} }
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{ {
if (!gps || !INTERPOSE_HOOK(buildingplan_hook, feed).apply() || !INTERPOSE_HOOK(buildingplan_hook, render).apply()) if (!gps)
out.printerr("Could not insert buildingplan hooks!\n"); return CR_FAILURE;
if (enable != is_enabled)
{
planner.reset(out);
if (!INTERPOSE_HOOK(buildingplan_hook, feed).apply(enable) ||
!INTERPOSE_HOOK(buildingplan_hook, render).apply(enable))
return CR_FAILURE;
is_enabled = enable;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back( commands.push_back(
PluginCommand( PluginCommand(
"buildingplan", "Place furniture before it's built", "buildingplan", "Place furniture before it's built",

@ -221,7 +221,8 @@ static void detect_digging(color_ostream &out)
} }
} }
static bool active = false; DFHACK_PLUGIN_IS_ENABLED(active);
static bool auto_grow = false; static bool auto_grow = false;
static std::vector<int> grow_burrows; static std::vector<int> grow_burrows;

@ -120,14 +120,14 @@ command_result catsplosion (color_ostream &out, std::vector <std::string> & para
female->relations.pregnancy_timer = rand() % 100 + 1; female->relations.pregnancy_timer = rand() % 100 + 1;
totalchanged++; totalchanged++;
} }
else if(!female->relations.pregnancy_ptr) else if(!female->relations.pregnancy_genes)
{ {
df::unit_genes *preg = new df::unit_genes; df::unit_genes *preg = new df::unit_genes;
preg->appearance = female->appearance.genes.appearance; preg->appearance = female->appearance.genes.appearance;
preg->colors = female->appearance.genes.colors; preg->colors = female->appearance.genes.colors;
female->relations.pregnancy_ptr = preg; female->relations.pregnancy_genes = preg;
female->relations.pregnancy_timer = rand() % 100 + 1; female->relations.pregnancy_timer = rand() % 100 + 1;
female->relations.pregnancy_mystery = 1; // WTF is this? female->relations.pregnancy_caste = 1;
totalcreated ++; totalcreated ++;
} }
} }

@ -0,0 +1,87 @@
// Destroys items being used as part of constructions
// and flags the constructions to recreate their components upon disassembly
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Maps.h"
#include "DataDefs.h"
#include "df/item.h"
#include "df/world.h"
#include "df/construction.h"
#include "df/map_block.h"
using namespace std;
using namespace DFHack;
using df::global::world;
DFHACK_PLUGIN("cleanconst");
command_result df_cleanconst(color_ostream &out, vector <string> & parameters)
{
CoreSuspender suspend;
if (!Maps::IsValid())
{
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
size_t numItems = world->items.all.size();
int cleaned_total = 0;
// proceed with the cleanup operation
for (size_t i = 0; i < numItems; i++)
{
df::item *item = world->items.all[i];
// only process items marked as "in construction"
if (!item->flags.bits.construction)
continue;
df::coord pos(item->pos.x, item->pos.y, item->pos.z);
df::construction *cons = df::construction::find(pos);
if (!cons)
{
out.printerr("Item at %i,%i,%i marked as construction but no construction is present!\n", pos.x, pos.y, pos.z);
continue;
}
// if the construction is already labeled as "no build item", then leave it alone
if (cons->flags.bits.no_build_item)
continue;
// only destroy the item if the construction claims to be made of the exact same thing
if (item->getType() != cons->item_type ||
item->getSubtype() != cons->item_subtype ||
item->getMaterial() != cons->mat_type ||
item->getMaterialIndex() != cons->mat_index)
continue;
item->flags.bits.garbage_collect = 1;
cons->flags.bits.no_build_item = 1;
cleaned_total++;
}
out.print("Done. %d construction items cleaned up.\n", cleaned_total);
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"cleanconst", "Cleans up construction materials.",
df_cleanconst, false,
" This utility alters all constructions on the map so that they spawn their\n"
" building component when they are disassembled, allowing their actual\n"
" build items to be safely deleted.\n"
));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}

@ -76,7 +76,7 @@ using df::global::world;
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
static int enable_autolabor = 0; DFHACK_PLUGIN_IS_ENABLED(enable_autolabor);
static bool print_debug = 0; static bool print_debug = 0;
@ -1375,6 +1375,7 @@ static void setOptionEnabled(ConfigFlags flag, bool on)
static void cleanup_state() static void cleanup_state()
{ {
enable_autolabor = false;
labor_infos.clear(); labor_infos.clear();
} }
@ -2384,6 +2385,27 @@ df::unit_labor lookup_labor_by_name (std::string& name)
return labor; return labor;
} }
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable )
{
if (!Core::getInstance().isWorldLoaded()) {
out.printerr("World is not loaded: please load a game first.\n");
return CR_FAILURE;
}
if (enable && !enable_autolabor)
{
enable_plugin(out);
}
else if(!enable && enable_autolabor)
{
enable_autolabor = false;
setOptionEnabled(CF_ENABLED, false);
out << "Autolabor is disabled." << endl;
}
return CR_OK;
}
command_result autolabor (color_ostream &out, std::vector <std::string> & parameters) command_result autolabor (color_ostream &out, std::vector <std::string> & parameters)
{ {
@ -2398,19 +2420,7 @@ command_result autolabor (color_ostream &out, std::vector <std::string> & parame
(parameters[0] == "enable" || parameters[0] == "disable")) (parameters[0] == "enable" || parameters[0] == "disable"))
{ {
bool enable = (parameters[0] == "enable"); bool enable = (parameters[0] == "enable");
if (enable && !enable_autolabor) return plugin_enable(out, enable);
{
enable_plugin(out);
}
else if(!enable && enable_autolabor)
{
enable_autolabor = false;
setOptionEnabled(CF_ENABLED, false);
out << "The plugin is disabled." << endl;
}
return CR_OK;
} }
else if (parameters.size() == 3 && else if (parameters.size() == 3 &&
(parameters[0] == "max" || parameters[0] == "priority")) (parameters[0] == "max" || parameters[0] == "priority"))

@ -16,6 +16,8 @@ using std::vector;
using std::string; using std::string;
using namespace DFHack; using namespace DFHack;
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
//FIXME: possible race conditions with calling kittens from the IO thread and shutdown from Core. //FIXME: possible race conditions with calling kittens from the IO thread and shutdown from Core.
bool shutdown_flag = false; bool shutdown_flag = false;
bool final_flag = true; bool final_flag = true;
@ -141,6 +143,7 @@ command_result trackmenu (color_ostream &out, vector <string> & parameters)
if(df::global::ui) if(df::global::ui)
{ {
trackmenu_flg = true; trackmenu_flg = true;
is_enabled = true;
last_menu = df::global::ui->main.mode; last_menu = df::global::ui->main.mode;
out.print("Menu: %d\n",last_menu); out.print("Menu: %d\n",last_menu);
return CR_OK; return CR_OK;
@ -155,6 +158,7 @@ command_result trackmenu (color_ostream &out, vector <string> & parameters)
command_result trackpos (color_ostream &out, vector <string> & parameters) command_result trackpos (color_ostream &out, vector <string> & parameters)
{ {
trackpos_flg = !trackpos_flg; trackpos_flg = !trackpos_flg;
is_enabled = true;
return CR_OK; return CR_OK;
} }
@ -214,6 +218,7 @@ command_result ktimer (color_ostream &out, vector <string> & parameters)
// harmless potential data race here... // harmless potential data race here...
timeLast = timeend; timeLast = timeend;
timering = true; timering = true;
is_enabled = true;
return CR_OK; return CR_OK;
} }

@ -15,6 +15,8 @@ using namespace DFHack;
uint64_t timeLast=0; uint64_t timeLast=0;
static tthread::mutex* mymutex=0; static tthread::mutex* mymutex=0;
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
struct memory_data struct memory_data
{ {
void * addr; void * addr;
@ -96,6 +98,7 @@ void Deinit()
{ {
if(memdata.state==STATE_ON) if(memdata.state==STATE_ON)
{ {
is_enabled = false;
memdata.state=STATE_OFF; memdata.state=STATE_OFF;
delete [] memdata.buf; delete [] memdata.buf;
delete [] memdata.lbuf; delete [] memdata.lbuf;
@ -140,6 +143,7 @@ command_result memview (color_ostream &out, vector <string> & parameters)
{ {
Deinit(); Deinit();
memdata.state=STATE_OFF; memdata.state=STATE_OFF;
is_enabled = false;
mymutex->unlock(); mymutex->unlock();
return CR_OK; return CR_OK;
} }
@ -156,6 +160,7 @@ command_result memview (color_ostream &out, vector <string> & parameters)
mymutex->unlock(); mymutex->unlock();
return CR_OK; return CR_OK;
} }
is_enabled = true;
memdata.state=STATE_ON; memdata.state=STATE_ON;
} }
if(parameters.size()>1) if(parameters.size()>1)

@ -31,7 +31,7 @@ static command_result nestboxes(color_ostream &out, vector <string> & parameters
DFHACK_PLUGIN("nestboxes"); DFHACK_PLUGIN("nestboxes");
static bool enabled = false; DFHACK_PLUGIN_IS_ENABLED(enabled);
static void eggscan(color_ostream &out) static void eggscan(color_ostream &out)
{ {
@ -97,6 +97,12 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out)
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
enabled = enable;
return CR_OK;
}
static command_result nestboxes(color_ostream &out, vector <string> & parameters) static command_result nestboxes(color_ostream &out, vector <string> & parameters)
{ {
CoreSuspender suspend; CoreSuspender suspend;

@ -23,6 +23,8 @@ using df::global::gps;
DFHACK_PLUGIN("vshook"); DFHACK_PLUGIN("vshook");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
struct title_hook : df::viewscreen_titlest { struct title_hook : df::viewscreen_titlest {
typedef df::viewscreen_titlest interpose_base; typedef df::viewscreen_titlest interpose_base;
@ -37,17 +39,30 @@ struct title_hook : df::viewscreen_titlest {
IMPLEMENT_VMETHOD_INTERPOSE(title_hook, render); IMPLEMENT_VMETHOD_INTERPOSE(title_hook, render);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable)
{ {
if (gps) if (!gps)
return CR_FAILURE;
if (enable != is_enabled)
{ {
if (!INTERPOSE_HOOK(title_hook, render).apply()) if (!INTERPOSE_HOOK(title_hook, render).apply(enable))
out.printerr("Could not interpose viewscreen_titlest::render\n"); return CR_FAILURE;
is_enabled = enable;
} }
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
// DON'T DO THIS IN NON-EXAMPLE PLUGINS
plugin_enable(out, true);
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out ) DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{ {
INTERPOSE_HOOK(title_hook, render).remove(); INTERPOSE_HOOK(title_hook, render).remove();

@ -179,9 +179,9 @@ public:
addDwarfActivity(unit, *entry); addDwarfActivity(unit, *entry);
} }
for_each_(dwarf_activity_values[unit], auto &values = dwarf_activity_values[unit];
[&] (const pair<activity_type, size_t> &x) for (auto it = values.begin(); it != values.end(); ++it)
{ dwarf_activity_values[unit][x.first] = getPercentage(x.second, dwarf_total); } ); it->second = getPercentage(it->second, dwarf_total);
dwarves_column.add(getUnitName(unit), unit); dwarves_column.add(getUnitName(unit), unit);
} }
@ -212,9 +212,8 @@ public:
vector<pair<activity_type, size_t>> rev_vec(dwarf_activities->begin(), dwarf_activities->end()); vector<pair<activity_type, size_t>> rev_vec(dwarf_activities->begin(), dwarf_activities->end());
sort(rev_vec.begin(), rev_vec.end(), less_second<activity_type, size_t>()); sort(rev_vec.begin(), rev_vec.end(), less_second<activity_type, size_t>());
for_each_(rev_vec, for (auto it = rev_vec.begin(); it != rev_vec.end(); ++it)
[&] (pair<activity_type, size_t> x) dwarf_activity_column.add(getActivityItem(it->first, it->second), it->first);
{ dwarf_activity_column.add(getActivityItem(x.first, x.second), x.first); });
} }
dwarf_activity_column.fixWidth(); dwarf_activity_column.fixWidth();
@ -754,9 +753,8 @@ public:
vector<pair<df::unit *, size_t>> rev_vec(dwarf_activities->begin(), dwarf_activities->end()); vector<pair<df::unit *, size_t>> rev_vec(dwarf_activities->begin(), dwarf_activities->end());
sort(rev_vec.begin(), rev_vec.end(), less_second<df::unit *, size_t>()); sort(rev_vec.begin(), rev_vec.end(), less_second<df::unit *, size_t>());
for_each_(rev_vec, for (auto it = rev_vec.begin(); it != rev_vec.end(); ++it)
[&] (pair<df::unit *, size_t> x) dwarf_activity_column.add(getDwarfAverage(it->first, it->second), it->first);
{ dwarf_activity_column.add(getDwarfAverage(x.first, x.second), x.first); });
} }
} }
@ -778,9 +776,8 @@ public:
vector<pair<activity_type, size_t>> rev_vec(category_activities->begin(), category_activities->end()); vector<pair<activity_type, size_t>> rev_vec(category_activities->begin(), category_activities->end());
sort(rev_vec.begin(), rev_vec.end(), less_second<activity_type, size_t>()); sort(rev_vec.begin(), rev_vec.end(), less_second<activity_type, size_t>());
for_each_(rev_vec, for (auto it = rev_vec.begin(); it != rev_vec.end(); ++it)
[&] (pair<activity_type, size_t> x) category_breakdown_column.add(getBreakdownAverage(it->first, it->second), it->first);
{ category_breakdown_column.add(getBreakdownAverage(x.first, x.second), x.first); });
} }
category_breakdown_column.fixWidth(); category_breakdown_column.fixWidth();
@ -1179,11 +1176,15 @@ IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, render); IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, render);
DFHACK_PLUGIN("dwarfmonitor"); DFHACK_PLUGIN("dwarfmonitor");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
static bool set_monitoring_mode(const string &mode, const bool &state) static bool set_monitoring_mode(const string &mode, const bool &state)
{ {
bool mode_recognized = false; bool mode_recognized = false;
if (!is_enabled)
return false;
if (mode == "work" || mode == "all") if (mode == "work" || mode == "all")
{ {
mode_recognized = true; mode_recognized = true;
@ -1201,6 +1202,24 @@ static bool set_monitoring_mode(const string &mode, const bool &state)
return mode_recognized; return mode_recognized;
} }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
if (!gps)
return CR_FAILURE;
if (is_enabled != enable)
{
if (!INTERPOSE_HOOK(dwarf_monitor_hook, feed).apply(enable) ||
!INTERPOSE_HOOK(dwarf_monitor_hook, render).apply(enable))
return CR_FAILURE;
reset();
is_enabled = enable;
}
return CR_OK;
}
static command_result dwarfmonitor_cmd(color_ostream &out, vector <string> & parameters) static command_result dwarfmonitor_cmd(color_ostream &out, vector <string> & parameters)
{ {
bool show_help = false; bool show_help = false;
@ -1222,6 +1241,9 @@ static command_result dwarfmonitor_cmd(color_ostream &out, vector <string> & par
} }
else if ((cmd == 'e' || cmd == 'E') && !mode.empty()) else if ((cmd == 'e' || cmd == 'E') && !mode.empty())
{ {
if (!is_enabled)
plugin_enable(out, true);
if (set_monitoring_mode(mode, true)) if (set_monitoring_mode(mode, true))
{ {
out << "Monitoring enabled: " << mode << endl; out << "Monitoring enabled: " << mode << endl;
@ -1257,9 +1279,6 @@ static command_result dwarfmonitor_cmd(color_ostream &out, vector <string> & par
DFhackCExport command_result plugin_init(color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init(color_ostream &out, std::vector <PluginCommand> &commands)
{ {
if (!gps || !INTERPOSE_HOOK(dwarf_monitor_hook, feed).apply() || !INTERPOSE_HOOK(dwarf_monitor_hook, render).apply())
out.printerr("Could not insert dwarfmonitor hooks!\n");
activity_labels[JOB_IDLE] = "Idle"; activity_labels[JOB_IDLE] = "Idle";
activity_labels[JOB_MILITARY] = "Military Duty"; activity_labels[JOB_MILITARY] = "Military Duty";
activity_labels[JOB_LEISURE] = "Leisure"; activity_labels[JOB_LEISURE] = "Leisure";

@ -19,6 +19,8 @@ using df::global::world;
// dfhack interface // dfhack interface
DFHACK_PLUGIN("fastdwarf"); DFHACK_PLUGIN("fastdwarf");
DFHACK_PLUGIN_IS_ENABLED(active);
static bool enable_fastdwarf = false; static bool enable_fastdwarf = false;
static bool enable_teledwarf = false; static bool enable_teledwarf = false;
@ -155,6 +157,8 @@ static command_result fastdwarf (color_ostream &out, vector <string> & parameter
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
active = enable_fastdwarf || enable_teledwarf;
out.print("Current state: fast = %d, teleport = %d.\n", out.print("Current state: fast = %d, teleport = %d.\n",
(df::global::debug_turbospeed && *df::global::debug_turbospeed) ? 2 : (enable_fastdwarf ? 1 : 0), (df::global::debug_turbospeed && *df::global::debug_turbospeed) ? 2 : (enable_fastdwarf ? 1 : 0),
enable_teledwarf ? 1 : 0); enable_teledwarf ? 1 : 0);
@ -162,6 +166,17 @@ static command_result fastdwarf (color_ostream &out, vector <string> & parameter
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable )
{
if (active != enable)
{
active = enable_fastdwarf = enable;
enable_teledwarf = false;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.push_back(PluginCommand("fastdwarf", commands.push_back(PluginCommand("fastdwarf",

@ -698,7 +698,7 @@ static void try_store_ammo(df::squad *squad)
} }
} }
static bool is_enabled = false; DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_onupdate(color_ostream &out, state_change_event event) DFhackCExport command_result plugin_onupdate(color_ostream &out, state_change_event event)
{ {
@ -810,6 +810,21 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
if (!Core::getInstance().isWorldLoaded()) {
out.printerr("World is not loaded: please load a game first.\n");
return CR_FAILURE;
}
if (enable)
enable_plugin(out);
else
disable_plugin(out);
return CR_OK;
}
static command_result fix_armory(color_ostream &out, vector <string> &parameters) static command_result fix_armory(color_ostream &out, vector <string> &parameters)
{ {
CoreSuspender suspend; CoreSuspender suspend;
@ -820,13 +835,9 @@ static command_result fix_armory(color_ostream &out, vector <string> &parameters
string cmd = parameters[0]; string cmd = parameters[0];
if (cmd == "enable") if (cmd == "enable")
{ return plugin_enable(out, true);
enable_plugin(out);
}
else if (cmd == "disable") else if (cmd == "disable")
{ return plugin_enable(out, false);
disable_plugin(out);
}
else else
return CR_WRONG_USAGE; return CR_WRONG_USAGE;

@ -24,6 +24,7 @@ int32_t prevX, prevY, prevZ;
uint8_t prevMenuWidth; uint8_t prevMenuWidth;
DFHACK_PLUGIN("follow"); DFHACK_PLUGIN("follow");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
@ -53,6 +54,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
followedUnit = 0; followedUnit = 0;
prevX=prevY=prevZ = -1; prevX=prevY=prevZ = -1;
prevMenuWidth = 0; prevMenuWidth = 0;
is_enabled = false;
break; break;
default: default:
break; break;
@ -97,6 +99,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
} }
else if((prevX != x || prevY != y || prevZ != z) && prevMenuWidth == menu_width) //User has manually moved the window, stop following the unit else if((prevX != x || prevY != y || prevZ != z) && prevMenuWidth == menu_width) //User has manually moved the window, stop following the unit
{ {
is_enabled = false;
followedUnit = 0; followedUnit = 0;
prevX=prevY=prevZ = -1; prevX=prevY=prevZ = -1;
prevMenuWidth = 0; prevMenuWidth = 0;
@ -146,6 +149,7 @@ command_result follow (color_ostream &out, std::vector <std::string> & parameter
followedUnit = Gui::getSelectedUnit(out); followedUnit = Gui::getSelectedUnit(out);
if (followedUnit) if (followedUnit)
{ {
is_enabled = true;
std::ostringstream ss; std::ostringstream ss;
ss << "Unpause to begin following " << df::global::world->raws.creatures.all[followedUnit->race]->name[0]; ss << "Unpause to begin following " << df::global::world->raws.creatures.all[followedUnit->race]->name[0];
if (followedUnit->name.has_name) ss << " " << followedUnit->name.first_name; if (followedUnit->name.has_name) ss << " " << followedUnit->name.first_name;
@ -153,5 +157,6 @@ command_result follow (color_ostream &out, std::vector <std::string> & parameter
out.print(ss.str().c_str()); out.print(ss.str().c_str());
} }
else followedUnit = 0; else followedUnit = 0;
is_enabled = (followedUnit != NULL);
return CR_OK; return CR_OK;
} }

@ -71,7 +71,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
*/ */
static size_t constructionSize = 0; static size_t constructionSize = 0;
static bool enabled = false; DFHACK_PLUGIN_IS_ENABLED(enabled);
void doInfiniteSky(color_ostream& out, int32_t howMany); void doInfiniteSky(color_ostream& out, int32_t howMany);
DFhackCExport command_result plugin_onupdate ( color_ostream &out ) DFhackCExport command_result plugin_onupdate ( color_ostream &out )
@ -155,6 +155,12 @@ void doInfiniteSky(color_ostream& out, int32_t howMany) {
} }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
enabled = enable;
return CR_OK;
}
command_result infiniteSky (color_ostream &out, std::vector <std::string> & parameters) command_result infiniteSky (color_ostream &out, std::vector <std::string> & parameters)
{ {
if ( parameters.size() > 1 ) if ( parameters.size() > 1 )

@ -159,22 +159,22 @@ function empregnate(unit)
unit.curse.add_tags2.STERILE=false unit.curse.add_tags2.STERILE=false
end end
local genes = unit.appearance.genes local genes = unit.appearance.genes
if unit.relations.pregnancy_ptr == nil then if unit.relations.pregnancy_genes == nil then
print("creating preg ptr.") print("creating preg ptr.")
if false then if false then
print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_ptr")))) print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_genes"))))
return return
end end
unit.relations.pregnancy_ptr = { new = true, assign = genes } unit.relations.pregnancy_genes = { new = true, assign = genes }
end end
local ngenes = unit.relations.pregnancy_ptr local ngenes = unit.relations.pregnancy_genes
if #ngenes.appearance ~= #genes.appearance or #ngenes.colors ~= #genes.colors then if #ngenes.appearance ~= #genes.appearance or #ngenes.colors ~= #genes.colors then
print("Array sizes incorrect, fixing.") print("Array sizes incorrect, fixing.")
ngenes:assign(genes); ngenes:assign(genes);
end end
print("Setting preg timer.") print("Setting preg timer.")
unit.relations.pregnancy_timer=10 unit.relations.pregnancy_timer=10
unit.relations.pregnancy_mystery=1 unit.relations.pregnancy_caste=1
end end
menu:add("Empregnate",empregnate) menu:add("Empregnate",empregnate)
function healunit(unit) function healunit(unit)

@ -73,11 +73,10 @@ function job_outputs.CustomReaction(callback, job)
if mat then if mat then
local rp = mat.material.reaction_product local rp = mat.material.reaction_product
local idx = utils.linear_index(rp.id, p_code) local idx = utils.linear_index(rp.id, p_code, 'value')
if not idx then if idx then
goto continue mat_type, mat_index = rp.material.mat_type[idx], rp.material.mat_index[idx]
end end
mat_type, mat_index = rp.material.mat_type[idx], rp.material.mat_index[idx]
else else
if p_code == "SOAP_MAT" then if p_code == "SOAP_MAT" then
mat_mask = { soap = true } mat_mask = { soap = true }

@ -1209,10 +1209,27 @@ IMPLEMENT_VMETHOD_INTERPOSE(unitlist_hook, render);
DFHACK_PLUGIN("manipulator"); DFHACK_PLUGIN("manipulator");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
if (!gps)
return CR_FAILURE;
if (enable != is_enabled)
{
if (!INTERPOSE_HOOK(unitlist_hook, feed).apply(enable) ||
!INTERPOSE_HOOK(unitlist_hook, render).apply(enable))
return CR_FAILURE;
is_enabled = enable;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
{ {
if (!gps || !INTERPOSE_HOOK(unitlist_hook, feed).apply() || !INTERPOSE_HOOK(unitlist_hook, render).apply())
out.printerr("Could not insert Dwarf Manipulator hooks!\n");
return CR_OK; return CR_OK;
} }

@ -15,6 +15,8 @@ using namespace std;
using namespace DFHack; using namespace DFHack;
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
static int factor = 1; static int factor = 1;
static map<int, int> processedThoughtCountTable; static map<int, int> processedThoughtCountTable;
@ -38,6 +40,7 @@ DFhackCExport command_result plugin_onupdate(color_ostream& out) {
if ( wasLoaded ) { if ( wasLoaded ) {
//we just unloaded the game: clear all data //we just unloaded the game: clear all data
factor = 1; factor = 1;
is_enabled = false;
processedThoughtCountTable.clear(); processedThoughtCountTable.clear();
fakeThoughts.clear(); fakeThoughts.clear();
wasLoaded = false; wasLoaded = false;
@ -138,6 +141,17 @@ DFhackCExport command_result plugin_init(color_ostream& out, vector<PluginComman
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
if (enable != is_enabled)
{
is_enabled = enable;
factor = enable ? 2 : 1;
}
return CR_OK;
}
command_result misery(color_ostream &out, vector<string>& parameters) { command_result misery(color_ostream &out, vector<string>& parameters) {
if ( !df::global::world || !df::global::world->map.block_index ) { if ( !df::global::world || !df::global::world->map.block_index ) {
out.printerr("misery can only be enabled in fortress mode with a fully-loaded game.\n"); out.printerr("misery can only be enabled in fortress mode with a fully-loaded game.\n");
@ -153,15 +167,18 @@ command_result misery(color_ostream &out, vector<string>& parameters) {
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
factor = 1; factor = 1;
is_enabled = false;
return CR_OK; return CR_OK;
} else if ( parameters[0] == "enable" ) { } else if ( parameters[0] == "enable" ) {
is_enabled = true;
factor = 2; factor = 2;
if ( parameters.size() == 2 ) { if ( parameters.size() == 2 ) {
factor = atoi(parameters[1].c_str()); int a = atoi(parameters[1].c_str());
if ( factor < 1 ) { if ( a <= 1 ) {
out.printerr("Second argument must be a positive integer.\n"); out.printerr("Second argument must be a positive integer.\n");
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
factor = a;
} }
} else if ( parameters[0] == "clear" ) { } else if ( parameters[0] == "clear" ) {
for ( size_t a = 0; a < fakeThoughts.size(); a++ ) { for ( size_t a = 0; a < fakeThoughts.size(); a++ ) {
@ -176,6 +193,7 @@ command_result misery(color_ostream &out, vector<string>& parameters) {
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
factor = a; factor = a;
is_enabled = factor > 1;
} }
return CR_OK; return CR_OK;

@ -33,12 +33,6 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{
// add tracking here
return CR_OK;
}
void printCurrentModes(t_gamemodes gm, Console & con) void printCurrentModes(t_gamemodes gm, Console & con)
{ {
con << "Current game type:\t" << gm.g_type << " ("; con << "Current game type:\t" << gm.g_type << " (";

@ -239,12 +239,28 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
IMPLEMENT_VMETHOD_INTERPOSE(mousequery_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(mousequery_hook, feed);
DFHACK_PLUGIN("mousequery"); DFHACK_PLUGIN("mousequery");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable)
{ {
if (!gps || !INTERPOSE_HOOK(mousequery_hook, feed).apply()) if (!gps)
out.printerr("Could not insert mousequery hooks!\n"); return CR_FAILURE;
if (is_enabled != enable)
{
last_x = last_y = last_z = -1;
if (!INTERPOSE_HOOK(mousequery_hook, feed).apply(enable))
return CR_FAILURE;
is_enabled = enable;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
last_x = last_y = last_z = -1; last_x = last_y = last_z = -1;
return CR_OK; return CR_OK;

@ -145,7 +145,7 @@ struct trap_hook : df::building_trapst {
INTERPOSE_NEXT(updateAction)(); INTERPOSE_NEXT(updateAction)();
} }
DEFINE_VMETHOD_INTERPOSE(void, drawBuilding, (df::building_drawbuffer *db, void *unk)) DEFINE_VMETHOD_INTERPOSE(void, drawBuilding, (df::building_drawbuffer *db, int16_t unk))
{ {
INTERPOSE_NEXT(drawBuilding)(db, unk); INTERPOSE_NEXT(drawBuilding)(db, unk);
@ -160,7 +160,7 @@ IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, getName);
IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, updateAction); IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, updateAction);
IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, drawBuilding); IMPLEMENT_VMETHOD_INTERPOSE(trap_hook, drawBuilding);
static bool enabled = false; DFHACK_PLUGIN_IS_ENABLED(enabled);
static void enable_hooks(bool enable) static void enable_hooks(bool enable)
{ {

@ -55,6 +55,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
static command_result rename(color_ostream &out, vector <string> & parameters); static command_result rename(color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("rename"); DFHACK_PLUGIN("rename");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
@ -174,6 +175,9 @@ KNOWN_BUILDINGS
static bool enable_building_rename(char code, bool enable) static bool enable_building_rename(char code, bool enable)
{ {
if (enable)
is_enabled = true;
if (code == 'Z') if (code == 'Z')
INTERPOSE_HOOK(dwarf_render_zone_hook, render).apply(enable); INTERPOSE_HOOK(dwarf_render_zone_hook, render).apply(enable);
@ -189,6 +193,7 @@ KNOWN_BUILDINGS
static void disable_building_rename() static void disable_building_rename()
{ {
is_enabled = false;
INTERPOSE_HOOK(dwarf_render_zone_hook, render).remove(); INTERPOSE_HOOK(dwarf_render_zone_hook, render).remove();
#define BUILDING(code, cname, tag) \ #define BUILDING(code, cname, tag) \

@ -107,7 +107,7 @@ struct SuspendedBuilding
} }
}; };
static bool enabled = false; DFHACK_PLUGIN_IS_ENABLED(enabled);
static bool buildings_scanned = false; static bool buildings_scanned = false;
static vector<SuspendedBuilding> suspended_buildings, resumed_buildings; static vector<SuspendedBuilding> suspended_buildings, resumed_buildings;
@ -125,8 +125,10 @@ void scan_for_suspended_buildings()
SuspendedBuilding sb(bld); SuspendedBuilding sb(bld);
sb.is_planned = job->job_items.size() == 1 && job->job_items[0]->item_type == item_type::NONE; sb.is_planned = job->job_items.size() == 1 && job->job_items[0]->item_type == item_type::NONE;
auto it = find_if(resumed_buildings.begin(), resumed_buildings.end(), auto it = resumed_buildings.begin();
[&] (SuspendedBuilding &rsb) { return rsb.bld == bld; });
for (; it != resumed_buildings.end(); ++it)
if (it->bld == bld) break;
sb.was_resumed = it != resumed_buildings.end(); sb.was_resumed = it != resumed_buildings.end();
@ -234,6 +236,23 @@ struct resume_hook : public df::viewscreen_dwarfmodest
IMPLEMENT_VMETHOD_INTERPOSE(resume_hook, render); IMPLEMENT_VMETHOD_INTERPOSE(resume_hook, render);
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable)
{
if (!gps)
return CR_FAILURE;
if (enabled != enable)
{
clear_scanned();
if (!INTERPOSE_HOOK(resume_hook, render).apply(enable))
return CR_FAILURE;
enabled = enable;
}
return CR_OK;
}
static command_result resume_cmd(color_ostream &out, vector <string> & parameters) static command_result resume_cmd(color_ostream &out, vector <string> & parameters)
{ {
@ -251,12 +270,12 @@ static command_result resume_cmd(color_ostream &out, vector <string> & parameter
} }
else if (cmd == 's') else if (cmd == 's')
{ {
enabled = true; plugin_enable(out, true);
out << "Overlay enabled" << endl; out << "Overlay enabled" << endl;
} }
else if (cmd == 'h') else if (cmd == 'h')
{ {
enabled = false; plugin_enable(out, false);
out << "Overlay disabled" << endl; out << "Overlay disabled" << endl;
} }
else if (cmd == 'a') else if (cmd == 'a')
@ -275,12 +294,8 @@ static command_result resume_cmd(color_ostream &out, vector <string> & parameter
return CR_OK; return CR_OK;
} }
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
if (!gps || !INTERPOSE_HOOK(resume_hook, render).apply())
out.printerr("Could not insert resume hooks!\n");
commands.push_back( commands.push_back(
PluginCommand( PluginCommand(
"resume", "A plugin to help display and resume suspended constructions conveniently", "resume", "A plugin to help display and resume suspended constructions conveniently",

@ -85,6 +85,8 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCom
return CR_OK; return CR_OK;
} }
DFHACK_PLUGIN_IS_ENABLED(is_active);
DFhackCExport command_result plugin_onupdate ( color_ostream &out ) DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{ {
t_gamemodes gm; t_gamemodes gm;
@ -117,6 +119,7 @@ command_result nopause (color_ostream &out, vector <string> & parameters)
nopause_state = 0; nopause_state = 0;
else else
nopause_state = 1; nopause_state = 1;
is_active = nopause_state || (revealed == REVEALED);
out.print("nopause %sactivated.\n", (nopause_state ? "" : "de")); out.print("nopause %sactivated.\n", (nopause_state ? "" : "de"));
} }
else else
@ -237,6 +240,7 @@ command_result reveal(color_ostream &out, vector<string> & params)
else else
revealed = DEMON_REVEALED; revealed = DEMON_REVEALED;
} }
is_active = nopause_state || (revealed == REVEALED);
con.print("Map revealed.\n"); con.print("Map revealed.\n");
if(!no_hell) if(!no_hell)
con.print("Unpausing can unleash the forces of hell, so it has been temporarily disabled.\n"); con.print("Unpausing can unleash the forces of hell, so it has been temporarily disabled.\n");
@ -296,6 +300,7 @@ command_result unreveal(color_ostream &out, vector<string> & params)
// give back memory. // give back memory.
hidesaved.clear(); hidesaved.clear();
revealed = NOT_REVEALED; revealed = NOT_REVEALED;
is_active = nopause_state || (revealed == REVEALED);
con.print("Map hidden!\n"); con.print("Map hidden!\n");
return CR_OK; return CR_OK;
} }
@ -490,6 +495,7 @@ command_result revforget(color_ostream &out, vector<string> & params)
// give back memory. // give back memory.
hidesaved.clear(); hidesaved.clear();
revealed = NOT_REVEALED; revealed = NOT_REVEALED;
is_active = nopause_state || (revealed == REVEALED);
con.print("Reveal data forgotten!\n"); con.print("Reveal data forgotten!\n");
return CR_OK; return CR_OK;
} }

@ -53,15 +53,26 @@ module DFHack
end end
# check item flags to see if it is suitable for use as a job input material # check item flags to see if it is suitable for use as a job input material
def item_isfree(i) def item_isfree(i, check_empty=true)
!i.flags.trader and !i.flags.trader and
!i.flags.in_job and !i.flags.in_job and
(!i.flags.in_inventory or i.general_refs.grep(GeneralRefContainedInItemst).first) and !i.flags.construction and
!i.flags.removed and !i.flags.removed and
!i.flags.in_building and !i.flags.forbid and
!i.flags.dump and
!i.flags.owned and !i.flags.owned and
!i.flags.forbid !i.flags.in_chest and # used as hospital supply ?
(!i.flags.container or not check_empty or
!i.general_refs.find { |ir| ir.kind_of?(DFHack::GeneralRefContainsItemst) }) and
(!i.flags.in_inventory or
(!i.general_refs.find { |ir| ir.kind_of?(DFHack::GeneralRefUnitHolderst) and # allow hauled items TODO check if holder is a thief
ir.unit_tg.inventory.find { |ii| ii.item == i and ii.mode != :Hauled } } and
!i.general_refs.find { |ir| ir.kind_of?(DFHack::GeneralRefContainedInItemst) and
!item_isfree(ir.item_tg, false) })) and
(!i.flags.in_building or
!i.general_refs.find { |ir| ir.kind_of?(DFHack::GeneralRefBuildingHolderst) and
ir.building_tg.contained_items.find { |bi| bi.use_mode == 2 and bi.item == i } }) and
(!i.flags.on_ground or !df.map_tile_at(i).designation.hidden) # i.flags.unk11?
end end
end end
end end

@ -475,7 +475,7 @@ module DFHack
class StlVector32 < MemStruct class StlVector32 < MemStruct
attr_accessor :_tg attr_accessor :_tg
def initialize(tg) def initialize(tg)
@_tg = tg @_tg = tg || Number.new(32, false, 0, nil)
end end
def length def length

@ -46,6 +46,16 @@ static std::vector<std::string> *dfhack_run_queue;
DFHACK_PLUGIN("ruby") DFHACK_PLUGIN("ruby")
DFhackDataExport bool plugin_is_enabled = true;
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
plugin_is_enabled = enable;
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
onupdate_active = 0; onupdate_active = 0;

@ -1609,6 +1609,7 @@ IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, burrow_search);
DFHACK_PLUGIN("search"); DFHACK_PLUGIN("search");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
#define SEARCH_HOOKS \ #define SEARCH_HOOKS \
HOOK_ACTION(unitlist_search_hook) \ HOOK_ACTION(unitlist_search_hook) \
@ -1624,15 +1625,28 @@ DFHACK_PLUGIN("search");
HOOK_ACTION(burrow_search_hook) \ HOOK_ACTION(burrow_search_hook) \
HOOK_ACTION(stockpile_search_hook) HOOK_ACTION(stockpile_search_hook)
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands) DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable)
{ {
if (!gps || !gview)
return CR_FAILURE;
if (is_enabled != enable)
{
#define HOOK_ACTION(hook) \ #define HOOK_ACTION(hook) \
!INTERPOSE_HOOK(hook, feed).apply() || \ !INTERPOSE_HOOK(hook, feed).apply(enable) || \
!INTERPOSE_HOOK(hook, render).apply() || !INTERPOSE_HOOK(hook, render).apply(enable) ||
if (SEARCH_HOOKS 0)
return CR_FAILURE;
is_enabled = enable;
}
if (!gps || !gview || SEARCH_HOOKS 0) return CR_OK;
out.printerr("Could not insert Search hooks!\n"); }
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
{
#undef HOOK_ACTION #undef HOOK_ACTION
const string a[] = {"Meager Quarters", "Modest Quarters", "Quarters", "Decent Quarters", "Fine Quarters", "Great Bedroom", "Grand Bedroom", "Royal Bedroom"}; const string a[] = {"Meager Quarters", "Modest Quarters", "Quarters", "Decent Quarters", "Fine Quarters", "Great Bedroom", "Grand Bedroom", "Royal Bedroom"};

@ -22,7 +22,7 @@ using namespace df::enums;
using df::global::world; using df::global::world;
const int buffer = 20; // seed number buffer - 20 is reasonable const int buffer = 20; // seed number buffer - 20 is reasonable
bool running = false; // whether seedwatch is counting the seeds or not DFHACK_PLUGIN_IS_ENABLED(running); // whether seedwatch is counting the seeds or not
// abbreviations for the standard plants // abbreviations for the standard plants
map<string, string> abbreviations; map<string, string> abbreviations;
@ -96,6 +96,12 @@ string searchAbbreviations(string in)
} }
}; };
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
running = enable;
return CR_OK;
}
command_result df_seedwatch(color_ostream &out, vector<string>& parameters) command_result df_seedwatch(color_ostream &out, vector<string>& parameters)
{ {
CoreSuspender suspend; CoreSuspender suspend;

@ -1766,7 +1766,7 @@ DFHACK_PLUGIN_LUA_COMMANDS {
DFHACK_LUA_END DFHACK_LUA_END
}; };
static bool is_enabled = false; DFHACK_PLUGIN_IS_ENABLED(is_enabled);
static void enable_hooks(bool enable) static void enable_hooks(bool enable)
{ {
@ -1809,6 +1809,25 @@ static void clear_caches(color_ostream &out)
} }
} }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
if (gamemode && *gamemode != game_mode::DWARF)
return CR_FAILURE;
if (enable != is_enabled)
{
if (enable)
enable_plugin();
else
{
World::DeletePersistentData(World::GetPersistentData("siege-engine/enabled"));
enable_hooks(false);
}
}
return CR_OK;
}
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{ {
switch (event) { switch (event) {

@ -721,7 +721,7 @@ struct workshop_hook : df::building_workshopst {
INTERPOSE_NEXT(updateAction)(); INTERPOSE_NEXT(updateAction)();
} }
DEFINE_VMETHOD_INTERPOSE(void, drawBuilding, (df::building_drawbuffer *db, void *unk)) DEFINE_VMETHOD_INTERPOSE(void, drawBuilding, (df::building_drawbuffer *db, int16_t unk))
{ {
INTERPOSE_NEXT(drawBuilding)(db, unk); INTERPOSE_NEXT(drawBuilding)(db, unk);
@ -950,8 +950,12 @@ static bool find_engines(color_ostream &out)
return !engines.empty(); return !engines.empty();
} }
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
static void enable_hooks(bool enable) static void enable_hooks(bool enable)
{ {
is_enabled = enable;
INTERPOSE_HOOK(liquid_hook, getItemDescription).apply(enable); INTERPOSE_HOOK(liquid_hook, getItemDescription).apply(enable);
INTERPOSE_HOOK(liquid_hook, adjustTemperature).apply(enable); INTERPOSE_HOOK(liquid_hook, adjustTemperature).apply(enable);
INTERPOSE_HOOK(liquid_hook, checkTemperatureDamage).apply(enable); INTERPOSE_HOOK(liquid_hook, checkTemperatureDamage).apply(enable);

@ -57,6 +57,7 @@
#include "df/activity_event_individual_skill_drillst.h" #include "df/activity_event_individual_skill_drillst.h"
#include "df/activity_event_skill_demonstrationst.h" #include "df/activity_event_skill_demonstrationst.h"
#include "df/activity_event_sparringst.h" #include "df/activity_event_sparringst.h"
#include "df/building_hivest.h"
#include <stdlib.h> #include <stdlib.h>
@ -136,6 +137,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector <Plugi
" to make them stand out more in the list.\n" " to make them stand out more in the list.\n"
" tweak military-training [disable]\n" " tweak military-training [disable]\n"
" Speed up melee squad training, removing inverse dependency on unit count.\n" " Speed up melee squad training, removing inverse dependency on unit count.\n"
" tweak hive-crash [disable]\n"
" Prevents crash if bees die in a hive with uncollected products (bug 6368).\n"
)); ));
return CR_OK; return CR_OK;
} }
@ -932,19 +935,60 @@ struct military_training_id_hook : df::activity_event_individual_skill_drillst {
IMPLEMENT_VMETHOD_INTERPOSE(military_training_id_hook, process); IMPLEMENT_VMETHOD_INTERPOSE(military_training_id_hook, process);
struct hive_crash_hook : df::building_hivest {
typedef df::building_hivest interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, updateAction, ())
{
bool any_bees = false;
for (size_t i = 0; i < contained_items.size(); i++)
{
if (contained_items[i]->item->getType() != item_type::VERMIN)
continue;
any_bees = true;
break;
}
if (!any_bees)
{
bool any_products = false;
for (size_t i = 0; i < contained_items.size(); i++)
{
if (contained_items[i]->use_mode != 0 ||
!contained_items[i]->item->flags.bits.in_building)
continue;
contained_items[i]->item->flags.bits.in_building = false;
any_products = true;
}
if (any_products)
{
color_ostream_proxy out(Core::getInstance().getConsole());
out.print("Bees died in hive with products at (%d,%d,%d); preventing crash.\n",
centerx, centery, z);
}
}
INTERPOSE_NEXT(updateAction)();
}
};
IMPLEMENT_VMETHOD_INTERPOSE(hive_crash_hook, updateAction);
static void enable_hook(color_ostream &out, VMethodInterposeLinkBase &hook, vector <string> &parameters) static void enable_hook(color_ostream &out, VMethodInterposeLinkBase &hook, vector <string> &parameters)
{ {
if (vector_get(parameters, 1) == "disable") if (vector_get(parameters, 1) == "disable")
{ {
hook.remove(); hook.remove();
out.print("Disabled tweak %s\n", parameters[0].c_str()); out.print("Disabled tweak %s (%s)\n", parameters[0].c_str(), hook.name());
} }
else else
{ {
if (hook.apply()) if (hook.apply())
out.print("Enabled tweak %s\n", parameters[0].c_str()); out.print("Enabled tweak %s (%s)\n", parameters[0].c_str(), hook.name());
else else
out.printerr("Could not activate tweak %s\n", parameters[0].c_str()); out.printerr("Could not activate tweak %s (%s)\n", parameters[0].c_str(), hook.name());
} }
} }
@ -1112,6 +1156,10 @@ static command_result tweak(color_ostream &out, vector <string> &parameters)
enable_hook(out, INTERPOSE_HOOK(military_training_sp_hook, process), parameters); enable_hook(out, INTERPOSE_HOOK(military_training_sp_hook, process), parameters);
enable_hook(out, INTERPOSE_HOOK(military_training_id_hook, process), parameters); enable_hook(out, INTERPOSE_HOOK(military_training_id_hook, process), parameters);
} }
else if (cmd == "hive-crash")
{
enable_hook(out, INTERPOSE_HOOK(hive_crash_hook, updateAction), parameters);
}
else else
return CR_WRONG_USAGE; return CR_WRONG_USAGE;

@ -427,7 +427,7 @@ public:
void clearSelection() void clearSelection()
{ {
for_each_(list, [] (ListEntry<T> &e) { e.selected = false; }); for_each_(list, clear_fn);
} }
void selectItem(const T elem) void selectItem(const T elem)
@ -550,8 +550,7 @@ public:
void sort() void sort()
{ {
if (force_sort || list.size() < 100) if (force_sort || list.size() < 100)
std::sort(list.begin(), list.end(), std::sort(list.begin(), list.end(), sort_fn);
[] (ListEntry<T> const& a, ListEntry<T> const& b) { return a.text.compare(b.text) < 0; });
filterDisplay(); filterDisplay();
} }
@ -569,6 +568,9 @@ public:
} }
private: private:
static void clear_fn(ListEntry<T> &e) { e.selected = false; }
static bool sort_fn(ListEntry<T> const& a, ListEntry<T> const& b) { return a.text.compare(b.text) < 0; }
vector<ListEntry<T>> list; vector<ListEntry<T>> list;
vector<ListEntry<T>*> display_list; vector<ListEntry<T>*> display_list;
string search_string; string search_string;

@ -402,7 +402,8 @@ public:
* GLOBAL VARIABLES * * GLOBAL VARIABLES *
******************************/ ******************************/
static bool enabled = false; DFHACK_PLUGIN_IS_ENABLED(enabled);
static PersistentDataItem config; static PersistentDataItem config;
static int last_tick_frame_count = 0; static int last_tick_frame_count = 0;
@ -1387,10 +1388,13 @@ static void update_data_structures(color_ostream &out)
* LUA API * * LUA API *
*************/ *************/
static bool isEnabled() { return enabled; } DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
static void setEnabled(color_ostream &out, bool enable)
{ {
if (!Core::getInstance().isWorldLoaded()) {
out.printerr("World is not loaded: please load a game first.\n");
return CR_FAILURE;
}
if (enable && !enabled) if (enable && !enabled)
{ {
enable_plugin(out); enable_plugin(out);
@ -1401,6 +1405,8 @@ static void setEnabled(color_ostream &out, bool enable)
setOptionEnabled(CF_ENABLED, false); setOptionEnabled(CF_ENABLED, false);
stop_protect(out); stop_protect(out);
} }
return CR_OK;
} }
static void push_count_history(lua_State *L, ItemConstraint *icv) static void push_count_history(lua_State *L, ItemConstraint *icv)
@ -1591,8 +1597,6 @@ static int getCountHistory(lua_State *L)
DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_PLUGIN_LUA_FUNCTIONS {
DFHACK_LUA_FUNCTION(isEnabled),
DFHACK_LUA_FUNCTION(setEnabled),
DFHACK_LUA_FUNCTION(deleteConstraint), DFHACK_LUA_FUNCTION(deleteConstraint),
DFHACK_LUA_END DFHACK_LUA_END
}; };
@ -1767,10 +1771,10 @@ static command_result workflow_cmd(color_ostream &out, vector <string> & paramet
{ {
bool enable = (cmd == "enable"); bool enable = (cmd == "enable");
if (enable) if (enable)
setEnabled(out, true); plugin_enable(out, true);
else if (parameters.size() == 1) else if (parameters.size() == 1)
{ {
setEnabled(out, false); plugin_enable(out, false);
out << "The plugin is disabled." << endl; out << "The plugin is disabled." << endl;
return CR_OK; return CR_OK;
@ -1805,7 +1809,10 @@ static command_result workflow_cmd(color_ostream &out, vector <string> & paramet
} }
if (!enabled) if (!enabled)
out << "Note: the plugin is not enabled." << endl; {
out.printerr("Error: the plugin is not enabled.\n");
return CR_WRONG_USAGE;
}
if (cmd == "jobs") if (cmd == "jobs")
{ {

@ -88,6 +88,10 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("zone"); DFHACK_PLUGIN("zone");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable);
const string zone_help = const string zone_help =
"Allows easier management of pens/pastures, pits and cages.\n" "Allows easier management of pens/pastures, pits and cages.\n"
"Options:\n" "Options:\n"
@ -3015,6 +3019,7 @@ command_result df_autobutcher(color_ostream &out, vector <string> & parameters)
} }
else if (p == "start") else if (p == "start")
{ {
plugin_enable(out, true);
enable_autobutcher = true; enable_autobutcher = true;
start_autobutcher(out); start_autobutcher(out);
return autoButcher(out, verbose); return autoButcher(out, verbose);
@ -3485,6 +3490,7 @@ command_result autoButcher( color_ostream &out, bool verbose = false )
command_result start_autobutcher(color_ostream &out) command_result start_autobutcher(color_ostream &out)
{ {
plugin_enable(out, true);
enable_autobutcher = true; enable_autobutcher = true;
if (!config_autobutcher.isValid()) if (!config_autobutcher.isValid())
@ -3545,6 +3551,7 @@ command_result init_autobutcher(color_ostream &out)
if(!enable_autobutcher) if(!enable_autobutcher)
return CR_OK; return CR_OK;
plugin_enable(out, true);
// read watchlist from save // read watchlist from save
std::vector<PersistentDataItem> items; std::vector<PersistentDataItem> items;
@ -3579,6 +3586,7 @@ command_result cleanup_autobutcher(color_ostream &out)
command_result start_autonestbox(color_ostream &out) command_result start_autonestbox(color_ostream &out)
{ {
plugin_enable(out, true);
enable_autonestbox = true; enable_autonestbox = true;
if (!config_autonestbox.isValid()) if (!config_autonestbox.isValid())
@ -3620,6 +3628,8 @@ command_result init_autonestbox(color_ostream &out)
sleep_autonestbox = config_autonestbox.ival(1); sleep_autonestbox = config_autonestbox.ival(1);
} }
} }
if (enable_autonestbox)
plugin_enable(out, true);
return CR_OK; return CR_OK;
} }
@ -3856,6 +3866,9 @@ static void autobutcher_setEnabled(color_ostream &out, bool enable)
config_autobutcher.ival(0) = enable_autobutcher; config_autobutcher.ival(0) = enable_autobutcher;
out << "Autobutcher stopped." << endl; out << "Autobutcher stopped." << endl;
} }
if (enable)
plugin_enable(out, true);
} }
static void autowatch_setEnabled(color_ostream &out, bool enable) static void autowatch_setEnabled(color_ostream &out, bool enable)
@ -4455,12 +4468,25 @@ IMPLEMENT_VMETHOD_INTERPOSE(zone_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(zone_hook, render); IMPLEMENT_VMETHOD_INTERPOSE(zone_hook, render);
//END zone filters //END zone filters
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable)
{
if (!gps)
return CR_FAILURE;
if (enable != is_enabled)
{
if (!INTERPOSE_HOOK(zone_hook, feed).apply(enable) ||
!INTERPOSE_HOOK(zone_hook, render).apply(enable))
return CR_FAILURE;
is_enabled = enable;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
if (!gps || !INTERPOSE_HOOK(zone_hook, feed).apply() || !INTERPOSE_HOOK(zone_hook, render).apply())
out.printerr("Could not insert jobutils hooks!\n");
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"zone", "manage activity zones.", "zone", "manage activity zones.",
df_zone, false, df_zone, false,

@ -0,0 +1,345 @@
-- Exports an ini file for Dwarf Therapist.
local utils = require 'utils'
local ms = require 'memscan'
-- Utility functions
local globals = df.global
local global_addr = dfhack.internal.getAddress
local os_type = dfhack.getOSType()
local rdelta = dfhack.internal.getRebaseDelta()
local vbias = 0
if os_type == 'windows' then vbias = -4 end
local lines = {}
local complete = true
local function header(name)
table.insert(lines, '')
table.insert(lines, '['..name..']')
end
local function value(name,addr)
local line
if not addr then
complete = false
line = name..'=0x0'
elseif addr < 0x10000 then
line = string.format('%s=0x%04x',name,addr)
else
line = string.format('%s=0x%08x',name,addr)
end
table.insert(lines, line)
end
local function address(name,bias,base,field,...)
local addr
if base == globals then
addr = global_addr(field)
bias = bias - rdelta
if addr and select('#',...) > 0 then
_,addr = df.sizeof(ms.field_ref(base,field,...))
end
elseif base._kind == 'class-type' then
-- field_offset crashes with classes due to vtable problems,
-- so we have to create a real temporary object here.
local obj = df.new(base)
if obj then
local _,a1 = df.sizeof(obj)
local _,a2 = df.sizeof(ms.field_ref(obj,field,...))
addr = a2-a1
obj:delete()
end
else
addr = ms.field_offset(base,field,...)
end
if addr then
addr = addr + bias
end
value(name, addr)
end
local function offset(name,base,...)
address(name,0,base,...)
end
local function vector(name,base,...)
address(name,vbias,base,...)
end
-- List of actual values
header('addresses')
vector('translation_vector',globals,'world','raws','language','translations')
vector('language_vector',globals,'world','raws','language','words')
vector('creature_vector',globals,'world','units','all')
vector('active_creature_vector',globals,'world','units','active')
offset('dwarf_race_index',globals,'ui','race_id')
vector('squad_vector',globals,'world','squads','all')
offset('current_year',globals,'cur_year')
offset('cur_year_tick',globals,'cur_year_tick')
offset('dwarf_civ_index',globals,'ui','civ_id')
vector('races_vector',globals,'world','raws','creatures','all')
vector('reactions_vector',globals,'world','raws','reactions')
vector('historical_figures',globals,'world','history','figures')
vector('fake_identities',globals,'world','assumed_identities','all')
vector('historical_figures_vector',globals,'world','history','figures')
vector('fake_identities_vector',globals,'world','assumed_identities','all')
offset('fortress_entity',globals,'ui','main','fortress_entity')
vector('historical_entities_vector',globals,'world','entities','all')
vector('weapons_vector',globals,'world','raws','itemdefs','weapons')
vector('trap_vector',globals,'world','raws','itemdefs','trapcomps')
vector('toy_vector',globals,'world','raws','itemdefs','toys')
vector('tool_vector',globals,'world','raws','itemdefs','tools')
vector('instrument_vector',globals,'world','raws','itemdefs','instruments')
vector('armor_vector',globals,'world','raws','itemdefs','armor')
vector('ammo_vector',globals,'world','raws','itemdefs','ammo')
vector('siegeammo_vector',globals,'world','raws','itemdefs','siege_ammo')
vector('glove_vector',globals,'world','raws','itemdefs','gloves')
vector('shoe_vector',globals,'world','raws','itemdefs','shoes')
vector('shield_vector',globals,'world','raws','itemdefs','shields')
vector('helm_vector',globals,'world','raws','itemdefs','helms')
vector('pant_vector',globals,'world','raws','itemdefs','pants')
vector('food_vector',globals,'world','raws','itemdefs','food')
vector('colors_vector',globals,'world','raws','language','colors')
vector('shapes_vector',globals,'world','raws','language','shapes')
offset('base_materials',globals,'world','raws','mat_table','builtin')
vector('inorganics_vector',globals,'world','raws','inorganics')
vector('plants_vector',globals,'world','raws','plants','all')
vector('material_templates_vector',globals,'world','raws','material_templates')
offset('world_data',globals,'world','world_data')
vector('active_sites_vector',df.world_data,'active_site')
offset('world_site_type',df.world_site,'type')
header('offsets')
offset('word_table',df.language_translation,'words')
value('string_buffer_offset', 0x0000)
header('word_offsets')
offset('base',df.language_word,'word')
offset('noun_singular',df.language_word,'forms','Noun')
offset('noun_plural',df.language_word,'forms','NounPlural')
offset('adjective',df.language_word,'forms','Adjective')
offset('verb',df.language_word,'forms','Verb')
offset('present_simple_verb',df.language_word,'forms','Verb3rdPerson')
offset('past_simple_verb',df.language_word,'forms','VerbPast')
offset('past_participle_verb',df.language_word,'forms','VerbPassive')
offset('present_participle_verb',df.language_word,'forms','VerbGerund')
offset('words',df.language_name,'words')
offset('word_type',df.language_name,'parts_of_speech')
offset('language_id',df.language_name,'language')
header('race_offsets')
offset('name_singular',df.creature_raw,'name',0)
offset('name_plural',df.creature_raw,'name',1)
offset('adjective',df.creature_raw,'name',2)
offset('baby_name_singular',df.creature_raw,'general_baby_name',0)
offset('baby_name_plural',df.creature_raw,'general_baby_name',1)
offset('child_name_singular',df.creature_raw,'general_child_name',0)
offset('child_name_plural',df.creature_raw,'general_child_name',1)
vector('pref_string_vector',df.creature_raw,'prefstring')
vector('castes_vector',df.creature_raw,'caste')
vector('pop_ratio_vector',df.creature_raw,'pop_ratio')
vector('materials_vector',df.creature_raw,'material')
offset('flags',df.creature_raw,'flags')
header('caste_offsets')
offset('caste_name',df.caste_raw,'caste_name')
offset('caste_descr',df.caste_raw,'description')
offset('caste_phys_att_ranges',df.caste_raw,'attributes','phys_att_range')
offset('caste_ment_att_ranges',df.caste_raw,'attributes','ment_att_range')
offset('adult_size',df.caste_raw,'misc','adult_size')
offset('flags',df.caste_raw,'flags')
vector('extracts',df.caste_raw,'extracts','extract_matidx')
offset('skill_rates',df.caste_raw,'skill_rates')
offset('caste_att_rates',df.caste_raw,'attributes','phys_att_rates')
offset('caste_att_caps',df.caste_raw,'attributes','phys_att_cap_perc')
header('hist_entity_offsets')
vector('squads',df.historical_entity,'squads')
vector('positions',df.historical_entity,'positions','own')
vector('assignments',df.historical_entity,'positions','assignments')
offset('assign_hist_id',df.entity_position_assignment,'histfig')
offset('assign_position_id',df.entity_position_assignment,'position_id')
offset('position_id',df.entity_position,'id')
offset('position_name',df.entity_position,'name')
offset('position_female_name',df.entity_position,'name_female')
offset('position_male_name',df.entity_position,'name_male')
header('hist_figure_offsets')
offset('hist_race',df.historical_figure,'race')
offset('hist_name',df.historical_figure,'name')
offset('id',df.historical_figure,'id')
offset('hist_fig_info',df.historical_figure,'info')
offset('reputation',df.historical_figure_info,'reputation')
offset('current_ident',df.historical_figure_info.T_reputation,'cur_identity')
offset('fake_name',df.assumed_identity,'name')
offset('fake_birth_year',df.assumed_identity,'birth_year')
offset('fake_birth_time',df.assumed_identity,'birth_second')
header('weapon_offsets')
offset('name_plural',df.itemdef_weaponst,'name_plural')
offset('single_size',df.itemdef_weaponst,'two_handed')
offset('multi_size',df.itemdef_weaponst,'minimum_size')
offset('ammo',df.itemdef_weaponst,'ranged_ammo')
header('material_offsets')
offset('solid_name',df.material_common,'state_name','Solid')
offset('liquid_name',df.material_common,'state_name','Liquid')
offset('gas_name',df.material_common,'state_name','Gas')
offset('powder_name',df.material_common,'state_name','Powder')
offset('paste_name',df.material_common,'state_name','Paste')
offset('pressed_name',df.material_common,'state_name','Pressed')
offset('inorganic_materials_vector',df.inorganic_raw,'material')
offset('flags',df.material_common,'flags')
header('plant_offsets')
offset('name',df.plant_raw,'name')
offset('name_plural',df.plant_raw,'name_plural')
offset('name_leaf_plural',df.plant_raw,'leaves_plural')
offset('name_seed_plural',df.plant_raw,'seed_plural')
vector('materials_vector',df.plant_raw,'material')
offset('flags',df.plant_raw,'flags')
header('item_offsets')
offset('name_plural',df.itemdef_armorst,'name_plural')
offset('adjective',df.itemdef_armorst,'name_preplural')
offset('mat_name',df.itemdef_armorst,'material_placeholder')
header('descriptor_offsets')
offset('color_name',df.descriptor_color,'name')
offset('shape_name_plural',df.descriptor_shape,'name_plural')
header('dwarf_offsets')
offset('first_name',df.unit,'name','first_name')
offset('nick_name',df.unit,'name','nickname')
offset('last_name',df.unit,'name','words')
offset('custom_profession',df.unit,'custom_profession')
offset('profession',df.unit,'profession')
offset('race',df.unit,'race')
offset('flags1',df.unit,'flags1')
offset('flags2',df.unit,'flags2')
offset('flags3',df.unit,'flags3')
offset('caste',df.unit,'caste')
offset('sex',df.unit,'sex')
offset('id',df.unit,'id')
offset('animal_type',df.unit,'training_level')
offset('civ',df.unit,'civ_id')
vector('specific_refs',df.unit,'specific_refs')
offset('squad_id',df.unit,'military','squad_id')
offset('squad_position',df.unit,'military','squad_position')
offset('recheck_equipment',df.unit,'military','pickup_flags')
offset('mood',df.unit,'mood')
offset('birth_year',df.unit,'relations','birth_year')
offset('birth_time',df.unit,'relations','birth_time')
offset('current_job',df.unit,'job','current_job')
offset('physical_attrs',df.unit,'body','physical_attrs')
vector('body_size',df.unit,'appearance','body_modifiers')
offset('curse',df.unit,'curse','name')
offset('curse_add_flags1',df.unit,'curse','add_tags1')
offset('turn_count',df.unit,'curse','time_on_site')
vector('souls',df.unit,'status','souls')
vector('states',df.unit,'status','misc_traits')
offset('labors',df.unit,'status','labors')
offset('happiness',df.unit,'status','happiness')
vector('thoughts',df.unit,'status','recent_events')
offset('squad_ref_id',df.unit,'hist_figure_id')
offset('hist_id',df.unit,'hist_figure_id')
offset('artifact_name',df.unit,'status','artifact_name')
header('soul_details')
offset('name',df.unit_soul,'name')
offset('mental_attrs',df.unit_soul,'mental_attrs')
vector('skills',df.unit_soul,'skills')
offset('traits',df.unit_soul,'traits')
vector('preferences',df.unit_soul,'preferences')
header('job_details')
offset('id',df.job,'job_type')
value('on_break_flag',df.misc_trait_type.OnBreak)
offset('sub_job_id',df.job,'reaction_name')
offset('reaction',df.reaction,'name')
offset('reaction_skill',df.reaction,'skill')
offset('mat_type',df.job,'mat_type')
offset('mat_index',df.job,'mat_index')
offset('mat_category',df.job,'material_category')
header('squad_offsets')
offset('id',df.squad,'id')
offset('name',df.squad,'name')
offset('name_old',df.squad,'name','words')
offset('alias',df.squad,'alias')
vector('members',df.squad,'positions')
-- Final creation of the file
local out = io.open('therapist.ini', 'w')
out:write('[info]\n')
-- TODO: add an api function to retrieve the checksum
out:write('checksum=<<fillme>>\n')
out:write('version_name='..dfhack.getDFVersion()..'\n')
out:write('complete='..(complete and 'true' or 'false')..'\n')
for i,v in ipairs(lines) do
out:write(v..'\n')
end
out:write[[
[valid_flags_1]
size=1
1\name=Not from around these parts
1\value=0x80000000
[valid_flags_2]
size=0
[invalid_flags_1]
size=10
1\name=a zombie
1\value=0x00001000
2\name=a skeleton
2\value=0x00002000
3\name=a merchant or diplomat
3\value=0x00000040
4\name=outpost liason
4\value=0x00000800
5\name=an invader or hostile
5\value=0x00020000
6\name=an invader or hostile
6\value=0x00080000
7\name=an invader or hostile
7\value=0x000C0000
8\name=a merchant escort
8\value=0x00000080
9\name="Dead, Jim."
9\value=0x00000002
10\name=marauder
10\value=0x00000010
[invalid_flags_2]
size=5
1\name="killed, Jim."
1\value=0x00000080
2\name=from the Underworld. SPOOKY!
2\value=0x00040000
3\name=resident
3\value=0x00080000
4\name=visitor_uninvited
4\value=0x00400000
5\name=visitor
5\value=0x00800000
[invalid_flags_3]
size=1
1\name=a ghost
1\value=0x00001000
]]
out:close()

@ -1306,6 +1306,27 @@ local function find_cur_year_tick()
ms.found_offset('cur_year_tick', addr) ms.found_offset('cur_year_tick', addr)
end end
local function find_cur_year_tick_advmode()
stop_autosave()
local feed = dwarfmode_to_top()
local addr = searcher:find_interactive(
'Searching for cur_year_tick_advmode.',
'int32_t',
function(idx)
if idx > 0 then
if not step_n_frames(1, feed) then
return false
end
end
return true, nil, 144
end,
20
)
ms.found_offset('cur_year_tick_advmode', addr)
end
-- --
-- cur_season_tick -- cur_season_tick
-- --
@ -1329,7 +1350,7 @@ menu, then do as instructed below:]],
return false return false
end end
end end
return true, math.floor(((df.global.cur_year_tick+10)%100800)/10) return true, math.floor((df.global.cur_year_tick%100800)/10)
end end
) )
ms.found_offset('cur_season_tick', addr) ms.found_offset('cur_season_tick', addr)
@ -1361,7 +1382,7 @@ menu, then do as instructed below:]],
return false return false
end end
end end
return true, math.floor((df.global.cur_year_tick+10)/100800)%4 return true, math.floor(df.global.cur_year_tick/100800)%4
end end
) )
ms.found_offset('cur_season', addr) ms.found_offset('cur_season', addr)
@ -1499,6 +1520,7 @@ print('\nUnpausing globals:\n')
exec_finder(find_cur_year, 'cur_year') exec_finder(find_cur_year, 'cur_year')
exec_finder(find_cur_year_tick, 'cur_year_tick') exec_finder(find_cur_year_tick, 'cur_year_tick')
exec_finder(find_cur_year_tick_advmode, 'cur_year_tick_advmode')
exec_finder(find_cur_season_tick, 'cur_season_tick') exec_finder(find_cur_season_tick, 'cur_season_tick')
exec_finder(find_cur_season, 'cur_season') exec_finder(find_cur_season, 'cur_season')
exec_finder(find_process_jobs, 'process_jobs') exec_finder(find_process_jobs, 'process_jobs')

@ -5,6 +5,11 @@
-- This allows just adding stub definitions, and simply saving and -- This allows just adding stub definitions, and simply saving and
-- reloading the game. -- reloading the game.
-- Usage example:
--[[
devel/inject-raws trapcomp ITEM_TRAPCOMP_STEAM_PISTON workshop STEAM_ENGINE MAGMA_STEAM_ENGINE reaction STOKE_BOILER
]]
local utils = require 'utils' local utils = require 'utils'
local raws = df.global.world.raws local raws = df.global.world.raws

@ -0,0 +1,132 @@
-- Generates an image using multiple octaves of perlin noise.
local args = {...}
local rng = dfhack.random.new(3)
if #args < 3 then
qerror('Usage: devel/test-perlin <fname.pgm> <density> <coeff|expr...x[...y[...z]]>...')
end
local fname = table.remove(args,1)
local goal = tonumber(table.remove(args,1)) or qerror('Invalid density')
local zscale = 6
local coeffs = {}
local fns = {}
local env = copyall(math)
env.apow = function(x,y) return math.pow(math.abs(x),y) end
for i = 1,#args do
local fn = rng:perlin(3);
local fn2 = rng:perlin(3);
local fn3 = rng:perlin(3);
local fn4 = rng:perlin(3);
fns[i] = fn;
local val = string.match(args[i],'^([+-]?[%d.]+)$')
if val then
coeffs[i] = function(x) return x * val end
else
local argstr = 'x'
if string.match(args[i], '%f[%w]w%f[^%w]') then
argstr = 'x,y,z,w'
fns[i] = function(x,y,z)
return fn(x,y,z), fn2(x,y,z), fn3(x+0.5,y+0.5,z+0.5), fn4(x+0.5,y+0.5,z+0.5)
end
elseif string.match(args[i], '%f[%w]z%f[^%w]') then
argstr = 'x,y,z'
fns[i] = function(x,y,z)
return fn(x,y,z), fn2(x,y,z), fn3(x+0.5,y+0.5,z+0.5)
end
elseif string.match(args[i], '%f[%w]y%f[^%w]') then
argstr = 'x,y'
fns[i] = function(x,y,z)
return fn(x,y,z), fn2(x,y,z)
end
end
local f,err = load(
'return function('..argstr..') return ('..args[i]..') end',
'=(expr)', 't', env
)
if not f then
qerror(err)
end
coeffs[i] = f()
end
end
function render(thresh,file)
local area = 0
local line, arr = '', {}
for zy = 0,1 do
for y = 0,48*4-1 do
line = ''
for zx = 0,1 do
for x = 0,48*4-1 do
local tx = (0.5+x)/(48*2)
local ty = (0.5+y)/(48*2)
local tz = 0.5+(zx+zy*2)/(48*2/zscale)
local v1 = 0
for i = 1,#coeffs do
v1 = v1 + coeffs[i](fns[i](tx,ty,tz))
tx = tx*2
ty = ty*2
tz = tz*2
end
local v = -1
if v1 > thresh then
v = v1;
area = area + 1
end
if file then
local c = math.max(0, math.min(255, v * 127 + 128))
arr[2*x+1] = c
arr[2*x+2] = c
end
end
if file then
line = line..string.char(table.unpack(arr))
end
end
if file then
file:write(line,line)
end
end
end
return area/4/(48*4)/(48*4)
end
function search(fn,min,max,goal,eps)
while true do
local center = (max+min)/2
local cval = fn(center)
print('At '..center..': '..cval)
if math.abs(cval-goal) < eps then
return center
end
if cval > goal then
min = center
else
max = center
end
end
end
local thresh = search(render, -1, 1, goal, 0.001)
local file,err = io.open(fname, 'wb')
if not file then
print('error: ',err)
return
end
file:write('P5\n768 768\n255\n')
local area = render(thresh, file)
file:close()
print('Area fraction: '..area)

@ -8,7 +8,7 @@ if cmd=="--file" or cmd=="-f" then
if f==nil then if f==nil then
qerror(err) qerror(err)
end end
dfhack.pcall(f,table.unpack(args,3)) dfhack.safecall(f,table.unpack(args,3))
elseif cmd=="--save" or cmd=="-s" then elseif cmd=="--save" or cmd=="-s" then
if df.global.world.cur_savegame.save_dir=="" then if df.global.world.cur_savegame.save_dir=="" then
qerror("Savefile not loaded") qerror("Savefile not loaded")
@ -19,7 +19,7 @@ elseif cmd=="--save" or cmd=="-s" then
if f==nil then if f==nil then
qerror(err) qerror(err)
end end
dfhack.pcall(f,table.unpack(args,3)) dfhack.safecall(f,table.unpack(args,3))
elseif cmd~=nil then elseif cmd~=nil then
-- Support some of the prefixes allowed by dfhack.interpreter -- Support some of the prefixes allowed by dfhack.interpreter
local prefix local prefix

@ -0,0 +1,9 @@
# patch start dwarf count
nr = $script_args[0].to_i
raise 'too low' if nr < 7
addr = df.get_global_address('start_dwarf_count')
df.memory_patch(addr, [nr].pack('L'))