develop
Timothy Collett 2013-03-14 13:35:28 -04:00
commit c93cb693c8
17 changed files with 940 additions and 342 deletions

@ -59,7 +59,7 @@ endif()
# set up versioning.
set(DF_VERSION "0.34.11")
SET(DFHACK_RELEASE "r2" CACHE STRING "Current release revision.")
SET(DFHACK_RELEASE "r3" CACHE STRING "Current release revision.")
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}")

@ -402,10 +402,16 @@ ul.auto-toc {
<li><a class="reference internal" href="#plugins" id="id52">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id53">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id54">sort</a></li>
<li><a class="reference internal" href="#eventful" id="id55">Eventful</a><ul>
<li><a class="reference internal" href="#list-of-events" id="id56">List of events</a></li>
<li><a class="reference internal" href="#functions" id="id57">Functions</a></li>
<li><a class="reference internal" href="#examples" id="id58">Examples</a></li>
</ul>
</li>
<li><a class="reference internal" href="#scripts" id="id55">Scripts</a><ul>
<li><a class="reference internal" href="#save-init-script" id="id56">Save init script</a></li>
</ul>
</li>
<li><a class="reference internal" href="#scripts" id="id59">Scripts</a><ul>
<li><a class="reference internal" href="#save-init-script" id="id60">Save init script</a></li>
</ul>
</li>
</ul>
@ -3038,9 +3044,93 @@ set is the same as used by the command line.</p>
<p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p>
</div>
<div class="section" id="eventful">
<h2><a class="toc-backref" href="#id55">Eventful</a></h2>
<p>This plugin exports some events to lua thus allowing to run lua functions
on DF world events.</p>
<div class="section" id="list-of-events">
<h3><a class="toc-backref" href="#id56">List of events</a></h3>
<ol class="arabic">
<li><p class="first"><tt class="docutils literal">onReactionComplete(reaction,unit,input_items,input_reagents,output_items,call_native)</tt></p>
<p>Auto activates if detects reactions starting with <tt class="docutils literal">LUA_HOOK_</tt>. Is called when reaction finishes.</p>
</li>
<li><p class="first"><tt class="docutils literal">onItemContaminateWound(item,unit,wound,number1,number2)</tt></p>
<p>Is called when item tries to contaminate wound (e.g. stuck in).</p>
</li>
<li><p class="first"><tt class="docutils literal">onProjItemCheckMovement(projectile)</tt></p>
<p>Is called when projectile moves.</p>
</li>
<li><p class="first"><tt class="docutils literal">onProjItemCheckImpact(projectile,somebool)</tt></p>
<p>Is called when projectile hits something.</p>
</li>
<li><p class="first"><tt class="docutils literal">onProjUnitCheckMovement(projectile)</tt></p>
<p>Is called when projectile moves.</p>
</li>
<li><p class="first"><tt class="docutils literal">onProjUnitCheckImpact(projectile,somebool)</tt></p>
<p>Is called when projectile hits something.</p>
</li>
<li><p class="first"><tt class="docutils literal">onWorkshopFillSidebarMenu(workshop,callnative)</tt></p>
<p>Is called when viewing a workshop in 'q' mode, to populate reactions, useful for custom viewscreens for shops.</p>
</li>
<li><p class="first"><tt class="docutils literal">postWorkshopFillSidebarMenu(workshop)</tt></p>
<p>Is called after calling (or not) native fillSidebarMenu(). Useful for job button
tweaking (e.g. adding custom reactions)</p>
</li>
</ol>
</div>
<div class="section" id="functions">
<h3><a class="toc-backref" href="#id57">Functions</a></h3>
<ol class="arabic">
<li><p class="first"><tt class="docutils literal">registerReaction(reaction_name,callback)</tt></p>
<p>Simplified way of using onReactionComplete; the callback is function (same params as event).</p>
</li>
<li><p class="first"><tt class="docutils literal">removeNative(shop_name)</tt></p>
<p>Removes native choice list from the building.</p>
</li>
<li><p class="first"><tt class="docutils literal">addReactionToShop(reaction_name,shop_name)</tt></p>
<p>Add a custom reaction to the building.</p>
</li>
</ol>
</div>
<div class="section" id="examples">
<h3><a class="toc-backref" href="#id58">Examples</a></h3>
<p>Spawn dragon breath on each item attempt to contaminate wound:</p>
<pre class="literal-block">
b=require &quot;plugins.eventful&quot;
b.onItemContaminateWound.one=function(item,unit,un_wound,x,y)
local flw=dfhack.maps.spawnFlow(unit.pos,6,0,0,50000)
end
</pre>
<p>Reaction complete example:</p>
<pre class="literal-block">
b=require &quot;plugins.eventful&quot;
b.onReactionComplete.one=function(reaction,unit,in_items,in_reag,out_items,call_native)
local pos=copyall(unit.pos)
-- spawn dragonbreath after 100 ticks
dfhack.timeout(100,&quot;ticks&quot;,function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end)
--do not call real item creation code
call_native.value=false
end
</pre>
<p>Grenade example:</p>
<pre class="literal-block">
b=require &quot;plugins.eventful&quot;
b.onProjItemCheckImpact.one=function(projectile)
-- you can check if projectile.item e.g. has correct material
dfhack.maps.spawnFlow(projectile.cur_pos,6,0,0,50000)
end
</pre>
<p>Integrated tannery:</p>
<pre class="literal-block">
b=require &quot;plugins.eventful&quot;
b.addReactionToShop(&quot;TAN_A_HIDE&quot;,&quot;LEATHERWORKS&quot;)
</pre>
</div>
</div>
</div>
<div class="section" id="scripts">
<h1><a class="toc-backref" href="#id55">Scripts</a></h1>
<h1><a class="toc-backref" href="#id59">Scripts</a></h1>
<p>Any files with the .lua extension placed into hack/scripts/*
are automatically used by the DFHack core as commands. The
matching command name consists of the name of the file sans
@ -3071,7 +3161,7 @@ The <tt class="docutils literal">name</tt> argument should be the name stem, as
</ul>
<p>Note that this function lets errors propagate to the caller.</p>
<div class="section" id="save-init-script">
<h2><a class="toc-backref" href="#id56">Save init script</a></h2>
<h2><a class="toc-backref" href="#id60">Save init script</a></h2>
<p>If a save directory contains a file called <tt class="docutils literal">raw/init.lua</tt>, it is
automatically loaded and executed every time the save is loaded. It
can also define the following functions to be called by dfhack:</p>

@ -2967,51 +2967,85 @@ on DF world events.
List of events
--------------
1. onReactionComplete(reaction,unit,input_items,input_reagents,output_items,call_native) - auto activates if detects reactions starting with ``LUA_HOOK_``. Is called when reaction finishes.
2. onItemContaminateWound(item,unit,wound,number1,number2) - Is called when item tries to contaminate wound (e.g. stuck in)
3. onProjItemCheckMovement(projectile) - is called when projectile moves
4. onProjItemCheckImpact(projectile,somebool) - is called when projectile hits something
5. onProjUnitCheckMovement(projectile) - is called when projectile moves
6. onProjUnitCheckImpact(projectile,somebool) - is called when projectile hits something
7. onWorkshopFillSidebarMenu(workshop,callnative) - is called when viewing a workshop in 'q' mode, to populate reactions, usefull for custom viewscreens for shops
8. postWorkshopFillSidebarMenu(workshop) - is called after calling (or not) native fillSidebarMenu(). Usefull for job button tweaking (e.g. adding custom reactions)
1. ``onReactionComplete(reaction,unit,input_items,input_reagents,output_items,call_native)``
Auto activates if detects reactions starting with ``LUA_HOOK_``. Is called when reaction finishes.
2. ``onItemContaminateWound(item,unit,wound,number1,number2)``
Is called when item tries to contaminate wound (e.g. stuck in).
3. ``onProjItemCheckMovement(projectile)``
Is called when projectile moves.
4. ``onProjItemCheckImpact(projectile,somebool)``
Is called when projectile hits something.
5. ``onProjUnitCheckMovement(projectile)``
Is called when projectile moves.
6. ``onProjUnitCheckImpact(projectile,somebool)``
Is called when projectile hits something.
7. ``onWorkshopFillSidebarMenu(workshop,callnative)``
Is called when viewing a workshop in 'q' mode, to populate reactions, useful for custom viewscreens for shops.
8. ``postWorkshopFillSidebarMenu(workshop)``
Is called after calling (or not) native fillSidebarMenu(). Useful for job button
tweaking (e.g. adding custom reactions)
Functions
---------
1. registerReaction(reaction_name,callback) - simplified way of using onReactionComplete, the callback is function (same params as event)
2. removeNative(shop_name) - removes native choice list from the building
3. addReactionToShop(reaction_name,shop_name) - add a custom reaction to the building
1. ``registerReaction(reaction_name,callback)``
Simplified way of using onReactionComplete; the callback is function (same params as event).
2. ``removeNative(shop_name)``
Removes native choice list from the building.
3. ``addReactionToShop(reaction_name,shop_name)``
Add a custom reaction to the building.
Examples
--------
Spawn dragon breath on each item attempt to contaminate wound:
::
Spawn dragon breath on each item attempt to contaminate wound::
b=require "plugins.eventful"
b=require "plugins.eventful"
b.onItemContaminateWound.one=function(item,unit,un_wound,x,y)
local flw=dfhack.maps.spawnFlow(unit.pos,6,0,0,50000)
end
Reaction complete example:
::
Reaction complete example::
b=require "plugins.eventful"
b.onReactionComplete.one=function(reaction,unit,in_items,in_reag,out_items,call_native)
local pos=copyall(unit.pos)
dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) -- spawn dragonbreath after 100 ticks
call_native.value=false --do not call real item creation code
-- spawn dragonbreath after 100 ticks
dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end)
--do not call real item creation code
call_native.value=false
end
Granade example:
::
Grenade example::
b=require "plugins.eventful"
b.onProjItemCheckImpact.one=function(projectile)
-- you can check if projectile.item e.g. has correct material
dfhack.maps.spawnFlow(projectile.cur_pos,6,0,0,50000)
end
Integrated tannery:
::
Integrated tannery::
b=require "plugins.eventful"
b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS")

@ -1,10 +1,15 @@
DFHack future
Is not yet known.
DFHack v0.34.11-r3
Internals:
- support for displaying active keybindings properly.
- support for reusable widgets in lua screen library.
- Maps::canStepBetween: returns whether you can walk between two tiles in one step.
- EventManager: monitors various in game events centrally so that individual plugins don't have to monitor the same things redundantly.
- EventManager: monitors various in game events centrally so that individual plugins
don't have to monitor the same things redundantly.
Notable bugfixes:
- autobutcher can be re-enabled again after being stopped.
- stopped Dwarf Manipulator from unmasking vampires.
@ -28,6 +33,7 @@ DFHack future
- stripcaged: mark items inside cages for dumping, eg caged goblin weapons.
- soundsense-season: writes the correct season to gamelog.txt on world load.
- create-items: spawn items
- fix/cloth-stockpile: fixes bug 5739; needs to be run after savegame load every time.
New GUI scripts:
- gui/guide-path: displays the cached path for minecart Guide orders.
- gui/workshop-job: displays inputs of a workshop job and allows tweaking them.

File diff suppressed because it is too large Load Diff

@ -449,6 +449,26 @@ Options:
:bees: turn colonies into honey bee colonies
createitem
----------
Allows creating new items of arbitrary types and made of arbitrary materials.
Any items created are spawned at the feet of the selected unit.
Specify the item and material information as you would indicate them in custom reaction raws, with the following differences:
* Separate the item and material with a space rather than a colon
* If the item has no subtype, omit the :NONE
* If the item is REMAINS, FISH, FISH_RAW, VERMIN, PET, or EGG, specify a CREATURE:CASTE pair instead of a material token.
Corpses, body parts, and prepared meals cannot be created using this tool.
Examples:
``createitem GLOVES:ITEM_GLOVES_GAUNTLETS INORGANIC:STEEL 2``
Create 2 pairs of steel gauntlets.
``createitem WOOD PLANT_MAT:TOWER_CAP:WOOD``
Create tower-cap logs.
``createitem FISH FISH_SHAD:MALE 5``
Create a stack of 5 cleaned shad, ready to eat.
deramp (by zilpin)
------------------
Removes all ramps designated for removal from the map. This is useful for replicating the old channel digging designation.
@ -1773,6 +1793,12 @@ Scripts in this subdirectory fix various bugs and issues, some of them obscure.
Diagnoses and fixes issues with nonexistant 'items occupying site', usually
caused by autodump bugs or other hacking mishaps.
* fix/cloth-stockpile
Fixes erratic behavior of cloth stockpiles by scanning material objects
in memory and patching up some invalid reference fields. Needs to be run
every time a save game is loaded; putting ``fix/cloth-stockpile enable``
in ``dfhack.init`` makes it run automatically.
gui/*
=====
@ -2032,6 +2058,17 @@ Exemples::
create-items bar CREATURE:CAT:SOAP
create-items bar adamantine
soundsense-season
=================
It is a well known issue that Soundsense cannot detect the correct
current season when a savegame is loaded and has to play random
season music until a season switch occurs.
This script registers a hook that prints the appropriate string
to gamelog.txt on every map load to fix this. For best results
call the script from ``dfhack.init``.
=======================
In-game interface tools
=======================
@ -2185,8 +2222,25 @@ To use, bind to a key (the example config uses Alt-L) and activate in the 'k' mo
.. image:: images/liquids.png
While active, use the suggested keys to switch the usual liquids parameters, and Enter
to select the target area and apply changes.
This script is a gui front-end to the liquids plugin and works similar to it,
allowing you to add or remove water & magma, and create obsidian walls & floors.
Note that there is **no undo support**, and that bugs in this plugin have been
known to create pathfinding problems and heat traps.
The ``b`` key changes how the affected area is selected. The default *Rectangle*
mode works by selecting two corners like any ordinary designation. The ``p``
key chooses between adding water, magma, obsidian walls & floors, or just
tweaking flags.
When painting liquids, it is possible to select the desired level with ``+-``,
and choose between setting it exactly, only increasing or only decreasing
with ``s``.
In addition, ``f`` allows disabling or enabling the flowing water computations
for an area, and ``r`` operates on the "permanent flow" property that makes
rivers power water wheels even when full and technically not flowing.
After setting up the desired operations using the described keys, use ``Enter`` to apply them.
gui/mechanisms
@ -2430,6 +2484,21 @@ keybinding. (e.g. keybinding set Ctrl-T gui/advfort). Possible arguments:
* job - selects that job (e.g. Dig or FellTree)
gui/companion-order
=======================
A script to issue orders for companions. Select companions with lower case chars, issue orders with upper
case. Must be in look or talk mode to issue command on tile.
* move - orders selected companions to move to location. If companions are following they will move no more than 3 tiles from you.
* equip - try to equip items on the ground.
* pick-up - try to take items into hand (also wield)
* unequip - remove and drop equipment
* unwield - drop held items
* wait - temporarely remove from party
* follow - rejoin the party after "wait"
* leave - remove from party (can be rejoined by talking)
gui/gm-editor
=============
@ -2442,7 +2511,7 @@ There are three ways to open this editor:
* using gui/gm-editor <lua command> - executes lua command and opens editor on
it's results (e.g. gui/gm-editor "df.global.world.items.all" shows all items)
* using gui/gm-edito dialog - shows an in game dialog to input lua command. Works
* using gui/gm-editor dialog - shows an in game dialog to input lua command. Works
the same as version above.
This editor allows to change and modify almost anything in df. Press '?' for an

@ -373,7 +373,8 @@ static bool try_autocomplete(color_ostream &con, const std::string &first, std::
if (possible.size() == 1)
{
completed = possible[0];
fprintf(stderr, "Autocompleted %s to %s\n", first.c_str(), completed.c_str());
//fprintf(stderr, "Autocompleted %s to %s\n", , );
con.printerr("%s is not recognized. Did you mean %s?\n", first.c_str(), completed.c_str());
return true;
}
@ -382,7 +383,8 @@ static bool try_autocomplete(color_ostream &con, const std::string &first, std::
std::string out;
for (size_t i = 0; i < possible.size(); i++)
out += " " + possible[i];
con.print("Possible completions:%s\n", out.c_str());
con.printerr("%s is not recognized. Possible completions:%s\n", first.c_str(), out.c_str());
return true;
}
return false;
@ -717,7 +719,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
else if (plug_mgr->eval_ruby && fileExists(filename + ".rb"))
res = runRubyScript(con, plug_mgr, first, parts);
else if (try_autocomplete(con, first, completed))
return runCommand(con, completed, parts);
return CR_NOT_IMPLEMENTED;// runCommand(con, completed, parts);
else
con.printerr("%s is not a recognized command.\n", first.c_str());
}

@ -1,5 +1,7 @@
-- Simple binary patch with IDA dif file support.
local _ENV = mkmodule('binpatch')
local function load_patch(name)
local filename = name
if not string.match(filename, '[./\\]') then

@ -1 +1 @@
Subproject commit c7e2c28febd6dca06ff7e9951090982fbbee12b5
Subproject commit 4d2afc3a0bcebdb17415dc2827b44fd35986a368

@ -136,6 +136,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(autoSyndrome autoSyndrome.cpp)
DFHACK_PLUGIN(trueTransformation trueTransformation.cpp)
DFHACK_PLUGIN(infiniteSky infiniteSky.cpp)
DFHACK_PLUGIN(createitem createitem.cpp)
endif()

@ -0,0 +1,257 @@
// Create arbitrary items
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "MiscUtils.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "modules/Items.h"
#include "modules/Materials.h"
#include "DataDefs.h"
#include "df/game_type.h"
#include "df/world.h"
#include "df/ui.h"
#include "df/unit.h"
#include "df/historical_entity.h"
#include "df/world_site.h"
#include "df/item.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
#include "df/reaction_reagent.h"
#include "df/reaction_product_itemst.h"
using namespace std;
using namespace DFHack;
using df::global::world;
using df::global::ui;
using df::global::gametype;
DFHACK_PLUGIN("createitem");
command_result df_createitem (color_ostream &out, vector <string> & parameters);
DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands)
{
commands.push_back(PluginCommand("createitem", "Create arbitrary item at the selected unit's feet.", df_createitem));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}
bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool glove2 = false)
{
vector<df::item *> out_items;
vector<df::reaction_reagent *> in_reag;
vector<df::item *> in_items;
bool is_gloves = (prod->item_type == df::item_type::GLOVES);
prod->produce(unit, &out_items, &in_reag, &in_items, 1, df::job_skill::NONE,
df::historical_entity::find(unit->civ_id),
((*gametype == df::game_type::DWARF_MAIN) || (*gametype == df::game_type::DWARF_RECLAIM)) ? df::world_site::find(ui->site_id) : NULL);
if (!out_items.size())
return false;
for (size_t i = 0; i < out_items.size(); i++)
{
out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z);
if (is_gloves)
{
// if the reaction creates gloves without handedness, then create 2 sets (left and right)
if (out_items[i]->getGloveHandedness() > 0)
is_gloves = false;
else
out_items[i]->setGloveHandedness(glove2 ? 2 : 1);
}
}
if (is_gloves && !glove2)
return makeItem(prod, unit, true);
return true;
}
command_result df_createitem (color_ostream &out, vector <string> & parameters)
{
string item_str, material_str;
df::item_type item_type = df::item_type::NONE;
int16_t item_subtype = -1;
int16_t mat_type = -1;
int32_t mat_index = -1;
int count = 1;
if ((parameters.size() < 2) || (parameters.size() > 3))
{
out.print("Syntax: createitem <item> <material> [count]\n"
" <item> - Item token for what you wish to create, as specified in custom\n"
" reactions. If the item has no subtype, omit the :NONE.\n"
" <material> - The material you want the item to be made of, as specified\n"
" in custom reactions. For REMAINS, FISH, FISH_RAW, VERMIN,\n"
" PET, and EGG, replace this with a creature ID and caste.\n"
" [count] - How many of the item you wish to create.\n"
);
return CR_WRONG_USAGE;
}
item_str = parameters[0];
material_str = parameters[1];
if (parameters.size() == 3)
{
stringstream ss(parameters[2]);
ss >> count;
if (count < 1)
{
out.printerr("You cannot produce less than one item!\n");
return CR_FAILURE;
}
}
ItemTypeInfo item;
MaterialInfo material;
vector<string> tokens;
if (!item.find(item_str))
{
out.printerr("Unrecognized item type!\n");
return CR_FAILURE;
}
item_type = item.type;
item_subtype = item.subtype;
switch (item.type)
{
case df::item_type::INSTRUMENT:
case df::item_type::TOY:
case df::item_type::WEAPON:
case df::item_type::ARMOR:
case df::item_type::SHOES:
case df::item_type::SHIELD:
case df::item_type::HELM:
case df::item_type::GLOVES:
case df::item_type::AMMO:
case df::item_type::PANTS:
case df::item_type::SIEGEAMMO:
case df::item_type::TRAPCOMP:
case df::item_type::TOOL:
if (item_subtype == -1)
{
out.printerr("You must specify a subtype!\n");
return CR_FAILURE;
}
default:
if (!material.find(material_str))
{
out.printerr("Unrecognized material!\n");
return CR_FAILURE;
}
mat_type = material.type;
mat_index = material.index;
break;
case df::item_type::REMAINS:
case df::item_type::FISH:
case df::item_type::FISH_RAW:
case df::item_type::VERMIN:
case df::item_type::PET:
case df::item_type::EGG:
split_string(&tokens, material_str, ":");
if (tokens.size() != 2)
{
out.printerr("You must specify a creature ID and caste for this item type!\n");
return CR_FAILURE;
}
for (size_t i = 0; i < world->raws.creatures.all.size(); i++)
{
df::creature_raw *creature = world->raws.creatures.all[i];
if (creature->creature_id == tokens[0])
{
for (size_t j = 0; j < creature->caste.size(); j++)
{
df::caste_raw *caste = creature->caste[j];
if (creature->caste[j]->caste_id == tokens[1])
{
mat_type = i;
mat_index = j;
break;
}
}
if (mat_type == -1)
{
out.printerr("The creature you specified has no such caste!\n");
return CR_FAILURE;
}
}
}
if (mat_type == -1)
{
out.printerr("Unrecognized creature ID!\n");
return CR_FAILURE;
}
break;
case df::item_type::CORPSE:
case df::item_type::CORPSEPIECE:
case df::item_type::FOOD:
out.printerr("Cannot create that type of item!\n");
return CR_FAILURE;
break;
}
CoreSuspender suspend;
df::unit *unit = Gui::getSelectedUnit(out, true);
if (!unit)
{
out.printerr("No unit selected!\n");
return CR_FAILURE;
}
if (!Maps::IsValid())
{
out.printerr("Map is not available.\n");
return CR_FAILURE;
}
df::map_block *block = Maps::getTileBlock(unit->pos.x, unit->pos.y, unit->pos.z);
if (block == NULL)
{
out.printerr("Unit does not reside in a valid map block, somehow?\n");
return CR_FAILURE;
}
df::reaction_product_itemst *prod = df::allocate<df::reaction_product_itemst>();
prod->item_type = item_type;
prod->item_subtype = item_subtype;
prod->mat_type = mat_type;
prod->mat_index = mat_index;
prod->probability = 100;
prod->count = count;
switch (item_type)
{
case df::item_type::BAR:
case df::item_type::POWDER_MISC:
case df::item_type::LIQUID_MISC:
case df::item_type::DRINK:
prod->product_dimension = 150;
break;
case df::item_type::THREAD:
prod->product_dimension = 15000;
break;
case df::item_type::CLOTH:
prod->product_dimension = 10000;
break;
default:
prod->product_dimension = 1;
break;
}
if (!makeItem(prod, unit))
{
out.printerr("Failed to create item!\n");
return CR_FAILURE;
}
return CR_OK;
}

@ -60,7 +60,7 @@ struct ProductInfo {
MaterialSource material;
bool isValid() {
return (material.mat_type >= 0 || material.reagent);
return true;//due to mat_type being -1 = any
}
};

@ -178,6 +178,7 @@ end
function BinaryPlugin:move_to_df()
local _,addr=df.sizeof(self.data)
markAsExecutable(addr)
return addr
end
function BinaryPlugin:print_data()
local out=""

@ -9,9 +9,18 @@ FriendshipRainbow.name="FriendshipRainbow"
-- os independant... I think...
FriendshipRainbow.ATTRS{filename="hack/lua/plugins/dfusion/friendship.o",name="FriendshipRainbow",race_data=DEFAULT_NIL}
FriendshipRainbow.class_status="valid, not installed"
function FriendshipRainbow:findall_needles(codesg,needle) -- todo move to memscan.lua
local cidx,caddr=codesg.uint8_t:find(needle)
local ret={}
while cidx~=nil do
table.insert(ret,{cidx,caddr})
cidx,caddr=codesg.uint8_t:find(needle,cidx+1)
end
return ret
end
function FriendshipRainbow:find_one(codesg,needle,crace)
dfu.concatTables(needle,dfu.dwordToTable(crace))
return codesg.uint8_t:findall(needle)
return self:findall_needles(codesg,needle)
end
function FriendshipRainbow:find_all()
local code=ms.get_code_segment()

@ -843,7 +843,7 @@ sub render_item_number {
} elsif ($subtype eq 'uint8_t') {
push @lines_rb, 'number 8, false';
} elsif ($subtype eq 'int8_t') {
push @lines_rb, 'number 8, false';
push @lines_rb, 'number 8, true';
} elsif ($subtype eq 'bool') {
push @lines_rb, 'number 8, true';
$initvalue ||= 'nil';

@ -251,10 +251,16 @@ struct stable_cursor_hook : df::viewscreen_dwarfmodest
// Force update of ui state
set<df::interface_key> tmp;
tmp.insert(interface_key::CURSOR_DOWN_Z);
if (last_cursor.z < 2)
tmp.insert(interface_key::CURSOR_UP_Z);
else
tmp.insert(interface_key::CURSOR_DOWN_Z);
INTERPOSE_NEXT(feed)(&tmp);
tmp.clear();
tmp.insert(interface_key::CURSOR_UP_Z);
if (last_cursor.z < 2)
tmp.insert(interface_key::CURSOR_DOWN_Z);
else
tmp.insert(interface_key::CURSOR_UP_Z);
INTERPOSE_NEXT(feed)(&tmp);
}
else if (!is_default && cur_cursor.isValid())
@ -809,14 +815,18 @@ struct military_training_ct_hook : df::activity_event_combat_trainingst {
spar++;
}
#if 0
color_ostream_proxy out(Core::getInstance().getConsole());
#endif
// If the xp gap is low, sometimes replace with sparring
if ((maxv - minv) < 64*15 && spar == units.size() &&
random_int(45) >= 30 + (maxv-minv)/64)
{
#if 0
out.print("Replacing %s demonstration (xp %d-%d, gap %d) with sparring.\n",
ENUM_KEY_STR(job_skill, sd->skill).c_str(), minv, maxv, maxv-minv);
#endif
if (auto spar = df::allocate<df::activity_event_sparringst>())
{
@ -838,18 +848,22 @@ struct military_training_ct_hook : df::activity_event_combat_trainingst {
// If the teacher has less xp than somebody else, switch
if (best >= 0 && maxv > cur_xp)
{
#if 0
out.print("Replacing %s teacher %d (%d xp) with %d (%d xp); xp gap %d.\n",
ENUM_KEY_STR(job_skill, sd->skill).c_str(),
sd->unit_id, cur_xp, units[best], maxv, maxv-minv);
#endif
sd->hist_figure_id = sd->participants.histfigs[best];
sd->unit_id = units[best];
}
else
{
#if 0
out.print("Not changing %s demonstration (xp %d-%d, gap %d).\n",
ENUM_KEY_STR(job_skill, sd->skill).c_str(),
minv, maxv, maxv-minv);
#endif
}
}
}

@ -43,7 +43,7 @@ for k,v in ipairs({...}) do --setting parsing
end
mode=mode or 0
last_building=last_building or {}
function Disclaimer(tlb)
local dsc={"The Gathering Against ",{text="Goblin ",pen=dfhack.pen.parse{fg=COLOR_GREEN,bg=0}}, "Oppresion ",
@ -73,6 +73,31 @@ function showHelp()
Disclaimer(helptext)
dialog.showMessage("Help!?!",helptext)
end
--[[ Util functions ]]--
function advGlobalPos()
local map=df.global.world.map
local wd=df.global.world.world_data
local adv=df.global.world.units.active[0]
--wd.adv_region_x*16+wd.adv_emb_x,wd.adv_region_y*16+wd.adv_emb_y
--return wd.adv_region_x*16+wd.adv_emb_x,wd.adv_region_y*16+wd.adv_emb_y
--return wd.adv_region_x*16+wd.adv_emb_x+adv.pos.x/16,wd.adv_region_y*16+wd.adv_emb_y+adv.pos.y/16
--print(map.region_x,map.region_y,adv.pos.x,adv.pos.y)
--print(map.region_x+adv.pos.x/48, map.region_y+adv.pos.y/48,wd.adv_region_x*16+wd.adv_emb_x,wd.adv_region_y*16+wd.adv_emb_y)
return math.floor(map.region_x+adv.pos.x/48), math.floor(map.region_y+adv.pos.y/48)
end
function inSite()
local tx,ty=advGlobalPos()
--print(tx,ty)
for k,v in pairs(df.global.world.world_data.sites) do
local tp={v.pos.x,v.pos.y}
if tx>=tp[1]*16+v.rgn_min_x and tx<=tp[1]*16+v.rgn_max_x and
ty>=tp[2]*16+v.rgn_min_y and ty<=tp[2]*16+v.rgn_max_y then
--print(k)
return v
end
end
end
--[[ low level job management ]]--
function getLastJobLink()
local st=df.global.world.job_list
@ -343,7 +368,12 @@ function BuildingChosen(inp_args,type_id,subtype_id,custom_id)
if inp_args then
args.pos=inp_args.pos or args.pos
end
last_building.type=args.type
last_building.subtype=args.subtype
last_building.custom=args.custom
if chooseBuildingWidthHeightDir(args) then
return
end
--if settings.build_by_items then
@ -458,8 +488,10 @@ function getItemsUncollected(job)
end
return ret
end
function AddItem(tbl,item,recurse)
table.insert(tbl,item)
function AddItem(tbl,item,recurse,skip_add)
if not skip_add then
table.insert(tbl,item)
end
if recurse then
local subitems=dfhack.items.getContainedItems(item)
if subitems~=nil then
@ -488,6 +520,8 @@ function EnumItems(args)
for k,v in pairs(args.unit.inventory) do
if args.inv[v.mode] then
AddItem(ret,v.item,args.deep)
elseif args.deep then
AddItem(ret,v.item,args.deep,true)
end
end
end
@ -711,35 +745,51 @@ function AssignJobItems(args)
return true
--]=]
end
function CheckAndFinishBuilding(args,bld)
for idx,job in pairs(bld.jobs) do
if job.job_type==df.job_type.ConstructBuilding then
args.job=job
break
end
end
if args.job~=nil then
local ok,msg=AssignJobItems(args)
if not ok then
return false,msg
else
AssignUnitToJob(args.job,args.unit,args.from_pos)
end
else
local t={items=buildings.getFiltersByType({},bld:getType(),bld:getSubtype(),bld:getCustomType())}
args.pre_actions={dfhack.curry(setFiltersUp,t),AssignJobItems,AssignBuildingRef}
local ok,msg=makeJob(args)
return ok,msg
end
end
function AssignJobToBuild(args)
local bld=dfhack.buildings.findAtTile(args.pos)
args.job_type=df.job_type.ConstructBuilding
if bld~=nil then
for idx,job in pairs(bld.jobs) do
if job.job_type==df.job_type.ConstructBuilding then
args.job=job
break
end
end
if args.job~=nil then
local ok,msg=AssignJobItems(args)
if not ok then
return false,msg
else
AssignUnitToJob(args.job,args.unit,args.from_pos)
end
else
local t={items=buildings.getFiltersByType({},bld:getType(),bld:getSubtype(),bld:getCustomType())}
args.pre_actions={dfhack.curry(setFiltersUp,t),AssignJobItems,AssignBuildingRef}
local ok,msg=makeJob(args)
return ok,msg
end
CheckAndFinishBuilding(args,bld)
else
bdialog.BuildingDialog{on_select=dfhack.curry(BuildingChosen,args),hide_none=true}:show()
end
return true
end
function BuildLast(args)
local bld=dfhack.buildings.findAtTile(args.pos)
args.job_type=df.job_type.ConstructBuilding
if bld~=nil then
CheckAndFinishBuilding(args,bld)
else
--bdialog.BuildingDialog{on_select=dfhack.curry(BuildingChosen,args),hide_none=true}:show()
if last_building and last_building.type then
BuildingChosen(args,last_building.type,last_building.subtype,last_building.custom)
end
end
return true
end
function CancelJob(unit)
local c_job=unit.job.current_job
if c_job then
@ -789,6 +839,7 @@ actions={
{"RemoveStairs" ,df.job_type.RemoveStairs,{IsStairs,NotConstruct}},
--{"HandleLargeCreature" ,df.job_type.HandleLargeCreature,{isUnit},{SetCreatureRef}},
{"Build" ,AssignJobToBuild,{NoConstructedBuilding}},
{"BuildLast" ,BuildLast,{NoConstructedBuilding}},
{"Clean" ,df.job_type.Clean,{}},
}
@ -827,8 +878,17 @@ function usetool:init(args)
visible=false,
text={
{id="text1",gap=1,key=keybinds.workshop.key,key_sep="()", text="Workshop menu",pen=dfhack.pen.parse{fg=COLOR_YELLOW,bg=0}}}
},
wid.Label{
view_id="siteLabel",
frame = {t=1,xalign=-1,yalign=0},
visible=false,
text={
{id="text1", text="Site:"},{id="site", text="name"}
}
}
}
end
function usetool:onIdle()
@ -948,7 +1008,7 @@ function usetool:openPutWindow(building)
local adv=df.global.world.units.active[0]
local items=EnumItems{pos=adv.pos,unit=adv,
inv={[df.unit_inventory_item.T_mode.Hauled]=true,[df.unit_inventory_item.T_mode.Worn]=true,
inv={[df.unit_inventory_item.T_mode.Hauled]=true,--[df.unit_inventory_item.T_mode.Worn]=true,
[df.unit_inventory_item.T_mode.Weapon]=true,},deep=true}
local choices={}
for k,v in pairs(items) do
@ -1040,7 +1100,12 @@ function usetool:armCleanTrap(building)
LoadStoneTrap,
LoadWeaponTrap,
]]
if building.trap_type==df.trap_type.Lever then
--link
return
end
--building.trap_type==df.trap_type.PressurePlate then
--settings/link
local args={unit=adv,post_actions={AssignBuildingRef,AssignJobItems},pos=adv.pos,from_pos=adv.pos,job_type=df.job_type.CleanTrap}
if building.trap_type==df.trap_type.CageTrap then
args.job_type=df.job_type.LoadCageTrap
@ -1157,7 +1222,7 @@ MODES={
input=usetool.operatePump,
},
[df.building_type.Trap]={
name="Arm/Clean Trap",
name="Interact",
input=usetool.armCleanTrap,
},
[df.building_type.Hive]={
@ -1168,8 +1233,8 @@ MODES={
function usetool:shopMode(enable,mode,building)
self.subviews.shopLabel.visible=enable
if mode then
self.subviews.shopLabel:itemById("text1").text=mode.name
self.building=building
self.subviews.shopLabel:itemById("text1").text=mode.name
self.building=building
end
self.mode=mode
end
@ -1178,20 +1243,7 @@ function usetool:shopInput(keys)
self:openShopWindowButtoned(self.in_shop)
end
end
function advGlobalPos()
local wd=df.global.world.world_data
return wd.adv_region_x*16+wd.adv_emb_x,wd.adv_region_y*16+wd.adv_emb_y
end
function inSite()
local tx,ty=advGlobalPos()
for k,v in pairs(df.global.world.world_data.sites) do
local tp={v.pos.x,v.pos.y}
if tx>=tp[1]*16+v.rgn_min_x and tx<=tp[1]*16+v.rgn_max_x and
ty>=tp[2]*16+v.rgn_min_y and ty<=tp[2]*16+v.rgn_max_y then
return v
end
end
end
function usetool:setupFields()
local adv=df.global.world.units.active[0]
local civ_id=df.global.world.units.active[0].civ_id
@ -1271,6 +1323,7 @@ function usetool:fieldInput(keys)
end
function usetool:onInput(keys)
local adv=df.global.world.units.active[0]
if keys.LEAVESCREEN then
if df.global.cursor.x~=-30000 then
self:sendInputToParent("LEAVESCREEN")
@ -1298,6 +1351,14 @@ function usetool:onInput(keys)
self:fieldInput(keys)
end
end
local site=inSite()
if site then
self.subviews.siteLabel.visible=true
self.subviews.siteLabel:itemById("site").text=dfhack.TranslateName(site.name)
else
self.subviews.siteLabel.visible=false
end
end
function usetool:isOnBuilding()
local adv=df.global.world.units.active[0]