Skip to content

Commit 082d707

Browse files
authored
Merge branch 'develop' into gui-slider-min-max
2 parents b919971 + c2f513d commit 082d707

49 files changed

Lines changed: 3006 additions & 160 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CMakeLists.txt‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ set(CMAKE_INSTALL_MESSAGE "LAZY")
88

99
# set up versioning.
1010
set(DF_VERSION "53.16")
11-
set(DFHACK_RELEASE "r1.1")
12-
set(DFHACK_PRERELEASE FALSE)
11+
set(DFHACK_RELEASE "r2rc2")
12+
set(DFHACK_PRERELEASE TRUE)
1313

1414
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
1515
set(DFHACK_ABI_VERSION 2)
@@ -356,7 +356,7 @@ INCLUDE(FetchContent)
356356
FetchContent_Declare(
357357
fmt
358358
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
359-
GIT_TAG 790b9389ae99c4ddebdd2736a8602eca1fec684e # 12.1.0 + bugfix for MSVC warning + build time improvements
359+
GIT_TAG 12.2.0
360360
)
361361
FetchContent_MakeAvailable(fmt)
362362
set(FMTLIB fmt)

‎docs/changelog.txt‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Template for new versions:
3333
## New Features
3434

3535
## Fixes
36+
- ``Units::setPathGoal``: no longer crashes when passed NULL as a unit. Also fixes ``dfhack.units.setPathGoal()``.
3637

3738
## Misc Improvements
3839

@@ -80,6 +81,7 @@ Template for new versions:
8081
- Fixed out-of-bounds color table access in ``Screen`` module when Lua pens use ``COLOR_RESET``
8182
- ``Units::teleport``: update unit occupancy on the full 3x3 footprint of EQUIPMENT units (e.g. wagons) instead of only their center tile
8283
- ``Units::teleport``: only clear tile unit occupancy flags when no other unit of the same kind remains on the tile
84+
- ``Units::isCitizen`` and ``Units::isResident`` now exclude dead units even when ``include_insane`` is set; the flag previously skipped the sanity check that also happened to exclude the dead
8385
- `3dveins`: fix crash when a tile's biome cannot be resolved
8486
- `3dveins`: fix failure on embarks that cross midmap tiles
8587
- `aquifer`: make ``--skip-top`` and top-relative ``--levels`` take effect for the ``drain``, ``convert``, and ``add`` actions instead of being silently ignored
@@ -89,9 +91,15 @@ Template for new versions:
8991
- `buildingplan`: fix roller material estimate asking for one chain per tile instead of one chain total
9092
- `buildingplan`: fix "Unlink all" only unlinking some mechanisms (or crashing) when freeing mechanisms from the building
9193
- `burrow`: fix ``tiles clear`` and other tile operations silently failing because burrow block z-coordinates were stored incorrectly in the ``Burrows`` module
94+
- `dfhack-run`: on Windows, no longer mutates, hides, and closes the console it inherits when run from an existing terminal (issue #3827)
95+
- `dig-now`: update light/outside flags of tiles below tiles that are dug into solid rather than open tiles
9296
- `export-world-map`: fix crash exporting site data for a site whose owner has an undefined race
9397
- `gui/quickfort`: show smoothing designations immediately after applying a blueprint
98+
- `liquids`: allow painting liquids and obsidian into unallocated sky blocks
99+
- `liquids`: update light/outside flags of covered tiles when painting obsidian or river sources
94100
- `overlay`: overlay hotkeys no longer steal typed characters while the game is capturing text input, e.g. when renaming a building
101+
- `preserve-rooms`: no longer assigns zones to dead units who still hold a noble position
102+
- `sort`: the clickable stress icon citizen lists no longer include dead or missing units (issue #5975)
95103
- `sort`: fix the Places/Workshops and task searches missing workshops by their current display names (e.g. "Stoneworker's Workshop", "Screw Press")
96104
- `stocks`: overlay now resets scroll position when collapsing categories so the item list is no longer left blank and unscrollable
97105
- `strangemood`: updated to match behavior of current DF version
@@ -101,27 +109,33 @@ Template for new versions:
101109
- `stocks`: overlay now resets scroll position when collapsing categories so the item list is no longer left blank and unscrollable
102110
- `strangemood`: fix crash when ``--id`` is given a non-numeric unit id
103111
- `suspendmanager`: fix out-of-bounds parameter read when ``set`` is given too few arguments
112+
- `probe`: fix malformed output of local/global map feature names
104113

105114
## Misc Improvements
106115
- Added ``Coord2d`` and ``Coord3d`` C++ templates, providing a standard set operations for 2-tuples and 3-tuples of any numeric type
107116
- Renamed the ``stockpiles`` tool tag to ``stockpile`` so it no longer collides with the `stockpiles` plugin in `gui/launcher`
117+
- Writes to ``stderr.log`` are no longer buffered on Windows, so log output is not lost if DF crashes
108118

109119
## Documentation
110120
- Document ``autodump-destroy-here``. Remove mention of ``autodump destroy`` able to revert destruction.
111121

112122
## API
123+
- Added ``Maps::getTileBlockCoord``, ``Maps::getBlockOrigin``, and ``Maps::getTileBlockOffset`` to convert between tile and block coordinates
113124
- Added ``Maps::getSiteTypeName`` to print the sites classification as a string (e.g. "mountain halls")
114125
- Added ``Maps::addRegionBiomeOffset`` to shift world region coordinate by region_details biome reference
115126
- Added ``Maps::describeSurroundings`` to get surroundings classification from savagery and evilness
116127
- Added ``Maps::getCurrentWeather`` to determine the current weather on the map.
117128
- Added ``Maps::forEachTile`` with ``Maps::TileFilter``/``Maps::TileActions`` to scan a cuboid of tiles, matching tiles by tiletype, tiletype attributes, and designation/occupancy bits, and counting, rewriting tiletypes, editing designation/occupancy bits, spawning constructions, or invoking a callback on matching tiles
129+
- Added ``MapExtras::MapCache::propagateVerticalFlags`` to update the light/outside/subterranean flags of tiles below a tile that changed between an open and a solid shape
118130
- Added ``MiscUtils::print_range`` to print ranges with prefix, separator, and suffix
119131
- Added ``Units::breathes`` and ``Units::getBreathingState``
120132
- Deprecated ``World::ReadCurrentWeather`` in favor of ``Maps::getCurrentWeather``
121133

122134
## Lua
123135
- Added ``dfhack.maps.forEachTile`` to scan a cuboid of tiles with a declarative filter and apply actions (count, set tiletype or per-tiletype replacements, set designation/occupancy fields, spawn constructions, Lua callback) in a single native call
124136
- ``widgets.Slider`` and ``widgets.RangeSlider``: fix sliders allowing values outside their number of stops (``num_stops``) when clicked or dragged with the mouse
137+
- Fixed ``ipairs()`` on enum attribute tables (e.g. ``df.item_type.attrs``) never terminating (issue #1860)
138+
- Added ``dfhack.maps.getTileBlockCoord``, ``dfhack.maps.getBlockOrigin``, and ``dfhack.maps.getTileBlockOffset`` to convert between tile and block coordinates
125139

126140
## Removed
127141

@@ -177,6 +191,7 @@ Template for new versions:
177191
- `EventManager`: add safety check to potentially avoid a DFHack crash when DF's ``reports`` table is out of order
178192

179193
## Documentation
194+
- ``dfhack.translation.generateName``: added a table containing explanations and data types for each of the parameters
180195

181196
## API
182197
- ``DFSDL``: added ``obtain_library_handle`` and ``obtain_image_library_handle`` so that a plugin can obtain DFHack's already-open handle to these libs instead of having to do it itself.

‎docs/dev/Lua API.rst‎

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,64 @@ Translation module
10601060

10611061
* ``dfhack.translation.generateName(name,language,type,major_selector,minor_selector)``
10621062

1063-
Dynamically generate a name using the same logic the game itself uses.
1063+
Dynamically generate a random name using the same logic the game itself uses.
1064+
1065+
**Parameters:**
1066+
1067+
.. list-table::
1068+
:class: dfhack-param-table
1069+
:header-rows: 1
1070+
:widths: 21 60 19
1071+
1072+
* - Name
1073+
- Explanation
1074+
- Data Type
1075+
* - ``name``
1076+
- | ``name`` property of the object that will have its name generated. This is an output parameter.
1077+
|
1078+
| Example values:
1079+
| ``df.global.world.entities.all[0].name``
1080+
| ``df.unit.find(79).name``
1081+
| ``dfhack.gui.getSelectedUnit().name``
1082+
| ``df.language_name::new()``
1083+
- ``df.language_name``
1084+
* - ``language``
1085+
- | Integer index of the language used for generating the name within ``df.language_translation``.
1086+
|
1087+
| Example values:
1088+
| ``df.global.world.entities.all[0].name.language``
1089+
| ``df.unit.find(79).name.language``
1090+
| ``dfhack.gui.getSelectedUnit().name.language``
1091+
| ``0``
1092+
- ``int``
1093+
* - ``type``
1094+
- | Integer value of the name type. This ensures that the generated name will be appropriate for the given category of object. For allowed values see ``df.language_name_type`` enum.
1095+
|
1096+
| Example values:
1097+
| ``df.global.world.entities.all[100].name.type``
1098+
| ``df.unit.find(79).name.type``
1099+
| ``dfhack.gui.getSelectedUnit().name.type``
1100+
| ``df.language_name_type.Figure``
1101+
| ``13``
1102+
- ``df.language_name_type``
1103+
* - ``major_selector``
1104+
- | Section of the loaded game raws containing words used for generating the name.
1105+
|
1106+
| Example value for sites belonging to civ with id 100:
1107+
| ``df.historical_entity.find(100).entity_raw.symbols.symbols_major[df.entity_name_type.SITE]``
1108+
|
1109+
| Example value for units:
1110+
| ``df.global.world.raws.language.word_table[0][df.language_name_category.Unit]``
1111+
- ``df.language_word_table``
1112+
* - ``minor_selector``
1113+
- | Section of the loaded game raws containing words used for generating the name.
1114+
|
1115+
| Example value for sites belonging to civ with id 100:
1116+
| ``df.historical_entity.find(100).entity_raw.symbols.symbols_minor[df.entity_name_type.SITE]``
1117+
|
1118+
| Example value for units:
1119+
| ``df.global.world.raws.language.word_table[1][df.language_name_category.Unit]``
1120+
- ``df.language_word_table``
10641121

10651122
Gui module
10661123
----------
@@ -1508,12 +1565,14 @@ Units module
15081565
same checks the game uses to decide game-over by extinction,
15091566
with an additional sanity check. You can identify citizens,
15101567
regardless of their sanity, by passing ``true`` as the optional
1511-
second parameter.
1568+
second parameter. Dead units are never considered citizens, even
1569+
when ``include_insane`` is set (though animate intelligent
1570+
undead citizens still count).
15121571

15131572
* ``dfhack.units.isResident(unit[,include_insane])``
15141573

1515-
The unit is a resident of the fortress. Same ``include_insane`` semantics as
1516-
``isCitizen``.
1574+
The unit is a non-dead resident of the fortress. Same
1575+
``include_insane`` semantics as ``isCitizen``.
15171576

15181577
* ``dfhack.units.isFortControlled(unit)``
15191578

@@ -2412,6 +2471,23 @@ Maps module
24122471

24132472
Like ``getTileBlock``, but if the block is not allocated, try creating it.
24142473

2474+
* ``dfhack.maps.getTileBlockCoord(coords)``, or ``getTileBlockCoord(x,y,z)``
2475+
2476+
Returns the *x, y, z* block coordinates of the map block containing the
2477+
given tile position. The z coordinate is a level and is preserved, not
2478+
scaled.
2479+
2480+
* ``dfhack.maps.getBlockOrigin(coords)``, or ``getBlockOrigin(x,y,z)``
2481+
2482+
Returns the *x, y, z* tile coordinates of the north-west corner of the map
2483+
block with the given block coordinates. The z coordinate is a level and is
2484+
preserved, not scaled.
2485+
2486+
* ``dfhack.maps.getTileBlockOffset(coords)``, or ``getTileBlockOffset(x,y,z)``
2487+
2488+
Returns the *x, y* offset (0-15) of the given tile position within its
2489+
containing map block, along with the unchanged *z* coordinate.
2490+
24152491
* ``dfhack.maps.getTileType(coords)``, or ``getTileType(x,y,z)``
24162492

24172493
Returns the tile type at the given coordinates, or *nil* if invalid.

‎docs/plugins/labormanager.rst‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,34 @@ history shapes specialization:
4848
(smithing, crafting, cooking, mechanics, engraving, and so on) are
4949
preferred for higher-skilled workers -- both when choosing a specialty
5050
and when deciding who to keep out of the laborer pool.
51+
* **Assignment stickiness.** A unit assigned to a skill detail keeps the
52+
assignment while any work for that skill remains -- including claimed
53+
jobs, the fetch-materials phase, and breaks -- so jobs aren't aborted
54+
by reassignment churn. For tool-carrying labors (mining, woodcutting,
55+
hunting) this also prevents dropping and re-equipping tools between
56+
cycles. Assignments are recorded in the save data and restored on load.
57+
* **Builtin tool details.** DF v50 only equips tools for members of the
58+
game's predefined work details, so mining, woodcutting, and hunting
59+
specialists are assigned to the builtin Miners, Woodcutters, and
60+
Hunters details instead of plugin-created ones. Memberships added by
61+
the plugin are tracked and removed cleanly on disable; members you
62+
assigned yourself are never touched.
5163
* **Strange-mood shaping.** Dwarves that can still have a strange mood
5264
(their race has the ``STRANGE_MOODS`` token and they haven't had one
5365
yet) and that have already started a moodable craft are steered toward
5466
skills a strange mood can advance -- preferably valuable ones like
5567
weaponsmithing or armorsmithing -- so a mood pays out in a useful
5668
legendary skill.
5769

70+
Workshop restrictions are honored as well: when a job is posted at a
71+
workshop that has a permitted-worker list, the engine ensures at least
72+
one listed worker is assigned the job's labor, and when the workshop
73+
restricts jobs by skill level it ensures at least one worker within the
74+
allowed range holds that labor. Units on any workshop's permitted list
75+
are treated as reserved for that shop's work -- they are preferentially
76+
assigned the labors its jobs require and deprioritized for the laborer
77+
pool and unrelated specialties.
78+
5879
Labormanager also reads each citizen's unmet personal needs and biases
5980
assignments toward work that satisfies them:
6081

@@ -146,6 +167,13 @@ Advanced usage
146167
command exists under `autolabor`. In monitor mode the plugin performs
147168
no labor management -- all work details are left to the player -- but
148169
still tracks the job board and shows the task starvation warning.
170+
``labormanager dump``
171+
Print a diagnostic snapshot of everything the engine can see: every
172+
job and posting on the board with its flags and resolved labor, the
173+
per-labor demand and starvation streaks, skill usage, tool counts,
174+
work detail memberships, and each citizen's state, pins, and enabled
175+
labors. Intended for bug reports; also available as
176+
``autolabor dump``, and meaningful in monitor mode.
149177

150178
Monitor mode (``labormanager mode monitor`` or the work details overlay)
151179
runs the same tracking without any labor management, for players who want

‎docs/styles/dfhack.css‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,12 @@ div.dfhack-tool-summary p:last-child,
7979
aside.dfhack-tool-summary p:last-child {
8080
margin-bottom: 0;
8181
}
82+
83+
table.dfhack-param-table {
84+
table-layout: fixed;
85+
width: 110%;
86+
}
87+
88+
table.dfhack-param-table span.pre {
89+
white-space: wrap;
90+
}

‎library/Console-windows.cpp‎

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ namespace DFHack
7878
state = con_unclaimed;
7979
in_batch = false;
8080
raw_cursor = 0;
81+
console_owned = false;
82+
saved_cp = 0;
83+
saved_output_cp = 0;
8184
};
8285
virtual ~Private()
8386
{
@@ -396,6 +399,9 @@ namespace DFHack
396399
HWND ConsoleWindow;
397400
HWND MainWindow;
398401
WORD default_attributes;
402+
bool console_owned; // false if the console was inherited from a parent process
403+
UINT saved_cp; // code pages to restore on shutdown if the console is borrowed
404+
UINT saved_output_cp;
399405
// current state
400406
enum console_state
401407
{
@@ -467,22 +473,32 @@ bool Console::init(bool)
467473
}
468474
d->MainWindow = h;
469475

470-
// Allocate a console!
471-
AllocConsole();
476+
// Allocate a console! If the process already has one (e.g. dfhack-run
477+
// launched from an existing terminal), the console is borrowed and must
478+
// not be mutated or freed.
479+
d->console_owned = AllocConsole() != FALSE;
472480
d->ConsoleWindow = GetConsoleWindow();
473481
wlock = new std::recursive_mutex();
474-
HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
475-
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
482+
if (d->console_owned)
483+
{
484+
HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
485+
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
486+
}
476487

477488
// force console code pages to utf-8
489+
d->saved_cp = GetConsoleCP();
490+
d->saved_output_cp = GetConsoleOutputCP();
478491
SetConsoleCP(CP_UTF8);
479492
SetConsoleOutputCP(CP_UTF8);
480493

481494
// set the screen buffer to be big enough to let us scroll text
482495
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
483496
d->default_attributes = coninfo.wAttributes;
484-
coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer
485-
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
497+
if (d->console_owned)
498+
{
499+
coninfo.dwSize.Y = MAX_CONSOLE_LINES; // How many lines do you want to have in the console buffer
500+
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
501+
}
486502

487503
// redirect unbuffered STDOUT to the console
488504
d->console_out = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -506,7 +522,10 @@ bool Console::init(bool)
506522

507523
// make our own weird streams so our IO isn't redirected
508524
std::cin.tie(this);
509-
clear();
525+
if (d->console_owned)
526+
{
527+
clear();
528+
}
510529
inited = true;
511530
// DOESN'T WORK - locks up DF!
512531
// ForceForegroundWindow(d->MainWindow);
@@ -518,7 +537,17 @@ bool Console::shutdown(void)
518537
{
519538
assert(inited);
520539
std::lock_guard<std::recursive_mutex> lock{*wlock};
521-
FreeConsole();
540+
if (d->console_owned)
541+
{
542+
FreeConsole();
543+
}
544+
else
545+
{
546+
// the console is borrowed from a parent process; restore the state
547+
// we changed and leave it attached
548+
SetConsoleCP(d->saved_cp);
549+
SetConsoleOutputCP(d->saved_output_cp);
550+
}
522551
inited = false;
523552
return true;
524553
}
@@ -611,12 +640,16 @@ void Console::msleep (unsigned int msec)
611640

612641
bool Console::hide()
613642
{
643+
if (!inited || !d->console_owned)
644+
return false;
614645
ShowWindow( GetConsoleWindow(), SW_HIDE );
615646
return true;
616647
}
617648

618649
bool Console::show()
619650
{
651+
if (!inited || !d->console_owned)
652+
return false;
620653
ShowWindow( GetConsoleWindow(), SW_RESTORE );
621654
return true;
622655
}

‎library/Core.cpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,9 @@ bool Core::InitMainThread(std::filesystem::path path) {
11141114
fprintf(stderr, "dfhack: redirecting stderr to stderr.log\n");
11151115
if (!freopen("stderr.log", "w", stderr))
11161116
std::cerr << "Could not redirect stderr to stderr.log" << std::endl;
1117+
// freopen makes stderr fully buffered on Windows; restore unbuffered
1118+
// writes so that stderr.log is up to date (e.g. in the event of a crash)
1119+
setvbuf(stderr, NULL, _IONBF, 0);
11171120

11181121
std::cerr << "DFHack build: " << Version::git_description() << std::endl;
11191122
if (strlen(Version::dfhack_run_url())) {

0 commit comments

Comments
 (0)