don't reveal map blocks that would trigger events

develop
Myk Taylor 2023-12-31 11:22:50 -08:00
parent 2ff6676122
commit 5d63e7a991
No known key found for this signature in database
3 changed files with 51 additions and 10 deletions

@ -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

@ -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``

@ -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 <unordered_set>
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<df::coord> & 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 <string> & parameters)
return CR_OK;
}
void revealAdventure(color_ostream &out)
void revealAdventure(color_ostream &out, const std::unordered_set<df::coord> & 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<df::coord> & 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<df::coord> & 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<string> & params)
{
bool no_hell = true;
@ -211,11 +246,16 @@ command_result reveal(color_ostream &out, vector<string> & 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<df::coord> 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<string> & 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;