From 5d63e7a991635b9a6d1e6c06003d6153cd3d7659 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 31 Dec 2023 11:22:50 -0800 Subject: [PATCH] don't reveal map blocks that would trigger events --- docs/changelog.txt | 1 + docs/plugins/reveal.rst | 4 +-- plugins/reveal.cpp | 56 +++++++++++++++++++++++++++++++++++------ 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index e4ef22dd5..37fb33266 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 diff --git a/docs/plugins/reveal.rst b/docs/plugins/reveal.rst index 2f4ebb5d8..df46b6ff5 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`` 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;