Merged branch develop into develop

develop
Japa 2017-03-18 00:26:01 +05:30
commit 61c2fb0a11
31 changed files with 562 additions and 141 deletions

@ -9,10 +9,31 @@ function(file_md5_if_exists FILE VAR)
endif() endif()
endfunction() endfunction()
function(search_downloads FILE_MD5 VAR)
set(${VAR} "" PARENT_SCOPE)
file(GLOB FILES ${CMAKE_SOURCE_DIR}/CMake/downloads/*)
foreach(FILE ${FILES})
file(MD5 "${FILE}" CUR_MD5)
if("${CUR_MD5}" STREQUAL "${FILE_MD5}")
set(${VAR} ${FILE} PARENT_SCOPE)
return()
endif()
endforeach()
endfunction()
function(download_file URL DEST EXPECTED_MD5) function(download_file URL DEST EXPECTED_MD5)
get_filename_component(FILENAME "${URL}" NAME) get_filename_component(FILENAME "${URL}" NAME)
file_md5_if_exists("${DEST}" CUR_MD5) file_md5_if_exists("${DEST}" CUR_MD5)
search_downloads(${EXPECTED_MD5} DLPATH)
if(NOT("${DLPATH}" STREQUAL ""))
message("* Copying ${FILENAME} from ${DLPATH}")
execute_process(COMMAND "${CMAKE_COMMAND}" -E copy
"${DLPATH}"
"${DEST}")
return()
endif()
if(NOT "${EXPECTED_MD5}" STREQUAL "${CUR_MD5}") if(NOT "${EXPECTED_MD5}" STREQUAL "${CUR_MD5}")
message("* Downloading ${FILENAME}") message("* Downloading ${FILENAME}")
file(DOWNLOAD "${URL}" "${DEST}" EXPECTED_MD5 "${EXPECTED_MD5}" SHOW_PROGRESS) file(DOWNLOAD "${URL}" "${DEST}" EXPECTED_MD5 "${EXPECTED_MD5}" SHOW_PROGRESS)

@ -0,0 +1,3 @@
*
!README.txt
!.gitignore

@ -0,0 +1,3 @@
This folder exists as an alternate location for downloaded files. Files will
ordinarily not be downloaded here, but CMake will look for them here anyway to
facilitate offline builds.

@ -137,7 +137,7 @@ endif()
# set up versioning. # set up versioning.
set(DF_VERSION "0.43.05") set(DF_VERSION "0.43.05")
SET(DFHACK_RELEASE "alpha4") SET(DFHACK_RELEASE "beta1")
SET(DFHACK_PRERELEASE TRUE) SET(DFHACK_PRERELEASE TRUE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")

@ -64,6 +64,7 @@ Ruby
New Plugins New Plugins
----------- -----------
- `dwarfvet` enables animal caretaking - `dwarfvet` enables animal caretaking
- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs
- `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor` - `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor`
- `misery`: re-added and updated for the 0.4x series - `misery`: re-added and updated for the 0.4x series
- `title-folder`: shows DF folder name in window title bar when enabled - `title-folder`: shows DF folder name in window title bar when enabled
@ -80,6 +81,7 @@ Fixes
----- -----
- The DF path on OS X can now contain spaces and ``:`` characters - The DF path on OS X can now contain spaces and ``:`` characters
- Buildings::setOwner() changes now persist properly when saved - Buildings::setOwner() changes now persist properly when saved
- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable
- `add-thought`: fixed support for emotion names - `add-thought`: fixed support for emotion names
- `autofarm`: Made surface farms detect local biome - `autofarm`: Made surface farms detect local biome
- `devel/find-offsets`: fixed a crash when vtables used by globals aren't available - `devel/find-offsets`: fixed a crash when vtables used by globals aren't available
@ -88,6 +90,10 @@ Fixes
- Fixed crash when selecting a profession from an empty list - Fixed crash when selecting a profession from an empty list
- Custom professions are now sorted alphabetically more reliably - Custom professions are now sorted alphabetically more reliably
- `modtools/create-unit`: stopped permanently overwriting the creature creation
menu in arena mode
- `title-version`: now hidden when loading an arena
Misc Improvements Misc Improvements
----------------- -----------------
- Documented all default keybindings (from :file:`dfhack.init-example`) in the - Documented all default keybindings (from :file:`dfhack.init-example`) in the
@ -101,6 +107,8 @@ Misc Improvements
- site towers, world buildings - site towers, world buildings
- surface material - surface material
- `title-version`: Added a prerelease indicator
DFHack 0.43.03-r1 DFHack 0.43.03-r1
================= =================

@ -1,9 +0,0 @@
@echo off
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32
cd VC2015_32
echo generating a build folder
rem for /f "delims=" %%a in ('DATE /T') do @set myvar=breakfast-%BUILD_NUMBER%
set myvar=breakfast-%BUILD_NUMBER%
cmake ..\..\.. -G"Visual Studio 14" -DDFHACK_RELEASE="%myvar%" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32 mkdir VC2015_32
cd VC2015_32 cd VC2015_32
echo generating a build folder echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_STONESENSE=1

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32 mkdir VC2015_32
cd VC2015_32 cd VC2015_32
echo generating a build folder echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_STONESENSE=0

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32 mkdir VC2015_32
cd VC2015_32 cd VC2015_32
echo generating a build folder echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DOCS=1 -DBUILD_STONESENSE=1

@ -1,9 +0,0 @@
@echo off
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015
cd VC2015
echo generating a build folder
rem for /f "delims=" %%a in ('DATE /T') do @set myvar=breakfast-%BUILD_NUMBER%
set myvar=breakfast-%BUILD_NUMBER%
cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DDFHACK_RELEASE="%myvar%" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015 mkdir VC2015
cd VC2015 cd VC2015
echo generating a build folder echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_STONESENSE=1

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015 mkdir VC2015
cd VC2015 cd VC2015
echo generating a build folder echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_RUBY=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_STONESENSE=0

@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015 mkdir VC2015
cd VC2015 cd VC2015
echo generating a build folder echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DOCS=1 -DBUILD_STONESENSE=1

@ -200,8 +200,8 @@
LUA_CDIR"?.so;" "./?.so" LUA_CDIR"?.so;" "./?.so"
#endif /* } */ #endif /* } */
#define LUA_PATH "DFHACK_LUA_PATH" #define LUA_PATH_VAR "DFHACK_LUA_PATH"
#define LUA_CPATH "DFHACK_LUA_CPATH" #define LUA_CPATH_VAR "DFHACK_LUA_CPATH"
/* /*
@@ LUA_DIRSEP is the directory separator (for submodules). @@ LUA_DIRSEP is the directory separator (for submodules).

@ -31,6 +31,8 @@ To get the latest development code (develop branch), clone as above and then::
git checkout develop git checkout develop
git submodule update git submodule update
Generally, you should only need to clone DFHack once.
**Important note regarding submodule update and changing branches**: **Important note regarding submodule update and changing branches**:
You must run ``git submodule update`` every time you change branches, You must run ``git submodule update`` every time you change branches,
@ -39,17 +41,10 @@ If a submodule only exists on the newer branch, you also need to run
``git submodule update --init``. Failure to do this may result in strange ``git submodule update --init``. Failure to do this may result in strange
build errors or "not a known DF version" errors. build errors or "not a known DF version" errors.
**Important note regarding very old git versions** **More notes**:
If you are using git 1.8.0 or older, and cloned DFHack before commit 85a920d * `note-offline-builds` - read this if your build machine may not have an internet connection!
(around DFHack v0.43.03-alpha1), you may run into fatal git errors when updating * `note-old-git-and-dfhack`
submodules after switching branches. This is due to those versions of git being
unable to handle our change from "scripts/3rdparty/name" submodules to a single
"scripts" submodule. This may be fixable by renaming .git/modules/scripts to
something else and re-running ``git submodule update --init`` on the branch with
the single scripts submodule (and running it again when switching back to the
one with multiple submodules, if necessary), but it is usually much simpler to
upgrade your git version.
Contributing to DFHack Contributing to DFHack
====================== ======================
@ -100,6 +95,9 @@ change, so specifying it explicitly is a good idea.
cmake .. -DDFHACK_BUILD_ARCH=64 cmake .. -DDFHACK_BUILD_ARCH=64
Note that the scripts in the "build" folder on Windows will set the architecture
automatically.
Other settings Other settings
-------------- --------------
There are a variety of other settings which you can find in CMakeCache.txt in There are a variety of other settings which you can find in CMakeCache.txt in
@ -355,47 +353,34 @@ Dependencies
------------ ------------
You will need the following: You will need the following:
* Microsoft Visual Studio 2010 SP1, with the C++ language * Microsoft Visual Studio 2015, with the C++ language
* Git * Git
* CMake * CMake
* Perl with XML::LibXML and XML::LibXSLT * Perl with XML::LibXML and XML::LibXSLT
* It is recommended to install StrawberryPerl, which includes both. * It is recommended to install StrawberryPerl, which includes both.
Microsoft Visual Studio 2010 SP1 * Python (for documentation; optional, except for release builds)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DFHack has to be compiled with the Microsoft Visual C++ 2010 SP1 toolchain; later
versions won't work against Dwarf Fortress due to ABI and STL incompatibilities.
At present, the only way to obtain the MSVC C++ 2010 toolchain is to install a
full copy of Microsoft Visual Studio 2010 SP1. The free Express version is sufficient.
You can grab it from `Microsoft's site <http://download.microsoft.com/download/1/E/5/1E5F1C0A-0D5B-426A-A603-1798B951DDAE/VS2010Express1.iso>`_.
You should also install the Visual Studio 2010 SP1 update.
You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE
and selecting About from the Help menu. If you have SP1 it will have *SP1Rel*
at the end of the version number, for example: *Version 10.0.40219.1 SP1Rel*
Use of pre-SP1 releases has been reported to cause issues and is therefore not
supported by DFHack. Please ensure you are using SP1 before raising any Issues.
If your Windows Update is configured to receive updates for all Microsoft Microsoft Visual Studio 2015
Products, not just Windows, you will receive the SP1 update automatically ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
through Windows Update (you will probably need to trigger a manual check.) DFHack has to be compiled with the Microsoft Visual C++ 2015 toolchain; other
versions won't work against Dwarf Fortress due to ABI and STL incompatibilities.
If not, you can download it directly `from this Microsoft Download link <https://www.microsoft.com/en-gb/download/details.aspx?id=23691>`_. At present, the only way to obtain the MSVC C++ 2015 toolchain is to install a
full copy of Microsoft Visual Studio 2015. The free Community version is
sufficient.
Additional dependencies: installing with the Chocolatey Package Manager Additional dependencies: installing with the Chocolatey Package Manager
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The remainder of dependencies - Git, CMake and StrawberryPerl - can be most
easily installed using the Chocolatey Package Manger. Chocolatey is a The remainder of dependencies - Git, CMake, StrawberryPerl, and Python - can be
most easily installed using the Chocolatey Package Manger. Chocolatey is a
\*nix-style package manager for Windows. It's fast, small (8-20MB on disk) \*nix-style package manager for Windows. It's fast, small (8-20MB on disk)
and very capable. Think "``apt-get`` for Windows." and very capable. Think "``apt-get`` for Windows."
Chocolatey is a preferred way of installing the required dependencies Chocolatey is a recommended way of installing the required dependencies
as it's quicker, less effort and will install known-good utilities as it's quicker, requires less effort, and will install known-good utilities
guaranteed to have the correct setup (especially PATH). guaranteed to have the correct setup (especially PATH).
To install Chocolatey and the required dependencies: To install Chocolatey and the required dependencies:
@ -482,8 +467,10 @@ install XML::LibXML and XML::LibXSLT for it using CPAN.
Build Build
----- -----
There are several different batch files in the ``build`` folder along There are several different batch files in the ``win32`` and ``win64``
with a script that's used for picking the DF path. subfolders in the ``build`` folder, along with a script that's used for picking
the DF path. Use the subfolder corresponding to the architecture that you want
to build for.
First, run ``set_df_path.vbs`` and point the dialog that pops up at First, run ``set_df_path.vbs`` and point the dialog that pops up at
a suitable DF installation which is of the appropriate version for the DFHack a suitable DF installation which is of the appropriate version for the DFHack
@ -501,6 +488,9 @@ solution file(s):
in, then hit configure, then generate. More options can appear after the configure step. in, then hit configure, then generate. More options can appear after the configure step.
* ``minimal`` will create a minimal solution with just the bare necessities - * ``minimal`` will create a minimal solution with just the bare necessities -
the main library and standard plugins. the main library and standard plugins.
* ``release`` will create a solution with everything that should be included in
release builds of DFHack. Note that this includes documentation, which requires
Python.
Then you can either open the solution with MSVC or use one of the msbuild scripts: Then you can either open the solution with MSVC or use one of the msbuild scripts:
@ -548,9 +538,10 @@ files as detailed above.
Building/installing from the Visual Studio IDE: Building/installing from the Visual Studio IDE:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After running the CMake generate script you will have a new folder called VC2010. After running the CMake generate script you will have a new folder called VC2015
Open the file ``dfhack.sln`` inside that folder. If you have multiple versions of or VC2015_32, depending on the architecture you specified. Open the file
Visual Studio installed, make sure you open with Visual Studio 2010. ``dfhack.sln`` inside that folder. If you have multiple versions of Visual
Studio installed, make sure you open with Visual Studio 2015.
The first thing you must then do is change the build type. It defaults to Debug, The first thing you must then do is change the build type. It defaults to Debug,
but this cannot be used on Windows. Debug is not binary-compatible with DF. but this cannot be used on Windows. Debug is not binary-compatible with DF.
@ -674,3 +665,52 @@ Chocolatey as outlined in the `Windows section <compile-windows>`::
Then close that Admin ``cmd.exe``, re-open another Admin ``cmd.exe``, and run:: Then close that Admin ``cmd.exe``, re-open another Admin ``cmd.exe``, and run::
pip install sphinx pip install sphinx
Misc. Notes
===========
.. _note-offline-builds:
Note on building DFHack offline
-------------------------------
As of 0.43.05, DFHack downloads several files during the build process, depending
on your target OS and architecture. If your build machine's internet connection
is unreliable, or nonexistent, you can download these files in advance.
First, you must locate the files you will need. These can be found in the
`dfhack-bin repo <https://github.com/DFHack/dfhack-bin/releases>`_. Look for the
most recent version number *before or equal to* the DF version which you are
building for. For example, suppose "0.43.05" and "0.43.07" are listed. You should
choose "0.43.05" if you are building for 0.43.05 or 0.43.06, and "0.43.07" if
you are building for 0.43.07 or 0.43.08.
Then, download all of the files you need, and save them to ``<path to DFHack
clone>/CMake/downloads/<any filename>``. The destination filename you choose
does not matter, as long as the files end up in the ``CMake/downloads`` folder.
You need to download all of the files for the architecture(s) you are building
for. For example, if you are building for 32-bit Linux and 64-bit Windows,
download all files starting with ``linux32`` and ``win64``. GitHub should sort
files alphabetically, so all the files you need should be next to each other.
It is recommended that you create a build folder and run CMake to verify that
you have downloaded everything at this point, assuming your download machine has
CMake installed. This involves running a "generate" batch script on Windows, or
a command starting with ``cmake ..`` on Linux and OS X. CMake should
automatically locate files that you placed in ``CMake/downloads``, and use them
instead of attempting to download them.
.. _note-old-git-and-dfhack:
Note on using very old git versions with pre-0.43.03 DFHack versions
--------------------------------------------------------------------
If you are using git 1.8.0 or older, and cloned DFHack before commit 85a920d
(around DFHack v0.43.03-alpha1), you may run into fatal git errors when updating
submodules after switching branches. This is due to those versions of git being
unable to handle our change from "scripts/3rdparty/name" submodules to a single
"scripts" submodule. This may be fixable by renaming .git/modules/scripts to
something else and re-running ``git submodule update --init`` on the branch with
the single scripts submodule (and running it again when switching back to the
one with multiple submodules, if necessary), but it is usually much simpler to
upgrade your git version.

@ -37,6 +37,38 @@ Development Changelog
.. contents:: .. contents::
:depth: 2 :depth: 2
DFHack 0.43.05-beta1
====================
Fixes
-----
- Fixed various crashes on 64-bit Windows related to DFHack screens, notably `manipulator`
- Fixed addresses of next_id globals on 64-bit Linux (fixes an `automaterial`/box-select crash)
- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable
- `modtools/create-unit`: stopped permanently overwriting the creature creation
menu in arena mode
- `season-palette`: fixed an issue where only part of the screen was redrawn
after changing the color scheme
- `title-version`: now hidden when loading an arena
Structures
----------
- ``file_compressorst``: fixed field sizes on x64
- ``historical_entity``: fixed alignment on x64
- ``ui_sidebar_menus.command_line``: fixed field sizes on x64
- ``viewscreen_choose_start_sitest``: added 3 missing fields, renamed ``in_embark_only_warning``
- ``viewscreen_layer_arena_creaturest``: identified more fields
- ``world.math``: identified
- ``world.murky_pools``: identified
Additions/Removals
------------------
- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs
Other Changes
-------------
- `title-version`: Added a prerelease indicator
DFHack 0.43.05-alpha4 DFHack 0.43.05-alpha4
===================== =====================

@ -2453,6 +2453,24 @@ armor onto a war animal or to add unusual items (such as crowns) to any unit.
For more information run ``forceequip help``. See also `modtools/equip-item`. For more information run ``forceequip help``. See also `modtools/equip-item`.
.. _generated-creature-renamer:
generated-creature-renamer
==========================
Automatically renames generated creatures, such as forgotten beasts, titans,
etc, to have raw token names that match the description given in-game.
The ``list-generated`` command can be used to list the token names of all
generated creatures in a given save, with an optional ``detailed`` argument
to show the accompanying description.
The ``save-generated-raws`` command will save a sample creature graphics file in
the Dwarf Fortress root directory, to use as a start for making a graphics set
for generated creatures using the new names that they get with this plugin.
The new names are saved with the save, and the plugin, when enabled, only runs once
per save, unless there's an update.
.. _lair: .. _lair:
lair lair
@ -2522,7 +2540,7 @@ Options:
:-unit: Make the strange mood strike the selected unit instead of picking :-unit: Make the strange mood strike the selected unit instead of picking
one randomly. Unit eligibility is still enforced. one randomly. Unit eligibility is still enforced.
:-type <T>: Force the mood to be of a particular type instead of choosing randomly based on happiness. :-type <T>: Force the mood to be of a particular type instead of choosing randomly based on happiness.
Valid values for Tare "fey", "secretive", "possessed", "fell", and "macabre". Valid values for T are "fey", "secretive", "possessed", "fell", and "macabre".
:-skill S: Force the mood to use a specific skill instead of choosing the highest moodable skill. :-skill S: Force the mood to use a specific skill instead of choosing the highest moodable skill.
Valid values are "miner", "carpenter", "engraver", "mason", "tanner", "weaver", Valid values are "miner", "carpenter", "engraver", "mason", "tanner", "weaver",
"clothier", "weaponsmith", "armorsmith", "metalsmith", "gemcutter", "gemsetter", "clothier", "weaponsmith", "armorsmith", "metalsmith", "gemcutter", "gemsetter",

@ -279,19 +279,24 @@ static void listScripts(PluginManager *plug_mgr, std::map<string,string> &pset,
std::vector<string> files; std::vector<string> files;
Filesystem::listdir(path, files); Filesystem::listdir(path, files);
path += '/';
for (size_t i = 0; i < files.size(); i++) for (size_t i = 0; i < files.size(); i++)
{ {
if (hasEnding(files[i], ".lua")) if (hasEnding(files[i], ".lua"))
{ {
std::string help = getScriptHelp(path + files[i], "--"); string help = getScriptHelp(path + files[i], "--");
string key = prefix + files[i].substr(0, files[i].size()-4);
pset[prefix + files[i].substr(0, files[i].size()-4)] = help; if (pset.find(key) == pset.end()) {
pset[key] = help;
}
} }
else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && hasEnding(files[i], ".rb")) else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && hasEnding(files[i], ".rb"))
{ {
std::string help = getScriptHelp(path + files[i], "#"); string help = getScriptHelp(path + files[i], "#");
string key = prefix + files[i].substr(0, files[i].size()-3);
pset[prefix + files[i].substr(0, files[i].size()-3)] = help; if (pset.find(key) == pset.end()) {
pset[key] = help;
}
} }
else if (all && !files[i].empty() && files[i][0] != '.') else if (all && !files[i].empty() && files[i][0] != '.')
{ {
@ -300,6 +305,14 @@ static void listScripts(PluginManager *plug_mgr, std::map<string,string> &pset,
} }
} }
static void listAllScripts(map<string, string> &pset, bool all)
{
vector<string> paths;
Core::getInstance().getScriptPaths(&paths);
for (string path : paths)
listScripts(Core::getInstance().getPluginManager(), pset, path, all);
}
namespace { namespace {
struct ScriptArgs { struct ScriptArgs {
const string *pcmd; const string *pcmd;
@ -418,7 +431,7 @@ static bool try_autocomplete(color_ostream &con, const std::string &first, std::
bool all = (first.find('/') != std::string::npos); bool all = (first.find('/') != std::string::npos);
std::map<string, string> scripts; std::map<string, string> scripts;
listScripts(plug_mgr, scripts, Core::getInstance().getHackPath() + "scripts/", all); listAllScripts(scripts, all);
for (auto iter = scripts.begin(); iter != scripts.end(); ++iter) for (auto iter = scripts.begin(); iter != scripts.end(); ++iter)
if (iter->first.substr(0, first.size()) == first) if (iter->first.substr(0, first.size()) == first)
possible.push_back(iter->first); possible.push_back(iter->first);
@ -907,7 +920,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
con.reset_color(); con.reset_color();
} }
std::map<string, string> scripts; std::map<string, string> scripts;
listScripts(plug_mgr, scripts, getHackPath() + "scripts/", all); listAllScripts(scripts, all);
if (!scripts.empty()) if (!scripts.empty())
{ {
con.print("\nscripts:\n"); con.print("\nscripts:\n");
@ -918,8 +931,8 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
} }
else if (builtin == "plug") else if (builtin == "plug")
{ {
const char *header_format = "%25s %10s %4s %8s\n"; const char *header_format = "%30s %10s %4s %8s\n";
const char *row_format = "%25s %10s %4i %8s\n"; const char *row_format = "%30s %10s %4i %8s\n";
con.print(header_format, "Name", "State", "Cmds", "Enabled"); con.print(header_format, "Name", "State", "Cmds", "Enabled");
plug_mgr->refresh(); plug_mgr->refresh();
@ -1043,7 +1056,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
<< " keybinding set <key>[@context] \"cmdline\" \"cmdline\"..." << endl << " keybinding set <key>[@context] \"cmdline\" \"cmdline\"..." << endl
<< " keybinding add <key>[@context] \"cmdline\" \"cmdline\"..." << endl << " keybinding add <key>[@context] \"cmdline\" \"cmdline\"..." << endl
<< "Later adds, and earlier items within one command have priority." << endl << "Later adds, and earlier items within one command have priority." << endl
<< "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, or F1-F9, or Enter)." << endl << "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, 0-9, F1-F12, or Enter)." << endl
<< "Context may be used to limit the scope of the binding, by" << endl << "Context may be used to limit the scope of the binding, by" << endl
<< "requiring the current context to have a certain prefix." << endl << "requiring the current context to have a certain prefix." << endl
<< "Current UI context is: " << "Current UI context is: "

@ -1386,6 +1386,16 @@ static std::string getOSType()
} }
} }
static int getArchitecture()
{
return sizeof(void*) * 8;
}
static std::string getArchitectureName()
{
return getArchitecture() == 64 ? "x86_64" : "x86";
}
static std::string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } static std::string getDFVersion() { return Core::getInstance().vinfo->getVersion(); }
static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); } static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); }
@ -1403,6 +1413,8 @@ static std::string df2console(std::string s) { return DF2CONSOLE(s); }
static const LuaWrapper::FunctionReg dfhack_module[] = { static const LuaWrapper::FunctionReg dfhack_module[] = {
WRAP(getOSType), WRAP(getOSType),
WRAP(getArchitecture),
WRAP(getArchitectureName),
WRAP(getDFVersion), WRAP(getDFVersion),
WRAP(getDFPath), WRAP(getDFPath),
WRAP(getTickCount), WRAP(getTickCount),
@ -2557,6 +2569,9 @@ static int internal_memscan(lua_State *L)
for (int i = 0; i <= hcount; i++) for (int i = 0; i <= hcount; i++)
{ {
uint8_t *p = haystack + i*hstep; uint8_t *p = haystack + i*hstep;
if (p + nsize > haystack + (hcount * hstep)) {
break;
}
if (memcmp(p, needle, nsize) == 0) { if (memcmp(p, needle, nsize) == 0) {
lua_pushinteger(L, i); lua_pushinteger(L, i);
lua_pushinteger(L, (lua_Integer)p); lua_pushinteger(L, (lua_Integer)p);

@ -342,12 +342,14 @@ int Process::adjustOffset(int offset, bool to_file)
return -1; return -1;
} }
string Process::doReadClassName (void * vptr) string Process::doReadClassName (void * vptr)
{ {
char * rtti = readPtr((char *)vptr - sizeof(void*)); char * rtti = readPtr((char *)vptr - sizeof(void*));
#ifdef DFHACK64 #ifdef DFHACK64
char * typeinfo = d->base + readDWord(rtti + 0xC); void *base;
if (!RtlPcToFileHeader(rtti, &base))
return "dummy";
char * typeinfo = (char *)base + readDWord(rtti + 0xC);
string raw = readCString(typeinfo + 0x10+4); // skips the .?AV string raw = readCString(typeinfo + 0x10+4); // skips the .?AV
#else #else
char * typeinfo = readPtr(rtti + 0xC); char * typeinfo = readPtr(rtti + 0xC);

@ -1 +1,6 @@
friend struct df::interfacest; friend struct df::interfacest;
void feed_key(df::interface_key key) {
std::set<df::interface_key> input;
input.insert(key);
feed(&input);
}

@ -354,6 +354,10 @@ function Painter:key(code,pen,...)
) )
end end
function Painter:key_string(code, text, ...)
return self:key(code):string(': '):string(text, ...)
end
-------------------------- --------------------------
-- Abstract view object -- -- Abstract view object --
-------------------------- --------------------------

@ -1182,52 +1182,52 @@ void Buildings::clearBuildings(color_ostream& out) {
void Buildings::updateBuildings(color_ostream& out, void* ptr) void Buildings::updateBuildings(color_ostream& out, void* ptr)
{ {
// int32_t id = (int32_t)ptr; int32_t id = *((int32_t*)ptr);
// auto building = df::building::find(id); auto building = df::building::find(id);
// if (building) if (building)
// { {
// // Already cached -> weird, so bail out // Already cached -> weird, so bail out
// if (corner1.count(id)) if (corner1.count(id))
// return; return;
// // Civzones cannot be cached because they can // Civzones cannot be cached because they can
// // overlap each other and normal buildings. // overlap each other and normal buildings.
// if (!building->isSettingOccupancy()) if (!building->isSettingOccupancy())
// return; return;
// df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z); df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z);
// df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z); df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z);
// corner1[id] = p1; corner1[id] = p1;
// corner2[id] = p2; corner2[id] = p2;
// for ( int32_t x = p1.x; x <= p2.x; x++ ) { for ( int32_t x = p1.x; x <= p2.x; x++ ) {
// for ( int32_t y = p1.y; y <= p2.y; y++ ) { for ( int32_t y = p1.y; y <= p2.y; y++ ) {
// df::coord pt(x,y,building->z); df::coord pt(x,y,building->z);
// if (containsTile(building, pt, false)) if (containsTile(building, pt, false))
// locationToBuilding[pt] = id; locationToBuilding[pt] = id;
// } }
// } }
// } }
// else if (corner1.count(id)) else if (corner1.count(id))
// { {
// //existing building: destroy it //existing building: destroy it
// df::coord p1 = corner1[id]; df::coord p1 = corner1[id];
// df::coord p2 = corner2[id]; df::coord p2 = corner2[id];
// for ( int32_t x = p1.x; x <= p2.x; x++ ) { for ( int32_t x = p1.x; x <= p2.x; x++ ) {
// for ( int32_t y = p1.y; y <= p2.y; y++ ) { for ( int32_t y = p1.y; y <= p2.y; y++ ) {
// df::coord pt(x,y,p1.z); df::coord pt(x,y,p1.z);
// auto cur = locationToBuilding.find(pt); auto cur = locationToBuilding.find(pt);
// if (cur != locationToBuilding.end() && cur->second == id) if (cur != locationToBuilding.end() && cur->second == id)
// locationToBuilding.erase(cur); locationToBuilding.erase(cur);
// } }
// } }
// corner1.erase(id); corner1.erase(id);
// corner2.erase(id); corner2.erase(id);
// } }
} }
void Buildings::getStockpileContents(df::building_stockpilest *stockpile, std::vector<df::item*> *items) void Buildings::getStockpileContents(df::building_stockpilest *stockpile, std::vector<df::item*> *items)

@ -273,7 +273,7 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event
} }
for ( size_t a = 0; a < df::global::world->buildings.all.size(); a++ ) { for ( size_t a = 0; a < df::global::world->buildings.all.size(); a++ ) {
df::building* b = df::global::world->buildings.all[a]; df::building* b = df::global::world->buildings.all[a];
Buildings::updateBuildings(out, (void*)b); Buildings::updateBuildings(out, (void*)&(b->id));
buildings.insert(b->id); buildings.insert(b->id);
} }
lastSyndromeTime = -1; lastSyndromeTime = -1;
@ -609,7 +609,7 @@ static void manageBuildingEvent(color_ostream& out) {
buildings.insert(a); buildings.insert(a);
for ( auto b = copy.begin(); b != copy.end(); b++ ) { for ( auto b = copy.begin(); b != copy.end(); b++ ) {
EventHandler bob = (*b).second; EventHandler bob = (*b).second;
bob.eventHandler(out, (void*)intptr_t(a)); bob.eventHandler(out, (void*)&a);
} }
} }
nextBuilding = *df::global::building_next_id; nextBuilding = *df::global::building_next_id;
@ -625,7 +625,7 @@ static void manageBuildingEvent(color_ostream& out) {
for ( auto b = copy.begin(); b != copy.end(); b++ ) { for ( auto b = copy.begin(); b != copy.end(); b++ ) {
EventHandler bob = (*b).second; EventHandler bob = (*b).second;
bob.eventHandler(out, (void*)intptr_t(id)); bob.eventHandler(out, (void*)&id);
} }
a = buildings.erase(a); a = buildings.erase(a);
} }

@ -1 +1 @@
Subproject commit 34331ef67f3d163f4ab66121449a8217eb1cfb47 Subproject commit a292304c6097a499dfa749d5cc8ab24e69e004f5

@ -122,6 +122,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(follow follow.cpp) DFHACK_PLUGIN(follow follow.cpp)
DFHACK_PLUGIN(forceequip forceequip.cpp) DFHACK_PLUGIN(forceequip forceequip.cpp)
DFHACK_PLUGIN(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib) DFHACK_PLUGIN(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib)
DFHACK_PLUGIN(generated-creature-renamer generated-creature-renamer.cpp)
DFHACK_PLUGIN(getplants getplants.cpp) DFHACK_PLUGIN(getplants getplants.cpp)
DFHACK_PLUGIN(hotkeys hotkeys.cpp) DFHACK_PLUGIN(hotkeys hotkeys.cpp)
DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp)

@ -128,7 +128,7 @@ public:
if (input->count(df::interface_key::SETUP_EMBARK)) if (input->count(df::interface_key::SETUP_EMBARK))
{ {
cancel = true; cancel = true;
screen->in_embark_normal = 1; screen->in_embark_only_warning = 1;
} }
}; };
}; };

@ -183,8 +183,8 @@ void ev_mng_invasion(color_ostream& out, void* ptr)
} }
static void ev_mng_building(color_ostream& out, void* ptr) static void ev_mng_building(color_ostream& out, void* ptr)
{ {
int32_t myId=*(int32_t*)&ptr; int32_t id = *((int32_t*)ptr);
onBuildingCreatedDestroyed(out,myId); onBuildingCreatedDestroyed(out, id);
} }
static void ev_mng_inventory(color_ostream& out, void* ptr) static void ev_mng_inventory(color_ostream& out, void* ptr)
{ {

@ -0,0 +1,274 @@
#include "Console.h"
#include "Core.h"
#include "DataDefs.h"
#include "Export.h"
#include "PluginManager.h"
#include "df/world.h"
#include "df/world_raws.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
#include "modules/World.h"
#include "MemAccess.h"
//#include "df/world.h"
using namespace DFHack;
DFHACK_PLUGIN("generated-creature-renamer");
REQUIRE_GLOBAL(world);
#define RENAMER_VERSION 3
command_result list_creatures(color_ostream &out, std::vector <std::string> & parameters);
command_result save_generated_raw(color_ostream &out, std::vector <std::string> & parameters);
DFhackCExport command_result plugin_init(color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"list-generated",
"Prints a list of generated creature tokens.",
list_creatures,
false, //allow non-interactive use
"Use \"list-generated detailed\" to show descriptions."
));
commands.push_back(PluginCommand(
"save-generated-raws",
"Saves a graphics raw file to use with the renamed generated creatures.",
save_generated_raw,
false, //allow non-interactive use
"Creates graphics_procedural_creatures.txt, with a full set of creature graphics definitions for all possible generated beasts. Modify the resulting file to suit your needs."
)); return CR_OK;
}
DFhackCExport command_result plugin_shutdown(color_ostream &out)
{
return CR_OK;
}
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
{
is_enabled = enable;
return CR_OK;
}
std::vector<std::string> descriptors = {
"blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", "damselfly", "stonefly",
"earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", "mantis", "louse",
"thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", "ladybug",
"weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", "dung beetle", "rhinoceros beetle",
"rove beetle", "snakefly", "lacewing", "antlion larva", "mosquito", "flea", "scorpionfly", "caddisfly",
"butterfly", "moth", "caterpillar", "maggot", "spider", "tarantula", "scorpion", "tick",
"mite", "shrimp", "lobster", "crab", "nematode", "snail", "slug", "earthworm",
"leech", "bristleworm", "ribbon worm", "flat worm", "toad", "frog", "salamander", "newt",
"alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", "gila monster",
"monitor", "serpent", "viper", "rattlesnake", "cobra", "python", "anaconda", "turtle",
"tortoise", "pterosaur", "dimetrodon", "sauropod", "theropod", "iguanodont", "hadrosaurid", "stegosaurid",
"ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken",
"quail", "pheasant", "gull", "loon", "grebe", "albatross", "petrel", "penguin",
"pelican", "stork", "vulture", "flamingo", "falcon", "kestrel", "condor", "osprey",
"buzzard", "eagle", "harrier", "kite", "crane", "dove", "pigeon", "parrot",
"cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", "hornbill", "quetzal",
"toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", "fantail", "shrike",
"crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit",
"warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow",
"tanager", "cardinal", "bunting", "finch", "titmouse", "chickadee", "waxwing", "flycatcher",
"opossum", "koala", "wombat", "kangaroo", "sloth", "anteater", "armadillo", "squirrel",
"marmot", "beaver", "gopher", "mouse", "porcupine", "chinchilla", "cavy", "capybara",
"rabbit", "hare", "lemur", "loris", "monkey", "hedgehog", "shrew", "mole",
"fruit bat", "wolf", "coyote", "jackal", "raccoon", "coati", "weasel", "otter",
"badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet",
"walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros",
"warthog", "hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope",
"sheep", "goat", "bison", "buffalo", "bull", "ape", "ant", "bat",
"owl", "pig", "bee", "fly", "hawk", "jay", "rat", "fox",
"cat", "ass", "elk"
};
std::vector<std::string> prefixes = {
"FORGOTTEN_BEAST_",
"TITAN_",
"DEMON_",
"NIGHT_CREATURE_",
"HF"
};
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{
if (!is_enabled)
return CR_OK;
if (event != DFHack::SC_WORLD_LOADED)
return CR_OK;
CoreSuspender suspend;
std::vector<int> descriptorCount = std::vector<int>(descriptors.size());
auto version = World::GetPersistentData("AlreadyRenamedCreatures");
if (version.isValid() && version.ival(1) >= RENAMER_VERSION)
{
return CR_OK;
}
int creatureCount = 0;
for (int i = 0; i < world->raws.creatures.all.size(); i++)
{
auto creatureRaw = world->raws.creatures.all[i];
if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED))
continue;
size_t minPos = std::string::npos;
size_t foundIndex = -1;
size_t prefixIndex = -1;
for (size_t j = 0; j < prefixes.size(); j++)
{
if (creatureRaw->creature_id.compare(0, prefixes[j].length(), prefixes[j]) == 0)
{
prefixIndex = j;
}
}
if (prefixIndex < 0)
continue; //unrecognized generaed type.
for (size_t j = 0; j < descriptors.size(); j++)
{
size_t pos = creatureRaw->caste[0]->description.find(" " + descriptors[j]);
if (pos < minPos)
{
minPos = pos;
foundIndex = j;
}
}
if (foundIndex < 0)
continue; //can't find a match.
auto descriptor = descriptors[foundIndex];
for (int j = 0; j < descriptor.size(); j++)
{
if (descriptor[j] == ' ')
descriptor[j] = '_';
else
descriptor[j] = toupper(descriptor[j]);
}
auto prefix = prefixes[prefixIndex];
if (prefix[prefix.length() - 1] != '_')
prefix.append("_");
creatureRaw->creature_id = prefixes[prefixIndex] + descriptor;
if (descriptorCount[foundIndex] > 0)
{
creatureRaw->creature_id.append("_" + std::to_string(descriptorCount[foundIndex]));
}
descriptorCount[foundIndex]++;
creatureCount++;
}
version = World::AddPersistentData("AlreadyRenamedCreatures");
version.ival(1) = RENAMER_VERSION;
out << "Renamed " << creatureCount << " generated creatures to have sensible names." << endl;
return CR_OK;
}
command_result list_creatures(color_ostream &out, std::vector <std::string> & parameters)
{
bool detailed = false;
if (!parameters.empty())
{
if (parameters.size() > 1)
return CR_WRONG_USAGE;
if(parameters[0].compare("detailed") != 0)
return CR_WRONG_USAGE;
detailed = true;
}
CoreSuspender suspend;
for (int i = 0; i < world->raws.creatures.all.size(); i++)
{
auto creatureRaw = world->raws.creatures.all[i];
if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED))
continue;
out.print(creatureRaw->creature_id.c_str());
if (detailed)
{
out.print("\t");
out.print(creatureRaw->caste[0]->description.c_str());
}
out.print("\n");
}
return CR_OK;
}
command_result save_generated_raw(color_ostream &out, std::vector <std::string> & parameters)
{
#ifdef LINUX_BUILD
std::string pathSep = "/";
#else
std::string pathSep = "\\";
#endif
int pageWidth = 16;
int pageHeight = (descriptors.size() / pageWidth) + ((descriptors.size() % pageWidth > 0) ? 1 : 0);
int tileWidth = 24;
int tileHeight = 24;
std::string fileName = "graphics_procedural_creatures";
std::string pageName = "PROCEDURAL_FRIENDLY";
int repeats = 128;
std::ofstream outputFile(fileName + ".txt", std::ios::out | std::ios::trunc);
outputFile << fileName << endl << endl;
outputFile << "[OBJECT:GRAPHICS]" << endl << endl;
outputFile << "[TILE_PAGE:" << pageName << "]" << endl;
outputFile << " [FILE:procedural_friendly.png]" << endl;
outputFile << " [TILE_DIM:" << tileWidth << ":" << tileHeight << "]" << endl;
outputFile << " [PAGE_DIM:" << pageWidth << ":" << pageHeight << "]" << endl << endl;
for (size_t descIndex = 0; descIndex < descriptors.size(); descIndex++)
{
for (size_t prefIndex = 0; prefIndex < prefixes.size(); prefIndex++)
{
for (size_t rep = 0; rep < repeats; rep++)
{
auto descriptor = descriptors[descIndex];
for (int j = 0; j < descriptor.size(); j++)
{
if (descriptor[j] == ' ')
descriptor[j] = '_';
else
descriptor[j] = toupper(descriptor[j]);
}
auto prefix = prefixes[prefIndex];
if (prefix[prefix.length() - 1] != '_')
prefix.append("_");
std::string token = prefix + descriptor;
if (rep > 0)
token.append("_" + std::to_string(rep));
outputFile << "[CREATURE_GRAPHICS:" << token << "]" << endl;
outputFile << " [DEFAULT:" << pageName << ":" << descIndex % pageWidth << ":" << descIndex / pageWidth << ":ADD_COLOR]" << endl;
}
outputFile << endl;
}
outputFile << endl;
}
outputFile.close();
return CR_OK;
}

@ -1 +1 @@
Subproject commit 20eb2146fb93912b07034f3192dde1cf95a9ec7f Subproject commit 7e8daa16822cc67f8e84adab7607694b622fe434