Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Template for new versions:

## Fixes
- Fix broken weather lookup in ``World::ReadCurrentWeather``
- `3dveins`: fix failure on embarks that cross midmap tiles
- `aquifer`: make ``--skip-top`` and top-relative ``--levels`` take effect for the ``drain``, ``convert``, and ``add`` actions instead of being silently ignored
- `autodump`: ``destroy`` no longer leaves the contents of destroyed containers in limbo or crashes when destroying unit-held items
- `timestream`: deal properly with units who have breathing difficulties
Expand Down
1 change: 1 addition & 0 deletions library/include/modules/MapCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ class DFHACK_EXPORT MapCache
uint32_t y_tmax;
uint32_t z_max;
std::vector<BiomeInfo> biomes;
std::map<df::coord2d, int> biome_index;
std::map<df::coord2d, df::world_region_details*> region_details;
std::map<DFCoord, Block *> blocks;
};
Expand Down
4 changes: 4 additions & 0 deletions library/include/modules/Maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ DFHACK_EXPORT df::coord2d addRegionBiomeOffset(df::coord2d world_pos, int8_t off
// Returns biome info about the specified world region.
DFHACK_EXPORT df::region_map_entry *getRegionBiome(df::coord2d rgn_pos);

// Returns world region coordinates of the BiomeOffset neighbor of a world
// region cell, clipped to the world boundaries. Idx must be in 0-8.
DFHACK_EXPORT df::coord2d getBiomeRgnPos(df::coord2d rgn_pos, int idx);

// Returns biome world region coordinates for the given tile within given block.
DFHACK_EXPORT df::coord2d getBlockTileBiomeRgn(df::map_block *block, df::coord2d pos);

Expand Down
114 changes: 79 additions & 35 deletions library/modules/MapCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1112,17 +1112,23 @@ void MapExtras::BlockInfo::SquashGrass(df::map_block *mb, t_blockmaterials &mate

int MapExtras::Block::biomeIndexAt(df::coord2d p)
{
if (!block)
if (!block || !world->world_data)
return -1;

auto des = index_tile(designation,p);
uint8_t idx = des.bits.biome;
if (idx >= 9)
return -1;
idx = block->region_offset[idx];
if (idx >= parent->biomes.size())
if (idx >= 9)
return -1;
// Biome indices are relative to the block's own region_pos, which may
// differ from the map's anchor region on embarks that cross midmap
// cell boundaries.
auto it = parent->biome_index.find(Maps::getBiomeRgnPos(block->region_pos, idx));
if (it == parent->biome_index.end())
return -1;
return idx;
return it->second;
}

const BiomeInfo &Block::biomeInfoAt(df::coord2d p)
Expand Down Expand Up @@ -1244,57 +1250,95 @@ MapExtras::MapCache::MapCache()
valid = 0;
Maps::getSize(x_bmax, y_bmax, z_max);
x_tmax = x_bmax*16; y_tmax = y_bmax*16;
std::vector<df::coord2d> geoidx;
std::vector<std::vector<int16_t> > layer_mats;
validgeo = Maps::ReadGeology(&layer_mats, &geoidx);
valid = true;
validgeo = false;

if (auto data = df::global::world->world_data)
{
validgeo = true;

for (size_t i = 0; i < data->midmap_data.region_details.size(); i++)
{
auto info = data->midmap_data.region_details[i];
region_details[info->pos] = info;
}
}

biomes.resize(layer_mats.size());
// Biome indices in map block designations are relative to each
// block's own region_pos, so the biome list must cover the
// neighborhood of every cell the map touches: embarks can span
// multiple midmap cells. The set of reachable cells is the
// neighborhood rectangle of all block cells, clipped to the world.
df::coord2d lo(data->world_width, data->world_height);
df::coord2d hi(-1, -1);

for (size_t i = 0; i < layer_mats.size(); i++)
{
biomes[i].pos = geoidx[i];
biomes[i].biome = Maps::getRegionBiome(geoidx[i]);
biomes[i].details = region_details[geoidx[i]];
for (auto block : world->map.map_blocks)
{
if (!block)
continue;
lo.x = std::min<int>(lo.x, block->region_pos.x - 1);
lo.y = std::min<int>(lo.y, block->region_pos.y - 1);
hi.x = std::max<int>(hi.x, block->region_pos.x + 1);
hi.y = std::max<int>(hi.y, block->region_pos.y + 1);
}

biomes[i].geo_index = biomes[i].biome ? biomes[i].biome->geo_index : -1;
biomes[i].geobiome = df::world_geo_biome::find(biomes[i].geo_index);
if (hi.x < 0)
{
// no map blocks; fall back to the map anchor region
lo.x = world->map.region_x / 16 - 1;
lo.y = world->map.region_y / 16 - 1;
hi.x = lo.x + 2;
hi.y = lo.y + 2;
}

biomes[i].lava_stone = -1;
biomes[i].default_soil = -1;
biomes[i].default_stone = -1;
lo.x = std::max<int>(lo.x, 0);
lo.y = std::max<int>(lo.y, 0);
hi.x = std::min<int>(hi.x, data->world_width - 1);
hi.y = std::min<int>(hi.y, data->world_height - 1);

if (biomes[i].details)
biomes[i].lava_stone = biomes[i].details->lava_stone;
for (int16_t y = lo.y; y <= hi.y; y++)
{
for (int16_t x = lo.x; x <= hi.x; x++)
{
df::coord2d pos(x, y);
biome_index[pos] = (int)biomes.size();
biomes.push_back(BiomeInfo());

memset(biomes[i].layer_stone, -1, sizeof(biomes[i].layer_stone));
auto &info = biomes.back();
info.pos = pos;
info.biome = Maps::getRegionBiome(pos);
info.details = region_details[pos];

for (size_t j = 0; j < std::min<size_t>(BiomeInfo::MAX_LAYERS,layer_mats[i].size()); j++)
{
biomes[i].layer_stone[j] = layer_mats[i][j];
info.geo_index = info.biome ? info.biome->geo_index : -1;
info.geobiome = df::world_geo_biome::find(info.geo_index);

auto raw = df::inorganic_raw::find(layer_mats[i][j]);
if (!raw)
continue;
info.lava_stone = info.details ? info.details->lava_stone : -1;
info.default_soil = -1;
info.default_stone = -1;

bool is_soil = raw->flags.is_set(inorganic_flags::SOIL_ANY);
if (is_soil)
biomes[i].default_soil = layer_mats[i][j];
else if (biomes[i].default_stone == -1)
biomes[i].default_stone = layer_mats[i][j];
}
memset(info.layer_stone, -1, sizeof(info.layer_stone));

if (info.geobiome)
{
auto &geolayers = info.geobiome->layers;

while (layer_mats[i].size() < 16)
layer_mats[i].push_back(-1);
for (size_t j = 0; j < std::min<size_t>(BiomeInfo::MAX_LAYERS, geolayers.size()); j++)
{
int16_t mat = geolayers[j]->mat_index;
info.layer_stone[j] = mat;

auto raw = df::inorganic_raw::find(mat);
if (!raw)
continue;

bool is_soil = raw->flags.is_set(inorganic_flags::SOIL_ANY);
if (is_soil)
info.default_soil = mat;
else if (info.default_stone == -1)
info.default_stone = mat;
}
}
}
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion library/modules/Maps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -963,8 +963,11 @@ static df::coord2d biome_offsets[9] = {
df::coord2d(-1,1), df::coord2d(0,1), df::coord2d(1,1)
};

inline df::coord2d getBiomeRgnPos(df::coord2d base, int idx)
df::coord2d Maps::getBiomeRgnPos(df::coord2d base, int idx)
{
if (!world->world_data || idx < 0 || idx >= eBiomeCount)
return df::coord2d();

auto r = base + biome_offsets[idx];

int world_width = world->world_data->world_width;
Expand Down
Loading