662 lines
15 KiB
C++
662 lines
15 KiB
C++
/*
|
|
www.sourceforge.net/projects/dfhack
|
|
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any
|
|
damages arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any
|
|
purpose, including commercial applications, and to alter it and
|
|
redistribute it freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must
|
|
not claim that you wrote the original software. If you use this
|
|
software in a product, an acknowledgment in the product documentation
|
|
would be appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and
|
|
must not be misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
distribution.
|
|
*/
|
|
|
|
#include "DFCommon.h"
|
|
// zlib helper functions for de/compressing files
|
|
#include "ZlibHelper.h"
|
|
#include "DfMapHeader.h"
|
|
|
|
// some bounds checking in debug mode. used in asserts
|
|
#define CheckBounds x < x_cell_count && x >= 0 && y < y_cell_count && y >= 0 && z < z_block_count && z >= 0
|
|
#define CheckBoundsXY x < x_cell_count && x >= 0 && y < y_cell_count && y >= 0
|
|
#define CheckBlockBounds x < x_block_count && x >= 0 && y < y_block_count && y >= 0 && z < z_block_count && z >= 0
|
|
|
|
// this expands into lots of ugly switch statement functions. some of them unused?, but kept for reference
|
|
#include "DFTileTypes.h"
|
|
|
|
// process vein vector into matgloss values...
|
|
void Block::collapseVeins()
|
|
{
|
|
// iterate through assigned veins
|
|
for( uint32_t i = 0; i < veins.size(); i++)
|
|
{
|
|
t_vein v = veins[i];
|
|
//iterate through vein assignment bit arrays - one for every row
|
|
for(uint32_t j = 0;j<16;j++)
|
|
{
|
|
//iterate through the bits
|
|
for (uint32_t k = 0; k< 16;k++)
|
|
{
|
|
// and the bit array with a one-bit mask, check if the bit is set
|
|
bool set = ((1 << k) & v.assignment[j]) >> k;
|
|
if(set)
|
|
{
|
|
material[k][j].type = Mat_Stone;
|
|
material[k][j].index = v.type;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DfMap::~DfMap()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
|
|
/// TODO: make this sync
|
|
void DfMap::clear()
|
|
{
|
|
if(valid)
|
|
{
|
|
valid = false;
|
|
for(uint32_t i = 0; i < x_block_count*y_block_count*z_block_count;i++)
|
|
{
|
|
Block * b = block[i];
|
|
if(b!=NULL)
|
|
{
|
|
delete b;
|
|
}
|
|
}
|
|
delete[] block;
|
|
}
|
|
for (uint32_t i = eNorthWest; i< eBiomeCount;i++)
|
|
{
|
|
v_geology[i].clear();
|
|
//geodebug[i].clear();
|
|
//geoblockadresses[i] = 0;
|
|
//regionadresses[i] = 0;
|
|
}
|
|
for(uint32_t counter = Mat_Wood; counter < NUM_MATGLOSS_TYPES; counter++)
|
|
{
|
|
v_matgloss[counter].clear();
|
|
}
|
|
// delete buildings, clear vector
|
|
for(uint32_t i = 0; i < v_buildings.size(); i++)
|
|
{
|
|
delete v_buildings[i];
|
|
}
|
|
v_buildings.clear();
|
|
|
|
// delete vegetation, clear vector
|
|
for(uint32_t i = 0; i < v_trees.size(); i++)
|
|
{
|
|
delete v_trees[i];
|
|
}
|
|
v_trees.clear();
|
|
// clear construction vector
|
|
v_constructions.clear();
|
|
blocks_allocated = 0;
|
|
///FIXME: destroy all the extracted data here
|
|
}
|
|
|
|
|
|
void DfMap::getRegionCoords (uint32_t &x,uint32_t &y,uint32_t &z)
|
|
{
|
|
x= regionX;
|
|
y= regionY;
|
|
z= regionZ;
|
|
}
|
|
|
|
|
|
void DfMap::setRegionCoords (uint32_t x,uint32_t y,uint32_t z)
|
|
{
|
|
regionX = x;
|
|
regionY = y;
|
|
regionZ = z;
|
|
}
|
|
|
|
|
|
void DfMap::allocBlockArray(uint32_t x,uint32_t y, uint32_t z)
|
|
{
|
|
clear();
|
|
x_block_count = x;
|
|
y_block_count = y;
|
|
z_block_count = z;
|
|
updateCellCount();
|
|
block = new Block*[x_block_count*y_block_count*z_block_count];
|
|
for (uint32_t i = 0; i < x_block_count*y_block_count*z_block_count; i++ )
|
|
{
|
|
block[i] = NULL;
|
|
}
|
|
blocks_allocated = 0;
|
|
valid = true;
|
|
}
|
|
|
|
|
|
DfMap::DfMap(uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
valid = false;
|
|
allocBlockArray(x,y,z);
|
|
}
|
|
|
|
|
|
DfMap::DfMap(string FileName)
|
|
{
|
|
valid = false;
|
|
valid = load( FileName);
|
|
}
|
|
|
|
|
|
bool DfMap::isValid ()
|
|
{
|
|
return valid;
|
|
}
|
|
|
|
|
|
Block * DfMap::getBlock (uint32_t x,uint32_t y,uint32_t z)
|
|
{
|
|
if(isValid())
|
|
{
|
|
return block[x*y_block_count*z_block_count + y*z_block_count + z];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
vector<t_building *> * DfMap::getBlockBuildingsVector(uint32_t x,uint32_t y,uint32_t z)
|
|
{
|
|
Block * b = getBlock(x,y,z);
|
|
if(b)
|
|
{
|
|
return &b->v_buildings;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
vector<t_tree_desc *> * DfMap::getBlockVegetationVector(uint32_t x,uint32_t y,uint32_t z)
|
|
{
|
|
Block * b = getBlock(x,y,z);
|
|
if(b)
|
|
{
|
|
return &b->v_trees;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
t_tree_desc *DfMap::getTree (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
for(uint32_t i = 0; i< v_trees.size();i++)
|
|
{
|
|
if(x == v_trees[i]->x
|
|
&& y == v_trees[i]->y
|
|
&& z == v_trees[i]->z)
|
|
{
|
|
return v_trees[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
t_building *DfMap::getBuilding (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
for(uint32_t i = 0; i< v_buildings.size();i++)
|
|
{
|
|
if(x >= v_buildings[i]->x1 && x <= v_buildings[i]->x2
|
|
&& y >= v_buildings[i]->y1 && y <= v_buildings[i]->y2
|
|
&& z == v_buildings[i]->z)
|
|
{
|
|
return v_buildings[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
Block * DfMap::allocBlock (uint32_t x,uint32_t y,uint32_t z)
|
|
{
|
|
if(isValid())
|
|
{
|
|
if(block[x*y_block_count*z_block_count + y*z_block_count + z])
|
|
{
|
|
return block[x*y_block_count*z_block_count + y*z_block_count + z];
|
|
}
|
|
Block *b = new Block;
|
|
block[x*y_block_count*z_block_count + y*z_block_count + z] = b;
|
|
blocks_allocated++;
|
|
return b;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void DfMap::updateCellCount()
|
|
{
|
|
x_cell_count = x_block_count * BLOCK_SIZE;
|
|
y_cell_count = y_block_count * BLOCK_SIZE;
|
|
z_cell_count = z_block_count;
|
|
}
|
|
|
|
|
|
void DfMap::applyGeoMatgloss(Block * b)
|
|
{
|
|
// load layer matgloss
|
|
for(int x_b = 0; x_b < BLOCK_SIZE; x_b++)
|
|
{
|
|
for(int y_b = 0; y_b < BLOCK_SIZE; y_b++)
|
|
{
|
|
int geolayer = b->designation[x_b][y_b].bits.geolayer_index;
|
|
int biome = b->designation[x_b][y_b].bits.biome;
|
|
b->material[x_b][y_b].type = Mat_Stone;
|
|
b->material[x_b][y_b].index = v_geology[b->RegionOffsets[biome]][geolayer];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
uint8_t DfMap::getLiquidLevel(uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->designation[x2][y2].bits.flow_size;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
uint16_t DfMap::getTileType(uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->tile_type[x2][y2];
|
|
}
|
|
if(isTileSky(x,y,z,x2,y2))
|
|
{
|
|
return 32;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
uint16_t DfMap::getTileType(uint32_t x, uint32_t y, uint32_t z, uint32_t blockX, uint32_t blockY)
|
|
{
|
|
assert(CheckBlockBounds);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->tile_type[blockX][blockY];
|
|
}
|
|
if(isTileSky(x,y,z,blockX,blockY))
|
|
{
|
|
return 32;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
uint32_t DfMap::getDesignations(uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->designation[x2][y2].whole;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
bool DfMap::isBlockInitialized(uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
// because of the way DfMap is done, more than one check must be made.
|
|
return getBlock(x,y,z) != NULL;
|
|
}
|
|
|
|
|
|
uint32_t DfMap::getOccupancies(uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->occupancy[x2][y2].whole;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
void DfMap::getGeoRegion (uint32_t x, uint32_t y, uint32_t z, int32_t& geoX, int32_t& geoY)
|
|
{
|
|
assert(CheckBoundsXY);
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
int biome = b->designation[x2][y2].bits.biome;
|
|
int BiomeOffset = b->RegionOffsets[biome];
|
|
int16_t X_biomeB = (regionX / 16) + (BiomeOffset % 3) - 1;
|
|
int16_t Y_biomeB = (regionY / 16) + (BiomeOffset / 3) - 1;
|
|
if(X_biomeB < 0) X_biomeB = 0;
|
|
if(Y_biomeB < 0) Y_biomeB = 0;
|
|
if( (uint32_t)X_biomeB >= worldSizeX)
|
|
{
|
|
X_biomeB = worldSizeX - 1;
|
|
}
|
|
if( (uint32_t)Y_biomeB >= worldSizeY)
|
|
{
|
|
Y_biomeB = worldSizeY - 1;
|
|
}
|
|
geoX = X_biomeB;
|
|
geoY = Y_biomeB;
|
|
}
|
|
else
|
|
{
|
|
geoX = regionX / 16;
|
|
geoY = regionY / 16;
|
|
}
|
|
}
|
|
|
|
|
|
t_matglossPair DfMap::getMaterialPair (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->material[x2][y2];
|
|
}
|
|
t_matglossPair fail = {-1,-1};
|
|
return fail;
|
|
};
|
|
|
|
|
|
// this is what the vein structures say it is
|
|
string DfMap::getGeoMaterialString (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return getMaterialString(b->material[x2][y2].type, b->material[x2][y2].index);
|
|
}
|
|
string fallback = "UNKNOWN";
|
|
return fallback;
|
|
}
|
|
|
|
|
|
string DfMap::getMaterialTypeString (uint32_t type)
|
|
{
|
|
string ret = "";
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
ret += "wood";
|
|
break;
|
|
case 1:
|
|
ret += "stone/soil";
|
|
break;
|
|
case 2:
|
|
ret += "metal";
|
|
break;
|
|
case 3:
|
|
ret += "plant";
|
|
break;
|
|
case 10:
|
|
ret += "leather";
|
|
break;
|
|
case 11:
|
|
ret += "silk cloth";
|
|
break;
|
|
case 12:
|
|
ret += "plant thread cloth";
|
|
break;
|
|
case 13: // green glass
|
|
ret += "green glass";
|
|
break;
|
|
case 14: // clear glass
|
|
ret += "clear glass";
|
|
break;
|
|
case 15: // crystal glass
|
|
ret += "crystal glass";
|
|
break;
|
|
case 17:
|
|
ret += "ice";
|
|
break;
|
|
case 18:
|
|
ret += "charcoal";
|
|
break;
|
|
case 19:
|
|
ret += "potash";
|
|
break;
|
|
case 20:
|
|
ret += "ashes";
|
|
break;
|
|
case 21:
|
|
ret += "pearlash";
|
|
break;
|
|
case 24:
|
|
ret += "soap";
|
|
break;
|
|
default:
|
|
ret += "unknown";
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
string DfMap::getMaterialString (uint32_t type, uint32_t index)
|
|
{
|
|
if(index != 65535 && type >= 0 && type < NUM_MATGLOSS_TYPES)
|
|
{
|
|
if(index < v_matgloss[type].size())
|
|
{
|
|
return v_matgloss[type][index];
|
|
}
|
|
else
|
|
{
|
|
string fallback = "ERROR";
|
|
return fallback;
|
|
}
|
|
}
|
|
string fallback = "UNKNOWN";
|
|
return fallback;
|
|
}
|
|
|
|
|
|
uint16_t DfMap::getNumMatGloss(uint16_t type)
|
|
{
|
|
return v_matgloss[type].size();
|
|
}
|
|
|
|
|
|
string DfMap::getBuildingTypeName(uint32_t index)
|
|
{
|
|
if(index < v_buildingtypes.size())
|
|
{
|
|
return v_buildingtypes[index];
|
|
}
|
|
return string("error");
|
|
}
|
|
|
|
|
|
string DfMap::getMatGlossString(uint16_t type,uint16_t index)
|
|
{
|
|
if(index < v_matgloss[type].size())
|
|
{
|
|
return v_matgloss[type][index];
|
|
}
|
|
return string("error");
|
|
}
|
|
|
|
|
|
// matgloss part of the designation
|
|
unsigned int DfMap::getGeolayerIndex (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->designation[x2][y2].bits.geolayer_index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
// matgloss part of the designation
|
|
unsigned int DfMap::getBiome (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return b->designation[x2][y2].bits.biome;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
bool DfMap::isHidden (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return (b->designation[x2][y2].bits.hidden);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool DfMap::isSubterranean (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return (b->designation[x2][y2].bits.subterranean);
|
|
}
|
|
if(isTileSky( x, y, z, x2, y2))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// x,y,z - coords of block
|
|
// blockX,blockY - coords of tile inside block
|
|
bool DfMap::isTileSky(uint32_t x, uint32_t y, uint32_t z, uint32_t blockX, uint32_t blockY)
|
|
{
|
|
assert(CheckBounds);
|
|
Block *b;
|
|
// trace down through blocks until we hit an inited one or the base
|
|
for (int i = z; i>= 0;i--)
|
|
{
|
|
b = getBlock(x,y,i);
|
|
if(b)
|
|
{
|
|
// is the inited block open to the sky?
|
|
return b->designation[blockX][blockY].bits.skyview;
|
|
}
|
|
}
|
|
// we hit base
|
|
return false;
|
|
}
|
|
|
|
|
|
// is the sky above this tile visible?
|
|
bool DfMap::isSkyView (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return (b->designation[x2][y2].bits.skyview);
|
|
}
|
|
if(isTileSky(x,y,z,x2,y2))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// is there light in this tile?
|
|
bool DfMap::isSunLit (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return (b->designation[x2][y2].bits.light);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool DfMap::isMagma (uint32_t x, uint32_t y, uint32_t z)
|
|
{
|
|
assert(CheckBounds);
|
|
uint32_t x2, y2;
|
|
convertToDfMapCoords(x, y, x, y, x2, y2);
|
|
Block *b = getBlock(x,y,z);
|
|
if(b != NULL)
|
|
{
|
|
return (b->designation[x2][y2].bits.liquid_type);
|
|
}
|
|
return false;
|
|
}
|