Merge branch 'master' of https://github.com/angavrilov/dfhack into experimental-dontmerge

develop
Warmist 2012-09-19 20:24:38 +03:00
commit bef9e9af7c
9 changed files with 1054 additions and 332 deletions

@ -199,7 +199,8 @@ Examples:
changevein
==========
Changes material of the vein under cursor to the specified inorganic RAW
material.
material. Only affects tiles within the current 16x16 block - for veins and
large clusters, you will need to use this command multiple times.
Example:
--------
@ -512,12 +513,6 @@ Removes invalid references to mineral inclusions and restores missing ones.
Use this if you broke your embark with tools like tiletypes, or if you
accidentally placed a construction on top of a valuable mineral floor.
fixwagons
=========
Due to a bug in all releases of version 0.31, merchants no longer bring wagons
with their caravans. This command re-enables them for all appropriate
civilizations.
flows
=====
A tool for checking how many tiles contain flowing liquids. If you suspect that
@ -707,6 +702,8 @@ Options
interface.
:rename unit-profession "custom profession": Change proffession name of the
highlighted unit/creature.
:rename building "name": Set a custom name for the selected building.
The building must be one of stockpile, workshop, furnace, trap or siege engine.
reveal
======
@ -907,6 +904,23 @@ Options
and are not flagged as tame), but you are allowed to mark them
for slaughter. Grabbing wagons results in some funny spam, then
they are scuttled.
:stable-cursor: Saves the exact cursor position between t/q/k/d/etc menus of dwarfmode.
:patrol-duty: Makes Train orders not count as patrol duty to stop unhappy thoughts.
Does NOT fix the problem when soldiers go off-duty (i.e. civilian).
:readable-build-plate: Fixes rendering of creature weight limits in pressure plate build menu.
:stable-temp: Fixes performance bug 6012 by squashing jitter in temperature updates.
In very item-heavy forts with big stockpiles this can improve FPS by 50-100%
:fast-heat: Further improves temperature update performance by ensuring that 1 degree
of item temperature is crossed in no more than specified number of frames
when updating from the environment temperature. This reduces the time it
takes for stable-temp to stop updates again when equilibrium is disturbed.
:fix-dimensions: Fixes subtracting small amount of thread/cloth/liquid from a stack
by splitting the stack and subtracting from the remaining single item.
This is a necessary addition to the binary patch in bug 808.
:advmode-contained: Works around bug 6202, i.e. custom reactions with container inputs
in advmode. The issue is that the screen tries to force you to select
the contents separately from the container. This forcefully skips child
reagents.
tubefill
========
@ -1414,16 +1428,16 @@ using this mode for birds is not recommanded.)
Will target any unit on a revealed tile of the map, including ambushers.
Ex:
::
Ex::
slayrace gob
To kill a single creature, select the unit with the 'v' cursor and:
::
To kill a single creature, select the unit with the 'v' cursor and::
slayrace him
To purify all elves on the map with fire (may have side-effects):
::
To purify all elves on the map with fire (may have side-effects)::
slayrace elve magma
@ -1435,8 +1449,8 @@ This script registers a map tile as a magma source, and every 12 game ticks
that tile receives 1 new unit of flowing magma.
Place the game cursor where you want to create the source (must be a
flow-passable tile, and not too high in the sky) and call
::
flow-passable tile, and not too high in the sky) and call::
magmasource here
To add more than 1 unit everytime, call the command again.
@ -1446,3 +1460,253 @@ To remove all placed sources, call ``magmasource stop``.
With no argument, this command shows an help message and list existing sources.
=======================
In-game interface tools
=======================
These tools work by displaying dialogs or overlays in the game window, and
are mostly implemented by lua scripts.
Dwarf Manipulator
=================
Implemented by the manipulator plugin. To activate, open the unit screen and
press 'l'.
This tool implements a Dwarf Therapist-like interface within the game UI. The
far left column displays the unit's Happiness (color-coded based on its
value), and the right half of the screen displays each dwarf's labor settings
and skill levels (0-9 for Dabbling thru Professional, A-E for Great thru Grand
Master, and U-Z for Legendary thru Legendary+5). Cells with red backgrounds
denote skills not controlled by labors.
Use the arrow keys or number pad to move the cursor around, holding Shift to
move 10 tiles at a time.
Press the Z-Up (<) and Z-Down (>) keys to move quickly between labor/skill
categories.
Press Enter to toggle the selected labor for the selected unit, or Shift+Enter
to toggle all labors within the selected category.
Press the ``+-`` keys to sort the unit list according to the currently selected
skill/labor, and press the ``*/`` keys to sort the unit list by Name, Profession,
or Happiness (using Tab to select which sort method to use here).
With a unit selected, you can press the "v" key to view its properties (and
possibly set a custom nickname or profession) or the "c" key to exit
Manipulator and zoom to its position within your fortress.
The following mouse shortcuts are also available:
* Click on a column header to sort the unit list. Left-click to sort it in one
direction (descending for happiness or labors/skills, ascending for name or
profession) and right-click to sort it in the opposite direction.
* Left-click on a labor cell to toggle that labor. Right-click to move the
cursor onto that cell instead of toggling it.
* Left-click on a unit's name or profession to view its properties.
* Right-click on a unit's name or profession to zoom to it.
Liquids
=======
Implemented by the gui/liquids script. To use, bind to a key and activate in the 'k' mode.
While active, use the suggested keys to switch the usual liquids parameters, and Enter
to select the target area and apply changes.
Mechanisms
==========
Implemented by the gui/mechanims script. To use, bind to a key and activate in the 'q' mode.
Lists mechanisms connected to the building, and their links. Navigating the list centers
the view on the relevant linked buildings.
To exit, press ESC or Enter; ESC recenters on the original building, while Enter leaves
focus on the current one. Shift-Enter has an effect equivalent to pressing Enter, and then
re-entering the mechanisms ui.
Power Meter
===========
Front-end to the power-meter plugin implemented by the gui/power-meter script. Bind to a
key and activate after selecting Pressure Plate in the build menu.
The script follows the general look and feel of the regular pressure plate build
configuration page, but configures parameters relevant to the modded power meter building.
Rename
======
Backed by the rename plugin, the gui/rename script allows entering the desired name
via a simple dialog in the game ui.
* ``gui/rename [building]`` in 'q' mode changes the name of a building.
The selected building must be one of stockpile, workshop, furnace, trap or siege engine.
* ``gui/rename [unit]`` with a unit selected changes the nickname.
* ``gui/rename unit-profession`` changes the selected unit's custom profession name.
The ``building`` or ``unit`` are automatically assumed when in relevant ui state.
Room List
=========
Implemented by the gui/room-list script. To use, bind to a key and activate in the 'q' mode,
either immediately or after opening the assign owner page.
The script lists other rooms owned by the same owner, or by the unit selected in the assign
list, and allows unassigning them.
Siege Engine
============
Front-end to the siege-engine plugin implemented by the gui/siege-engine script. Bind to a
key and activate after selecting a siege engine in 'q' mode.
The main mode displays the current target, selected ammo item type, linked stockpiles and
the allowed operator skill range. The map tile color is changed to signify if it can be
hit by the selected engine: green for fully reachable, blue for out of range, red for blocked,
yellow for partially blocked.
Pressing 'r' changes into the target selection mode, which works by highlighting two points
with Enter like all designations. When a target area is set, the engine projectiles are
aimed at that area, or units within it, instead of the vanilla four directions.
After setting the target in this way for one engine, you can 'paste' the same area into others
just by pressing 'p' in the main page of this script. The area to paste is kept until you quit
DF, or select another area manually.
Pressing 't' switches to a mode for selecting a stockpile to take ammo from.
Exiting from the siege engine script via ESC reverts the view to the state prior to starting
the script. Shift-ESC retains the current viewport, and also exits from the 'q' mode to main
menu.
**DISCLAIMER**: Siege engines are a very interesting feature, but currently nearly useless
because they haven't been updated since 2D and can only aim in four directions. This is an
attempt to bring them more up to date until Toady has time to work on it. Actual improvements,
e.g. like making siegers bring their own, are something only Toady can do.
=========
RAW hacks
=========
These plugins detect certain structures in RAWs, and enhance them in various ways.
Steam Engine
============
The steam-engine plugin detects custom workshops with STEAM_ENGINE in
their token, and turns them into real steam engines.
Rationale
---------
The vanilla game contains only water wheels and windmills as sources of
power, but windmills give relatively little power, and water wheels require
flowing water, which must either be a real river and thus immovable and
limited in supply, or actually flowing and thus laggy.
Steam engines are an alternative to water reactors that actually makes
sense, and hopefully doesn't lag. Also, unlike e.g. animal treadmills,
it can be done just by combining existing features of the game engine
in a new way with some glue code and a bit of custom logic.
Construction
------------
The workshop needs water as its input, which it takes via a
passable floor tile below it, like usual magma workshops do.
The magma version also needs magma.
**ISSUE**: Since this building is a machine, and machine collapse
code cannot be modified, it would collapse over true open space.
As a loophole, down stair provides support to machines, while
being passable, so use them.
After constructing the building itself, machines can be connected
to the edge tiles that look like gear boxes. Their exact position
is extracted from the workshop raws.
**ISSUE**: Like with collapse above, part of the code involved in
machine connection cannot be modified. As a result, the workshop
can only immediately connect to machine components built AFTER it.
This also means that engines cannot be chained without intermediate
short axles that can be built later.
Operation
---------
In order to operate the engine, queue the Stoke Boiler job (optionally
on repeat). A furnace operator will come, possibly bringing a bar of fuel,
and perform it. As a result, a "boiling water" item will appear
in the 't' view of the workshop.
**NOTE**: The completion of the job will actually consume one unit
of the appropriate liquids from below the workshop.
Every such item gives 100 power, up to a limit of 300 for coal,
and 500 for a magma engine. The building can host twice that
amount of items to provide longer autonomous running. When the
boiler gets filled to capacity, all queued jobs are suspended;
once it drops back to 3+1 or 5+1 items, they are re-enabled.
While the engine is providing power, steam is being consumed.
The consumption speed includes a fixed 10% waste rate, and
the remaining 90% are applied proportionally to the actual
load in the machine. With the engine at nominal 300 power with
150 load in the system, it will consume steam for actual
300*(10% + 90%*150/300) = 165 power.
Masterpiece mechanism and chain will decrease the mechanical
power drawn by the engine itself from 10 to 5. Masterpiece
barrel decreases waste rate by 4%. Masterpiece piston and pipe
decrease it by further 4%, and also decrease the whole steam
use rate by 10%.
Explosions
----------
The engine must be constructed using barrel, pipe and piston
from fire-safe, or in the magma version magma-safe metals.
During operation weak parts get gradually worn out, and
eventually the engine explodes. It should also explode if
toppled during operation by a building destroyer, or a
tantruming dwarf.
Save files
----------
It should be safe to load and view engine-using fortresses
from a DF version without DFHack installed, except that in such
case the engines won't work. However actually making modifications
to them, or machines they connect to (including by pulling levers),
can easily result in inconsistent state once this plugin is
available again. The effects may be as weird as negative power
being generated.
Add Spatter
===========
This plugin makes reactions with names starting with ``SPATTER_ADD_``
produce contaminants on the items instead of improvements.
Intended to give some use to all those poisons that can be bought from caravans.
To be really useful this needs patches from bug 808, ``tweak fix-dimensions``
and ``tweak advmode-contained``.

File diff suppressed because it is too large Load Diff

@ -397,7 +397,7 @@ static void enable_hooks(bool enable)
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{
switch (event) {
case SC_MAP_LOADED:
case SC_WORLD_LOADED:
if (find_reactions(out))
{
out.print("Detected spatter add reactions - enabling plugin.\n");
@ -406,7 +406,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
else
enable_hooks(false);
break;
case SC_MAP_UNLOADED:
case SC_WORLD_UNLOADED:
enable_hooks(false);
reactions.clear();
products.clear();
@ -420,8 +420,8 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
if (Core::getInstance().isMapLoaded())
plugin_onstatechange(out, SC_MAP_LOADED);
if (Core::getInstance().isWorldLoaded())
plugin_onstatechange(out, SC_WORLD_LOADED);
return CR_OK;
}

@ -338,7 +338,7 @@ public:
std::string getFocusString() { return "unitlabors"; }
viewscreen_unitlaborsst(vector<df::unit*> &src);
viewscreen_unitlaborsst(vector<df::unit*> &src, int cursor_pos);
~viewscreen_unitlaborsst() { };
protected:
@ -354,7 +354,7 @@ protected:
void calcSize ();
};
viewscreen_unitlaborsst::viewscreen_unitlaborsst(vector<df::unit*> &src)
viewscreen_unitlaborsst::viewscreen_unitlaborsst(vector<df::unit*> &src, int cursor_pos)
{
for (size_t i = 0; i < src.size(); i++)
{
@ -382,12 +382,23 @@ viewscreen_unitlaborsst::viewscreen_unitlaborsst(vector<df::unit*> &src)
units.push_back(cur);
}
std::sort(units.begin(), units.end(), sortByName);
altsort = ALTSORT_NAME;
first_row = sel_row = 0;
first_column = sel_column = 0;
first_row = 0;
sel_row = cursor_pos;
calcSize();
// recalculate first_row to roughly match the original layout
first_row = 0;
while (first_row < sel_row - num_rows + 1)
first_row += num_rows + 2;
// make sure the selection stays visible
if (first_row > sel_row)
first_row = sel_row - num_rows + 1;
// don't scroll beyond the end
if (first_row > units.size() - num_rows)
first_row = units.size() - num_rows;
}
void viewscreen_unitlaborsst::calcSize()
@ -528,11 +539,131 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
if (first_column < sel_column - col_widths[DISP_COLUMN_LABORS] + 1)
first_column = sel_column - col_widths[DISP_COLUMN_LABORS] + 1;
UnitInfo *cur = units[sel_row];
if (events->count(interface_key::SELECT) && (cur->allowEdit) && (columns[sel_column].labor != unit_labor::NONE))
int input_row = sel_row;
int input_column = sel_column;
int input_sort = altsort;
// Translate mouse input to appropriate keyboard input
if (enabler->tracking_on && gps->mouse_x != -1 && gps->mouse_y != -1)
{
int click_header = DISP_COLUMN_MAX; // group ID of the column header clicked
int click_body = DISP_COLUMN_MAX; // group ID of the column body clicked
int click_unit = -1; // Index into units[] (-1 if out of range)
int click_labor = -1; // Index into columns[] (-1 if out of range)
for (int i = 0; i < DISP_COLUMN_MAX; i++)
{
if ((gps->mouse_x >= col_offsets[i]) &&
(gps->mouse_x < col_offsets[i] + col_widths[i]))
{
if ((gps->mouse_y >= 1) && (gps->mouse_y <= 2))
click_header = i;
if ((gps->mouse_y >= 4) && (gps->mouse_y <= 4 + num_rows))
click_body = i;
}
}
if ((gps->mouse_x >= col_offsets[DISP_COLUMN_LABORS]) &&
(gps->mouse_x < col_offsets[DISP_COLUMN_LABORS] + col_widths[DISP_COLUMN_LABORS]))
click_labor = gps->mouse_x - col_offsets[DISP_COLUMN_LABORS] + first_column;
if ((gps->mouse_y >= 4) && (gps->mouse_y <= 4 + num_rows))
click_unit = gps->mouse_y - 4 + first_row;
switch (click_header)
{
case DISP_COLUMN_HAPPINESS:
if (enabler->mouse_lbut || enabler->mouse_rbut)
{
input_sort = ALTSORT_HAPPINESS;
if (enabler->mouse_lbut)
events->insert(interface_key::SECONDSCROLL_PAGEUP);
if (enabler->mouse_rbut)
events->insert(interface_key::SECONDSCROLL_PAGEDOWN);
}
break;
case DISP_COLUMN_NAME:
if (enabler->mouse_lbut || enabler->mouse_rbut)
{
input_sort = ALTSORT_NAME;
if (enabler->mouse_lbut)
events->insert(interface_key::SECONDSCROLL_PAGEDOWN);
if (enabler->mouse_rbut)
events->insert(interface_key::SECONDSCROLL_PAGEUP);
}
break;
case DISP_COLUMN_PROFESSION:
if (enabler->mouse_lbut || enabler->mouse_rbut)
{
input_sort = ALTSORT_PROFESSION;
if (enabler->mouse_lbut)
events->insert(interface_key::SECONDSCROLL_PAGEDOWN);
if (enabler->mouse_rbut)
events->insert(interface_key::SECONDSCROLL_PAGEUP);
}
break;
case DISP_COLUMN_LABORS:
if (enabler->mouse_lbut || enabler->mouse_rbut)
{
input_column = click_labor;
if (enabler->mouse_lbut)
events->insert(interface_key::SECONDSCROLL_UP);
if (enabler->mouse_rbut)
events->insert(interface_key::SECONDSCROLL_DOWN);
}
break;
}
switch (click_body)
{
case DISP_COLUMN_HAPPINESS:
// do nothing
break;
case DISP_COLUMN_NAME:
case DISP_COLUMN_PROFESSION:
// left-click to view, right-click to zoom
if (enabler->mouse_lbut)
{
input_row = click_unit;
events->insert(interface_key::UNITJOB_VIEW);
}
if (enabler->mouse_rbut)
{
input_row = click_unit;
events->insert(interface_key::UNITJOB_ZOOM_CRE);
}
break;
case DISP_COLUMN_LABORS:
// left-click to toggle, right-click to just highlight
if (enabler->mouse_lbut || enabler->mouse_rbut)
{
if (enabler->mouse_lbut)
{
input_row = click_unit;
input_column = click_labor;
events->insert(interface_key::SELECT);
}
if (enabler->mouse_rbut)
{
sel_row = click_unit;
sel_column = click_labor;
}
}
break;
}
enabler->mouse_lbut = enabler->mouse_rbut = 0;
}
UnitInfo *cur = units[input_row];
if (events->count(interface_key::SELECT) && (cur->allowEdit) && (columns[input_column].labor != unit_labor::NONE))
{
df::unit *unit = cur->unit;
const SkillColumn &col = columns[sel_column];
const SkillColumn &col = columns[input_column];
bool newstatus = !unit->status.labors[col.labor];
if (col.special)
{
@ -551,7 +682,7 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
if (events->count(interface_key::SELECT_ALL) && (cur->allowEdit))
{
df::unit *unit = cur->unit;
const SkillColumn &col = columns[sel_column];
const SkillColumn &col = columns[input_column];
bool newstatus = !unit->status.labors[col.labor];
for (int i = 0; i < NUM_COLUMNS; i++)
{
@ -576,15 +707,15 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
if (events->count(interface_key::SECONDSCROLL_UP) || events->count(interface_key::SECONDSCROLL_DOWN))
{
descending = events->count(interface_key::SECONDSCROLL_UP);
sort_skill = columns[sel_column].skill;
sort_labor = columns[sel_column].labor;
sort_skill = columns[input_column].skill;
sort_labor = columns[input_column].labor;
std::sort(units.begin(), units.end(), sortBySkill);
}
if (events->count(interface_key::SECONDSCROLL_PAGEUP) || events->count(interface_key::SECONDSCROLL_PAGEDOWN))
{
descending = events->count(interface_key::SECONDSCROLL_PAGEUP);
switch (altsort)
switch (input_sort)
{
case ALTSORT_NAME:
std::sort(units.begin(), units.end(), sortByName);
@ -619,7 +750,7 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
{
for (int i = 0; i < unitlist->units[unitlist->page].size(); i++)
{
if (unitlist->units[unitlist->page][i] == units[sel_row]->unit)
if (unitlist->units[unitlist->page][i] == units[input_row]->unit)
{
unitlist->cursor_pos[unitlist->page] = i;
unitlist->feed(events);
@ -647,6 +778,11 @@ void viewscreen_unitlaborsst::render()
Screen::clear();
Screen::drawBorder(" Dwarf Manipulator - Manage Labors ");
Screen::paintString(Screen::Pen(' ', 7, 0), col_offsets[DISP_COLUMN_HAPPINESS], 2, "Hap.");
Screen::paintString(Screen::Pen(' ', 7, 0), col_offsets[DISP_COLUMN_NAME], 2, "Name");
Screen::paintString(Screen::Pen(' ', 7, 0), col_offsets[DISP_COLUMN_PROFESSION], 2, "Profession");
for (int col = 0; col < col_widths[DISP_COLUMN_LABORS]; col++)
{
int col_offset = col + first_column;
@ -860,7 +996,7 @@ struct unitlist_hook : df::viewscreen_unitlistst
{
if (units[page].size())
{
Screen::show(new viewscreen_unitlaborsst(units[page]));
Screen::show(new viewscreen_unitlaborsst(units[page], cursor_pos[page]));
return;
}
}

@ -200,7 +200,7 @@ DFHACK_PLUGIN_LUA_FUNCTIONS {
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{
switch (event) {
case SC_MAP_LOADED:
case SC_WORLD_LOADED:
{
auto pworld = Core::getInstance().getWorld();
bool enable = pworld->GetPersistentData("power-meter/enabled").isValid();
@ -212,7 +212,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
}
}
break;
case SC_MAP_UNLOADED:
case SC_WORLD_UNLOADED:
enable_hooks(false);
break;
default:
@ -224,8 +224,8 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
if (Core::getInstance().isMapLoaded())
plugin_onstatechange(out, SC_MAP_LOADED);
if (Core::getInstance().isWorldLoaded())
plugin_onstatechange(out, SC_WORLD_LOADED);
return CR_OK;
}

@ -22,8 +22,8 @@
[PERMITTED_REACTION:BISMUTH_BRONZE_MAKING]
[PERMITTED_REACTION:ADAMANTINE_WAFERS]
+ [PERMITTED_REACTION:STOKE_BOILER]
+ [PERMITTED_REACTION:SPATTER_ADD_EXTRACT_WEAPON]
+ [PERMITTED_REACTION:SPATTER_ADD_EXTRACT_AMMO]
+ [PERMITTED_REACTION:SPATTER_ADD_WEAPON_EXTRACT]
+ [PERMITTED_REACTION:SPATTER_ADD_AMMO_EXTRACT]
[WORLD_CONSTRUCTION:TUNNEL]
[WORLD_CONSTRUCTION:BRIDGE]
[WORLD_CONSTRUCTION:ROAD]

@ -10,6 +10,7 @@ Reaction name must start with 'SPATTER_ADD_':
[SKILL:WAX_WORKING]
[REAGENT:extract:150:LIQUID_MISC:NONE:NONE:NONE]
[MIN_DIMENSION:150]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
[REAGENT:extract container:1:NONE:NONE:NONE:NONE]
[CONTAINS:extract]
[PRESERVE_REAGENT]
@ -17,8 +18,10 @@ Reaction name must start with 'SPATTER_ADD_':
The object to improve must be after the input mat, so that it is known:
[REAGENT:object:1:NONE:NONE:NONE:NONE]
[PRESERVE_REAGENT]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
Need some excuse why the spatter is water-resistant:
[REAGENT:grease:1:GLOB:NONE:NONE:NONE][REACTION_CLASS:FAT][UNROTTEN]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
The probability is used as spatter size; Legendary gives +90%:
COVERED = liquid, GLAZED = solid, BANDS = paste, SPIKES = powder
[IMPROVEMENT:800:object:COVERED:GET_MATERIAL_FROM_REAGENT:extract:NONE]
@ -30,6 +33,7 @@ Reaction name must start with 'SPATTER_ADD_':
[REAGENT:extract:150:LIQUID_MISC:NONE:NONE:NONE]
[MIN_DIMENSION:150]
[REACTION_CLASS:CREATURE_EXTRACT]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
[REAGENT:extract container:1:NONE:NONE:NONE:NONE]
[CONTAINS:extract]
[PRESERVE_REAGENT]
@ -37,8 +41,10 @@ Reaction name must start with 'SPATTER_ADD_':
The object to improve must be after the input mat, so that it is known:
[REAGENT:object:1:WEAPON:NONE:NONE:NONE]
[PRESERVE_REAGENT]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
Need some excuse why the spatter is water-resistant:
[REAGENT:grease:1:GLOB:NONE:NONE:NONE][REACTION_CLASS:TALLOW][UNROTTEN]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
The probability is used as spatter size; Legendary gives +90%:
COVERED = liquid, GLAZED = solid, BANDS = paste, SPIKES = powder
[IMPROVEMENT:800:object:COVERED:GET_MATERIAL_FROM_REAGENT:extract:NONE]
@ -50,6 +56,7 @@ Reaction name must start with 'SPATTER_ADD_':
[REAGENT:extract:50:LIQUID_MISC:NONE:NONE:NONE]
[MIN_DIMENSION:50]
[REACTION_CLASS:CREATURE_EXTRACT]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
[REAGENT:extract container:1:NONE:NONE:NONE:NONE]
[CONTAINS:extract]
[PRESERVE_REAGENT]
@ -57,8 +64,11 @@ Reaction name must start with 'SPATTER_ADD_':
The object to improve must be after the input mat, so that it is known:
[REAGENT:object:1:AMMO:NONE:NONE:NONE]
[PRESERVE_REAGENT]
[MIN_DIMENSION:5] don't waste materials on single bolts
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
Need some excuse why the spatter is water-resistant:
[REAGENT:grease:1:GLOB:NONE:NONE:NONE][REACTION_CLASS:TALLOW][UNROTTEN]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
The probability is used as spatter size; Legendary gives +90%:
COVERED = liquid, GLAZED = solid, BANDS = paste, SPIKES = powder
[IMPROVEMENT:200:object:COVERED:GET_MATERIAL_FROM_REAGENT:extract:NONE]

@ -1821,6 +1821,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
{
switch (event) {
case SC_MAP_LOADED:
if (!gamemode || *gamemode == game_mode::DWARF)
{
auto pworld = Core::getInstance().getWorld();
bool enable = pworld->GetPersistentData("siege-engine/enabled").isValid();

@ -972,7 +972,7 @@ static void enable_hooks(bool enable)
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{
switch (event) {
case SC_MAP_LOADED:
case SC_WORLD_LOADED:
if (find_engines())
{
out.print("Detected steam engine workshops - enabling plugin.\n");
@ -981,7 +981,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
else
enable_hooks(false);
break;
case SC_MAP_UNLOADED:
case SC_WORLD_UNLOADED:
enable_hooks(false);
engines.clear();
break;
@ -994,8 +994,8 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
if (Core::getInstance().isMapLoaded())
plugin_onstatechange(out, SC_MAP_LOADED);
if (Core::getInstance().isWorldLoaded())
plugin_onstatechange(out, SC_WORLD_LOADED);
return CR_OK;
}