develop
Japa 2015-01-19 20:02:19 +05:30
commit ae2e4f99eb
154 changed files with 8192 additions and 14426 deletions

@ -58,7 +58,7 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac
endif()
# set up versioning.
set(DF_VERSION "0.40.19")
set(DF_VERSION "0.40.23")
SET(DFHACK_RELEASE "r1" CACHE STRING "Current release revision.")
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
@ -188,5 +188,10 @@ ELSEIF(WIN32)
SET(CPACK_GENERATOR "ZIP")
ENDIF()
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_FILE_NAME "dfhack-${DFHACK_VERSION}-${CMAKE_SYSTEM_NAME}")
IF(APPLE)
set(DFHACK_PACKAGE_PLATFORM_NAME OSX)
ELSE()
set(DFHACK_PACKAGE_PLATFORM_NAME ${CMAKE_SYSTEM_NAME})
ENDIF()
set(CPACK_PACKAGE_FILE_NAME "dfhack-${DFHACK_VERSION}-${DFHACK_PACKAGE_PLATFORM_NAME}")
INCLUDE(CPack)

@ -469,9 +469,10 @@ This will take some time—maybe hours, depending on your machine.</li>
<blockquote>
<ul class="simple">
<li><a class="reference external" href="http://brew.sh/">Install Homebrew</a> and run:</li>
<li><tt class="docutils literal">brew tap lethosor/gcc</tt></li>
<li><tt class="docutils literal">brew install git</tt></li>
<li><tt class="docutils literal">brew install cmake</tt></li>
<li><tt class="docutils literal">brew install gcc45 <span class="pre">--enable-multilib</span></tt></li>
<li><tt class="docutils literal">brew install lethosor/gcc/gcc45 <span class="pre">--enable-multilib</span></tt></li>
</ul>
</blockquote>
</blockquote>

@ -106,9 +106,10 @@ If you are building on 10.6, please read the subsection below titled "Snow Leopa
Option 2: Using Homebrew:
* `Install Homebrew <http://brew.sh/>`_ and run:
* ``brew tap lethosor/gcc``
* ``brew install git``
* ``brew install cmake``
* ``brew install gcc45 --enable-multilib``
* ``brew install lethosor/gcc/gcc45 --enable-multilib``
5. Install perl dependencies

@ -403,6 +403,13 @@ ul.auto-toc {
<li>Angus Mezick &lt;<a class="reference external" href="mailto:amezick&#64;gmail.com">amezick&#64;gmail.com</a>&gt;</li>
<li>PeridexisErrant &lt;<a class="reference external" href="mailto:PeridexisErrant&#64;gmail.com">PeridexisErrant&#64;gmail.com</a>&gt;</li>
<li>Putnam</li>
<li>Danaris</li>
<li>Lethosor</li>
<li>Eswald</li>
<li>Ramblurr</li>
<li>MithrilTuxedo</li>
<li>AndreasPK</li>
<li>cdombroski</li>
</ul>
<p>And those are the cool people who made <strong>stonesense</strong>.</p>
<ul class="simple">

@ -63,6 +63,13 @@ The following is a list of people who have contributed to **DFHack**.
- Angus Mezick <amezick@gmail.com>
- PeridexisErrant <PeridexisErrant@gmail.com>
- Putnam
- Danaris
- Lethosor
- Eswald
- Ramblurr
- MithrilTuxedo
- AndreasPK
- cdombroski
And those are the cool people who made **stonesense**.

50
NEWS

@ -1,9 +1,59 @@
DFHack Future
Internals
EventManager: fixed crash error with EQUIPMENT_CHANGE event.
key modifier state exposed to Lua
Fixes
dfhack script can now be run from other directories on OSX
New Plugins
blueprint: export part of your fortress to quickfort .csv files
New Scripts
hotkey-notes: print key, name, and jump position of hotkeys
Removed
embark.lua
needs_porting/*
New Tweaks
Misc Improvements
added support for searching more lists
DFHack 0.40.23-r1
Internals
plugins will not be loaded if globals they specify as required are not located (should prevent some crashes)
Fixes
Fixed numerous (mostly Lua-related) crashes on OS X by including a more up-to-date libstdc++
Alt should no longer get stuck on Windows (and perhaps other platforms as well)
advfort works again
autobutcher takes sexualities into account
devel/export-dt-ini: Updated for 0.40.20+
digfort: now checks file type and existence
exportlegends: Fixed map export
full-heal: Fixed a problem with selecting units in the GUI
gui/hack-wish: Fixed restrictive material filters
mousequery: Changed box-select key to Alt+M
plugins/dwarfmonitor: correct date display (month index, separator)
scripts/putontable: added to the readme
siren should work again
stderr.log: removed excessive debug output on OS X
trackstop: No longer prevents cancelling the removal of a track stop or roller.
Fixed a display issue with PRINT_MODE:TEXT
Fixed a symbol error (MapExtras::BiomeInfo::MAX_LAYERS) when compiling DFHack in Debug mode
New Plugins
fortplan: designate construction of (limited) buildings from .csv file, quickfort-style
New Scripts
gui/stockpiles: an in-game interface for saving and loading stockpile
settings files.
position: Reports the current date, time, month, and season, plus
some location info. Port/update of position.py
hfs-pit: Digs a hole to hell under the cursor. Replaces needs_porting/hellhole.cpp
Removed
embark.lua: Obsolete, use `embark-tools`
New tweaks:
eggs-fertile: Displays an egg fertility indicator on nestboxes
max-wheelbarrow: Allows assigning more than 3 wheelbarrows to a stockpile
Misc Improvements
embark-tools: Added basic mouse support on the local map
Made some adventure mode keybindings in dfhack.init-example only work in adventure mode
Added a default keybinding for "gui/companion-order"
further work on needs_porting
DFHack 0.40.19-r1
Internals:

File diff suppressed because it is too large Load Diff

@ -311,6 +311,9 @@ Toggle between displaying/not displaying liquid depth as numbers.
stockpile settings management
-----------------------------
Save and load stockpile settings. See the gui/stockpiles for an in-game GUI to
this plugin.
copystock
~~~~~~~~~
@ -1329,6 +1332,8 @@ Subcommands that persist until disabled or DF quit:
:manager-quantity: Removes the limit of 30 jobs per manager order
:civ-view-agreement: Fixes overlapping text on the "view agreement" screen
:nestbox-color: Fixes the color of built nestboxes
:eggs-fertile: Displays a fertility indicator on nestboxes
:max-wheelbarrow: Allows assigning more than 3 wheelbarrows to a stockpile
fix-armory
----------
@ -1472,6 +1477,23 @@ Options:
:maps: Exports all seventeen detailed maps
:all: Equivalent to calling all of the above, in that order
blueprint
---------
Exports a portion of your fortress into QuickFort style blueprint files.::
blueprint <x> <y> <z> <name> [dig] [build] [place] [query]
Options:
:x,y,z: Size of map area to export
:name: Name of export files
:dig: Export dig commands to "<name>-dig.csv"
:build: Export build commands to "<name>-build.csv"
:place: Export stockpile commands to "<name>-place.csv"
:query: Export query commands to "<name>-query.csv"
If only region and name are given, all exports are performed.
Job management
==============
@ -2066,6 +2088,7 @@ Usage::
Tools:
* ``anywhere``: Allows embarking anywhere (including sites, mountain-only biomes, and oceans). Use with caution.
* ``mouse``: Implements mouse controls (currently in the local embark region only)
* ``nano``: An implementation of nano embark - allows resizing below 2x2 when enabled.
* ``sand``: Displays an indicator when sand is present in the currently-selected area, similar to the default clay/stone indicators.
* ``sticky``: Maintains the selected local area while navigating the world map
@ -2195,6 +2218,18 @@ directory.
A graphical interface for creating items.
* gui/stockpiles
Load and save stockpile settings from the 'q' menu.
Usage:
gui/stockpiles -save to save the current stockpile
gui/stockpiles -load to load settings into the current stockpile
gui/stockpiles -dir <path> set the default directory to save settings into
gui/stockpiles -help to see this message
Don't forget to `enable stockpiles` and create the `stocksettings` directory in
the DF folder before trying to use this plugin.
binpatch
========
@ -2273,10 +2308,6 @@ dfstatus
========
Show a quick overview of critical stock quantities, including food, dirnks, wood, and various bars.
embark
======
Allows to embark anywhere. Currently windows only.
exterminate
===========
Kills any unit of a given race.
@ -2316,6 +2347,39 @@ To purify all elves on the map with fire (may have side-effects)::
exterminate elve magma
fortplan
========
Usage: fortplan [filename]
Designates furniture for building according to a .csv file with
quickfort-style syntax. Companion to digfort.
The first line of the file must contain the following:
#build start(X; Y; <start location description>)
...where X and Y are the offset from the top-left corner of the file's area
where the in-game cursor should be located, and <start location description>
is an optional description of where that is. You may also leave a description
of the contents of the file itself following the closing parenthesis on the
same line.
The syntax of the file itself is similar to digfort or quickfort. At present,
only buildings constructed of an item with the same name as the building
are supported. All other characters are ignored. For example:
`,`,d,`,`
`,f,`,t,`
`,s,b,c,`
This section of a file would designate for construction a door and some
furniture inside a bedroom: specifically, clockwise from top left, a cabinet,
a table, a chair, a bed, and a statue.
All of the building designation uses Planning Mode, so you do not need to
have the items available to construct all the buildings when you run
fortplan with the .csv file.
growcrops
=========
Instantly grow seeds inside farming plots.
@ -2329,6 +2393,24 @@ For example, to grow 40 plump helmet spawn::
growcrops plump 40
hfs-pit
=======
Creates a pit to the underworld at the cursor.
Takes three arguments: diameter of the pit in tiles, whether to wall off
the pit, and whether to insert stairs. If no arguments are given, the default
is "hfs-pit 1 0 0", ie single-tile wide with no walls or stairs.
hfs-pit 4 0 1
hfs-pit 2 1 0
First example is a four-across pit with stairs but no walls; second is a
two-across pit with stairs but no walls.
hotkey-notes
============
Lists the key, name, and jump position of your hotkeys.
lever
=====
Allow manipulation of in-game levers from the dfhack console.
@ -2399,6 +2481,16 @@ Example::
multicmd locate-ore iron ; digv
position
========
Reports the current time: date, clock time, month, and season. Also reports
location: z-level, cursor position, window size, and mouse location.
putontable
==========
Makes item appear on the table, like in adventure mode shops. Arguments: '-a'
or '--all' for all items.
quicksave
=========

@ -0,0 +1,123 @@
#!/bin/bash
# This implements steps 7 and 8 of the OSX compilation procedure described in Compile.rst
# If build-osx does not exist in the parent directory, it will be created.
LUA_PATCH=1
ME=$PWD/`basename $0`
usage() {
echo "Usage: $0 [options] {DF_OSX_PATH}"
echo -e "\told\t- use on pre-Snow Leopard OSX installations"
echo -e "\tbrew\t- if GCC 4.5 was installed with homebrew"
echo -e "\tport\t- if GCC 4.5 was insalled with macports"
echo -e "\tclean\t- delete ../build-osx before compiling"
echo "Example:"
echo -e "\t$0 old brew ../../../personal/df_osx"
echo -e "\t$0 port clean /Users/dfplayer/df_osx"
exit $1
}
options() {
case $1 in
brew)
echo "Using homebrew gcc."
export CC=/usr/local/bin/gcc-4.5
export CXX=/usr/local/bin/g++-4.5
targetted=1
;;
port)
echo "Using macports gcc."
export CC=/opt/local/bin/gcc-mp-4.5
export CXX=/opt/local/bin/g++-mp-4.5
targetted=1
;;
old)
LUA_PATCH=0
;;
clean)
echo "Deleting ../build-osx"
rm -rf ../build-osx
;;
*)
;;
esac
}
# sanity checks
if [[ $# -lt 1 ]]
then
echo "Not enough arguments."
usage 0
fi
if [[ $# -gt 4 ]]
then
echo "Too many arguments."
usage 1
fi
# run through the arguments
for last
do
options $last
done
# last keeps the last argument
if [[ $targetted -eq 0 ]]
then
echo "You did not specify whether you intalled GCC 4.5 from brew or ports."
echo "If you continue, your default compiler will be used."
read -p "Are you sure you want to continue? [y/N] " -n 1 -r
echo # (optional) move to a new line
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
exit 0
fi
fi
# check for build folder and start working there
if [[ ! -d ../build-osx ]]
then
mkdir ../build-osx
fi
cd ../build-osx
# patch if necessary
if [[ $LUA_PATCH -ne 0 ]]
then
cd ..
echo "$PWD"
sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0
cd -
fi
echo "Generate"
cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX="$last"
echo "Build"
make
echo "Install"
make install
# unpatch if /libarary/luaTypes.cpp was patched
if [[ $LUA_PATCH -ne 0 ]]
then
cd ..
echo -n "un"
sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0 -R
cd -
fi
exit 0
# PATCHCODE - everything below this line is fed into patch
--- library/LuaTypes.cpp 2014-08-20 00:13:17.000000000 -0700
+++ library/LuaTypes.cpp 2014-08-31 23:31:00.000000000 -0700
@@ -464,7 +464,7 @@
{
case struct_field_info::STATIC_STRING:
{
- int len = strnlen((char*)ptr, field->count);
+ int len = strlen((char*)ptr);
lua_pushlstring(state, (char*)ptr, len);
return;
}

@ -52,8 +52,9 @@ keybinding add Ctrl-Shift-F@dwarfmode forum-dwarves
# Generic adv mode bindings #
##############################
keybinding add Ctrl-B adv-bodyswap
keybinding add Ctrl-Shift-B "adv-bodyswap force"
keybinding add Ctrl-B@dungeonmode adv-bodyswap
keybinding add Ctrl-Shift-B@dungeonmode "adv-bodyswap force"
keybinding add Shift-O@dungeonmode gui/companion-order
##############################
# Generic legends bindings #
@ -72,9 +73,13 @@ keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show"
# open an overview window summarising some stocks (dfstatus)
keybinding add Ctrl-Shift-I@dwarfmode/Default "gui/dfstatus"
# q->stockpile; p - copy & paste stockpiles
# q->stockpile - copy & paste stockpiles
keybinding add Alt-P copystock
# q->stockpile - load and save stockpile settings out of game
keybinding add Alt-L@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -load"
keybinding add Alt-S@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -save"
# q->workshop - duplicate the selected job
keybinding add Ctrl-D job-duplicate
@ -174,6 +179,7 @@ tweak import-priority-category
# Misc. UI tweaks
tweak civ-view-agreement
tweak max-wheelbarrow
###########################
# Globally acting plugins #
@ -189,7 +195,7 @@ enable search
enable automaterial
# Other interface improvement tools
enable dwarfmonitor mousequery automelt autotrade buildingplan resume trackstop zone stocks autochop
enable dwarfmonitor mousequery automelt autotrade buildingplan resume trackstop zone stocks autochop stockpiles
# allow the fortress bookkeeper to queue jobs through the manager
stockflow enable

@ -87,15 +87,15 @@ ENDIF()
SET(MAIN_SOURCES_LINUX
Console-posix.cpp
Hooks-linux.cpp
PlugLoad-linux.cpp
PlugLoad-posix.cpp
Process-linux.cpp
)
SET(MAIN_SOURCES_DARWIN
Console-posix.cpp
PlugLoad-darwin.cpp
Process-darwin.cpp
Hooks-darwin.cpp
PlugLoad-posix.cpp
Process-darwin.cpp
)
SET(MAIN_SOURCES_LINUX_EGGY
@ -306,6 +306,12 @@ IF(UNIX)
DESTINATION .)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/darwin/dfhack-run
DESTINATION .)
OPTION(INSTALL_NEW_LIBSTDCXX "Install a version of libstdc++ from GCC 4.5.4 to fix various crashes" ON)
IF(INSTALL_NEW_LIBSTDCXX)
execute_process(COMMAND bunzip2 --keep --force ${dfhack_SOURCE_DIR}/package/darwin/libstdc++.6.dylib.bz2)
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/darwin/libstdc++.6.dylib
DESTINATION ./hack/)
ENDIF(INSTALL_NEW_LIBSTDCXX)
else()
# On linux, copy our version of the df launch script which sets LD_PRELOAD
install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack

@ -714,7 +714,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
std::string keystr = parts[1];
if (parts[0] == "set")
ClearKeyBindings(keystr);
for (int i = parts.size()-1; i >= 2; i--)
for (int i = parts.size()-1; i >= 2; i--)
{
if (!AddKeyBinding(keystr, parts[i])) {
con.printerr("Invalid key spec: %s\n", keystr.c_str());
@ -910,7 +910,7 @@ void fIOthread(void * iodata)
main_history.add(command);
main_history.save("dfhack.history");
}
auto rv = core->runCommand(con, command);
if (rv == CR_NOT_IMPLEMENTED)
@ -1091,6 +1091,7 @@ bool Core::Init()
screen_window = new Windows::top_level_window();
screen_window->addChild(new Windows::dfhack_dummy(5,10));
started = true;
modstate = 0;
cerr << "Starting the TCP listener.\n";
server = new ServerMain();
@ -1579,6 +1580,8 @@ int UnicodeAwareSym(const SDL::KeyboardEvent& ke)
//MEMO: return false if event is consumed
int Core::DFH_SDL_Event(SDL::Event* ev)
{
//static bool alt = 0;
// do NOT process events before we are ready.
if(!started) return true;
if(!ev)
@ -1587,26 +1590,27 @@ int Core::DFH_SDL_Event(SDL::Event* ev)
{
auto ke = (SDL::KeyboardEvent *)ev;
if(ke->state == SDL::BTN_PRESSED && !hotkey_states[ke->ksym.sym])
if (ke->ksym.sym == SDL::K_LSHIFT || ke->ksym.sym == SDL::K_RSHIFT)
modstate = (ev->type == SDL::ET_KEYDOWN) ? modstate | DFH_MOD_SHIFT : modstate & ~DFH_MOD_SHIFT;
else if (ke->ksym.sym == SDL::K_LCTRL || ke->ksym.sym == SDL::K_RCTRL)
modstate = (ev->type == SDL::ET_KEYDOWN) ? modstate | DFH_MOD_CTRL : modstate & ~DFH_MOD_CTRL;
else if (ke->ksym.sym == SDL::K_LALT || ke->ksym.sym == SDL::K_RALT)
modstate = (ev->type == SDL::ET_KEYDOWN) ? modstate | DFH_MOD_ALT : modstate & ~DFH_MOD_ALT;
else if(ke->state == SDL::BTN_PRESSED && !hotkey_states[ke->ksym.sym])
{
hotkey_states[ke->ksym.sym] = true;
int mod = 0;
if (ke->ksym.mod & SDL::KMOD_SHIFT) mod |= 1;
if (ke->ksym.mod & SDL::KMOD_CTRL) mod |= 2;
if (ke->ksym.mod & SDL::KMOD_ALT) mod |= 4;
// Use unicode so Windows gives the correct value for the
// user's Input Language
if((ke->ksym.unicode & 0xff80) == 0)
{
int key = UnicodeAwareSym(*ke);
SelectHotkey(key, mod);
SelectHotkey(key, modstate);
}
else
{
// Pretend non-ascii characters don't happen:
SelectHotkey(ke->ksym.sym, mod);
SelectHotkey(ke->ksym.sym, modstate);
}
}
else if(ke->state == SDL::BTN_RELEASED)
@ -1703,7 +1707,7 @@ static bool parseKeySpec(std::string keyspec, int *psym, int *pmod, std::string
} else if (keyspec.size() > 4 && keyspec.substr(0, 4) == "Alt-") {
*pmod |= 4;
keyspec = keyspec.substr(4);
} else
} else
break;
}

@ -49,16 +49,19 @@ typedef struct interpose_s
#include "Hooks.h"
#include <iostream>
/*static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) =
/*static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) =
{
{ (void *)DFH_SDL_Init, (void *)SDL_Init },
{ (void *)DFH_SDL_PollEvent, (void *)SDL_PollEvent },
{ (void *)DFH_SDL_Quit, (void *)SDL_Quit },
{ (void *)DFH_SDL_NumJoysticks, (void *)SDL_NumJoysticks },
};*/
#define DYLD_INTERPOSE(_replacment,_replacee) __attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } \
_interpose_##_replacee __attribute__ ((section ("__DATA,__interpose"))) = \
{ (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
DYLD_INTERPOSE(DFH_SDL_Init,SDL_Init);
DYLD_INTERPOSE(DFH_SDL_PollEvent,SDL_PollEvent);
@ -94,7 +97,7 @@ DFhackCExport void DFH_SDL_Quit(void)
{
_SDL_Quit();
}*/
SDL_Quit();
}
@ -170,10 +173,10 @@ DFhackCExport int DFH_SDL_Init(uint32_t flags)
fprintf(stderr,"dfhack: something went horribly wrong\n");
exit(1);
}
DFHack::Core & c = DFHack::Core::getInstance();
//c.Init();
//int ret = _SDL_Init(flags);
int ret = SDL_Init(flags);
return ret;
@ -270,4 +273,4 @@ DFhackCExport int DFH_SDL_UpperBlit(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Re
}
return SDL_UpperBlit(src, srcrect, dst, dstrect);
}
}

@ -2008,10 +2008,12 @@ static void *checkaddr(lua_State *L, int idx, bool allow_null = false)
static uint32_t getImageBase() { return Core::getInstance().p->getBase(); }
static int getRebaseDelta() { return Core::getInstance().vinfo->getRebaseDelta(); }
static int8_t getModstate() { return Core::getInstance().getModstate(); }
static const LuaWrapper::FunctionReg dfhack_internal_module[] = {
WRAP(getImageBase),
WRAP(getRebaseDelta),
WRAP(getModstate),
{ NULL, NULL }
};
@ -2351,6 +2353,22 @@ static int internal_runCommand(lua_State *L)
return 1;
}
static int internal_getModifiers(lua_State *L)
{
int8_t modstate = Core::getInstance().getModstate();
lua_newtable(L);
lua_pushstring(L, "shift");
lua_pushboolean(L, modstate & DFH_MOD_SHIFT);
lua_settable(L, -3);
lua_pushstring(L, "ctrl");
lua_pushboolean(L, modstate & DFH_MOD_CTRL);
lua_settable(L, -3);
lua_pushstring(L, "alt");
lua_pushboolean(L, modstate & DFH_MOD_ALT);
lua_settable(L, -3);
return 1;
}
static const luaL_Reg dfhack_internal_funcs[] = {
{ "getAddress", internal_getAddress },
{ "setAddress", internal_setAddress },
@ -2365,6 +2383,7 @@ static const luaL_Reg dfhack_internal_funcs[] = {
{ "diffscan", internal_diffscan },
{ "getDir", internal_getDir },
{ "runCommand", internal_runCommand },
{ "getModifiers", internal_getModifiers },
{ NULL, NULL }
};

@ -1,44 +0,0 @@
#include <stdio.h>
#include <dlfcn.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <map>
#include "DFHack.h"
#include "PluginManager.h"
#include "Hooks.h"
#include <iostream>
/*
* Plugin loading functions
*/
namespace DFHack
{
DFLibrary * OpenPlugin (const char * filename)
{
dlerror();
DFLibrary * ret = (DFLibrary *) dlopen(filename, RTLD_NOW);
if(!ret)
{
std::cerr << dlerror() << std::endl;
}
return ret;
}
void * LookupPlugin (DFLibrary * plugin ,const char * function)
{
return (DFLibrary *) dlsym((void *)plugin, function);
}
void ClosePlugin (DFLibrary * plugin)
{
dlclose((void *) plugin);
}
}

@ -35,10 +35,10 @@ namespace DFHack
}
void * LookupPlugin (DFLibrary * plugin ,const char * function)
{
return (DFLibrary *) dlsym((void *)plugin, function);
return (void *) dlsym((void *)plugin, function);
}
void ClosePlugin (DFLibrary * plugin)
{
dlclose((void *) plugin);
}
}
}

@ -30,6 +30,7 @@ distribution.
#include "RemoteServer.h"
#include "Console.h"
#include "Types.h"
#include "VersionInfo.h"
#include "DataDefs.h"
#include "MiscUtils.h"
@ -167,6 +168,7 @@ Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _f
}
plugin_lib = 0;
plugin_init = 0;
plugin_globals = 0;
plugin_shutdown = 0;
plugin_status = 0;
plugin_onupdate = 0;
@ -235,13 +237,32 @@ bool Plugin::load(color_ostream &con)
*plug_self = this;
RefAutolock lock(access);
plugin_init = (command_result (*)(color_ostream &, std::vector <PluginCommand> &)) LookupPlugin(plug, "plugin_init");
if(!plugin_init)
std::vector<std::string>** plugin_globals_ptr = (std::vector<std::string>**) LookupPlugin(plug, "plugin_globals");
if(!plugin_init || !plugin_globals_ptr)
{
con.printerr("Plugin %s has no init function.\n", filename.c_str());
con.printerr("Plugin %s has no init function or globals vector.\n", filename.c_str());
ClosePlugin(plug);
state = PS_BROKEN;
return false;
}
plugin_globals = *plugin_globals_ptr;
if (plugin_globals->size())
{
std::vector<std::string> missing_globals;
for (auto it = plugin_globals->begin(); it != plugin_globals->end(); ++it)
{
if (!Core::getInstance().vinfo->getAddress(it->c_str()))
missing_globals.push_back(*it);
}
if (missing_globals.size())
{
con.printerr("Plugin %s is missing required globals: %s\n",
*plug_name, join_strings(", ", missing_globals).c_str());
ClosePlugin(plug);
state = PS_BROKEN;
return false;
}
}
plugin_status = (command_result (*)(color_ostream &, std::string &)) LookupPlugin(plug, "plugin_status");
plugin_onupdate = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_onupdate");
plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown");

@ -188,7 +188,7 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
temp.valid = true;
ranges.push_back(temp);
fprintf(stderr,
/*fprintf(stderr,
"%08x-%08x %8uK %c%c%c/%c%c%c %11s %6s %10s uwir=%hu sub=%u dlname: %s\n",
address, (address + vmsize), (vmsize >> 10),
(info.protection & VM_PROT_READ) ? 'r' : '-',
@ -202,7 +202,7 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
behavior_strings[info.behavior],
info.user_wired_count,
info.reserved,
dlinfo.dli_fname);
dlinfo.dli_fname);*/
address += vmsize;
} else if (kr != KERN_INVALID_ADDRESS) {

@ -36,6 +36,10 @@ distribution.
#include "RemoteClient.h"
#define DFH_MOD_SHIFT 1
#define DFH_MOD_CTRL 2
#define DFH_MOD_ALT 4
struct WINDOW;
namespace tthread
@ -142,6 +146,7 @@ namespace DFHack
bool ClearKeyBindings(std::string keyspec);
bool AddKeyBinding(std::string keyspec, std::string cmdline);
std::vector<std::string> ListKeyBindings(std::string keyspec);
int8_t getModstate() { return modstate; }
std::string getHackPath();
@ -216,6 +221,7 @@ namespace DFHack
std::string cmdline;
std::string focus;
};
int8_t modstate;
std::map<int, std::vector<KeyBinding> > key_bindings;
std::map<int, bool> hotkey_states;

@ -47,6 +47,7 @@ namespace SDL
// these functions are here because they call into DFHack::Core and therefore need to
// be declared as friend functions/known
#ifdef _DARWIN
#include "modules/Graphic.h"
DFhackCExport int DFH_SDL_NumJoysticks(void);
DFhackCExport void DFH_SDL_Quit(void);
DFhackCExport int DFH_SDL_PollEvent(SDL::Event* event);

@ -27,6 +27,7 @@ distribution.
#include "Export.h"
#include "Hooks.h"
#include "ColorText.h"
#include "MiscUtils.h"
#include <map>
#include <string>
#include <vector>
@ -205,6 +206,7 @@ namespace DFHack
void reset_lua();
bool *plugin_is_enabled;
std::vector<std::string>* plugin_globals;
command_result (*plugin_init)(color_ostream &, std::vector <PluginCommand> &);
command_result (*plugin_status)(color_ostream &, std::string &);
command_result (*plugin_shutdown)(color_ostream &);
@ -264,7 +266,9 @@ namespace DFHack
#define DFHACK_PLUGIN(plugin_name) \
DFhackDataExport const char * version = DFHACK_VERSION;\
DFhackDataExport const char * name = plugin_name;\
DFhackDataExport Plugin *plugin_self = NULL;
DFhackDataExport Plugin *plugin_self = NULL;\
std::vector<std::string> _plugin_globals;\
DFhackDataExport std::vector<std::string>* plugin_globals = &_plugin_globals;
#define DFHACK_PLUGIN_IS_ENABLED(varname) \
DFhackDataExport bool plugin_is_enabled = false; \
@ -281,3 +285,8 @@ namespace DFHack
#define DFHACK_LUA_FUNCTION(name) { #name, df::wrap_function(name,true) }
#define DFHACK_LUA_EVENT(name) { #name, &name##_event }
#define DFHACK_LUA_END { NULL, NULL }
#define REQUIRE_GLOBAL(global_name) \
using df::global::global_name; \
static int VARIABLE_IS_NOT_USED CONCAT_TOKENS(required_globals_, __LINE__) = \
(plugin_globals->push_back(#global_name), 0);

@ -69,6 +69,7 @@ SOFTWARE.
#ifdef _WIN32
#include <direct.h>
#define NOMINMAX
#include <windows.h>
#include <io.h>
#include <sys/locking.h>

@ -763,8 +763,6 @@ static void manageEquipmentEvent(color_ostream& out) {
handle.eventHandler(out, (void*)&data);
}
}
if ( !hadEquipment )
delete temp;
//check for dropped items
for ( auto b = v.begin(); b != v.end(); b++ ) {
InventoryItem i = *b;
@ -777,6 +775,8 @@ static void manageEquipmentEvent(color_ostream& out) {
handle.eventHandler(out, (void*)&data);
}
}
if ( !hadEquipment )
delete temp;
//update equipment
vector<InventoryItem>& equipment = equipmentLog[unit->id];

@ -130,7 +130,6 @@ _filetype DFHack::Filesystem::filetype (std::string path)
{
STAT_STRUCT info;
DFHack::Filesystem::stat(path, info);
std::cout << info.st_mode << std::endl;
return mode2type(info.st_mode);
}

@ -74,6 +74,10 @@ using df::global::world;
extern bool GetLocalFeature(t_feature &feature, df::coord2d rgn_pos, int32_t index);
#ifdef LINUX_BUILD
const unsigned MapExtras::BiomeInfo::MAX_LAYERS;
#endif
const BiomeInfo MapCache::biome_stub = {
df::coord2d(),
-1, -1, -1, -1,

@ -1 +1 @@
Subproject commit 55b60e3aa99aece7e9a239b041dc4f95a58dcef3
Subproject commit 20014d2f501b76b697e594d56e594ea8f143ea24

@ -1,543 +0,0 @@
#ifndef SEGMENTED_FINDER_H
#define SEGMENTED_FINDER_H
#include <malloc.h>
#include <iosfwd>
#include <iterator>
class SegmentedFinder;
class SegmentFinder
{
public:
SegmentFinder(DFHack::t_memrange & mr, DFHack::Context * DF, SegmentedFinder * SF)
{
_DF = DF;
mr_ = mr;
valid=false;
if(mr.valid)
{
mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start);
_SF = SF;
try
{
DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer);
valid = true;
}
catch (DFHack::Error::MemoryAccessDenied &)
{
free(mr_.buffer);
valid = false;
mr.valid = false; // mark the range passed in as bad
cout << "Range 0x" << hex << mr_.start << " - 0x" << mr_.end;
if (strlen(mr_.name) != 0)
cout << " (" << mr_.name << ")";
cout << dec << " not readable." << endl;
cout << "Skipping this range on future scans." << endl;
}
}
}
~SegmentFinder()
{
if(valid)
free(mr_.buffer);
}
bool isValid()
{
return valid;
}
template <class needleType, class hayType, typename comparator >
bool Find (needleType needle, const uint8_t increment , vector <uint64_t> &newfound, comparator oper)
{
if(!valid) return !newfound.empty();
//loop
for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment)
{
if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
newfound.push_back(mr_.start + offset);
}
return !newfound.empty();
}
template < class needleType, class hayType, typename comparator >
uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
{
if(!valid) return 0;
uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length);
//loop
for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1)
{
if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
return mr_.start + offset;
}
return 0;
}
template <class needleType, class hayType, typename comparator >
bool Filter (needleType needle, vector <uint64_t> &found, vector <uint64_t> &newfound, comparator oper)
{
if(!valid) return !newfound.empty();
for( uint64_t i = 0; i < found.size(); i++)
{
if(mr_.isInRange(found[i]))
{
uint64_t corrected = found[i] - mr_.start;
if( oper(_SF,(hayType *)(mr_.buffer + corrected), needle) )
newfound.push_back(found[i]);
}
}
return !newfound.empty();
}
private:
friend class SegmentedFinder;
SegmentedFinder * _SF;
DFHack::Context * _DF;
DFHack::t_memrange mr_;
bool valid;
};
class SegmentedFinder
{
public:
SegmentedFinder(vector <DFHack::t_memrange>& ranges, DFHack::Context * DF)
{
_DF = DF;
for(size_t i = 0; i < ranges.size(); i++)
{
segments.push_back(new SegmentFinder(ranges[i], DF, this));
}
}
~SegmentedFinder()
{
for(size_t i = 0; i < segments.size(); i++)
{
delete segments[i];
}
}
SegmentFinder * getSegmentForAddress (uint64_t addr)
{
for(size_t i = 0; i < segments.size(); i++)
{
if(segments[i]->mr_.isInRange(addr))
{
return segments[i];
}
}
return 0;
}
template <class needleType, class hayType, typename comparator >
bool Find (const needleType needle, const uint8_t increment, vector <uint64_t> &found, comparator oper)
{
found.clear();
for(size_t i = 0; i < segments.size(); i++)
{
segments[i]->Find<needleType,hayType,comparator>(needle, increment, found, oper);
}
return !(found.empty());
}
template < class needleType, class hayType, typename comparator >
uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
{
SegmentFinder * sf = getSegmentForAddress(start);
if(sf)
{
return sf->FindInRange<needleType,hayType,comparator>(needle, oper, start, length);
}
return 0;
}
template <class needleType, class hayType, typename comparator >
bool Filter (const needleType needle, vector <uint64_t> &found, comparator oper)
{
vector <uint64_t> newfound;
for(size_t i = 0; i < segments.size(); i++)
{
segments[i]->Filter<needleType,hayType,comparator>(needle, found, newfound, oper);
}
found.clear();
found = newfound;
return !(found.empty());
}
template <class needleType, class hayType, typename comparator >
bool Incremental (needleType needle, const uint8_t increment ,vector <uint64_t> &found, comparator oper)
{
if(found.empty())
{
return Find <needleType, hayType, comparator>(needle,increment,found,oper);
}
else
{
return Filter <needleType, hayType, comparator>(needle,found,oper);
}
}
template <typename T>
T * Translate(uint64_t address)
{
for(size_t i = 0; i < segments.size(); i++)
{
if(segments[i]->mr_.isInRange(address))
{
return (T *) (segments[i]->mr_.buffer + address - segments[i]->mr_.start);
}
}
return 0;
}
template <typename T>
T Read(uint64_t address)
{
return *Translate<T>(address);
}
template <typename T>
bool Read(uint64_t address, T& target)
{
T * test = Translate<T>(address);
if(test)
{
target = *test;
return true;
}
return false;
}
private:
DFHack::Context * _DF;
vector <SegmentFinder *> segments;
};
template <typename T>
bool equalityP (SegmentedFinder* s, T *x, T y)
{
return (*x) == y;
}
struct vecTriplet
{
uint32_t start;
uint32_t finish;
uint32_t alloc_finish;
};
template <typename Needle>
bool vectorLength (SegmentedFinder* s, vecTriplet *x, Needle &y)
{
if(x->start <= x->finish && x->finish <= x->alloc_finish)
if((x->finish - x->start) == y)
return true;
return false;
}
// find a vector of 32bit pointers, where an object pointed to has a string 'y' as the first member
bool vectorString (SegmentedFinder* s, vecTriplet *x, const char *y)
{
uint32_t object_ptr;
// iterate over vector of pointers
for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
{
// deref ptr idx, get ptr to object
if(!s->Read(idx,object_ptr))
{
return false;
}
// deref ptr to first object, get ptr to string
uint32_t string_ptr;
if(!s->Read(object_ptr,string_ptr))
return false;
// get string location in our local cache
char * str = s->Translate<char>(string_ptr);
if(!str)
return false;
if(strcmp(y, str) == 0)
return true;
}
return false;
}
// find a vector of 32bit pointers, where the first object pointed to has a string 'y' as the first member
bool vectorStringFirst (SegmentedFinder* s, vecTriplet *x, const char *y)
{
uint32_t object_ptr;
uint32_t idx = x->start;
// deref ptr idx, get ptr to object
if(!s->Read(idx,object_ptr))
{
return false;
}
// deref ptr to first object, get ptr to string
uint32_t string_ptr;
if(!s->Read(object_ptr,string_ptr))
return false;
// get string location in our local cache
char * str = s->Translate<char>(string_ptr);
if(!str)
return false;
if(strcmp(y, str) == 0)
return true;
return false;
}
// test if the address is between vector.start and vector.finish
// not very useful alone, but could be a good step to filter some things
bool vectorAddrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
{
if(address < x->finish && address >= x->start)
return true;
return false;
}
// test if an object address is within the vector of pointers
//
bool vectorOfPtrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
{
uint32_t object_ptr;
for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
{
if(!s->Read(idx,object_ptr))
{
return false;
}
if(object_ptr == address)
return true;
}
return false;
}
bool vectorAll (SegmentedFinder* s, vecTriplet *x, int )
{
if(x->start <= x->finish && x->finish <= x->alloc_finish)
{
if(s->getSegmentForAddress(x->start) == s->getSegmentForAddress(x->finish)
&& s->getSegmentForAddress(x->finish) == s->getSegmentForAddress(x->alloc_finish))
return true;
}
return false;
}
class Bytestreamdata
{
public:
void * object;
uint32_t length;
uint32_t allocated;
uint32_t n_used;
};
class Bytestream
{
public:
Bytestream(void * obj, uint32_t len, bool alloc = false)
{
d = new Bytestreamdata();
d->allocated = alloc;
d->object = obj;
d->length = len;
d->n_used = 1;
constant = false;
}
Bytestream()
{
d = new Bytestreamdata();
d->allocated = false;
d->object = 0;
d->length = 0;
d->n_used = 1;
constant = false;
}
Bytestream( Bytestream & bs)
{
d =bs.d;
d->n_used++;
constant = false;
}
Bytestream( const Bytestream & bs)
{
d =bs.d;
d->n_used++;
constant = true;
}
~Bytestream()
{
d->n_used --;
if(d->allocated && d->object && d->n_used == 0)
{
free (d->object);
free (d);
}
}
bool Allocate(size_t bytes)
{
if(constant)
return false;
if(d->allocated)
{
d->object = realloc(d->object, bytes);
}
else
{
d->object = malloc( bytes );
}
if(d->object)
{
d->allocated = bytes;
return true;
}
else
{
d->allocated = 0;
return false;
}
}
template < class T >
bool insert( T what )
{
if(constant)
return false;
if(d->length+sizeof(T) >= d->allocated)
Allocate((d->length+sizeof(T)) * 2);
(*(T *)( (uint64_t)d->object + d->length)) = what;
d->length += sizeof(T);
return true;
}
Bytestreamdata * d;
bool constant;
};
std::ostream& operator<< ( std::ostream& out, Bytestream& bs )
{
if(bs.d->object)
{
out << "bytestream " << dec << bs.d->length << "/" << bs.d->allocated << " bytes" << endl;
for(size_t i = 0; i < bs.d->length; i++)
{
out << hex << (int) ((uint8_t *) bs.d->object)[i] << " ";
}
out << endl;
}
else
{
out << "empty bytestresm" << endl;
}
return out;
}
std::istream& operator>> ( std::istream& out, Bytestream& bs )
{
string read;
while(!out.eof())
{
string tmp;
out >> tmp;
read.append(tmp);
}
cout << read << endl;
bs.d->length = 0;
size_t first = read.find_first_of("\"");
size_t last = read.find_last_of("\"");
size_t start = first + 1;
if(first == read.npos)
{
std::transform(read.begin(), read.end(), read.begin(), (int(*)(int)) tolower);
bs.Allocate(read.size()); // overkill. size / 2 should be good, but this is safe
int state = 0;
char big = 0;
char small = 0;
string::iterator it = read.begin();
// iterate through string, construct a bytestream out of 00-FF bytes
while(it != read.end())
{
char reads = *it;
if((reads >='0' && reads <= '9'))
{
if(state == 0)
{
big = reads - '0';
state = 1;
}
else if(state == 1)
{
small = reads - '0';
state = 0;
bs.insert<char>(big*16 + small);
}
}
if((reads >= 'a' && reads <= 'f'))
{
if(state == 0)
{
big = reads - 'a' + 10;
state = 1;
}
else if(state == 1)
{
small = reads - 'a' + 10;
state = 0;
bs.insert<char>(big*16 + small);
}
}
it++;
}
// we end in state= 1. should we add or should we trim... or throw errors?
// I decided on adding
if (state == 1)
{
small = 0;
bs.insert<char>(big*16 + small);
}
}
else
{
if(last == first)
{
// only one "
last = read.size();
}
size_t length = last - start;
// construct bytestream out of stuff between ""
bs.d->length = length;
if(length)
{
// todo: Bytestream should be able to handle this without external code
bs.Allocate(length);
bs.d->length = length;
const char* strstart = read.c_str();
memcpy(bs.d->object, strstart + start, length);
}
else
{
bs.d->object = 0;
}
}
cout << bs;
return out;
}
bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare )
{
if(memcmp(addr, compare.d->object, compare.d->length) == 0)
return true;
return false;
}
bool findString (SegmentedFinder* s, uint32_t *addr, const char * compare )
{
// read string pointer, translate to local scheme
char *str = s->Translate<char>(*addr);
// verify
if(!str)
return false;
if(strcmp(str, compare) == 0)
return true;
return false;
}
bool findStrBuffer (SegmentedFinder* s, uint32_t *addr, const char * compare )
{
if(memcmp((const char *)addr, compare, strlen(compare)) == 0)
return true;
return false;
}
#endif // SEGMENTED_FINDER_H

@ -1,30 +0,0 @@
Notes by PeridexisErrant, on the needs_porting scripts and plugins:
I deleted:
attachtest.py obsolete
digger.cpp less useful than digger2, replaced by autochop
digger2.cpp replaced by digfort
dfstatus.cpp replaced by dfstatus.lua
drawtile.cpp replaced by tiletypes
fix-3708.cpp obsolete, bug fixed in vanilla
lair.cpp replaced by lair
reveal.py replaced by reveal
treedump.py replaced by prospect & autochop
veinlook.cpp replaced by prospect
veinswap.cpp replaced by changevein
To investigate further:
creaturemanager.cpp modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere
digpattern.cpp allows multi-Z designations. Obsolete, or is there more here?
incrementalsearch.cpp linux-only memory stuff; unqualified to judge
SegementedFinder.h more memory stuff
To port:
copypaste.cpp high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions
dfbauxtite.cpp changes material of mechanisms to bauxtite (ie magma-safe)
hellhole.cpp instantly creates a hole to the HFS
hotkeynotedump.py outputs a list of hotkeys and names; most useful before keybindings were possible. Trival to port but low value.
itemdesignator.cpp mostly replaced by Falconne's enhanced stocks, but could port the interesting 'set fire to things' function
position.py outputs very detailed time& place info

@ -1,479 +0,0 @@
// Console version of DF copy paste, proof of concept
// By belal
#include <iostream>
#include <iomanip>
#include <climits>
#include <vector>
#include <sstream>
#include <ctime>
#include <cstdio>
#include <fstream>
#define DFHACK_WANT_MISCUTILS
#define DFHACK_WANT_TILETYPES
#include <DFHack.h>
#include "modules/WindowIO.h"
using namespace DFHack;
//bool waitTillCursorState(DFHack::Context *DF, bool On);
//bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z);
//change this if you are having problems getting correct results, lower if you would like to go faster
//const int WAIT_AMT = 25;
void sort(uint32_t &a,uint32_t &b)
{
if(a > b){
uint32_t c = b;
b = a;
a = c;
}
}
void sort(int32_t &a,int32_t &b)
{
if(a > b){
int16_t c = b;
b = a;
a = c;
}
}
void printVecOfVec(ostream &out, vector<vector<vector<string> > >vec,char sep)
{
for(size_t k=0;k<vec.size();k++)
{
for(size_t i =0;i<vec[k].size();i++)
{
for(size_t j=0;j<vec[k][i].size();j++)
{
out << vec[k][i][j];
if(j==vec[k][i].size()-1)
{
out << "\n";
}
else
{
out << sep;
}
}
}
out << "#<\n";
}
}
int main (int numargs, const char ** args)
{
map<string, string> buildCommands;
buildCommands["building_stockpilest"]="";
buildCommands["building_zonest"]="";
buildCommands["building_construction_blueprintst"]="";
buildCommands["building_wagonst"]="";
buildCommands["building_armor_standst"]="a";
buildCommands["building_bedst"]="b";
buildCommands["building_seatst"]="c";
buildCommands["building_burial_receptaclest"]="n";
buildCommands["building_doorst"]="d";
buildCommands["building_floodgatest"]="x";
buildCommands["building_floor_hatchst"]="H";
buildCommands["building_wall_gratest"]="W";
buildCommands["building_floor_gratest"]="G";
buildCommands["building_vertical_barsst"]="B";
buildCommands["building_floor_barsst"]="alt-b";
buildCommands["building_cabinetst"]="f";
buildCommands["building_containerst"]="h";
buildCommands["building_shopst"]="";
buildCommands["building_workshopst"]="";
buildCommands["building_alchemists_laboratoryst"]="wa";
buildCommands["building_carpenters_workshopst"]="wc";
buildCommands["building_farmers_workshopst"]="ww";
buildCommands["building_masons_workshopst"]="wm";
buildCommands["building_craftdwarfs_workshopst"]="wr";
buildCommands["building_jewelers_workshopst"]="wj";
buildCommands["building_metalsmiths_workshopst"]="wf";
buildCommands["building_magma_forgest"]="";
buildCommands["building_bowyers_workshopst"]="wb";
buildCommands["building_mechanics_workshopst"]="wt";
buildCommands["building_siege_workshopst"]="ws";
buildCommands["building_butchers_shopst"]="wU";
buildCommands["building_leather_worksst"]="we";
buildCommands["building_tanners_shopst"]="wn";
buildCommands["building_clothiers_shopst"]="wk";
buildCommands["building_fisheryst"]="wh";
buildCommands["building_stillst"]="wl";
buildCommands["building_loomst"]="wo";
buildCommands["building_quernst"]="wq";
buildCommands["building_kennelsst"]="k";
buildCommands["building_kitchenst"]="wz";
buildCommands["building_asheryst"]="wy";
buildCommands["building_dyers_shopst"]="wd";
buildCommands["building_millstonest"]="wM";
buildCommands["building_farm_plotst"]="p";
buildCommands["building_weapon_rackst"]="r";
buildCommands["building_statuest"]="s";
buildCommands["building_tablest"]="t";
buildCommands["building_paved_roadst"]="o";
buildCommands["building_bridgest"]="g";
buildCommands["building_wellst"]="l";
buildCommands["building_siege enginest"]="i";
buildCommands["building_catapultst"]="ic";
buildCommands["building_ballistast"]="ib";
buildCommands["building_furnacest"]="";
buildCommands["building_wood_furnacest"]="ew";
buildCommands["building_smelterst"]="es";
buildCommands["building_glass_furnacest"]="ek";
buildCommands["building_kilnst"]="ek";
buildCommands["building_magma_smelterst"]="es";
buildCommands["building_magma_glass_furnacest"]="ek";
buildCommands["building_magma_kilnst"]="ek";
buildCommands["building_glass_windowst"]="y";
buildCommands["building_gem_windowst"]="Y";
buildCommands["building_tradedepotst"]="D";
buildCommands["building_mechanismst"]="";
buildCommands["building_leverst"]="Tl";
buildCommands["building_pressure_platest"]="Tp";
buildCommands["building_cage_trapst"]="Tc";
buildCommands["building_stonefall_trapst"]="Ts";
buildCommands["building_weapon_trapst"]="Tw";
buildCommands["building_spikest"]="";
buildCommands["building_animal_trapst"]="m";
buildCommands["building_screw_pumpst"]="Ms";
buildCommands["building_water_wheelst"]="Mw";
buildCommands["building_windmillst"]="Mm";
buildCommands["building_gear_assemblyst"]="Mg";
buildCommands["building_horizontal_axlest"]="Mh";
buildCommands["building_vertical_axlest"]="Mv";
buildCommands["building_supportst"]="S";
buildCommands["building_cagest"]="j";
buildCommands["building_archery_targetst"]="A";
buildCommands["building_restraintst"]="v";
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context *DF = DFMgr.getSingleContext();
try
{
DF->Attach();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Gui *Gui = DF->getGui();
DFHack::VersionInfo* mem = DF->getMemoryInfo();
DFHack::Process * p = DF->getProcess();
OffsetGroup * OG_Maps = mem->getGroup("Maps");
OffsetGroup * OG_MapBlock = OG_Maps->getGroup("block");
OffsetGroup * OG_LocalFt = OG_Maps->getGroup("features")->getGroup("local");
uint32_t designations = OG_MapBlock->getOffset("designation");
uint32_t block_feature1 = OG_MapBlock->getOffset("feature_local");
uint32_t block_feature2 = OG_MapBlock->getOffset("feature_global");
uint32_t region_x_offset = OG_Maps->getAddress("region_x");
uint32_t region_y_offset = OG_Maps->getAddress("region_y");
uint32_t region_z_offset = OG_Maps->getAddress("region_z");
uint32_t feature1_start_ptr = OG_LocalFt->getAddress("start_ptr");
int32_t regionX, regionY, regionZ;
// read position of the region inside DF world
p->readDWord (region_x_offset, (uint32_t &)regionX);
p->readDWord (region_y_offset, (uint32_t &)regionY);
p->readDWord (region_z_offset, (uint32_t &)regionZ);
while(1){
int32_t cx1,cy1,cz1;
cx1 = -30000;
while(cx1 == -30000)
{
DF->ForceResume();
cout << "Set cursor at first position, then press any key";
cin.ignore();
DF->Suspend();
Gui->getCursorCoords(cx1,cy1,cz1);
}
uint32_t tx1,ty1,tz1;
tx1 = cx1/16;
ty1 = cy1/16;
tz1 = cz1;
int32_t cx2,cy2,cz2;
cx2 = -30000;
while(cx2 == -30000)
{
DF->Resume();
cout << "Set cursor at second position, then press any key";
cin.ignore();
DF->Suspend();
Gui->getCursorCoords(cx2,cy2,cz2);
}
uint32_t tx2,ty2,tz2;
tx2 = cx2/16;
ty2 = cy2/16;
tz2 = cz2;
sort(tx1,tx2);
sort(ty1,ty2);
sort(tz1,tz2);
sort(cx1,cx2);
sort(cy1,cy2);
sort(cz1,cz2);
vector <vector<vector<string> > >dig(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
vector <vector<vector<string> > >build(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
mapblock40d block;
DFHack::Maps *Maps = DF->getMaps();
Maps->Start();
for(uint32_t y = ty1;y<=ty2;y++)
{
for(uint32_t x = tx1;x<=tx2;x++)
{
for(uint32_t z = tz1;z<=tz2;z++)
{
if(Maps->isValidBlock(x,y,z))
{
if(Maps->ReadBlock40d(x,y,z,&block))
{
int ystart,yend,xstart,xend;
ystart=xstart=0;
yend=xend=15;
if(y == ty2)
{
yend = cy2 % 16;
}
if(y == ty1)
{
ystart = cy1 % 16;
}
if(x == tx2)
{
xend = cx2 % 16;
}
if(x == tx1)
{
xstart = cx1 % 16;
}
int zidx = z-tz1;
for(int yy = ystart; yy <= yend;yy++)
{
int yidx = yy+(16*(y-ty1)-(cy1%16));
for(int xx = xstart; xx <= xend;xx++)
{
int xidx = xx+(16*(x-tx1)-(cx1%16));
int16_t tt = block.tiletypes[xx][yy];
DFHack::TileShape ts = DFHack::tileShape(tt);
if(DFHack::isOpenTerrain(tt) || DFHack::isFloorTerrain(tt))
{
dig[zidx][yidx][xidx] = "d";
}
else if(DFHack::STAIR_DOWN == ts)
{
dig [zidx][yidx][xidx] = "j";
build [zidx][yidx][xidx] = "Cd";
}
else if(DFHack::STAIR_UP == ts)
{
dig [zidx][yidx][xidx] = "u";
build [zidx][yidx][xidx] = "Cu";
}
else if(DFHack::STAIR_UPDOWN == ts)
{
dig [zidx][yidx][xidx] = "i";
build [zidx][yidx][xidx] = "Cx";
}
else if(DFHack::isRampTerrain(tt))
{
dig [zidx][yidx][xidx] = "r";
build [zidx][yidx][xidx] = "Cr";
}
else if(DFHack::isWallTerrain(tt))
{
build [zidx][yidx][xidx] = "Cw";
}
}
yidx++;
}
}
}
}
}
}
DFHack::Buildings * Bld = DF->getBuildings();
std::map <uint32_t, std::string> custom_workshop_types;
uint32_t numBuildings;
if(Bld->Start(numBuildings))
{
Bld->ReadCustomWorkshopTypes(custom_workshop_types);
for(uint32_t i = 0; i < numBuildings; i++)
{
DFHack::t_building temp;
Bld->Read(i, temp);
if(temp.type != 0xFFFFFFFF) // check if type isn't invalid
{
std::string typestr;
mem->resolveClassIDToClassname(temp.type, typestr);
if(temp.z == cz1 && cx1 <= temp.x1 && cx2 >= temp.x2 && cy1 <= temp.y1 && cy2 >= temp.y2)
{
string currStr = build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1];
stringstream stream;
string newStr = buildCommands[typestr];
if(temp.x1 != temp.x2)
{
stream << "(" << temp.x2-temp.x1+1 << "x" << temp.y2-temp.y1+1 << ")";
newStr += stream.str();
}
build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1] = newStr + currStr;
}
}
}
}
// for testing purposes
//ofstream outfile("test.txt");
// printVecOfVec(outfile, dig,'\t');
// outfile << endl;
// printVecOfVec(outfile, build,'\t');
// outfile << endl;
// outfile.close();
int32_t cx3,cy3,cz3,cx4,cy4,cz4;
uint32_t tx3,ty3,tz3,tx4,ty4,tz4;
char result;
while(1){
cx3 = -30000;
while(cx3 == -30000){
DF->Resume();
cout << "Set cursor at new position, then press any key:";
result = cin.get();
DF->Suspend();
Gui->getCursorCoords(cx3,cy3,cz3);
}
if(result == 'q'){
break;
}
cx4 = cx3+cx2-cx1;
cy4 = cy3+cy2-cy1;
cz4 = cz3+cz2-cz1;
tx3=cx3/16;
ty3=cy3/16;
tz3=cz3;
tx4=cx4/16;
ty4=cy4/16;
tz4=cz4;
DFHack::WindowIO * Win = DF->getWindowIO();
designations40d designationBlock;
for(uint32_t y = ty3;y<=ty4;y++)
{
for(uint32_t x = tx3;x<=tx4;x++)
{
for(uint32_t z = tz3;z<=tz4;z++)
{
Maps->Start();
Maps->ReadBlock40d(x,y,z,&block);
Maps->ReadDesignations(x,y,z,&designationBlock);
int ystart,yend,xstart,xend;
ystart=xstart=0;
yend=xend=15;
if(y == ty4){
yend = cy4 % 16;
}
if(y == ty3){
ystart = cy3 % 16;
}
if(x == tx4){
xend = cx4 % 16;
}
if(x == tx3){
xstart = cx3 % 16;
}
int zidx = z-tz3;
for(int yy = ystart; yy <= yend;yy++){
int yidx = yy+(16*(y-ty3)-(cy3%16));
for(int xx = xstart; xx <= xend;xx++){
int xidx = xx+(16*(x-tx3)-(cx3%16));
if(dig[zidx][yidx][xidx] != ""){
char test = dig[zidx][yidx][xidx].c_str()[0];
switch (test){
case 'd':
designationBlock[xx][yy].bits.dig = DFHack::designation_default;
break;
case 'i':
designationBlock[xx][yy].bits.dig = DFHack::designation_ud_stair;
break;
case 'u':
designationBlock[xx][yy].bits.dig = DFHack::designation_u_stair;
break;
case 'j':
designationBlock[xx][yy].bits.dig = DFHack::designation_d_stair;
break;
case 'r':
designationBlock[xx][yy].bits.dig = DFHack::designation_ramp;
break;
}
}
}
yidx++;
}
Maps->Start();
Maps->WriteDesignations(x,y,z,&designationBlock);
}
}
}
}
}
DF->Detach();
#ifndef LINUX_BUILD
std::cout << "Done. Press any key to continue" << std::endl;
cin.ignore();
#endif
return 0;
}
/*
bool waitTillCursorState(DFHack::Context *DF, bool On)
{
DFHack::WindowIO * w = DF->getWindowIO();
DFHack::Position * p = DF->getPosition();
int32_t x,y,z;
int tryCount = 0;
DF->Suspend();
bool cursorResult = p->getCursorCoords(x,y,z);
while(tryCount < 50 && On && !cursorResult || !On && cursorResult)
{
DF->Resume();
w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
tryCount++;
DF->Suspend();
cursorResult = p->getCursorCoords(x,y,z);
}
if(tryCount >= 50)
{
cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl;
return false;
}
DF->Resume();
return true;
}
bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z)
{
DFHack::WindowIO * w = DF->getWindowIO();
DFHack::Position * p = DF->getPosition();
int32_t x2,y2,z2;
int tryCount = 0;
DF->Suspend();
bool cursorResult = p->getCursorCoords(x2,y2,z2);
while(tryCount < 50 && (x != x2 || y != y2 || z != z2))
{
DF->Resume();
w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
tryCount++;
DF->Suspend();
cursorResult = p->getCursorCoords(x2,y2,z2);
}
if(tryCount >= 50)
{
cerr << "Something went wrong, cursor at x: " << x2 << " y: " << y2 << " z: " << z2 << endl;
return false;
}
DF->Resume();
return true;
}*/

File diff suppressed because it is too large Load Diff

@ -1,161 +0,0 @@
/*
DFBauxite - Converts all your mechanisms to bauxite (for use in magma).
Author: Alex Legg
Based on code from and uses DFHack - www.sourceforge.net/projects/dfhack
*/
#include <sstream>
#include <iostream>
#include <string.h>
#include <cstdlib>
#include <assert.h>
#include <string>
#include <vector>
using namespace std;
#include <DFIntegers.h>
#include <DFExport.h>
#include <DFError.h>
#include <DFVector.h>
#include <DFMemInfo.h>
#include <DFProcess.h>
#include <DFTypes.h>
using namespace DFHack;
int main ()
{
DFHack::Process *proc;
DFHack::memory_info *meminfo;
DFHack::DfVector <uint32_t> *items_vector;
DFHack::t_item_df40d item_40d;
DFHack::t_matglossPair item_40d_material;
vector<DFHack::t_matgloss> stoneMat;
uint32_t item_material_offset;
uint32_t temp;
int32_t type;
int items;
int found = 0, converted = 0;
DFHack::ContextManager DF("Memory.xml");
try
{
DF.Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
// Find out which material is bauxite
if(!DF.ReadStoneMatgloss(stoneMat))
{
cout << "Materials not supported for this version of DF, exiting." << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
DF.Detach();
return EXIT_FAILURE;
}
int bauxiteIndex = -1;
for (int i = 0; i < stoneMat.size();i++)
{
if(strcmp(stoneMat[i].id, "BAUXITE") == 0)
{
bauxiteIndex = i;
break;
}
}
if(bauxiteIndex == -1)
{
cout << "Cannot locate bauxite in the DF raws, exiting" << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
DF.Detach();
return EXIT_FAILURE;
}
// Get some basics needed for full access
proc = DF.getProcess();
meminfo = proc->getDescriptor();
// Get the object name/ID mapping
//FIXME: work on the 'supported features' system required
// Check availability of required addresses and offsets (doing custom stuff here)
items = meminfo->getAddress("items");
item_material_offset = meminfo->getOffset("item_materials");
if( !items || ! item_material_offset)
{
cout << "Items not supported for this DF version, exiting" << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
DF.Detach();
return EXIT_FAILURE;
}
items_vector = new DFHack::DfVector <uint32_t> (proc, items);
for(uint32_t i = 0; i < items_vector->size(); i++)
{
// get pointer to object
temp = items_vector->at (i);
// read object
proc->read (temp, sizeof (DFHack::t_item_df40d), (uint8_t *) &item_40d);
// resolve object type
type = -1;
// skip things we can't identify
if(!meminfo->resolveObjectToClassID (temp, type))
continue;
string classname;
if(!meminfo->resolveClassIDToClassname (type, classname))
continue;
if(classname == "item_trapparts")
{
proc->read (temp + item_material_offset, sizeof (DFHack::t_matglossPair), (uint8_t *) &item_40d_material);
cout << dec << "Mechanism at x:" << item_40d.x << " y:" << item_40d.y << " z:" << item_40d.z << " ID:" << item_40d.ID << endl;
if (item_40d_material.index != bauxiteIndex)
{
item_40d_material.index = bauxiteIndex;
proc->write (temp + item_material_offset, sizeof (DFHack::t_matglossPair), (uint8_t *) &item_40d_material);
converted++;
}
found++;
}
}
if (found == 0)
{
cout << "No mechanisms to convert" << endl;
} else {
cout << found << " mechanisms found" << endl;
cout << converted << " mechanisms converted" << endl;
}
DF.Resume();
DF.Detach();
delete items_vector;
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -1,259 +0,0 @@
#include <iostream>
#include <string.h> // for memset
#include <string>
#include <vector>
#include <stack>
#include <map>
#include <stdio.h>
#include <cstdlib>
using namespace std;
#include <DFHack.h>
#include <extra/MapExtras.h>
using namespace MapExtras;
//#include <argstream.h>
void usage(int argc, const char * argv[])
{
cout
<< "Usage:" << endl
<< argv[0] << " [option 1] [option 2] [...]" << endl
<< "-q : Suppress \"Press any key to continue\" at program termination" << endl
<< "-u <n> : Dig upwards <n> times (default 5)" << endl
<< "-d <n> : Dig downwards <n> times (default 5)" << endl
;
}
void digat(MapCache * MCache, DFHack::DFCoord xy)
{
int16_t tt;
tt = MCache->tiletypeAt(xy);
if(!DFHack::isWallTerrain(tt))
return;
// found a good tile, dig+unset material
DFHack::t_designation des = MCache->designationAt(xy);
if(MCache->testCoord(xy))
{
MCache->clearMaterialAt(xy);
if(des.bits.dig == DFHack::designation_no)
des.bits.dig = DFHack::designation_default;
MCache->setDesignationAt(xy,des);
}
}
int strtoint(const string &str)
{
stringstream ss(str);
int result;
return ss >> result ? result : -1;
}
typedef struct
{
int16_t x;
int16_t y;
} pos;
int main (int argc, const char* argv[])
{
// Command line options
bool updown = false;
bool quiet = true;
// let's be more useful when double-clicked on windows
#ifndef LINUX_BUILD
quiet = false;
#endif
int dig_up_n = 5;
int dig_down_n = 5;
for(int i = 1; i < argc; i++)
{
string arg_cur = argv[i];
string arg_next = "";
int arg_next_int = -99999;
/* Check if argv[i+1] is a number >= 0 */
if (i < argc-1) {
arg_next = argv[i+1];
arg_next_int = strtoint(arg_next);
if (arg_next != "0" && arg_next_int == 0) {
arg_next_int = -99999;
}
}
if (arg_cur == "-x")
{
updown = true;
}
else if (arg_cur == "-q")
{
quiet = true;
}
else if(arg_cur == "-u" && i < argc-1)
{
if (arg_next_int < 0 || arg_next_int >= 99999) {
usage(argc, argv);
return 1;
}
dig_up_n = arg_next_int;
i++;
}
else if(arg_cur == "-d" && i < argc-1)
{
if (arg_next_int < 0 || arg_next_int >= 99999) {
usage(argc, argv);
return 1;
}
dig_down_n = arg_next_int;
i++;
}
else
{
usage(argc, argv);
return 1;
}
}
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF;
try
{
DF = DFMgr.getSingleContext();
DF->Attach();
}
catch (exception& e)
{
cerr << "Error getting context: " << e.what() << endl;
if (!quiet)
cin.ignore();
return 1;
}
uint32_t x_max,y_max,z_max;
DFHack::Maps * Maps = DF->getMaps();
DFHack::Gui * Gui = DF->getGui();
// init the map
if(!Maps->Start())
{
cerr << "Can't init map. Make sure you have a map loaded in DF." << endl;
DF->Detach();
if (!quiet)
cin.ignore();
return 1;
}
int32_t cx, cy, cz;
Maps->getSize(x_max,y_max,z_max);
uint32_t tx_max = x_max * 16;
uint32_t ty_max = y_max * 16;
Gui->getCursorCoords(cx,cy,cz);
if (cx == -30000)
{
cerr << "Cursor is not active. Point the cursor at the position to dig at." << endl;
DF->Detach();
if (!quiet)
{
cin.ignore();
}
return 1;
}
DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz);
if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1)
{
cerr << "I won't dig the borders. That would be cheating!" << endl;
DF->Detach();
if (!quiet)
{
cin.ignore();
}
return 1;
}
MapCache * MCache = new MapCache(Maps);
DFHack::t_designation des = MCache->designationAt(xy);
int16_t tt = MCache->tiletypeAt(xy);
int16_t veinmat = MCache->veinMaterialAt(xy);
/*
if( veinmat == -1 )
{
cerr << "This tile is non-vein. Bye :)" << endl;
delete MCache;
DF->Detach();
if (!quiet) {
cin.ignore();
}
return 1;
}
*/
printf("Digging at (%d/%d/%d), tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole);
// 1 < xy.x < tx_max - 1
// 1 < xy.y < ty_max - 1
// xy.z
// X____
// X_XXX
// XXXXX
// __XXX
// __XXX
// _____
pos map[] =
{
{ 0,0 }
, { 0,1 }
, { 0,2 } , { 2,2 }, { 3,2 }, { 4,2 }
, { 0,3 }, { 1,3 }, { 2,3 }, { 3,3 }, { 4,3 }
, { 2,4 }, { 3,4 }, { 4,4 }
// this is mirrored, goes left instead of right
, {-2,2 }, {-3,2 }, {-4,2 }
, {-1,3 }, {-2,3 }, {-3,3 }, {-4,3 }
, {-2,4 }, {-3,4 }, {-4,4 }
};
DFHack::DFCoord npos = xy;
if (dig_up_n > 0)
{
for (int j = 0; j < dig_up_n; j++)
{
for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++)
{
npos=xy;
npos.x += map[i].x;
npos.y -= 4*j + map[i].y;
printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z);
digat(MCache, npos);
}
}
}
if (dig_down_n > 0)
{
for (int j = 0; j < dig_down_n; j++)
{
for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++)
{
npos=xy;
npos.x += map[i].x;
npos.y += 4*j + map[i].y;
printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z);
digat(MCache, npos);
}
}
}
MCache->WriteAll();
delete MCache;
DF->Detach();
if (!quiet) {
cout << "Done. Press any key to continue" << endl;
cin.ignore();
}
return 0;
}

File diff suppressed because it is too large Load Diff

@ -1,20 +0,0 @@
from context import Context, ContextManager
cm = ContextManager("Memory.xml")
df = cm.get_single_context()
df.attach()
gui = df.gui
print "Hotkeys"
hotkeys = gui.read_hotkeys()
for key in hotkeys:
print "x: %d\ny: %d\tz: %d\ttext: %s" % (key.x, key.y, key.z, key.name)
df.detach()
print "Done. Press any key to continue"
raw_input()

File diff suppressed because it is too large Load Diff

@ -1,148 +0,0 @@
// Item designator
#include <iostream>
#include <iomanip>
#include <sstream>
#include <climits>
#include <vector>
using namespace std;
#include <DFHack.h>
#include <DFVector.h>
using namespace DFHack;
int main ()
{
DFHack::ContextManager CM ("Memory.xml");
DFHack::Context * DF;
DFHack::VersionInfo *mem;
DFHack::Gui * Gui;
DFHack::Materials * Mats;
DFHack::Items * Items;
cout << "This utility lets you mass-designate items by type and material." << endl
<< "Like set on fire all MICROCLINE item_stone..." << endl
<< "Some unusual combinations might be untested and cause the program to crash..."<< endl
<< "so, watch your step and backup your fort" << endl;
try
{
DF = CM.getSingleContext();
DF->Attach();
mem = DF->getMemoryInfo();
Gui = DF->getGui();
Mats = DF->getMaterials();
Mats->ReadAllMaterials();
Items = DF->getItems();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Process * p = DF->getProcess();
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
unsigned vector_addr = itemGroup->getAddress("items_vector");
DFHack::DfVector <uint32_t> p_items (p, vector_addr);
uint32_t numItems = p_items.size();
map< string, map<string,vector< dfh_item > > > itemmap;
map< string, map< string, vector< dfh_item > > >::iterator it1;
int failedItems = 0;
map <string, int > bad_mat_items;
for(uint32_t i=0; i< numItems; i++)
{
DFHack::dfh_item temp;
Items->readItem(p_items[i],temp);
string typestr = Items->getItemClass(temp);
string material = Mats->getDescription(temp.matdesc);
itemmap[typestr][material].push_back(temp);
}
int i =0;
for( it1 = itemmap.begin(); it1!=itemmap.end();it1++)
{
cout << i << ": " << it1->first << "\n";
i++;
}
if(i == 0)
{
cout << "No items found" << endl;
DF->Detach();
return 0;
}
cout << endl << "Select an item type from the list:";
int number;
string in;
stringstream ss;
getline(cin, in);
ss.str(in);
ss >> number;
int j = 0;
it1 = itemmap.begin();
while(j < number && it1!=itemmap.end())
{
it1++;
j++;
}
cout << it1->first << "\n";
map<string,vector<dfh_item> >::iterator it2;
i=0;
for(it2 = it1->second.begin();it2!=it1->second.end();it2++){
cout << i << ":\t" << it2->first << " [" << it2->second.size() << "]" << endl;
i++;
}
cout << endl << "Select a material type: ";
int number2;
ss.clear();
getline(cin, in);
ss.str(in);
ss >> number2;
decideAgain:
cout << "Select a designation - (d)ump, (f)orbid, (m)melt, set on fi(r)e :" << flush;
string designationType;
getline(cin,designationType);
DFHack::t_itemflags changeFlag = {0};
if(designationType == "d" || designationType == "dump")
{
changeFlag.dump = 1;
}
else if(designationType == "f" || designationType == "forbid")
{
changeFlag.forbid = 1;
}
else if(designationType == "m" || designationType == "melt")
{
changeFlag.melt = 1;
}
else if(designationType == "r" || designationType == "fire")
{
changeFlag.on_fire = 1;
}
else
{
goto decideAgain;
}
j=0;
it2= it1->second.begin();
while(j < number2 && it2!=it1->second.end())
{
it2++;
j++;
}
for(uint32_t k = 0;k< it2->second.size();k++)
{
DFHack::dfh_item & t = it2->second[k];
t.base.flags.whole |= changeFlag.whole;
Items->writeItem(t);
}
DF->Detach();
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}

@ -1,71 +0,0 @@
import sys
from pydfhack import ContextManager
df_cm = ContextManager("Memory.xml")
df = df_cm.get_single_context()
if not df.attach():
print "Unable to attach!"
print "Press any key to continue"
raw_input()
sys.exit(1)
gui = df.gui
if gui is not None:
maps = df.maps
world = df.world
have_maps = maps.start()
world.start()
gm = world.read_game_mode()
if gm is not None:
print gm
date_tuple = (world.read_current_year(), world.read_current_month(), world.read_current_day(), world.read_current_tick())
print "Year: %d Month: %d Day: %d Tick: %d" % date_tuple
v_coords = gui.get_view_coords()
c_coords = gui.get_cursor_coords()
w_coords = (-1, -1, -1)
world_pos_string = ""
if have_maps is True:
w_coords = maps.getPosition()
x = (v_coords[0] + w_coords[0]) * 48
y = (v_coords[1] + w_coords[1]) * 48
z = (v_coords[2] + w_coords[2])
world_pos_string = " world: %d/%d/%d" % (x, y, z)
print "Map world offset: %d/%d/%d embark squares" % w_coords
if v_coords != (-1, -1, -1):
print "view coords: %d/%d/%d" % v_coords
if have_maps is True:
print world_pos_string
if c_coords != (-1, -1, -1):
print "cursor coords: %d/%d/%d" % c_coords
if have_maps is True:
print world_pos_string
window_size = gui.get_window_size()
if window_size != (-1, -1):
print "window size : %d %d" % window_size
else:
print "cursor and window parameters are unsupported on your version of DF"
if not df.detach():
print "Unable to detach!"
print "Done. Press any key to continue"
raw_input()

@ -0,0 +1 @@
libstdc++.6.dylib

@ -1,5 +1,6 @@
#!/bin/sh
PWD=`dirname "${0}"`
cd "${PWD}"
#thanks to Iriel for figuring this out
OSREV=`uname -r | cut -d. -f1`
if [ "$OSREV" -ge 11 ] ; then
@ -11,7 +12,6 @@ else
fi
old_tty_settings=$(stty -g)
cd "${PWD}"
DYLD_INSERT_LIBRARIES=./hack/libdfhack.dylib ./dwarfort.exe "$@" 2>&1 | tee dfhack.log
DYLD_INSERT_LIBRARIES=./hack/libdfhack.dylib ./dwarfort.exe "$@"
stty "$old_tty_settings"
echo ""

@ -65,7 +65,7 @@ case "$1" in
ret=$?
;;
*)
setarch i386 -R env LD_PRELOAD=$PRELOAD_LIB ./libs/Dwarf_Fortress "$@" 2>&1 | tee dfhack.log
setarch i386 -R env LD_PRELOAD=$PRELOAD_LIB ./libs/Dwarf_Fortress "$@"
ret=$?
;;
esac

@ -41,13 +41,12 @@ using namespace DFHack;
using namespace MapExtras;
using namespace DFHack::Random;
using df::global::world;
using df::global::gametype;
DFHACK_PLUGIN("3dveins");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(gametype);
command_result cmd_3dveins(color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("3dveins");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -91,9 +91,10 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(automaterial automaterial.cpp)
DFHACK_PLUGIN(automelt automelt.cpp)
DFHACK_PLUGIN(autotrade autotrade.cpp)
DFHACK_PLUGIN(blueprint blueprint.cpp)
DFHACK_PLUGIN(burrows burrows.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(building-hacks building-hacks.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(buildingplan buildingplan.cpp)
DFHACK_PLUGIN(buildingplan buildingplan-lib.cpp buildingplan.cpp)
DFHACK_PLUGIN(catsplosion catsplosion.cpp)
DFHACK_PLUGIN(changeitem changeitem.cpp)
DFHACK_PLUGIN(changelayer changelayer.cpp)
@ -122,6 +123,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(flows flows.cpp)
DFHACK_PLUGIN(follow follow.cpp)
DFHACK_PLUGIN(forceequip forceequip.cpp)
DFHACK_PLUGIN(fortplan buildingplan-lib.cpp fortplan.cpp)
DFHACK_PLUGIN(getplants getplants.cpp)
DFHACK_PLUGIN(hotkeys hotkeys.cpp)
DFHACK_PLUGIN(infiniteSky infiniteSky.cpp)
@ -152,7 +154,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(sort sort.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(steam-engine steam-engine.cpp)
DFHACK_PLUGIN(stockflow stockflow.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(stockpiles stockpiles.cpp PROTOBUFS stockpiles)
add_subdirectory(stockpiles)
DFHACK_PLUGIN(stocks stocks.cpp)
DFHACK_PLUGIN(strangemood strangemood.cpp)
DFHACK_PLUGIN(tiletypes tiletypes.cpp Brushes.h)

@ -41,14 +41,13 @@ using std::stack;
using namespace DFHack;
using namespace df::enums;
using df::global::gps;
using df::global::world;
using df::global::ui;
typedef df::reaction_product_item_improvementst improvement_product;
DFHACK_PLUGIN("add-spatter");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
typedef df::reaction_product_item_improvementst improvement_product;
struct ReagentSource {
int idx;

@ -37,14 +37,15 @@
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui_advmode;
using df::nemesis_record;
using df::historical_figure;
using namespace DFHack::Translation;
DFHACK_PLUGIN("advtools");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui_advmode);
/*********************
* PLUGIN INTERFACE *
*********************/
@ -54,8 +55,6 @@ static bool bodyswap_hotkey(df::viewscreen *top);
command_result adv_bodyswap (color_ostream &out, std::vector <std::string> & parameters);
command_result adv_tools (color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("advtools");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
if (!ui_advmode)

@ -36,12 +36,10 @@ using std::set;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui;
#define PLUGIN_VERSION 0.3
DFHACK_PLUGIN("autochop");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
static bool autochop_enabled = false;
static int min_logs, max_logs;

@ -34,10 +34,10 @@ using namespace df::enums;
using MapExtras::Block;
using MapExtras::MapCache;
using df::global::world;
using df::building_stockpilest;
DFHACK_PLUGIN("autodump");
REQUIRE_GLOBAL(world);
// Stockpile interface START
static const string PERSISTENCE_KEY = "autodump/stockpiles";

@ -44,8 +44,10 @@ using std::endl;
using std::vector;
using namespace DFHack;
using namespace df::enums;
using df::global::ui;
using df::global::world;
DFHACK_PLUGIN("autolabor");
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(world);
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
@ -91,10 +93,6 @@ enum ConfigFlags {
// mostly to allow having the mandatory stuff on top of the file and commands on the bottom
command_result autolabor (color_ostream &out, std::vector <std::string> & parameters);
// A plugin must be able to return its name and version.
// The name string provided must correspond to the filename - autolabor.plug.so or autolabor.plug.dll in this case
DFHACK_PLUGIN("autolabor");
static void generate_labor_to_skill_map();
enum labor_mode {
@ -477,7 +475,9 @@ static const struct labor_default default_labor_infos[] = {
/* PULL_LEVER */ {HAULERS, false, 1, 200, 0},
/* REMOVE_CONSTRUCTION */ {HAULERS, false, 1, 200, 0},
/* HAUL_WATER */ {HAULERS, false, 1, 200, 0},
/* GELD */ {AUTOMATIC, false, 1, 200, 0}
/* GELD */ {AUTOMATIC, false, 1, 200, 0},
/* BUILD_ROAD */ {AUTOMATIC, false, 1, 200, 0},
/* BUILD_CONSTRUCTION */ {AUTOMATIC, false, 1, 200, 0}
};
static const int responsibility_penalties[] = {

@ -43,11 +43,11 @@ using std::vector;
using namespace DFHack;
using namespace df::enums;
using df::global::gps;
using df::global::ui;
using df::global::ui_build_selector;
DFHACK_PLUGIN("automaterial");
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_build_selector);
struct MaterialDescriptor
{

@ -14,13 +14,13 @@
#include "modules/World.h"
#include "df/item_quality.h"
using df::global::world;
using df::global::cursor;
using df::global::ui;
using df::building_stockpilest;
DFHACK_PLUGIN("automelt");
#define PLUGIN_VERSION 0.3
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);
REQUIRE_GLOBAL(ui);
static const string PERSISTENCE_KEY = "automelt/stockpiles";

@ -19,12 +19,12 @@
#include "df/mandate.h"
#include "modules/Maps.h"
using df::global::world;
using df::global::cursor;
using df::global::ui;
using df::building_stockpilest;
DFHACK_PLUGIN("autotrade");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);
REQUIRE_GLOBAL(ui);
static const string PERSISTENCE_KEY = "autotrade/stockpiles";

@ -0,0 +1,682 @@
//Blueprint
//By cdombroski
//Translates a region of tiles specified by the cursor and arguments/prompts into a series of blueprint files suitable for digfort/buildingplan/quickfort
#include <Console.h>
#include <PluginManager.h>
#include "modules/Buildings.h"
#include "modules/Gui.h"
#include "modules/MapCache.h"
#include "df/building_axle_horizontalst.h"
#include "df/building_bridgest.h"
#include "df/building_constructionst.h"
#include "df/building_furnacest.h"
#include "df/building_rollersst.h"
#include "df/building_screw_pumpst.h"
#include "df/building_siegeenginest.h"
#include "df/building_trapst.h"
#include "df/building_water_wheelst.h"
#include "df/building_workshopst.h"
using std::string;
using std::endl;
using std::vector;
using std::ofstream;
using std::swap;
using std::find;
using std::pair;
using namespace DFHack;
using namespace df::enums;
DFHACK_PLUGIN("blueprint");
enum phase {DIG=1, BUILD=2, PLACE=4, QUERY=8};
command_result blueprint(color_ostream &out, vector <string> &parameters);
DFhackCExport command_result plugin_init(color_ostream &out, vector<PluginCommand> &commands)
{
commands.push_back(PluginCommand("blueprint", "Convert map tiles into a blueprint", blueprint, false));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown(color_ostream &out)
{
return CR_OK;
}
command_result help(color_ostream &out)
{
out << "blueprint width height depth name [dig] [build] [place] [query]" << endl
<< " width, height, depth: area to translate in tiles" << endl
<< " name: base name for blueprint files" << endl
<< " dig: generate blueprints for digging" << endl
<< " build: generate blueprints for building" << endl
<< " place: generate blueprints for stockpiles" << endl
<< " query: generate blueprints for querying (room designations)" << endl
<< " defaults to generating all blueprints" << endl
<< endl
<< "blueprint translates a portion of your fortress into blueprints suitable for" << endl
<< " digfort/fortplan/quickfort. Blueprints are created in the DF folder with names" << endl
<< " following a \"name-phase.csv\" pattern. Translation starts at the current" << endl
<< " cursor location and includes all tiles in the range specified." << endl;
return CR_OK;
}
pair<uint32_t, uint32_t> get_building_size(df::building* b)
{
return pair<uint32_t, uint32_t>(b->x2 - b->x1 + 1, b->y2 - b->y1 + 1);
}
char get_tile_dig(MapExtras::MapCache mc, int32_t x, int32_t y, int32_t z)
{
df::tiletype tt = mc.tiletypeAt(DFCoord(x, y, z));
df::tiletype_shape ts = tileShape(tt);
switch (ts)
{
case tiletype_shape::EMPTY:
case tiletype_shape::RAMP_TOP:
return 'h';
case tiletype_shape::FLOOR:
case tiletype_shape::BOULDER:
case tiletype_shape::PEBBLES:
case tiletype_shape::BROOK_TOP:
return 'd';
case tiletype_shape::FORTIFICATION:
return 'F';
case tiletype_shape::STAIR_UP:
return 'u';
case tiletype_shape::STAIR_DOWN:
return 'j';
case tiletype_shape::STAIR_UPDOWN:
return 'i';
case tiletype_shape::RAMP:
return 'r';
default:
return ' ';
}
}
string get_tile_build(uint32_t x, uint32_t y, df::building* b)
{
if (! b)
return " ";
bool at_nw_corner = x == b->x1 && y == b->y1;
bool at_se_corner = x == b->x2 && y == b->y2;
bool at_center = x == b->centerx && y == b->centery;
pair<uint32_t, uint32_t> size = get_building_size(b);
stringstream out;// = stringstream();
switch(b->getType())
{
case building_type::Armorstand:
return "a";
case building_type::Bed:
return "b";
case building_type::Chair:
return "c";
case building_type::Door:
return "d";
case building_type::Floodgate:
return "x";
case building_type::Cabinet:
return "f";
case building_type::Box:
return "h";
//case building_type::Kennel is missing
case building_type::FarmPlot:
if(!at_nw_corner)
return "`";
out << "p(" << size.first << "x" << size.second << ")";
return out.str();
case building_type::Weaponrack:
return "r";
case building_type::Statue:
return "s";
case building_type::Table:
return "t";
case building_type::RoadPaved:
if(! at_nw_corner)
return "`";
out << "o(" << size.first << "x" << size.second << ")";
return out.str();
case building_type::RoadDirt:
if(! at_nw_corner)
return "`";
out << "O(" << size.first << "x" << size.second << ")";
return out.str();
case building_type::Bridge:
if(! at_nw_corner)
return "`";
switch(((df::building_bridgest*) b)->direction)
{
case df::building_bridgest::T_direction::Down:
out << "gx";
break;
case df::building_bridgest::T_direction::Left:
out << "ga";
break;
case df::building_bridgest::T_direction::Up:
out << "gw";
break;
case df::building_bridgest::T_direction::Right:
out << "gd";
break;
case df::building_bridgest::T_direction::Retracting:
out << "gs";
break;
}
out << "(" << size.first << "x" << size.second << ")";
return out.str();
case building_type::Well:
return "l";
case building_type::SiegeEngine:
if (! at_center)
return "`";
return ((df::building_siegeenginest*) b)->type == df::siegeengine_type::Ballista ? "ib" : "ic";
case building_type::Workshop:
if (! at_center)
return "`";
switch (((df::building_workshopst*) b)->type)
{
case workshop_type::Leatherworks:
return "we";
case workshop_type::Quern:
return "wq";
case workshop_type::Millstone:
return "wM";
case workshop_type::Loom:
return "wo";
case workshop_type::Clothiers:
return "wk";
case workshop_type::Bowyers:
return "wb";
case workshop_type::Carpenters:
return "wc";
case workshop_type::MetalsmithsForge:
return "wf";
case workshop_type::MagmaForge:
return "wv";
case workshop_type::Jewelers:
return "wj";
case workshop_type::Masons:
return "wm";
case workshop_type::Butchers:
return "wu";
case workshop_type::Tanners:
return "wn";
case workshop_type::Craftsdwarfs:
return "wr";
case workshop_type::Siege:
return "ws";
case workshop_type::Mechanics:
return "wt";
case workshop_type::Still:
return "wl";
case workshop_type::Farmers:
return "ww";
case workshop_type::Kitchen:
return "wz";
case workshop_type::Fishery:
return "wh";
case workshop_type::Ashery:
return "wy";
case workshop_type::Dyers:
return "wd";
case workshop_type::Custom:
//can't do anything with custom workshop
return "`";
}
case building_type::Furnace:
if (! at_center)
return "`";
switch (((df::building_furnacest*) b)->type)
{
case furnace_type::WoodFurnace:
return "ew";
case furnace_type::Smelter:
return "es";
case furnace_type::GlassFurnace:
return "eg";
case furnace_type::Kiln:
return "ek";
case furnace_type::MagmaSmelter:
return "el";
case furnace_type::MagmaGlassFurnace:
return "ea";
case furnace_type::MagmaKiln:
return "en";
case furnace_type::Custom:
//can't do anything with custom furnace
return "`";
}
case building_type::WindowGlass:
return "y";
case building_type::WindowGem:
return "Y";
case building_type::Construction:
switch (((df::building_constructionst*) b)->type)
{
case construction_type::Fortification:
return "CF";
case construction_type::Wall:
return "CW";
case construction_type::Floor:
return "Cf";
case construction_type::UpStair:
return "Cu";
case construction_type::DownStair:
return "Cj";
case construction_type::UpDownStair:
return "Cx";
case construction_type::Ramp:
return "Cr";
case construction_type::TrackN:
return "trackN";
case construction_type::TrackS:
return "trackS";
case construction_type::TrackE:
return "trackE";
case construction_type::TrackW:
return "trackW";
case construction_type::TrackNS:
return "trackNS";
case construction_type::TrackNE:
return "trackNE";
case construction_type::TrackNW:
return "trackNW";
case construction_type::TrackSE:
return "trackSE";
case construction_type::TrackSW:
return "trackSW";
case construction_type::TrackEW:
return "trackEW";
case construction_type::TrackNSE:
return "trackNSE";
case construction_type::TrackNSW:
return "trackNSW";
case construction_type::TrackNEW:
return "trackNEW";
case construction_type::TrackSEW:
return "trackSEW";
case construction_type::TrackNSEW:
return "trackNSEW";
case construction_type::TrackRampN:
return "trackrampN";
case construction_type::TrackRampS:
return "trackrampS";
case construction_type::TrackRampE:
return "trackrampE";
case construction_type::TrackRampW:
return "trackrampW";
case construction_type::TrackRampNS:
return "trackrampNS";
case construction_type::TrackRampNE:
return "trackrampNE";
case construction_type::TrackRampNW:
return "trackrampNW";
case construction_type::TrackRampSE:
return "trackrampSE";
case construction_type::TrackRampSW:
return "trackrampSW";
case construction_type::TrackRampEW:
return "trackrampEW";
case construction_type::TrackRampNSE:
return "trackrampNSE";
case construction_type::TrackRampNSW:
return "trackrampNSW";
case construction_type::TrackRampNEW:
return "trackrampNEW";
case construction_type::TrackRampSEW:
return "trackrampSEW";
case construction_type::TrackRampNSEW:
return "trackrampNSEW";
}
case building_type::Shop:
if (! at_center)
return "`";
return "z";
case building_type::AnimalTrap:
return "m";
case building_type::Chain:
return "v";
case building_type::Cage:
return "j";
case building_type::TradeDepot:
if (! at_center)
return "`";
return "D";
case building_type::Trap:
switch (((df::building_trapst*) b)->trap_type)
{
case trap_type::StoneFallTrap:
return "Ts";
case trap_type::WeaponTrap:
return "Tw";
case trap_type::Lever:
return "Tl";
case trap_type::PressurePlate:
return "Tp";
case trap_type::CageTrap:
return "Tc";
case trap_type::TrackStop:
df::building_trapst* ts = (df::building_trapst*) b;
out << "CS";
if (ts->use_dump)
{
if (ts->dump_x_shift == 0)
{
if (ts->dump_y_shift > 0)
out << "dd";
else
out << "d";
}
else
{
if (ts->dump_x_shift > 0)
out << "ddd";
else
out << "dddd";
}
}
switch (ts->friction)
{
case 10:
out << "a";
case 50:
out << "a";
case 500:
out << "a";
case 10000:
out << "a";
}
return out.str();
}
case building_type::ScrewPump:
if (! at_se_corner) //screw pumps anchor at bottom/right
return "`";
switch (((df::building_screw_pumpst*) b)->direction)
{
case screw_pump_direction::FromNorth:
return "Msu";
case screw_pump_direction::FromEast:
return "Msk";
case screw_pump_direction::FromSouth:
return "Msm";
case screw_pump_direction::FromWest:
return "Msh";
}
case building_type::WaterWheel:
if (! at_center)
return "`";
//s swaps orientation which defaults to vertical
return ((df::building_water_wheelst*) b)->is_vertical ? "Mw" : "Mws";
case building_type::Windmill:
if (! at_center)
return "`";
return "Mm";
case building_type::GearAssembly:
return "Mg";
case building_type::AxleHorizontal:
if (! at_nw_corner) //a guess based on how constructions work
return "`";
//same as water wheel but reversed
out << "Mh" << (((df::building_axle_horizontalst*) b)->is_vertical ? "s" : "")
<< "(" << size.first << "x" << size.second << ")";
return out.str();
case building_type::AxleVertical:
return "Mv";
case building_type::Rollers:
if (! at_nw_corner)
return "`";
out << "Mr";
switch (((df::building_rollersst*) b)->direction)
{
case screw_pump_direction::FromNorth:
break;
case screw_pump_direction::FromEast:
out << "s";
case screw_pump_direction::FromSouth:
out << "s";
case screw_pump_direction::FromWest:
out << "s";
}
out << "(" << size.first << "x" << size.second << ")";
return out.str();
case building_type::Support:
return "S";
case building_type::ArcheryTarget:
return "A";
case building_type::TractionBench:
return "R";
case building_type::Hatch:
return "H";
case building_type::Slab:
//how to mine alt key?!?
//alt+s
return " ";
case building_type::NestBox:
return "N";
case building_type::Hive:
//alt+h
return " ";
case building_type::GrateWall:
return "W";
case building_type::GrateFloor:
return "G";
case building_type::BarsVertical:
return "B";
case building_type::BarsFloor:
//alt+b
return " ";
default:
return " ";
}
}
string get_tile_place(uint32_t x, uint32_t y, df::building* b)
{
if (! b || b->getType() != building_type::Stockpile)
return " ";
if (b->x1 != x || b->y1 != y)
return "`";
pair<uint32_t, uint32_t> size = get_building_size(b);
df::building_stockpilest* sp = (df::building_stockpilest*) b;
stringstream out;// = stringstream();
switch (sp->settings.flags.whole)
{
case df::stockpile_group_set::mask_animals:
out << "a";
break;
case df::stockpile_group_set::mask_food:
out << "f";
break;
case df::stockpile_group_set::mask_furniture:
out << "u";
break;
case df::stockpile_group_set::mask_corpses:
out << "y";
break;
case df::stockpile_group_set::mask_refuse:
out << "r";
break;
case df::stockpile_group_set::mask_wood:
out << "w";
break;
case df::stockpile_group_set::mask_stone:
out << "s";
break;
case df::stockpile_group_set::mask_gems:
out << "e";
break;
case df::stockpile_group_set::mask_bars_blocks:
out << "b";
break;
case df::stockpile_group_set::mask_cloth:
out << "h";
break;
case df::stockpile_group_set::mask_leather:
out << "l";
break;
case df::stockpile_group_set::mask_ammo:
out << "z";
break;
case df::stockpile_group_set::mask_coins:
out << "n";
break;
case df::stockpile_group_set::mask_finished_goods:
out << "g";
break;
case df::stockpile_group_set::mask_weapons:
out << "p";
break;
case df::stockpile_group_set::mask_armor:
out << "d";
break;
default: //multiple stockpile type
return "`";
}
out << "("<< size.first << "x" << size.second << ")";
return out.str();
}
string get_tile_query(df::building* b)
{
if (b && b->is_room)
return "r+";
return " ";
}
command_result do_transform(DFCoord start, DFCoord end, string name, uint32_t phases)
{
ofstream dig, build, place, query;
if (phases & QUERY)
{
//query = ofstream((name + "-query.csv").c_str(), ofstream::trunc);
query.open(name+"-query.csv", ofstream::trunc);
query << "#query" << endl;
}
if (phases & PLACE)
{
//place = ofstream(name + "-place.csv", ofstream::trunc);
place.open(name+"-place.csv", ofstream::trunc);
place << "#place" << endl;
}
if (phases & BUILD)
{
//build = ofstream(name + "-build.csv", ofstream::trunc);
build.open(name+"-build.csv", ofstream::trunc);
build << "#build" << endl;
}
if (phases & DIG)
{
//dig = ofstream(name + "-dig.csv", ofstream::trunc);
dig.open(name+"-dig.csv", ofstream::trunc);
dig << "#dig" << endl;
}
if (start.x > end.x)
{
swap(start.x, end.x);
start.x++;
end.x++;
}
if (start.y > end.y)
{
swap(start.y, end.y);
start.y++;
end.y++;
}
if (start.z > end.z)
{
swap(start.z, end.z);
start.z++;
end.z++;
}
MapExtras::MapCache mc;
for (int32_t z = start.z; z < end.z; z++)
{
for (int32_t y = start.y; y < end.y; y++)
{
for (int32_t x = start.x; x < end.x; x++)
{
df::building* b = DFHack::Buildings::findAtTile(DFCoord(x, y, z));
if (phases & QUERY)
query << get_tile_query(b) << ',';
if (phases & PLACE)
place << get_tile_place(x, y, b) << ',';
if (phases & BUILD)
build << get_tile_build(x, y, b) << ',';
if (phases & DIG)
dig << get_tile_dig(mc, x, y, z) << ',';
}
if (phases & QUERY)
query << "#" << endl;
if (phases & PLACE)
place << "#" << endl;
if (phases & BUILD)
build << "#" << endl;
if (phases & DIG)
dig << "#" << endl;
}
if (z < end.z - 1)
{
if (phases & QUERY)
query << "#<" << endl;
if (phases & PLACE)
place << "#<" << endl;
if (phases & BUILD)
build << "#<" << endl;
if (phases & DIG)
dig << "#<" << endl;
}
}
if (phases & QUERY)
query.close();
if (phases & PLACE)
place.close();
if (phases & BUILD)
build.close();
if (phases & DIG)
dig.close();
return CR_OK;
}
bool cmd_option_exists(vector<string>& parameters, const string& option)
{
return find(parameters.begin(), parameters.end(), option) != parameters.end();
}
command_result blueprint(color_ostream &out, vector<string> &parameters)
{
if (parameters.size() < 4 || parameters.size() > 8)
return help(out);
CoreSuspender suspend;
if (!Maps::IsValid())
{
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
int32_t x, y, z;
if (!Gui::getCursorCoords(x, y, z))
{
out.printerr("Can't get cursor coords! Make sure you have an active cursor in DF.\n");
return CR_FAILURE;
}
DFCoord start (x, y, z);
DFCoord end (x + stoi(parameters[0]), y + stoi(parameters[1]), z + stoi(parameters[2]));
if (parameters.size() == 4)
return do_transform(start, end, parameters[3], DIG | BUILD | PLACE | QUERY);
uint32_t option = 0;
if (cmd_option_exists(parameters, "dig"))
option |= DIG;
if (cmd_option_exists(parameters, "build"))
option |= BUILD;
if (cmd_option_exists(parameters, "place"))
option |= PLACE;
if (cmd_option_exists(parameters, "query"))
option |= QUERY;
return do_transform(start, end, parameters[3], option);
}

@ -24,9 +24,10 @@
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("building-hacks");
REQUIRE_GLOBAL(world);
struct graphic_tile //could do just 31x31 and be done, but it's nicer to have flexible imho.
{
int16_t tile; //originally uint8_t but we need to indicate non-animated tiles

@ -0,0 +1,660 @@
#include "buildingplan-lib.h"
#define PLUGIN_VERSION 0.00
void debug(const string &msg)
{
if (!show_debugging)
return;
color_ostream_proxy out(Core::getInstance().getConsole());
out << "DEBUG (" << PLUGIN_VERSION << "): " << msg << endl;
}
void enable_quickfort_fn(pair<const df::building_type, bool>& pair) { pair.second = true; }
/*
* Material Choice Screen
*/
static std::string material_to_string_fn(DFHack::MaterialInfo m) { return m.toString(); }
bool ItemFilter::matchesMask(DFHack::MaterialInfo &mat)
{
return (mat_mask.whole) ? mat.matches(mat_mask) : true;
}
bool ItemFilter::matches(const df::dfhack_material_category mask) const
{
return mask.whole & mat_mask.whole;
}
bool ItemFilter::matches(DFHack::MaterialInfo &material) const
{
for (auto it = materials.begin(); it != materials.end(); ++it)
if (material.matches(*it))
return true;
return false;
}
bool ItemFilter::matches(df::item *item)
{
if (item->getQuality() < min_quality)
return false;
if (decorated_only && !item->hasImprovements())
return false;
auto imattype = item->getActualMaterial();
auto imatindex = item->getActualMaterialIndex();
auto item_mat = DFHack::MaterialInfo(imattype, imatindex);
return (materials.size() == 0) ? matchesMask(item_mat) : matches(item_mat);
}
std::vector<std::string> ItemFilter::getMaterialFilterAsVector()
{
std::vector<std::string> descriptions;
transform_(materials, descriptions, material_to_string_fn);
if (descriptions.size() == 0)
bitfield_to_string(&descriptions, mat_mask);
if (descriptions.size() == 0)
descriptions.push_back("any");
return descriptions;
}
std::string ItemFilter::getMaterialFilterAsSerial()
{
std::string str;
str.append(bitfield_to_string(mat_mask, ","));
str.append("/");
if (materials.size() > 0)
{
for (size_t i = 0; i < materials.size(); i++)
str.append(materials[i].getToken() + ",");
if (str[str.size()-1] == ',')
str.resize(str.size () - 1);
}
return str;
}
bool ItemFilter::parseSerializedMaterialTokens(std::string str)
{
valid = false;
std::vector<std::string> tokens;
split_string(&tokens, str, "/");
if (tokens.size() > 0 && !tokens[0].empty())
{
if (!parseJobMaterialCategory(&mat_mask, tokens[0]))
return false;
}
if (tokens.size() > 1 && !tokens[1].empty())
{
std::vector<std::string> mat_names;
split_string(&mat_names, tokens[1], ",");
for (auto m = mat_names.begin(); m != mat_names.end(); m++)
{
DFHack::MaterialInfo material;
if (!material.find(*m) || !material.isValid())
return false;
materials.push_back(material);
}
}
valid = true;
return true;
}
std::string ItemFilter::getMinQuality()
{
return ENUM_KEY_STR(item_quality, min_quality);
}
bool ItemFilter::isValid()
{
return valid;
}
void ItemFilter::clear()
{
mat_mask.whole = 0;
materials.clear();
}
static DFHack::MaterialInfo &material_info_identity_fn(DFHack::MaterialInfo &m) { return m; }
ViewscreenChooseMaterial::ViewscreenChooseMaterial(ItemFilter *filter)
{
selected_column = 0;
masks_column.setTitle("Type");
masks_column.multiselect = true;
masks_column.allow_search = false;
masks_column.left_margin = 2;
materials_column.left_margin = MAX_MASK + 3;
materials_column.setTitle("Material");
materials_column.multiselect = true;
this->filter = filter;
masks_column.changeHighlight(0);
populateMasks();
populateMaterials();
masks_column.selectDefaultEntry();
materials_column.selectDefaultEntry();
materials_column.changeHighlight(0);
}
void ViewscreenChooseMaterial::feed(set<df::interface_key> *input)
{
bool key_processed = false;
switch (selected_column)
{
case 0:
key_processed = masks_column.feed(input);
if (input->count(interface_key::SELECT))
populateMaterials(); // Redo materials lists based on category selection
break;
case 1:
key_processed = materials_column.feed(input);
break;
}
if (key_processed)
return;
if (input->count(interface_key::LEAVESCREEN))
{
input->clear();
Screen::dismiss(this);
return;
}
if (input->count(interface_key::CUSTOM_SHIFT_C))
{
filter->clear();
masks_column.clearSelection();
materials_column.clearSelection();
populateMaterials();
}
else if (input->count(interface_key::SEC_SELECT))
{
// Convert list selections to material filters
filter->mat_mask.whole = 0;
filter->materials.clear();
// Category masks
auto masks = masks_column.getSelectedElems();
for (auto it = masks.begin(); it != masks.end(); ++it)
filter->mat_mask.whole |= it->whole;
// Specific materials
auto materials = materials_column.getSelectedElems();
transform_(materials, filter->materials, material_info_identity_fn);
Screen::dismiss(this);
}
else if (input->count(interface_key::CURSOR_LEFT))
{
--selected_column;
validateColumn();
}
else if (input->count(interface_key::CURSOR_RIGHT))
{
selected_column++;
validateColumn();
}
else if (enabler->tracking_on && enabler->mouse_lbut)
{
if (masks_column.setHighlightByMouse())
selected_column = 0;
else if (materials_column.setHighlightByMouse())
selected_column = 1;
enabler->mouse_lbut = enabler->mouse_rbut = 0;
}
}
void ViewscreenChooseMaterial::render()
{
if (Screen::isDismissed(this))
return;
dfhack_viewscreen::render();
Screen::clear();
Screen::drawBorder(" Building Material ");
masks_column.display(selected_column == 0);
materials_column.display(selected_column == 1);
int32_t y = gps->dimy - 3;
int32_t x = 2;
OutputHotkeyString(x, y, "Toggle", "Enter");
x += 3;
OutputHotkeyString(x, y, "Save", "Shift-Enter");
x += 3;
OutputHotkeyString(x, y, "Clear", "C");
x += 3;
OutputHotkeyString(x, y, "Cancel", "Esc");
}
// START Room Reservation
ReservedRoom::ReservedRoom(df::building *building, std::string noble_code)
{
this->building = building;
config = DFHack::World::AddPersistentData("buildingplan/reservedroom");
config.val() = noble_code;
config.ival(1) = building->id;
pos = df::coord(building->centerx, building->centery, building->z);
}
ReservedRoom::ReservedRoom(PersistentDataItem &config, color_ostream &out)
{
this->config = config;
building = df::building::find(config.ival(1));
if (!building)
return;
pos = df::coord(building->centerx, building->centery, building->z);
}
bool ReservedRoom::checkRoomAssignment()
{
if (!isValid())
return false;
auto np = getOwnersNobleCode();
bool correctOwner = false;
for (auto iter = np.begin(); iter != np.end(); iter++)
{
if (iter->position->code == getCode())
{
correctOwner = true;
break;
}
}
if (correctOwner)
return true;
for (auto iter = world->units.active.begin(); iter != world->units.active.end(); iter++)
{
df::unit* unit = *iter;
if (!Units::isCitizen(unit))
continue;
if (DFHack::Units::isDead(unit))
continue;
np = getUniqueNoblePositions(unit);
for (auto iter = np.begin(); iter != np.end(); iter++)
{
if (iter->position->code == getCode())
{
Buildings::setOwner(building, unit);
break;
}
}
}
return true;
}
std::string RoomMonitor::getReservedNobleCode(int32_t buildingId)
{
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end(); iter++)
{
if (buildingId == iter->getId())
return iter->getCode();
}
return "";
}
void RoomMonitor::toggleRoomForPosition(int32_t buildingId, std::string noble_code)
{
bool found = false;
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end(); iter++)
{
if (buildingId != iter->getId())
{
continue;
}
else
{
if (noble_code == iter->getCode())
{
iter->remove();
reservedRooms.erase(iter);
}
else
{
iter->setCode(noble_code);
}
found = true;
break;
}
}
if (!found)
{
ReservedRoom room(df::building::find(buildingId), noble_code);
reservedRooms.push_back(room);
}
}
void RoomMonitor::doCycle()
{
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end();)
{
if (iter->checkRoomAssignment())
{
++iter;
}
else
{
iter->remove();
iter = reservedRooms.erase(iter);
}
}
}
void RoomMonitor::reset(color_ostream &out)
{
reservedRooms.clear();
std::vector<PersistentDataItem> items;
DFHack::World::GetPersistentData(&items, "buildingplan/reservedroom");
for (auto i = items.begin(); i != items.end(); i++)
{
ReservedRoom rr(*i, out);
if (rr.isValid())
addRoom(rr);
}
}
static void delete_item_fn(df::job_item *x) { delete x; }
// START Planning
PlannedBuilding::PlannedBuilding(df::building *building, ItemFilter *filter)
{
this->building = building;
this->filter = *filter;
pos = df::coord(building->centerx, building->centery, building->z);
config = DFHack::World::AddPersistentData("buildingplan/constraints");
config.val() = filter->getMaterialFilterAsSerial();
config.ival(1) = building->id;
config.ival(2) = filter->min_quality + 1;
config.ival(3) = static_cast<int>(filter->decorated_only) + 1;
}
PlannedBuilding::PlannedBuilding(PersistentDataItem &config, color_ostream &out)
{
this->config = config;
if (!filter.parseSerializedMaterialTokens(config.val()))
{
out.printerr("Buildingplan: Cannot parse filter: %s\nDiscarding.", config.val().c_str());
return;
}
building = df::building::find(config.ival(1));
if (!building)
return;
pos = df::coord(building->centerx, building->centery, building->z);
filter.min_quality = static_cast<df::item_quality>(config.ival(2) - 1);
filter.decorated_only = config.ival(3) - 1;
}
bool PlannedBuilding::assignClosestItem(std::vector<df::item *> *items_vector)
{
decltype(items_vector->begin()) closest_item;
int32_t closest_distance = -1;
for (auto item_iter = items_vector->begin(); item_iter != items_vector->end(); item_iter++)
{
auto item = *item_iter;
if (!filter.matches(item))
continue;
auto pos = item->pos;
auto distance = abs(pos.x - building->centerx) +
abs(pos.y - building->centery) +
abs(pos.z - building->z) * 50;
if (closest_distance > -1 && distance >= closest_distance)
continue;
closest_distance = distance;
closest_item = item_iter;
}
if (closest_distance > -1 && assignItem(*closest_item))
{
debug("Item assigned");
items_vector->erase(closest_item);
remove();
return true;
}
return false;
}
bool PlannedBuilding::assignItem(df::item *item)
{
auto ref = df::allocate<df::general_ref_building_holderst>();
if (!ref)
{
Core::printerr("Could not allocate general_ref_building_holderst\n");
return false;
}
ref->building_id = building->id;
if (building->jobs.size() != 1)
return false;
auto job = building->jobs[0];
for_each_(job->job_items, delete_item_fn);
job->job_items.clear();
job->flags.bits.suspend = false;
bool rough = false;
Job::attachJobItem(job, item, df::job_item_ref::Hauled);
if (item->getType() == item_type::BOULDER)
rough = true;
building->mat_type = item->getMaterial();
building->mat_index = item->getMaterialIndex();
job->mat_type = building->mat_type;
job->mat_index = building->mat_index;
if (building->needsDesign())
{
auto act = (df::building_actual *) building;
act->design = new df::building_design();
act->design->flags.bits.rough = rough;
}
return true;
}
bool PlannedBuilding::isValid()
{
bool valid = filter.isValid() &&
building && Buildings::findAtTile(pos) == building &&
building->getBuildStage() == 0;
if (!valid)
remove();
return valid;
}
void Planner::reset(color_ostream &out)
{
planned_buildings.clear();
std::vector<PersistentDataItem> items;
DFHack::World::GetPersistentData(&items, "buildingplan/constraints");
for (auto i = items.begin(); i != items.end(); i++)
{
PlannedBuilding pb(*i, out);
if (pb.isValid())
planned_buildings.push_back(pb);
}
}
void Planner::initialize()
{
std::vector<std::string> item_names;
typedef df::enum_traits<df::item_type> item_types;
int size = item_types::last_item_value - item_types::first_item_value+1;
for (size_t i = 1; i < size; i++)
{
is_relevant_item_type[(df::item_type) (i-1)] = false;
std::string item_name = toLower(item_types::key_table[i]);
std::string item_name_clean;
for (auto c = item_name.begin(); c != item_name.end(); c++)
{
if (*c == '_')
continue;
item_name_clean += *c;
}
item_names.push_back(item_name_clean);
}
typedef df::enum_traits<df::building_type> building_types;
size = building_types::last_item_value - building_types::first_item_value+1;
for (size_t i = 1; i < size; i++)
{
auto building_type = (df::building_type) (i-1);
if (building_type == building_type::Weapon || building_type == building_type::Floodgate)
continue;
std::string building_name = toLower(building_types::key_table[i]);
for (size_t j = 0; j < item_names.size(); j++)
{
if (building_name == item_names[j])
{
auto btype = (df::building_type) (i-1);
auto itype = (df::item_type) j;
item_for_building_type[btype] = itype;
default_item_filters[btype] = ItemFilter();
available_item_vectors[itype] = std::vector<df::item *>();
is_relevant_item_type[itype] = true;
if (planmode_enabled.find(btype) == planmode_enabled.end())
{
planmode_enabled[btype] = false;
}
}
}
}
}
void Planner::doCycle()
{
debug("Running Cycle");
if (planned_buildings.size() == 0)
return;
debug("Planned count: " + int_to_string(planned_buildings.size()));
gather_available_items();
for (auto building_iter = planned_buildings.begin(); building_iter != planned_buildings.end();)
{
if (building_iter->isValid())
{
if (show_debugging)
debug(std::string("Trying to allocate ") + enum_item_key_str(building_iter->getType()));
auto required_item_type = item_for_building_type[building_iter->getType()];
auto items_vector = &available_item_vectors[required_item_type];
if (items_vector->size() == 0 || !building_iter->assignClosestItem(items_vector))
{
debug("Unable to allocate an item");
++building_iter;
continue;
}
}
debug("Removing building plan");
building_iter = planned_buildings.erase(building_iter);
}
}
bool Planner::allocatePlannedBuilding(df::building_type type)
{
coord32_t cursor;
if (!DFHack::Gui::getCursorCoords(cursor.x, cursor.y, cursor.z))
return false;
auto newinst = Buildings::allocInstance(cursor.get_coord16(), type);
if (!newinst)
return false;
df::job_item *filter = new df::job_item();
filter->item_type = item_type::NONE;
filter->mat_index = 0;
filter->flags2.bits.building_material = true;
std::vector<df::job_item*> filters;
filters.push_back(filter);
if (!Buildings::constructWithFilters(newinst, filters))
{
delete newinst;
return false;
}
for (auto iter = newinst->jobs.begin(); iter != newinst->jobs.end(); iter++)
{
(*iter)->flags.bits.suspend = true;
}
if (type == building_type::Door)
{
auto door = virtual_cast<df::building_doorst>(newinst);
if (door)
door->door_flags.bits.pet_passable = true;
}
addPlannedBuilding(newinst);
return true;
}
PlannedBuilding *Planner::getSelectedPlannedBuilding()
{
for (auto building_iter = planned_buildings.begin(); building_iter != planned_buildings.end(); building_iter++)
{
if (building_iter->isCurrentlySelectedBuilding())
{
return &(*building_iter);
}
}
return nullptr;
}
void Planner::cycleDefaultQuality(df::building_type type)
{
auto quality = &getDefaultItemFilterForType(type)->min_quality;
*quality = static_cast<df::item_quality>(*quality + 1);
if (*quality == item_quality::Artifact)
(*quality) = item_quality::Ordinary;
}

@ -0,0 +1,495 @@
#ifndef BUILDINGPLAN_H
#define BUILDINGPLAN_H
#include "uicommon.h"
#include <functional>
// DF data structure definition headers
#include "DataDefs.h"
#include "Types.h"
#include "df/build_req_choice_genst.h"
#include "df/build_req_choice_specst.h"
#include "df/item.h"
#include "df/ui.h"
#include "df/ui_build_selector.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/items_other_id.h"
#include "df/job.h"
#include "df/world.h"
#include "df/building_constructionst.h"
#include "df/building_design.h"
#include "df/entity_position.h"
#include "modules/Buildings.h"
#include "modules/Maps.h"
#include "modules/Items.h"
#include "modules/Units.h"
#include "modules/Gui.h"
#include "TileTypes.h"
#include "df/job_item.h"
#include "df/dfhack_material_category.h"
#include "df/general_ref_building_holderst.h"
#include "modules/Job.h"
#include "df/building_design.h"
#include "df/buildings_other_id.h"
#include "modules/World.h"
#include "df/building.h"
#include "df/building_doorst.h"
using df::global::ui;
using df::global::ui_build_selector;
using df::global::world;
struct MaterialDescriptor
{
df::item_type item_type;
int16_t item_subtype;
int16_t type;
int32_t index;
bool valid;
bool matches(const MaterialDescriptor &a) const
{
return a.valid && valid &&
a.type == type &&
a.index == index &&
a.item_type == item_type &&
a.item_subtype == item_subtype;
}
};
#define MAX_MASK 10
#define MAX_MATERIAL 21
#define SIDEBAR_WIDTH 30
static bool canReserveRoom(df::building *building)
{
if (!building)
return false;
if (building->jobs.size() > 0 && building->jobs[0]->job_type == job_type::DestroyBuilding)
return false;
return building->is_room;
}
static std::vector<Units::NoblePosition> getUniqueNoblePositions(df::unit *unit)
{
std::vector<Units::NoblePosition> np;
Units::getNoblePositions(&np, unit);
for (auto iter = np.begin(); iter != np.end(); iter++)
{
if (iter->position->code == "MILITIA_CAPTAIN")
{
np.erase(iter);
break;
}
}
return np;
}
static void delete_item_fn(df::job_item *x);
static MaterialInfo &material_info_identity_fn(MaterialInfo &m);
static map<df::building_type, bool> planmode_enabled, saved_planmodes;
void enable_quickfort_fn(pair<const df::building_type, bool>& pair);
void debug(const std::string &msg);
static std::string material_to_string_fn(MaterialInfo m);
static bool show_debugging = false;
static bool show_help = false;
struct ItemFilter
{
df::dfhack_material_category mat_mask;
std::vector<DFHack::MaterialInfo> materials;
df::item_quality min_quality;
bool decorated_only;
ItemFilter() : min_quality(df::item_quality::Ordinary), decorated_only(false), valid(true)
{ }
bool matchesMask(DFHack::MaterialInfo &mat);
bool matches(const df::dfhack_material_category mask) const;
bool matches(DFHack::MaterialInfo &material) const;
bool matches(df::item *item);
std::vector<std::string> getMaterialFilterAsVector();
std::string getMaterialFilterAsSerial();
bool parseSerializedMaterialTokens(std::string str);
std::string getMinQuality();
bool isValid();
void clear();
private:
bool valid;
};
class ViewscreenChooseMaterial : public dfhack_viewscreen
{
public:
ViewscreenChooseMaterial(ItemFilter *filter);
void feed(set<df::interface_key> *input);
void render();
std::string getFocusString() { return "buildingplan_choosemat"; }
private:
ListColumn<df::dfhack_material_category> masks_column;
ListColumn<MaterialInfo> materials_column;
int selected_column;
ItemFilter *filter;
df::building_type btype;
void addMaskEntry(df::dfhack_material_category &mask, const std::string &text)
{
auto entry = ListEntry<df::dfhack_material_category>(pad_string(text, MAX_MASK, false), mask);
if (filter->matches(mask))
entry.selected = true;
masks_column.add(entry);
}
void populateMasks()
{
masks_column.clear();
df::dfhack_material_category mask;
mask.whole = 0;
mask.bits.stone = true;
addMaskEntry(mask, "Stone");
mask.whole = 0;
mask.bits.wood = true;
addMaskEntry(mask, "Wood");
mask.whole = 0;
mask.bits.metal = true;
addMaskEntry(mask, "Metal");
mask.whole = 0;
mask.bits.soap = true;
addMaskEntry(mask, "Soap");
masks_column.filterDisplay();
}
void populateMaterials()
{
materials_column.clear();
df::dfhack_material_category selected_category;
std::vector<df::dfhack_material_category> selected_masks = masks_column.getSelectedElems();
if (selected_masks.size() == 1)
selected_category = selected_masks[0];
else if (selected_masks.size() > 1)
return;
df::world_raws &raws = world->raws;
for (int i = 1; i < DFHack::MaterialInfo::NUM_BUILTIN; i++)
{
auto obj = raws.mat_table.builtin[i];
if (obj)
{
MaterialInfo material;
material.decode(i, -1);
addMaterialEntry(selected_category, material, material.toString());
}
}
for (size_t i = 0; i < raws.inorganics.size(); i++)
{
df::inorganic_raw *p = raws.inorganics[i];
MaterialInfo material;
material.decode(0, i);
addMaterialEntry(selected_category, material, material.toString());
}
decltype(selected_category) wood_flag;
wood_flag.bits.wood = true;
if (!selected_category.whole || selected_category.bits.wood)
{
for (size_t i = 0; i < raws.plants.all.size(); i++)
{
df::plant_raw *p = raws.plants.all[i];
for (size_t j = 0; p->material.size() > 1 && j < p->material.size(); j++)
{
auto t = p->material[j];
if (p->material[j]->id != "WOOD")
continue;
MaterialInfo material;
material.decode(DFHack::MaterialInfo::PLANT_BASE+j, i);
auto name = material.toString();
ListEntry<MaterialInfo> entry(pad_string(name, MAX_MATERIAL, false), material);
if (filter->matches(material))
entry.selected = true;
materials_column.add(entry);
}
}
}
materials_column.sort();
}
void addMaterialEntry(df::dfhack_material_category &selected_category,
MaterialInfo &material, std::string name)
{
if (!selected_category.whole || material.matches(selected_category))
{
ListEntry<MaterialInfo> entry(pad_string(name, MAX_MATERIAL, false), material);
if (filter->matches(material))
entry.selected = true;
materials_column.add(entry);
}
}
void validateColumn()
{
set_to_limit(selected_column, 1);
}
void resize(int32_t x, int32_t y)
{
dfhack_viewscreen::resize(x, y);
masks_column.resize();
materials_column.resize();
}
};
class ReservedRoom
{
public:
ReservedRoom(df::building *building, std::string noble_code);
ReservedRoom(PersistentDataItem &config, color_ostream &out);
bool checkRoomAssignment();
void remove() { DFHack::World::DeletePersistentData(config); }
bool isValid()
{
if (!building)
return false;
if (Buildings::findAtTile(pos) != building)
return false;
return canReserveRoom(building);
}
int32_t getId()
{
if (!isValid())
return 0;
return building->id;
}
std::string getCode() { return config.val(); }
void setCode(const std::string &noble_code) { config.val() = noble_code; }
private:
df::building *building;
PersistentDataItem config;
df::coord pos;
std::vector<Units::NoblePosition> getOwnersNobleCode()
{
if (!building->owner)
return std::vector<Units::NoblePosition> ();
return getUniqueNoblePositions(building->owner);
}
};
class RoomMonitor
{
public:
RoomMonitor() { }
std::string getReservedNobleCode(int32_t buildingId);
void toggleRoomForPosition(int32_t buildingId, std::string noble_code);
void doCycle();
void reset(color_ostream &out);
private:
std::vector<ReservedRoom> reservedRooms;
void addRoom(ReservedRoom &rr)
{
for (auto iter = reservedRooms.begin(); iter != reservedRooms.end(); iter++)
{
if (iter->getId() == rr.getId())
return;
}
reservedRooms.push_back(rr);
}
};
// START Planning
class PlannedBuilding
{
public:
PlannedBuilding(df::building *building, ItemFilter *filter);
PlannedBuilding(PersistentDataItem &config, color_ostream &out);
bool assignClosestItem(std::vector<df::item *> *items_vector);
bool assignItem(df::item *item);
bool isValid();
df::building_type getType() { return building->getType(); }
bool isCurrentlySelectedBuilding() { return isValid() && (building == world->selected_building); }
ItemFilter *getFilter() { return &filter; }
void remove() { DFHack::World::DeletePersistentData(config); }
private:
df::building *building;
PersistentDataItem config;
df::coord pos;
ItemFilter filter;
};
class Planner
{
public:
bool in_dummmy_screen;
Planner() : quickfort_mode(false), in_dummmy_screen(false) { }
bool isPlanableBuilding(const df::building_type type) const
{
return item_for_building_type.find(type) != item_for_building_type.end();
}
void reset(color_ostream &out);
void initialize();
void addPlannedBuilding(df::building *bld)
{
PlannedBuilding pb(bld, &default_item_filters[bld->getType()]);
planned_buildings.push_back(pb);
}
void doCycle();
bool allocatePlannedBuilding(df::building_type type);
PlannedBuilding *getSelectedPlannedBuilding();
void removeSelectedPlannedBuilding() { getSelectedPlannedBuilding()->remove(); }
ItemFilter *getDefaultItemFilterForType(df::building_type type) { return &default_item_filters[type]; }
void cycleDefaultQuality(df::building_type type);
void enableQuickfortMode()
{
saved_planmodes = planmode_enabled;
for_each_(planmode_enabled, enable_quickfort_fn);
quickfort_mode = true;
}
void disableQuickfortMode()
{
planmode_enabled = saved_planmodes;
quickfort_mode = false;
}
bool inQuickFortMode() { return quickfort_mode; }
private:
map<df::building_type, df::item_type> item_for_building_type;
map<df::building_type, ItemFilter> default_item_filters;
map<df::item_type, std::vector<df::item *>> available_item_vectors;
map<df::item_type, bool> is_relevant_item_type; //Needed for fast check when looping over all items
bool quickfort_mode;
std::vector<PlannedBuilding> planned_buildings;
void gather_available_items()
{
debug("Gather available items");
for (auto iter = available_item_vectors.begin(); iter != available_item_vectors.end(); iter++)
{
iter->second.clear();
}
// Precompute a bitmask with the bad flags
df::item_flags bad_flags;
bad_flags.whole = 0;
#define F(x) bad_flags.bits.x = true;
F(dump); F(forbid); F(garbage_collect);
F(hostile); F(on_fire); F(rotten); F(trader);
F(in_building); F(construction); F(artifact);
#undef F
std::vector<df::item*> &items = world->items.other[items_other_id::IN_PLAY];
for (size_t i = 0; i < items.size(); i++)
{
df::item *item = items[i];
if (item->flags.whole & bad_flags.whole)
continue;
df::item_type itype = item->getType();
if (!is_relevant_item_type[itype])
continue;
if (itype == item_type::BOX && item->isBag())
continue; //Skip bags
if (item->flags.bits.artifact)
continue;
if (item->flags.bits.in_job ||
item->isAssignedToStockpile() ||
item->flags.bits.owned ||
item->flags.bits.in_chest)
{
continue;
}
available_item_vectors[itype].push_back(item);
}
}
};
static Planner planner;
static RoomMonitor roomMonitor;
#endif

File diff suppressed because it is too large Load Diff

@ -37,9 +37,10 @@ using namespace DFHack;
using namespace df::enums;
using namespace dfproto;
using df::global::ui;
using df::global::world;
using df::global::gamemode;
DFHACK_PLUGIN("burrows");
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(gamemode);
/*
* Initialization.
@ -47,8 +48,6 @@ using df::global::gamemode;
static command_result burrow(color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("burrows");
static void init_map(color_ostream &out);
static void deinit_map(color_ostream &out);

@ -25,11 +25,11 @@ using namespace std;
#include <df/unit_genes.h>
using namespace DFHack;
using df::global::world;
command_result catsplosion (color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("catsplosion");
REQUIRE_GLOBAL(world);
command_result catsplosion (color_ostream &out, std::vector <std::string> & parameters);
// Mandatory init function. If you have some global state, create it here.
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)

@ -31,9 +31,9 @@ using namespace df::enums;
using MapExtras::Block;
using MapExtras::MapCache;
using df::global::world;
DFHACK_PLUGIN("changeitem");
REQUIRE_GLOBAL(world);
command_result df_changeitem(color_ostream &out, vector <string> & parameters);

@ -28,8 +28,9 @@ using namespace std;
using std::vector;
using std::string;
using df::global::world;
using df::global::cursor;
DFHACK_PLUGIN("changelayer");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);
const string changelayer_help =
" Allows to change the material of whole geology layers.\n"
@ -83,8 +84,6 @@ const string changelayer_trouble =
command_result changelayer (color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("changelayer");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -15,8 +15,9 @@ using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::cursor;
DFHACK_PLUGIN("changevein");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);
command_result df_changevein (color_ostream &out, vector <string> & parameters)
{
@ -77,8 +78,6 @@ command_result df_changevein (color_ostream &out, vector <string> & parameters)
return CR_OK;
}
DFHACK_PLUGIN("changevein");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand("changevein",

@ -16,9 +16,8 @@
using namespace std;
using namespace DFHack;
using df::global::world;
DFHACK_PLUGIN("cleanconst");
REQUIRE_GLOBAL(world);
command_result df_cleanconst(color_ostream &out, vector <string> & parameters)
{

@ -18,10 +18,9 @@ using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::cursor;
DFHACK_PLUGIN("cleaners");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);
command_result cleanmap (color_ostream &out, bool snow, bool mud, bool item_spatter)
{

@ -23,12 +23,11 @@ using namespace std;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("cleanowned");
REQUIRE_GLOBAL(world);
command_result df_cleanowned (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("cleanowned");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -14,6 +14,7 @@ using namespace DFHack;
command_result colonies (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("colonies");
REQUIRE_GLOBAL(world); // used by Materials
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{

@ -22,9 +22,10 @@
using namespace DFHack;
using namespace df::enums;
using df::global::ui;
using df::global::gps;
using df::global::enabler;
DFHACK_PLUGIN("command-prompt");
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(enabler);
std::vector<std::string> command_history;
@ -303,7 +304,7 @@ void viewscreen_commandpromptst::feed(std::set<df::interface_key> *events)
frame = 0;
}
DFHACK_PLUGIN("command-prompt");
command_result show_prompt(color_ostream &out, std::vector <std::string> & parameters)
{
if (Gui::getCurFocus() == "dfhack/commandprompt")

@ -31,11 +31,10 @@ using std::vector;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui;
using df::global::gametype;
DFHACK_PLUGIN("createitem");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(gametype);
int dest_container = -1, dest_building = -1;

@ -48,12 +48,12 @@ using std::vector;
using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::cursor;
command_result cursecheck (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("cursecheck");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);
command_result cursecheck (color_ostream &out, vector <string> & parameters);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{

@ -14,9 +14,8 @@ using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("deramp");
REQUIRE_GLOBAL(world);
command_result df_deramp (color_ostream &out, vector <string> & parameters)
{

@ -18,8 +18,10 @@ using namespace df::enums;
using std::string;
using std::vector;
using df::global::gps;
using df::global::enabler;
DFHACK_PLUGIN("dfstream");
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(enabler);
// The error messages are taken from the clsocket source code
const char * translate_socket_error(CSimpleSocket::CSocketError err) {
@ -283,8 +285,6 @@ public:
}
};
DFHACK_PLUGIN("dfstream");
inline df::renderer *& active_renderer() {
return enabler->renderer;
}

@ -27,6 +27,7 @@ command_result digcircle (color_ostream &out, vector <string> & parameters);
command_result digtype (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("dig");
REQUIRE_GLOBAL(world);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{

@ -21,14 +21,11 @@
using namespace DFHack;
using namespace std;
using df::global::world;
// using df::global::process_jobs;
// using df::global::process_dig;
DFHACK_PLUGIN("digFlood");
REQUIRE_GLOBAL(world);
command_result digFlood (color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("digFlood");
void onDig(color_ostream& out, void* ptr);
void maybeExplore(color_ostream& out, MapExtras::MapCache& cache, df::coord pt, set<df::coord>& jobLocations);
EventManager::EventHandler digHandler(onDig, 0);
@ -178,8 +175,10 @@ command_result digFlood (color_ostream &out, std::vector <std::string> & paramet
continue;
}
if ( parameters[a] == "CLEAR" )
if ( parameters[a] == "CLEAR" ) {
autodigMaterials.clear();
continue;
}
if ( parameters[a] == "digAll0" ) {
digAll = false;

@ -77,6 +77,7 @@ void findAndAssignInvasionJob(color_ostream& out, void*);
DFHACK_PLUGIN_IS_ENABLED(enabled);
DFHACK_PLUGIN("diggingInvaders");
REQUIRE_GLOBAL(world);
//TODO: when world unloads
static int32_t lastInvasionJob=-1;
@ -386,8 +387,8 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
unordered_set<uint16_t> localConnectivity;
//find all locals and invaders
for ( size_t a = 0; a < df::global::world->units.all.size(); a++ ) {
df::unit* unit = df::global::world->units.all[a];
for ( size_t a = 0; a < world->units.all.size(); a++ ) {
df::unit* unit = world->units.all[a];
if ( unit->flags1.bits.dead )
continue;
if ( Units::isCitizen(unit) ) {
@ -597,7 +598,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
lastInvasionDigger = firstInvader->id;
lastInvasionJob = firstInvader->job.current_job ? firstInvader->job.current_job->id : -1;
invaderJobs.erase(lastInvasionJob);
for ( df::job_list_link* link = &df::global::world->job_list; link != NULL; link = link->next ) {
for ( df::job_list_link* link = &world->job_list; link != NULL; link = link->next ) {
if ( link->item == NULL )
continue;
df::job* job = link->item;

@ -15,9 +15,8 @@ using std::vector;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("drybuckets");
REQUIRE_GLOBAL(world);
command_result df_drybuckets (color_ostream &out, vector <string> & parameters)
{

@ -43,9 +43,11 @@
using std::deque;
using df::global::current_weather;
using df::global::world;
using df::global::ui;
DFHACK_PLUGIN("dwarfmonitor");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(current_weather);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
typedef int16_t activity_type;
@ -1720,10 +1722,10 @@ struct dwarf_monitor_hook : public df::viewscreen_dwarfmodest
int y = 0;
ostringstream date_str;
auto month = World::ReadCurrentMonth();
auto month = World::ReadCurrentMonth() + 1;
auto day = World::ReadCurrentDay();
date_str << "Date:" << World::ReadCurrentYear() << "/" <<
((month < 10) ? "0" : "") << month << "/" <<
date_str << "Date:" << World::ReadCurrentYear() << "-" <<
((month < 10) ? "0" : "") << month << "-" <<
((day < 10) ? "0" : "") << day;
OutputString(COLOR_GREY, x, y, date_str.str());
@ -1775,9 +1777,6 @@ struct dwarf_monitor_hook : public df::viewscreen_dwarfmodest
IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, render);
DFHACK_PLUGIN("dwarfmonitor");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
static bool set_monitoring_mode(const string &mode, const bool &state)
{
bool mode_recognized = false;

@ -3,6 +3,7 @@
#include "DataDefs.h"
#include "Export.h"
#include "PluginManager.h"
#include "MiscUtils.h"
#include "modules/Screen.h"
#include "modules/Gui.h"
@ -16,6 +17,8 @@
#include "df/interface_key.h"
using namespace DFHack;
using df::global::enabler;
using df::global::gps;
#define FOR_ITER_TOOLS(iter) for(auto iter = tools.begin(); iter != tools.end(); iter++)
@ -34,17 +37,36 @@ void update_embark_sidebar (df::viewscreen_choose_start_sitest * screen)
}
}
void get_embark_pos (df::viewscreen_choose_start_sitest * screen,
int& x1, int& x2, int& y1, int& y2, int& w, int& h)
{
x1 = screen->location.embark_pos_min.x,
x2 = screen->location.embark_pos_max.x,
y1 = screen->location.embark_pos_min.y,
y2 = screen->location.embark_pos_max.y,
w = x2 - x1 + 1,
h = y2 - y1 + 1;
}
void set_embark_pos (df::viewscreen_choose_start_sitest * screen,
int x1, int x2, int y1, int y2)
{
screen->location.embark_pos_min.x = x1;
screen->location.embark_pos_max.x = x2;
screen->location.embark_pos_min.y = y1;
screen->location.embark_pos_max.y = y2;
}
#define GET_EMBARK_POS(screen, a, b, c, d, e, f) \
int a, b, c, d, e, f; \
get_embark_pos(screen, a, b, c, d, e, f);
void resize_embark (df::viewscreen_choose_start_sitest * screen, int dx, int dy)
{
/* Reproduces DF's embark resizing functionality
* Local area resizes up and to the right, unless it's already touching the edge
*/
int x1 = screen->location.embark_pos_min.x,
x2 = screen->location.embark_pos_max.x,
y1 = screen->location.embark_pos_min.y,
y2 = screen->location.embark_pos_max.y,
width = x2 - x1 + dx,
height = y2 - y1 + dy;
GET_EMBARK_POS(screen, x1, x2, y1, y2, width, height);
if (x1 == x2 && dx == -1)
dx = 0;
if (y1 == y2 && dy == -1)
@ -66,11 +88,7 @@ void resize_embark (df::viewscreen_choose_start_sitest * screen, int dx, int dy)
}
y2 = std::min(15, y2);
screen->location.embark_pos_min.x = x1;
screen->location.embark_pos_max.x = x2;
screen->location.embark_pos_min.y = y1;
screen->location.embark_pos_max.y = y2;
set_embark_pos(screen, x1, x2, y1, y2);
update_embark_sidebar(screen);
}
@ -96,6 +114,7 @@ public:
virtual void after_render(start_sitest* screen) { };
virtual void before_feed(start_sitest* screen, ikey_set* input, bool &cancel) { };
virtual void after_feed(start_sitest* screen, ikey_set* input) { };
virtual void after_mouse_event(start_sitest* screen) { };
};
std::vector<EmbarkTool*> tools;
@ -320,6 +339,294 @@ public:
};
};
class MouseControl : public EmbarkTool
{
protected:
// Used for event handling
int prev_x;
int prev_y;
bool prev_lbut;
// Used for controls
bool base_max_x;
bool base_max_y;
bool in_local_move;
bool in_local_edge_resize_x;
bool in_local_edge_resize_y;
bool in_local_corner_resize;
// These keep track of where the embark location would be (i.e. if
// the mouse is dragged out of the local embark area), to prevent
// the mouse from moving the actual area when it's 20+ tiles away
int local_overshoot_x1;
int local_overshoot_x2;
int local_overshoot_y1;
int local_overshoot_y2;
inline bool in_local_adjust()
{
return in_local_move || in_local_edge_resize_x || in_local_edge_resize_y ||
in_local_corner_resize;
}
void lbut_press(start_sitest* screen, bool pressed, int x, int y)
{
GET_EMBARK_POS(screen, x1, x2, y1, y2, width, height);
in_local_move = in_local_edge_resize_x = in_local_edge_resize_y =
in_local_corner_resize = false;
if (pressed)
{
if (x >= 1 && x <= 16 && y >= 2 && y <= 17)
{
// Local embark - translate to local map coordinates
x -= 1;
y -= 2;
if ((x == x1 || x == x2) && (y == y1 || y == y2))
{
in_local_corner_resize = true;
base_max_x = (x == x2);
base_max_y = (y == y2);
}
else if (x == x1 || x == x2)
{
in_local_edge_resize_x = true;
base_max_x = (x == x2);
base_max_y = false;
}
else if (y == y1 || y == y2)
{
in_local_edge_resize_y = true;
base_max_x = false;
base_max_y = (y == y2);
}
else if (x > x1 && x < x2 && y > y1 && y < y2)
{
in_local_move = true;
base_max_x = base_max_y = false;
local_overshoot_x1 = x1;
local_overshoot_x2 = x2;
local_overshoot_y1 = y1;
local_overshoot_y2 = y2;
}
}
}
update_embark_sidebar(screen);
}
void mouse_move(start_sitest* screen, int x, int y)
{
GET_EMBARK_POS(screen, x1, x2, y1, y2, width, height);
if (x == -1 && prev_x > (2 + 16))
{
x = gps->dimx;
gps->mouse_x = x - 1;
}
if (y == -1 && prev_y > (1 + 16))
{
y = gps->dimy;
gps->mouse_y = y - 1;
}
if (in_local_corner_resize || in_local_edge_resize_x || in_local_edge_resize_y)
{
x -= 1;
y -= 2;
}
if (in_local_corner_resize)
{
x = std::max(0, std::min(15, x));
y = std::max(0, std::min(15, y));
if (base_max_x)
x2 = x;
else
x1 = x;
if (base_max_y)
y2 = y;
else
y1 = y;
if (x1 > x2)
{
std::swap(x1, x2);
base_max_x = !base_max_x;
}
if (y1 > y2)
{
std::swap(y1, y2);
base_max_y = !base_max_y;
}
}
else if (in_local_edge_resize_x)
{
x = std::max(0, std::min(15, x));
if (base_max_x)
x2 = x;
else
x1 = x;
if (x1 > x2)
{
std::swap(x1, x2);
base_max_x = !base_max_x;
}
}
else if (in_local_edge_resize_y)
{
y = std::max(0, std::min(15, y));
if (base_max_y)
y2 = y;
else
y1 = y;
if (y1 > y2)
{
std::swap(y1, y2);
base_max_y = !base_max_y;
}
}
else if (in_local_move)
{
int dx = x - prev_x;
int dy = y - prev_y;
local_overshoot_x1 += dx;
local_overshoot_x2 += dx;
local_overshoot_y1 += dy;
local_overshoot_y2 += dy;
if (local_overshoot_x1 < 0)
{
x1 = 0;
x2 = width - 1;
}
else if (local_overshoot_x2 > 15)
{
x1 = 15 - (width - 1);
x2 = 15;
}
else
{
x1 = local_overshoot_x1;
x2 = local_overshoot_x2;
}
if (local_overshoot_y1 < 0)
{
y1 = 0;
y2 = height - 1;
}
else if (local_overshoot_y2 > 15)
{
y1 = 15 - (height - 1);
y2 = 15;
}
else
{
y1 = local_overshoot_y1;
y2 = local_overshoot_y2;
}
}
set_embark_pos(screen, x1, x2, y1, y2);
}
public:
MouseControl()
:EmbarkTool(),
prev_x(0),
prev_y(0),
prev_lbut(false),
base_max_x(false),
base_max_y(false),
in_local_move(false),
in_local_edge_resize_x(false),
in_local_edge_resize_y(false),
in_local_corner_resize(false),
local_overshoot_x1(0),
local_overshoot_x2(0),
local_overshoot_y1(0),
local_overshoot_y2(0)
{ }
virtual std::string getId() { return "mouse"; }
virtual std::string getName() { return "Mouse control"; }
virtual std::string getDesc() { return "Implements mouse controls on the embark screen"; }
virtual df::interface_key getToggleKey() { return df::interface_key::CUSTOM_M; }
virtual void after_render(start_sitest* screen)
{
GET_EMBARK_POS(screen, x1, x2, y1, y2, width, height);
int mouse_x = gps->mouse_x, mouse_y = gps->mouse_y;
int local_x = prev_x - 1;
int local_y = prev_y - 2;
if (local_x >= x1 && local_x <= x2 && local_y >= y1 && local_y <= y2)
{
int screen_x1 = x1 + 1;
int screen_x2 = x2 + 1;
int screen_y1 = y1 + 2;
int screen_y2 = y2 + 2;
UIColor fg = in_local_adjust() ? COLOR_GREY : COLOR_DARKGREY;
Screen::Pen corner_ul = Screen::Pen((char)201, fg, COLOR_BLACK);
Screen::Pen corner_ur = Screen::Pen((char)187, fg, COLOR_BLACK);
Screen::Pen corner_dl = Screen::Pen((char)200, fg, COLOR_BLACK);
Screen::Pen corner_dr = Screen::Pen((char)188, fg, COLOR_BLACK);
Screen::Pen border_ud = Screen::Pen((char)205, fg, COLOR_BLACK);
Screen::Pen border_lr = Screen::Pen((char)186, fg, COLOR_BLACK);
if (in_local_corner_resize ||
((local_x == x1 || local_x == x2) && (local_y == y1 || local_y == y2)))
{
if (local_x == x1 && local_y == y1)
Screen::paintTile(corner_ul, screen_x1, screen_y1);
else if (local_x == x2 && local_y == y1)
Screen::paintTile(corner_ur, screen_x2, screen_y1);
else if (local_x == x1 && local_y == y2)
Screen::paintTile(corner_dl, screen_x1, screen_y2);
else if (local_x == x2 && local_y == y2)
Screen::paintTile(corner_dr, screen_x2, screen_y2);
}
else if (in_local_edge_resize_x || local_x == x1 || local_x == x2)
{
if ((in_local_edge_resize_x && !base_max_x) || local_x == x1)
{
Screen::paintTile(corner_ul, screen_x1, screen_y1);
for (int i = screen_y1 + 1; i <= screen_y2 - 1; ++i)
Screen::paintTile(border_lr, screen_x1, i);
Screen::paintTile(corner_dl, screen_x1, screen_y2);
}
else
{
Screen::paintTile(corner_ur, screen_x2, screen_y1);
for (int i = screen_y1 + 1; i <= screen_y2 - 1; ++i)
Screen::paintTile(border_lr, screen_x2, i);
Screen::paintTile(corner_dr, screen_x2, screen_y2);
}
}
else if (in_local_edge_resize_y || local_y == y1 || local_y == y2)
{
if ((in_local_edge_resize_y && !base_max_y) || local_y == y1)
{
Screen::paintTile(corner_ul, screen_x1, screen_y1);
for (int i = screen_x1 + 1; i <= screen_x2 - 1; ++i)
Screen::paintTile(border_ud, i, screen_y1);
Screen::paintTile(corner_ur, screen_x2, screen_y1);
}
else
{
Screen::paintTile(corner_dl, screen_x1, screen_y2);
for (int i = screen_x1 + 1; i <= screen_x2 - 1; ++i)
Screen::paintTile(border_ud, i, screen_y2);
Screen::paintTile(corner_dr, screen_x2, screen_y2);
}
}
else
{
Screen::paintTile(corner_ul, screen_x1, screen_y1);
Screen::paintTile(corner_ur, screen_x2, screen_y1);
Screen::paintTile(corner_dl, screen_x1, screen_y2);
Screen::paintTile(corner_dr, screen_x2, screen_y2);
}
}
}
virtual void after_mouse_event(start_sitest* screen)
{
if (enabler->mouse_lbut != prev_lbut)
{
lbut_press(screen, enabler->mouse_lbut, gps->mouse_x, gps->mouse_y);
}
if (gps->mouse_x != prev_x || gps->mouse_y != prev_y)
{
mouse_move(screen, gps->mouse_x, gps->mouse_y);
}
prev_lbut = enabler->mouse_lbut;
prev_x = gps->mouse_x;
prev_y = gps->mouse_y;
};
};
class embark_tools_settings : public dfhack_viewscreen
{
public:
@ -352,8 +659,9 @@ public:
EmbarkTool* t = *iter;
x = min_x + 2;
OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(t->getToggleKey()));
OutputString(COLOR_WHITE, x, y, ": " + t->getName() +
(t->getEnabled() ? ": Enabled" : ": Disabled"));
OutputString(COLOR_WHITE, x, y, ": " + t->getName() + ": ");
OutputString(t->getEnabled() ? COLOR_GREEN : COLOR_RED, x, y,
t->getEnabled() ? "Enabled" : "Disabled");
y++;
}
};
@ -427,28 +735,24 @@ struct choose_start_site_hook : df::viewscreen_choose_start_sitest
y = dim.y - 5;
OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::CUSTOM_S));
OutputString(COLOR_WHITE, x, y, ": Enabled: ");
std::list<std::string> parts;
FOR_ITER_TOOLS(iter)
std::vector<std::string> parts;
FOR_ITER_TOOLS(it)
{
EmbarkTool* tool = *iter;
if (tool->getEnabled())
{
parts.push_back(tool->getName());
parts.push_back(", ");
}
if ((*it)->getEnabled())
parts.push_back((*it)->getName());
}
if (parts.size())
{
parts.pop_back(); // Remove trailing comma
for (auto iter = parts.begin(); iter != parts.end(); iter++)
std::string label = join_strings(", ", parts);
if (label.size() > dim.x - x - 1)
{
OutputString(COLOR_LIGHTMAGENTA, x, y, *iter);
label.resize(dim.x - x - 1 - 3);
label.append("...");
}
OutputString(COLOR_LIGHTMAGENTA, x, y, label);
}
else
{
OutputString(COLOR_LIGHTMAGENTA, x, y, "(none)");
}
}
void display_settings()
@ -511,6 +815,7 @@ command_result embark_tools_cmd (color_ostream &out, std::vector <std::string> &
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
tools.push_back(new EmbarkAnywhere);
tools.push_back(new MouseControl);
tools.push_back(new NanoEmbark);
tools.push_back(new SandIndicator);
tools.push_back(new StablePosition);
@ -550,6 +855,35 @@ DFhackCExport command_result plugin_enable (color_ostream &out, bool enable)
return CR_OK;
}
DFhackCExport command_result plugin_onupdate (color_ostream &out)
{
static int8_t mask = 0;
static decltype(gps->mouse_x) prev_x = -1;
static decltype(gps->mouse_y) prev_y = -1;
df::viewscreen* parent = DFHack::Gui::getCurViewscreen();
VIRTUAL_CAST_VAR(screen, df::viewscreen_choose_start_sitest, parent);
if (!screen)
return CR_OK;
int8_t new_mask = (enabler->mouse_lbut << 1) |
(enabler->mouse_rbut << 2) |
(enabler->mouse_lbut_down << 3) |
(enabler->mouse_rbut_down << 4) |
(enabler->mouse_lbut_lift << 5) |
(enabler->mouse_rbut_lift << 6);
if (mask != new_mask || prev_x != gps->mouse_x || prev_y != gps->mouse_y)
{
FOR_ITER_TOOLS(iter)
{
if ((*iter)->getEnabled())
(*iter)->after_mouse_event(screen);
}
}
mask = new_mask;
prev_x = gps->mouse_x;
prev_y = gps->mouse_y;
return CR_OK;
}
command_result embark_tools_cmd (color_ostream &out, std::vector <std::string> & parameters)
{
CoreSuspender suspend;

@ -34,14 +34,13 @@ using std::stack;
using namespace DFHack;
using namespace df::enums;
using df::global::gps;
using df::global::world;
using df::global::ui;
DFHACK_PLUGIN("eventful");
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
typedef df::reaction_product_itemst item_product;
DFHACK_PLUGIN("eventful");
struct ReagentSource {
int idx;
df::reaction_reagent *reagent;

@ -17,13 +17,10 @@ using std::vector;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::debug_turbospeed;
// dfhack interface
DFHACK_PLUGIN("fastdwarf");
DFHACK_PLUGIN_IS_ENABLED(active);
REQUIRE_GLOBAL(world);
using df::global::debug_turbospeed; // not required
static bool enable_fastdwarf = false;
static bool enable_teledwarf = false;

@ -17,7 +17,8 @@ using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("feature");
REQUIRE_GLOBAL(world);
static command_result feature(color_ostream &out, vector <string> &parameters)
@ -92,8 +93,6 @@ static command_result feature(color_ostream &out, vector <string> &parameters)
return CR_OK;
}
DFHACK_PLUGIN("feature");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -18,7 +18,8 @@ using std::vector;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("fixpositions");
REQUIRE_GLOBAL(world);
command_result df_fixdiplomats (color_ostream &out, vector<string> &parameters)
{
@ -226,8 +227,6 @@ command_result df_fixmerchants (color_ostream &out, vector<string> &parameters)
return CR_OK;
}
DFHACK_PLUGIN("fixpositions");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -19,7 +19,8 @@ using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("fixveins");
REQUIRE_GLOBAL(world);
bool setTileMaterial(df::tiletype &tile, const df::tiletype_material mat)
{
@ -95,8 +96,6 @@ command_result df_fixveins (color_ostream &out, vector <string> & parameters)
return CR_OK;
}
DFHACK_PLUGIN("fixveins");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand("fixveins",

@ -15,7 +15,8 @@ using std::vector;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("flows");
REQUIRE_GLOBAL(world);
command_result df_flows (color_ostream &out, vector <string> & parameters)
{
@ -56,8 +57,6 @@ command_result df_flows (color_ostream &out, vector <string> & parameters)
return CR_OK;
}
DFHACK_PLUGIN("flows");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand("flows",

@ -16,7 +16,9 @@
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("follow");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(world);
command_result follow (color_ostream &out, std::vector <std::string> & parameters);
@ -24,9 +26,6 @@ df::unit *followedUnit;
int32_t prevX, prevY, prevZ;
uint8_t prevMenuWidth;
DFHACK_PLUGIN("follow");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -46,13 +46,13 @@ using namespace df::enums;
using MapExtras::Block;
using MapExtras::MapCache;
using df::global::world;
DFHACK_PLUGIN("forceequip");
REQUIRE_GLOBAL(world);
const int const_GloveRightHandedness = 1;
const int const_GloveLeftHandedness = 2;
DFHACK_PLUGIN("forceequip");
command_result df_forceequip(color_ostream &out, vector <string> & parameters);
const string forceequip_help =

@ -0,0 +1,375 @@
#include "buildingplan-lib.h"
#include <fstream>
#include <vector>
#include "modules/Filesystem.h"
DFHACK_PLUGIN("fortplan");
#define PLUGIN_VERSION 0.15
command_result fortplan(color_ostream &out, vector<string> & params);
struct BuildingInfo {
std::string code;
df::building_type type;
df::furnace_type furnaceType;
df::workshop_type workshopType;
df::trap_type trapType;
std::string name;
bool variableSize;
int defaultHeight;
int defaultWidth;
bool hasCustomOptions;
BuildingInfo(std::string theCode, df::building_type theType, std::string theName, int height, int width) {
code = theCode;
type = theType;
name = theName;
variableSize = false;
defaultHeight = height;
defaultWidth = width;
hasCustomOptions = false;
}
bool allocate() {
return planner.allocatePlannedBuilding(type);
}
};
class MatchesCode
{
std::string _code;
public:
MatchesCode(const std::string &code) : _code(code) {}
bool operator()(const BuildingInfo &check) const
{
return check.code == _code;
}
};
std::vector<BuildingInfo> buildings;
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands) {
commands.push_back(PluginCommand("fortplan","Lay out buildings in your fortress based on a Quickfort-style CSV input file.",fortplan,false,
"Lay out buildings in your fortress based on a Quickfort-style CSV input file.\n"
"Usage: fortplan [filename]\n"));
buildings.push_back(BuildingInfo("c",df::building_type::Chair,"Chair",1,1));
buildings.push_back(BuildingInfo("b",df::building_type::Bed,"Bed",1,1));
buildings.push_back(BuildingInfo("t",df::building_type::Table,"Table",1,1));
buildings.push_back(BuildingInfo("n",df::building_type::Coffin,"Coffin",1,1));
buildings.push_back(BuildingInfo("d",df::building_type::Door,"Door",1,1));
buildings.push_back(BuildingInfo("x",df::building_type::Floodgate,"Floodgate",1,1));
buildings.push_back(BuildingInfo("h",df::building_type::Box,"Box",1,1));
buildings.push_back(BuildingInfo("r",df::building_type::Weaponrack,"Weapon Rack",1,1));
buildings.push_back(BuildingInfo("a",df::building_type::Armorstand,"Armor Stand",1,1));
buildings.push_back(BuildingInfo("f",df::building_type::Cabinet,"Cabinet",1,1));
buildings.push_back(BuildingInfo("s",df::building_type::Statue,"Statue",1,1));
buildings.push_back(BuildingInfo("y",df::building_type::WindowGlass,"Glass Window",1,1));
buildings.push_back(BuildingInfo("m",df::building_type::AnimalTrap,"Animal Trap",1,1));
buildings.push_back(BuildingInfo("v",df::building_type::Chain,"Chain",1,1));
buildings.push_back(BuildingInfo("j",df::building_type::Cage,"Cage",1,1));
buildings.push_back(BuildingInfo("H",df::building_type::Hatch,"Floor Hatch",1,1));
buildings.push_back(BuildingInfo("W",df::building_type::GrateWall,"Wall Grate",1,1));
buildings.push_back(BuildingInfo("G",df::building_type::GrateFloor,"Floor Grate",1,1));
buildings.push_back(BuildingInfo("B",df::building_type::BarsVertical,"Vertical Bars",1,1));
buildings.push_back(BuildingInfo("~b",df::building_type::BarsFloor,"Floor Bars",1,1));
buildings.push_back(BuildingInfo("R",df::building_type::TractionBench,"Traction Bench",1,1));
buildings.push_back(BuildingInfo("~s",df::building_type::Slab,"Slab",1,1));
buildings.push_back(BuildingInfo("N",df::building_type::NestBox,"Nest Box",1,1));
buildings.push_back(BuildingInfo("~h",df::building_type::Hive,"Hive",1,1));
planner.initialize();
return CR_OK;
}
#define DAY_TICKS 1200
DFhackCExport command_result plugin_onupdate(color_ostream &out)
{
static decltype(world->frame_counter) last_frame_count = 0;
if ((world->frame_counter - last_frame_count) >= DAY_TICKS/2)
{
last_frame_count = world->frame_counter;
planner.doCycle();
}
return CR_OK;
}
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)
{
planner.reset(out);
is_enabled = enable;
}
return CR_OK;
}
std::vector<std::vector<std::string>> tokenizeFile(std::string filename) {
std::ifstream infile(filename.c_str());
std::vector<std::vector<std::string>> fileTokens(128, std::vector<std::string>(128));
std::vector<std::vector<std::string>>::size_type x, y;
if (!infile.good()) {
throw -1;
}
std::string line;
y = 0;
while (std::getline(infile, line)) {
x = 0;
if (strcmp(line.substr(0,1).c_str(),"#")==0) {
fileTokens[y++][0] = line;
continue;
}
int start = 0;
auto nextInd = line.find(',');
std::string curCell = line.substr(start,nextInd-start);
do {
fileTokens[y][x] = curCell;
start = nextInd+1;
nextInd = line.find(',',start);
curCell = line.substr(start,nextInd-start);
x++;
} while (nextInd != line.npos);
y++;
}
return fileTokens;
}
command_result fortplan(color_ostream &out, vector<string> & params) {
auto & con = out;
std::vector<std::vector<std::string>> layout(128, std::vector<std::string>(128));
if (params.size()) {
coord32_t cursor;
coord32_t userCursor;
coord32_t startCursor;
if (!DFHack::Gui::getCursorCoords(cursor.x, cursor.y, cursor.z)) {
con.print("You must have an active in-game cursor.\n");
return CR_FAILURE;
}
DFHack::Gui::getCursorCoords(startCursor.x, startCursor.y, startCursor.z);
userCursor = startCursor;
std::string cwd = Filesystem::getcwd();
std::string filename = cwd+"/"+params[0];
con.print("Loading file '%s'...\n",filename.c_str());
try {
layout = tokenizeFile(filename);
} catch (int e) {
con.print("Could not open the file.\n");
return CR_FAILURE;
}
if (!is_enabled) {
plugin_enable(out, true);
}
con.print("Loaded.\n");
std::vector<std::vector<std::string>>::size_type x, y;
bool started = false;
for (y = 0; y < layout.size(); y++) {
x = 0;
auto hashBuild = layout[y][x].find("#build");
if (hashBuild != layout[y][x].npos) {
auto startLoc = layout[y][x].find("start(");
if (startLoc != layout[y][x].npos) {
startLoc += 6;
auto nextDelimiter = layout[y][x].find(";",startLoc);
std::string startXStr = layout[y][x].substr(startLoc,nextDelimiter-startLoc);
int startXOffset = std::stoi(startXStr);
startLoc = nextDelimiter+1;
nextDelimiter = layout[y][x].find(";",startLoc);
std::string startYStr = layout[y][x].substr(startLoc,nextDelimiter-startLoc);
int startYOffset = std::stoi(startYStr);
startCursor.x -= startXOffset;
startCursor.y -= startYOffset;
DFHack::Gui::setCursorCoords(startCursor.x,startCursor.y,startCursor.z);
started = true;
auto startEnd = layout[y][x].find(")",nextDelimiter);
con.print("Starting at (%d,%d,%d) which is described as: %s\n",startCursor.x,startCursor.y,startCursor.z,layout[y][x].substr(nextDelimiter+1,startEnd-nextDelimiter).c_str());
std::string desc = layout[y][x].substr(startEnd+1);
if (desc.size()>0) {
con.print("Description of this plan: %s\n",desc.c_str());
}
continue;
} else {
con.print("No start location found for this block\n");
}
} else if (!started) {
con.print("Not a build file: %s\n",layout[y][x].c_str());
break;
}
for (x = 0; x < layout[y].size(); x++) {
if (strcmp(layout[y][x].substr(0,1).c_str(),"#")==0) {
continue;
}
if (strcmp(layout[y][x].c_str(),"`")!=0) {
auto dataIndex = layout[y][x].find("(");
std::string curCode;
std::vector<std::string> curData;
if (dataIndex != layout[y][x].npos) {
curCode = layout[y][x].substr(0,dataIndex);
int dataStart = dataIndex+1;
auto nextDataStart = layout[y][x].find(",",dataStart);
while (nextDataStart!=layout[y][x].npos) {
std::string nextData = layout[y][x].substr(dataStart,nextDataStart);
if (strcmp(nextData.substr(nextData.size()-1,1).c_str(),")")==0) {
nextData = nextData.substr(0,nextData.size()-1);
}
curData.push_back(nextData);
dataStart = nextDataStart+1;
nextDataStart = layout[y][x].find(",",dataStart);
}
} else {
curCode = layout[y][x];
}
//con.print("Found a cell with '%s' in it (layout[y][x] %d:%d-%d)\n",layout[y][x].c_str(),lineNum,start,nextInd);
auto buildingIndex = std::find_if(buildings.begin(), buildings.end(), MatchesCode(curCode.c_str()));
// = std::find(validInstructions.begin(), validInstructions.end(), layout[y][x]);
if(buildingIndex == buildings.end()) {
//con.print("That is not a valid code.\n");
} else {
//con.print("I can build that!\n");
BuildingInfo buildingInfo = *buildingIndex;
if (buildingInfo.variableSize || buildingInfo.defaultHeight > 1 || buildingInfo.defaultWidth > 1) {
//con.print("Found a building at (%d,%d) called %s, which has a size %dx%d or variable size\n",x,y,buildingInfo.name.c_str(),buildingInfo.defaultWidth, buildingInfo.defaultHeight);
// TODO: Make this function smarter, able to determine the exact shape
// and location of the building
// For now, we just assume that we are always looking at the top left
// corner of where it is located in the input file
coord32_t buildingSize;
if (!buildingInfo.variableSize) {
bool single = true;
bool block = true;
std::vector<std::vector<std::string>>::size_type checkX, checkY;
int yOffset = ((buildingInfo.defaultHeight-1)/2);
int xOffset = ((buildingInfo.defaultWidth-1)/2);
//con.print(" - Checking to see if it's a single, with %d<=x<%d and %d<=y<%d...\n",x-xOffset,x+xOffset,y-yOffset,y+yOffset);
// First, check to see if this is in the center of an empty square of its default size
for (checkY = y-yOffset; checkY <= (y+yOffset); checkY++) {
for (checkX = x-xOffset; checkX <= (x+xOffset); checkX++) {
if (checkX==x && checkY==y) {
continue;
}
auto checkDataIndex = layout[checkY][checkX].find("(");
std::string checkCode;
if (checkDataIndex != layout[checkY][checkX].npos) {
checkCode = layout[checkY][checkX].substr(0,checkDataIndex);
} else {
checkCode = layout[checkY][checkX];
}
con.print(" - Code at (%d,%d) is '%s': ",checkX,checkY,checkCode.c_str());
auto checkIndex = std::find_if(buildings.begin(), buildings.end(), MatchesCode(checkCode.c_str()));
//if (checkIndex == buildings.end()) {
// con.print("this is not a valid code, so we keep going.\n");
// continue;
//}
//if (curCode.compare(layout[checkY][checkX]) != 0) {
if (checkIndex != buildings.end()) {
//con.print("this is a building, so we break.\n");
single = false;
break;
} else {
//con.print("this is not a building, so we keep going.\n");
}
}
if (!single) {
//con.print("Not a single. Moving forward.\n");
break;
}
}
if (!single) {
// If that's not the case, check to see if this is the top-left corner of
// a square of its default size
//con.print(" - It's not single; checking to see if it's a block...\n");
for (checkY = y; checkY < (y+buildingInfo.defaultHeight); checkY++) {
for (checkX = x; checkX < (x+buildingInfo.defaultWidth); checkX++) {
if (checkX==x && checkY==y) {
continue;
}
auto checkDataIndex = layout[checkY][checkX].find("(");
std::string checkCode;
if (checkDataIndex != layout[checkY][checkX].npos) {
checkCode = layout[checkY][checkX].substr(0,checkDataIndex);
} else {
checkCode = layout[checkY][checkX];
}
//con.print(" - Code at (%d,%d) is '%s': ",checkX,checkY,checkCode.c_str());
if (curCode.compare(checkCode) != 0) {
//con.print("this is not the same as '%s', so we break.\n",curCode.c_str());
block = false;
break;
} else {
//con.print("this is the same as '%s', so we erase it and move on.\n",curCode.c_str());
layout[checkY][checkX] = "``";
}
}
if (!block) {
//con.print("Not a block. Moving forward.\n");
break;
}
}
}
if (single) {
//con.print("Placing a building with code '%s' centered at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight);
coord32_t offsetCursor = cursor;
offsetCursor.x -= xOffset;
offsetCursor.y -= yOffset;
DFHack::Gui::setCursorCoords(offsetCursor.x, offsetCursor.y, offsetCursor.z);
if (!buildingInfo.allocate()) {
con.print("*** There was an error placing building with code '%s' centered at (%d,%d).\n",curCode.c_str(),x,y);
}
DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z);
} else if (block) {
//con.print("Placing a building with code '%s' with corner at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight);
if (!buildingInfo.allocate()) {
con.print("*** There was an error placing building with code '%s' with corner at (%d,%d).\n",curCode.c_str(),x,y);
}
} else {
con.print("*** Found a code '%s' at (%d,%d) for a building with default size %dx%d with an invalid size designation.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight);
}
} else {
//buildingSize = findBuildingExtent(layout, x, y, -1, -1, out);
//con.print(" - The building has variable size %dx%d\n",buildingSize.x, buildingSize.y);
//con.print(" - The building has a variable size, which is not yet handled.\n");
}
} else {
//con.print("Building a(n) %s.\n",buildingInfo.name.c_str());
if (!buildingInfo.allocate()) {
con.print("*** There was an error placing the %s at (%d,%d).\n",buildingInfo.name.c_str(),x,y);
}
}
}
}
cursor.x++;
DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z);
}
cursor.y++;
cursor.x = startCursor.x;
}
DFHack::Gui::setCursorCoords(userCursor.x, userCursor.y, userCursor.z);
con.print("Done with file.\n");
} else {
con.print("You must supply a filename to read.\n");
}
return CR_OK;
}

@ -22,7 +22,8 @@ using std::set;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("getplants");
REQUIRE_GLOBAL(world);
command_result df_getplants (color_ostream &out, vector <string> & parameters)
{
@ -148,8 +149,6 @@ command_result df_getplants (color_ostream &out, vector <string> & parameters)
return CR_OK;
}
DFHACK_PLUGIN("getplants");
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -23,12 +23,11 @@ using namespace std;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("infiniteSky");
REQUIRE_GLOBAL(world);
command_result infiniteSky (color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("infiniteSky");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -12,13 +12,12 @@ using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::d_init;
DFHACK_PLUGIN("initflags");
REQUIRE_GLOBAL(d_init);
command_result twaterlvl(color_ostream &out, vector <string> & parameters);
command_result tidlers(color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("initflags");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
if (d_init) {

@ -31,10 +31,11 @@ using namespace DFHack;
using namespace df::enums;
using namespace isoworldremote;
using df::global::gamemode;
using df::global::world;
using df::global::cur_year;
using df::global::cur_season;
DFHACK_PLUGIN("isoworldremote");
REQUIRE_GLOBAL(gamemode);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cur_year);
REQUIRE_GLOBAL(cur_season);
// Here go all the command declarations...
// mostly to allow having the mandatory stuff on top of the file and commands on the bottom
@ -47,11 +48,6 @@ static command_result GetRawNames(color_ostream &stream, const MapRequest *in, R
bool gather_embark_tile_layer(int EmbX, int EmbY, int EmbZ, EmbarkTileLayer * tile, MapExtras::MapCache * MP);
bool gather_embark_tile(int EmbX, int EmbY, EmbarkTile * tile, MapExtras::MapCache * MP);
// A plugin must be able to return its name and version.
// The name string provided must correspond to the filename - skeleton.plug.so or skeleton.plug.dll in this case
DFHACK_PLUGIN("isoworldremote");
// Mandatory init function. If you have some global state, create it here.
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{

@ -31,11 +31,12 @@ using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui;
using df::global::ui_build_selector;
using df::global::ui_workshop_job_cursor;
using df::global::job_next_id;
DFHACK_PLUGIN("jobutils");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_build_selector);
REQUIRE_GLOBAL(ui_workshop_job_cursor);
REQUIRE_GLOBAL(job_next_id);
/* Plugin registration */
@ -45,8 +46,6 @@ static command_result job_material(color_ostream &out, vector <string> & paramet
static command_result job_duplicate(color_ostream &out, vector <string> & parameters);
static command_result job_cmd(color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("jobutils");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
if (!world || !ui)

@ -12,9 +12,9 @@
#include "modules/Gui.h"
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("lair");
REQUIRE_GLOBAL(world);
enum state
{

@ -46,15 +46,15 @@ using std::set;
using namespace MapExtras;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
DFHACK_PLUGIN("liquids");
REQUIRE_GLOBAL(world);
CommandHistory liquids_hist;
command_result df_liquids (color_ostream &out, vector <string> & parameters);
command_result df_liquids_here (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("liquids");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
liquids_hist.load("liquids.history");

@ -0,0 +1,199 @@
local _ENV = mkmodule('plugins.stockpiles')
--[[
Native functions:
* stockpiles_list_settings(dir_path), list files in directory
* stockpiles_load(file), with full path
* stockpiles_save(file), with full path
* isEnabled()
--]]
--
function safe_require(module)
local status, module = pcall(require, module)
return status and module or nil
end
local gui = require 'gui'
local widgets = require('gui.widgets')
local dlg = require('gui.dialogs')
local script = require 'gui.script'
local persist = safe_require('persist-table')
function ListFilterDialog(args)
args.text = args.prompt or 'Type or select an option'
args.text_pen = COLOR_WHITE
args.with_filter = true
args.icon_width = 2
local choices = {}
if not args.hide_none then
table.insert(choices, {
icon = '?', text = args.none_caption or 'none',
index = -1, name = -1
})
end
local filter = args.item_filter
for i,v in ipairs(args.items) do
if not filter or filter(v,-1) then
local name = v
local icon
table.insert(choices, {
icon = icon, search_key = string.lower(name), text = name, index = i
})
end
end
args.choices = choices
if args.on_select then
local cb = args.on_select
args.on_select = function(idx, obj)
return cb(obj.index, args.items[obj.index])
end
end
return dlg.ListBox(args)
end
function showFilterPrompt(title, list, text,item_filter,hide_none)
ListFilterDialog{
frame_title=title,
items=list,
prompt=text,
item_filter=item_filter,
hide_none=hide_none,
on_select=script.mkresume(true),
on_cancel=script.mkresume(false),
on_close=script.qresume(nil)
}:show()
return script.wait()
end
function init()
if persist == nil then return end
if dfhack.isMapLoaded() then
if persist.GlobalTable.stockpiles == nil then
persist.GlobalTable.stockpiles = {}
persist.GlobalTable.stockpiles['settings_path'] = './stocksettings'
end
end
end
function tablify(iterableObject)
t={}
for k,v in ipairs(iterableObject) do
t[k] = v~=nil and v or 'nil'
end
return t
end
function load_settings()
init()
local path = get_path()
local ok, list = pcall(stockpiles_list_settings, path)
if not ok then
show_message_box("Stockpile Settings", "The stockpile settings folder doesn't exist.", true)
return
end
if #list == 0 then
show_message_box("Stockpile Settings", "There are no saved stockpile settings.", true)
return
end
local choice_list = {}
for i,v in ipairs(list) do
choice_list[i] = string.gsub(v, "/", "/ ")
choice_list[i] = string.gsub(choice_list[i], "-", " - ")
choice_list[i] = string.gsub(choice_list[i], "_", " ")
end
script.start(function()
local ok2,index,name=showFilterPrompt('Stockpile Settings', choice_list, 'Choose a stockpile', function(item) return true end, true)
if ok2 then
local filename = list[index];
stockpiles_load(path..'/'..filename)
end
end)
end
function save_settings(stockpile)
init()
script.start(function()
local suggested = stockpile.name
if #suggested == 0 then
suggested = 'Stock1'
end
local path = get_path()
local sok,filename = script.showInputPrompt('Stockpile Settings', 'Enter stockpile name', COLOR_WHITE, suggested)
if sok then
if filename == nil or filename == '' then
script.showMessage('Stockpile Settings', 'Invalid File Name', COLOR_RED)
else
print("saving...", path..'/'..filename)
stockpiles_save(path..'/'..filename)
end
end
end)
end
function manage_settings(sp)
init()
if not guard() then return false end
script.start(function()
local list = {'Load', 'Save'}
local tok,i = script.showListPrompt('Stockpile Settings','Load or Save Settings?',COLOR_WHITE,tablify(list))
if tok then
if i == 1 then
load_settings()
else
save_settings(sp)
end
end
end)
end
function show_message_box(title, msg, iserror)
local color = COLOR_WHITE
if iserror then
color = COLOR_RED
end
script.start(function()
script.showMessage(title, msg, color)
end)
end
function guard()
if not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/QueryBuilding/Some/Stockpile') then
qerror("This script requires a stockpile selected in the 'q' mode")
return false
end
return true
end
function set_path(path)
init()
if persist == nil then
qerror("This version of DFHack doesn't support setting the stockpile settings path. Sorry.")
return
end
persist.GlobalTable.stockpiles['settings_path'] = path
end
function get_path()
init()
if persist == nil then
return "stocksettings"
end
return persist.GlobalTable.stockpiles['settings_path']
end
return _ENV

@ -36,10 +36,12 @@ using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui;
using df::global::gps;
using df::global::enabler;
DFHACK_PLUGIN("manipulator");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(enabler);
struct SkillLevel
{
@ -189,7 +191,9 @@ const SkillColumn columns[] = {
{12, 4, profession::ALCHEMIST, unit_labor::ALCHEMIST, job_skill::ALCHEMY, "Al"},
{12, 4, profession::NONE, unit_labor::CLEAN, job_skill::NONE, "Cl"},
{12, 4, profession::NONE, unit_labor::PULL_LEVER, job_skill::NONE, "Lv"},
{12, 4, profession::NONE, unit_labor::REMOVE_CONSTRUCTION, job_skill::NONE, "Co"},
{12, 4, profession::NONE, unit_labor::BUILD_ROAD, job_skill::NONE, "Ro"},
{12, 4, profession::NONE, unit_labor::BUILD_CONSTRUCTION, job_skill::NONE, "Co"},
{12, 4, profession::NONE, unit_labor::REMOVE_CONSTRUCTION, job_skill::NONE, "CR"},
// Military - Weapons
{13, 7, profession::WRESTLER, unit_labor::NONE, job_skill::WRESTLING, "Wr"},
{13, 7, profession::AXEMAN, unit_labor::NONE, job_skill::AXE, "Ax"},
@ -1219,7 +1223,7 @@ void viewscreen_unitlaborsst::render()
OutputString(10, x, y, Screen::getKeyDisplay(interface_key::OPTION20));
OutputString(15, x, y, ": Toggle View, ");
OutputString(10, x, y, Screen::getKeyDisplay(interface_key::SECONDSCROLL_DOWN));
OutputString(10, x, y, Screen::getKeyDisplay(interface_key::SECONDSCROLL_UP));
OutputString(15, x, y, ": Sort by Skill, ");
@ -1291,10 +1295,6 @@ struct unitlist_hook : df::viewscreen_unitlistst
IMPLEMENT_VMETHOD_INTERPOSE(unitlist_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(unitlist_hook, render);
DFHACK_PLUGIN("manipulator");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
if (!gps)

@ -15,11 +15,12 @@
using namespace std;
using namespace DFHack;
using df::global::world;
using df::global::ui;
DFHACK_PLUGIN("misery");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
static int factor = 1;
static map<int, int> processedThoughtCountTable;
@ -28,8 +29,6 @@ static vector<std::pair<int,int> > fakeThoughts;
static int count;
const int maxCount = 1000;
DFHACK_PLUGIN("misery");
command_result misery(color_ostream& out, vector<string>& parameters);
DFhackCExport command_result plugin_shutdown(color_ostream& out) {

@ -21,14 +21,13 @@
#include "TileTypes.h"
#include "DataFuncs.h"
using df::global::world;
using df::global::ui;
using df::global::ui_build_selector;
DFHACK_PLUGIN("mousequery");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_build_selector);
using namespace df::enums::ui_sidebar_mode;
DFHACK_PLUGIN("mousequery");
#define PLUGIN_VERSION 0.18
static int32_t last_clicked_x, last_clicked_y, last_clicked_z;
@ -99,7 +98,7 @@ static vector<df::unit *> get_units_at(const df::coord pos, bool only_one)
{
df::unit *unit = world->units.active[i];
if(unit->pos.x == pos.x && unit->pos.y == pos.y && unit->pos.z == pos.z &&
if(unit->pos.x == pos.x && unit->pos.y == pos.y && unit->pos.z == pos.z &&
!(unit->flags1.whole & bad_flags.whole) &&
unit->profession != profession::THIEF && unit->profession != profession::MASTER_THIEF)
{
@ -169,7 +168,7 @@ static df::interface_key get_default_query_mode(const df::coord pos)
{
// For containers use item view, for everything else, query view
return (type == building_type::Box || type == building_type::Cabinet ||
type == building_type::Weaponrack || type == building_type::Armorstand)
type == building_type::Weaponrack || type == building_type::Armorstand)
? df::interface_key::D_BUILDITEM : df::interface_key::D_BUILDJOB;
}
}
@ -210,13 +209,22 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
case DesignateCarveTrack:
case DesignateEngrave:
case DesignateCarveFortification:
case DesignateItemsClaim:
case DesignateItemsForbid:
case DesignateItemsMelt:
case DesignateItemsUnmelt:
case DesignateItemsDump:
case DesignateItemsUndump:
case DesignateItemsHide:
case DesignateItemsUnhide:
case DesignateChopTrees:
case DesignateToggleEngravings:
case DesignateRemoveConstruction:
case DesignateToggleMarker:
case DesignateTrafficHigh:
case DesignateTrafficNormal:
case DesignateTrafficLow:
case DesignateTrafficRestricted:
case DesignateRemoveConstruction:
return true;
case Burrows:
@ -268,7 +276,7 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
bool isInAreaSelectionMode()
{
bool selectableMode =
bool selectableMode =
isInDesignationMenu() ||
ui->main.mode == Stockpiles ||
ui->main.mode == Zones;
@ -357,13 +365,13 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
enabler->mouse_lbut = 0;
// Can't check limits earlier as we must be sure we are in query or default mode
// Can't check limits earlier as we must be sure we are in query or default mode
// (so we can clear the button down flag)
int right_bound = (dims.menu_x1 > 0) ? dims.menu_x1 - 2 : gps->dimx - 2;
if (mx < 1 || mx > right_bound || my < 1 || my > gps->dimy - 2)
return false;
if (ui->main.mode == df::ui_sidebar_mode::Zones ||
if (ui->main.mode == df::ui_sidebar_mode::Zones ||
ui->main.mode == df::ui_sidebar_mode::Stockpiles)
{
int32_t x, y, z;
@ -414,7 +422,7 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
using namespace df::enums::ui_sidebar_mode;
if ((ui->main.mode == QueryBuilding || ui->main.mode == BuildingItems ||
ui->main.mode == ViewUnits || ui->main.mode == LookAround) ||
ui->main.mode == ViewUnits || ui->main.mode == LookAround) ||
(isInTrackableMode() && tracking_enabled))
{
sendKey(df::interface_key::LEAVESCREEN);
@ -436,7 +444,7 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
sendKey(interface_key::CURSOR_DOWN_FAST);
}
}
else if (input->count(interface_key::CUSTOM_M) && isInDesignationMenu())
else if (input->count(interface_key::CUSTOM_ALT_M) && isInDesignationMenu())
{
box_designation_enabled = !box_designation_enabled;
}
@ -549,7 +557,7 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
mpos_valid = false;
// Check if in lever binding mode
if (Gui::getFocusString(Core::getTopViewscreen()) ==
if (Gui::getFocusString(Core::getTopViewscreen()) ==
"dwarfmode/QueryBuilding/Some/Lever/AddJob")
{
return;
@ -571,9 +579,9 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
if (isInDesignationMenu())
{
int x = left_margin;
int y = 24;
OutputString(COLOR_BROWN, x, y, "DFHack MouseQuery", true, left_margin);
OutputToggleString(x, y, "Box Select", "m", box_designation_enabled, true, left_margin);
int y = gps->dimy - 2;
OutputToggleString(x, y, "Box Select", "Alt+M", box_designation_enabled,
true, left_margin, COLOR_WHITE, COLOR_LIGHTRED);
}
//Display selection dimensions
@ -651,7 +659,7 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
if (Gui::getDesignationCoords(x, y, z))
{
color = COLOR_WHITE;
if (ui->main.mode == df::ui_sidebar_mode::Zones ||
if (ui->main.mode == df::ui_sidebar_mode::Zones ||
ui->main.mode == df::ui_sidebar_mode::Stockpiles)
{
auto dX = abs(x - mpos.x);
@ -670,8 +678,8 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest
if (shouldTrack())
{
if (delta_t <= scroll_delay && (mx < scroll_buffer ||
mx > dims.menu_x1 - scroll_buffer ||
if (delta_t <= scroll_delay && (mx < scroll_buffer ||
mx > dims.menu_x1 - scroll_buffer ||
my < scroll_buffer ||
my > gps->dimy - scroll_buffer))
{
@ -831,7 +839,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
commands.push_back(
PluginCommand(
"mousequery", "Add mouse functionality to Dwarf Fortress",
mousequery_cmd, false,
mousequery_cmd, false,
"mousequery [plugin|rbutton|track|edge|live] [enabled|disabled]\n"
" plugin: enable/disable the entire plugin\n"
" rbutton: enable/disable right mouse button\n"

@ -20,17 +20,17 @@
using namespace DFHack;
using namespace std;
using df::global::world;
DFHACK_PLUGIN("petcapRemover");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(world);
static int32_t howOften = 10000;
static int32_t popcap = 100;
static int32_t pregtime = 200000;
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
command_result petcapRemover (color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("petcapRemover");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(

@ -18,11 +18,11 @@
using std::vector;
using std::string;
using namespace DFHack;
using df::global::world;
const uint32_t sapling_to_tree_threshold = 120 * 28 * 12 * 3 - 1; // 3 years minus 1 - let the game handle the actual growing-up
DFHACK_PLUGIN("plants");
REQUIRE_GLOBAL(world);
const uint32_t sapling_to_tree_threshold = 120 * 28 * 12 * 3 - 1; // 3 years minus 1 - let the game handle the actual growing-up
/* Immolate/Extirpate no longer work in 0.40
enum do_what

@ -38,12 +38,11 @@ using std::stack;
using namespace DFHack;
using namespace df::enums;
using df::global::gps;
using df::global::world;
using df::global::ui;
using df::global::ui_build_selector;
DFHACK_PLUGIN("power-meter");
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_build_selector);
static const uint32_t METER_BIT = 0x80000000U;

@ -33,15 +33,15 @@ using std::vector;
using std::string;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::cursor;
DFHACK_PLUGIN("probe");
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(cursor);
command_result df_probe (color_ostream &out, vector <string> & parameters);
command_result df_cprobe (color_ostream &out, vector <string> & parameters);
command_result df_bprobe (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("probe");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand("probe",

Some files were not shown because too many files have changed in this diff Show More