diff --git a/docs/changelog.txt b/docs/changelog.txt index b7a08788e..dee191fb9 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,6 +57,7 @@ Template for new versions: - `sort`: search and sort for the "choose unit to elevate to the barony" screen. units are sorted by the number of item preferences they have and the units are annotated with the items that they have preferences for ## Fixes +- `reveal`: now avoids revealing blocks that contain divine treasures, encased horrors, and deep vein hollows (so the surprise triggers are not triggered prematurely) - `sort`: fix mouse clicks falling through the squad assignment overlay panel when clicking on the panel but not on a clickable widget - `sort`: fix potential crash when removing jobs directly from the Tasks info screen - `misery`: fix error when changing the misery factor diff --git a/docs/plugins/reveal.rst b/docs/plugins/reveal.rst index 2f4ebb5d8..524b57d99 100644 --- a/docs/plugins/reveal.rst +++ b/docs/plugins/reveal.rst @@ -32,8 +32,8 @@ Usage ``reveal [hell|demon]`` Reveal the whole map. If ``hell`` is specified, also reveal HFS areas, but you are required to run ``unreveal`` before unpausing is allowed in order - to prevent the demons from spawning. If you really want to unpause with hell - revealed, specify ``demon`` instead of ``hell``. + to prevent the demons (or treasures) from spawning. If you really want to + unpause with secrets revealed, specify ``demon`` instead of ``hell``. ``unreveal`` Reverts the effects of ``reveal``. ``revtoggle`` @@ -54,3 +54,14 @@ Usage forced by `reveal` ``hell``. This is nice for digging under rivers. Use ``nopause 1`` to prevent pausing and ``nopause 0`` to allow pausing like normal. + +Note +---- + +Sometimes, the map generates secret hollows adjacent to caverns in such a way +that the ceiling of the hollow collapses on the first tick of the embark, +leaving the hollow exposed to the caverns. In this case, the secret event will +be triggered as soon as the cavern is discovered and that tile is unhidden. +This would happen anyway even if you don't use `reveal`, but be aware that it +is possible to trigger *some* events when you run `reveal`, even without the +``hell`` option. diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index b8a4ae902..344e513a9 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -5,9 +5,9 @@ #include "Core.h" #include "Console.h" -#include "Export.h" #include "PluginManager.h" +#include "modules/EventManager.h" #include "modules/Maps.h" #include "modules/World.h" #include "modules/MapCache.h" @@ -17,8 +17,13 @@ #include "df/block_square_event_frozen_liquidst.h" #include "df/construction.h" +#include "df/deep_vein_hollow.h" +#include "df/divine_treasure.h" +#include "df/encased_horror.h" #include "df/world.h" +#include + using MapExtras::MapCache; using std::string; @@ -33,15 +38,23 @@ DFHACK_PLUGIN_IS_ENABLED(is_active); REQUIRE_GLOBAL(world); /* - * Anything that might reveal Hell is unsafe. + * Anything that might reveal Hell or trigger gemstone pillar events is unsafe. */ -bool isSafe(df::coord c) +bool isSafe(df::coord c, const std::unordered_set & trigger_cache) { + // convert to block coordinates + c.x >>= 4; + c.y >>= 4; + + // Don't reveal blocks that contain trigger events + if (trigger_cache.contains(c)) + return false; + t_feature local_feature; t_feature global_feature; // get features of block // error -> obviously not safe to manipulate - if(!Maps::ReadFeatures(c.x >> 4,c.y >> 4,c.z,&local_feature,&global_feature)) + if(!Maps::ReadFeatures(c.x,c.y,c.z,&local_feature,&global_feature)) return false; // Adamantine tubes and temples lead to Hell @@ -154,13 +167,13 @@ command_result nopause (color_ostream &out, vector & parameters) return CR_OK; } -void revealAdventure(color_ostream &out) +void revealAdventure(color_ostream &out, const std::unordered_set & trigger_cache) { for (size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block *block = world->map.map_blocks[i]; // in 'no-hell'/'safe' mode, don't reveal blocks with hell and adamantine - if (!isSafe(block->map_pos)) + if (!isSafe(block->map_pos, trigger_cache)) continue; designations40d & designations = block->designation; // for each tile in block @@ -175,6 +188,28 @@ void revealAdventure(color_ostream &out) out.print("Local map revealed.\n"); } +static void cache_tiles(const df::coord_path & tiles, std::unordered_set & trigger_cache) +{ + size_t num_tiles = tiles.size(); + for (size_t idx = 0; idx < num_tiles; ++idx) + { + df::coord pos = tiles[idx]; + pos.x >>= 4; + pos.y >>= 4; + trigger_cache.insert(pos); + } +} + +static void initialize_trigger_cache(std::unordered_set & trigger_cache) +{ + for (auto & horror : world->encased_horrors) + cache_tiles(horror->tiles, trigger_cache); + for (auto & hollow : world->deep_vein_hollows) + cache_tiles(hollow->tiles, trigger_cache); + for (auto & treasure : world->divine_treasures) + cache_tiles(treasure->tiles, trigger_cache); +} + command_result reveal(color_ostream &out, vector & params) { bool no_hell = true; @@ -211,11 +246,16 @@ command_result reveal(color_ostream &out, vector & params) out.printerr("Map is not available!\n"); return CR_FAILURE; } + + size_t initial_buckets = 2 * (world->encased_horrors.size() + world->divine_treasures.size() + world->deep_vein_hollows.size()); + std::unordered_set trigger_cache(initial_buckets); + initialize_trigger_cache(trigger_cache); + t_gamemodes gm; World::ReadGameMode(gm); if(gm.g_mode == game_mode::ADVENTURE) { - revealAdventure(out); + revealAdventure(out, trigger_cache); return CR_OK; } if(gm.g_mode != game_mode::DWARF) @@ -230,7 +270,7 @@ command_result reveal(color_ostream &out, vector & params) { df::map_block *block = world->map.map_blocks[i]; // in 'no-hell'/'safe' mode, don't reveal blocks with hell and adamantine - if (no_hell && !isSafe(block->map_pos)) + if (no_hell && !isSafe(block->map_pos, trigger_cache)) continue; hideblock hb; hb.c = block->map_pos;