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

develop
Warmist 2013-03-05 00:29:22 +02:00
commit bb85d361eb
10 changed files with 798 additions and 292 deletions

@ -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="#plugins" id="id52">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id53">burrows</a></li> <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="#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> </ul>
</li> </li>
<li><a class="reference internal" href="#scripts" id="id55">Scripts</a><ul> </ul>
<li><a class="reference internal" href="#save-init-script" id="id56">Save init script</a></li> </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> </ul>
</li> </li>
</ul> </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 <p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p> calls lua code to perform the actual ordering of list items.</p>
</div> </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>
<div class="section" id="scripts"> <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/* <p>Any files with the .lua extension placed into hack/scripts/*
are automatically used by the DFHack core as commands. The are automatically used by the DFHack core as commands. The
matching command name consists of the name of the file sans 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> </ul>
<p>Note that this function lets errors propagate to the caller.</p> <p>Note that this function lets errors propagate to the caller.</p>
<div class="section" id="save-init-script"> <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 <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 automatically loaded and executed every time the save is loaded. It
can also define the following functions to be called by dfhack:</p> can also define the following functions to be called by dfhack:</p>

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

@ -4,7 +4,8 @@ DFHack future
- support for displaying active keybindings properly. - support for displaying active keybindings properly.
- support for reusable widgets in lua screen library. - support for reusable widgets in lua screen library.
- Maps::canStepBetween: returns whether you can walk between two tiles in one step. - 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: Notable bugfixes:
- autobutcher can be re-enabled again after being stopped. - autobutcher can be re-enabled again after being stopped.
- stopped Dwarf Manipulator from unmasking vampires. - stopped Dwarf Manipulator from unmasking vampires.
@ -28,6 +29,7 @@ DFHack future
- stripcaged: mark items inside cages for dumping, eg caged goblin weapons. - stripcaged: mark items inside cages for dumping, eg caged goblin weapons.
- soundsense-season: writes the correct season to gamelog.txt on world load. - soundsense-season: writes the correct season to gamelog.txt on world load.
- create-items: spawn items - create-items: spawn items
- fix/cloth-stockpile: fixes bug 5739; needs to be run after savegame load every time.
New GUI scripts: New GUI scripts:
- gui/guide-path: displays the cached path for minecart Guide orders. - gui/guide-path: displays the cached path for minecart Guide orders.
- gui/workshop-job: displays inputs of a workshop job and allows tweaking them. - 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 :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) deramp (by zilpin)
------------------ ------------------
Removes all ramps designated for removal from the map. This is useful for replicating the old channel digging designation. 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 Diagnoses and fixes issues with nonexistant 'items occupying site', usually
caused by autodump bugs or other hacking mishaps. 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/* gui/*
===== =====
@ -2032,6 +2058,17 @@ Exemples::
create-items bar CREATURE:CAT:SOAP create-items bar CREATURE:CAT:SOAP
create-items bar adamantine 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 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 .. image:: images/liquids.png
While active, use the suggested keys to switch the usual liquids parameters, and Enter This script is a gui front-end to the liquids plugin and works similar to it,
to select the target area and apply changes. 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 gui/mechanisms

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

@ -136,6 +136,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(autoSyndrome autoSyndrome.cpp) DFHACK_PLUGIN(autoSyndrome autoSyndrome.cpp)
DFHACK_PLUGIN(trueTransformation trueTransformation.cpp) DFHACK_PLUGIN(trueTransformation trueTransformation.cpp)
DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp)
DFHACK_PLUGIN(createitem createitem.cpp)
endif() 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;
}

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

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