252 lines
8.5 KiB
C++
252 lines
8.5 KiB
C++
#include "edgeCost.h"
|
|
|
|
#include "modules/Buildings.h"
|
|
#include "modules/Maps.h"
|
|
#include "modules/MapCache.h"
|
|
|
|
#include "df/building.h"
|
|
#include "df/coord.h"
|
|
#include "df/map_block.h"
|
|
#include "df/tile_building_occ.h"
|
|
#include "df/tiletype.h"
|
|
#include "df/tiletype_material.h"
|
|
#include "df/tiletype_shape.h"
|
|
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
|
|
int64_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
|
|
int32_t dx = pt2.x - pt1.x;
|
|
int32_t dy = pt2.y - pt1.y;
|
|
int32_t dz = pt2.z - pt1.z;
|
|
int64_t cost = costWeight[CostDimension::Distance];
|
|
|
|
if ( Maps::canStepBetween(pt1, pt2) ) {
|
|
return cost;
|
|
}
|
|
|
|
if ( Maps::getTileBlock(pt2) == NULL )
|
|
return -1;
|
|
|
|
df::tiletype* type2 = Maps::getTileType(pt2);
|
|
df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2);
|
|
|
|
if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
|
|
return -1;
|
|
}
|
|
|
|
if ( shape2 == df::enums::tiletype_shape::TREE )
|
|
return -1;
|
|
|
|
df::building* building2 = Buildings::findAtTile(pt2);
|
|
if ( building2 )
|
|
cost += costWeight[CostDimension::DestroyBuilding];
|
|
|
|
bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION;
|
|
if ( construction2 )
|
|
cost += costWeight[CostDimension::DestroyConstruction];
|
|
|
|
if ( dz == 0 ) {
|
|
if ( !building2 && !construction2 ) {
|
|
//it has to be a wall
|
|
if ( shape2 != df::enums::tiletype_shape::WALL ) {
|
|
//out << "shape = " << (int32_t)shape2 << endl;
|
|
//out << __FILE__ << ", line " << __LINE__ << ": WTF?" << endl;
|
|
return cost;
|
|
}
|
|
cost += costWeight[CostDimension::Dig];
|
|
}
|
|
} else {
|
|
if ( dx == 0 && dy == 0 ) {
|
|
if ( dz > 0 ) {
|
|
bool passable_low2 = ENUM_ATTR(tiletype_shape, passable_low, shape2);
|
|
if ( !passable_low2 ) {
|
|
if ( building2 || construction2 )
|
|
return -1;
|
|
cost += costWeight[CostDimension::Dig];
|
|
}
|
|
} else {
|
|
bool passable_high2 = ENUM_ATTR(tiletype_shape, passable_high, shape2);
|
|
if ( !passable_high2 ) {
|
|
if ( building2 || construction2 )
|
|
return -1;
|
|
|
|
if ( shape2 != df::enums::tiletype_shape::WALL )
|
|
return -1;
|
|
cost += costWeight[CostDimension::Dig];
|
|
}
|
|
}
|
|
} else {
|
|
//nonvertical
|
|
//out.print("%s, line %d: (%d,%d,%d)->(%d,%d,%d)\n", __FILE__, __LINE__, pt1.x,pt1.y,pt1.z, pt2.x,pt2.y,pt2.z);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return cost;
|
|
}
|
|
|
|
int64_t getEdgeCostOld(color_ostream& out, df::coord pt1, df::coord pt2) {
|
|
//first, list all the facts
|
|
int32_t dx = pt2.x - pt1.x;
|
|
int32_t dy = pt2.y - pt1.y;
|
|
int32_t dz = pt2.z - pt1.z;
|
|
int64_t cost = costWeight[CostDimension::Distance];
|
|
|
|
if ( false ) {
|
|
if ( Maps::canStepBetween(pt1,pt2) )
|
|
return cost;
|
|
return 100 + cost;
|
|
}
|
|
|
|
Maps::ensureTileBlock(pt1);
|
|
Maps::ensureTileBlock(pt2);
|
|
df::tiletype* type1 = Maps::getTileType(pt1);
|
|
df::tiletype* type2 = Maps::getTileType(pt2);
|
|
df::map_block* block1 = Maps::getTileBlock(pt1);
|
|
df::map_block* block2 = Maps::getTileBlock(pt2);
|
|
df::tiletype_shape shape1 = ENUM_ATTR(tiletype, shape, *type1);
|
|
df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2);
|
|
|
|
bool construction1 = ENUM_ATTR(tiletype, material, *type1) == df::enums::tiletype_material::CONSTRUCTION;
|
|
bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION;
|
|
bool passable1 = block1->walkable[pt1.x&0xF][pt1.y&0xF] != 0;
|
|
bool passable2 = block2->walkable[pt2.x&0xF][pt2.y&0xF] != 0;
|
|
bool passable_high1 = ENUM_ATTR(tiletype_shape, passable_high, shape1);
|
|
bool passable_high2 = ENUM_ATTR(tiletype_shape, passable_high, shape2);
|
|
bool passable_low1 = ENUM_ATTR(tiletype_shape, passable_low, shape1);
|
|
bool passable_low2 = ENUM_ATTR(tiletype_shape, passable_low, shape2);
|
|
|
|
bool building1, building2;
|
|
bool sameBuilding = false;
|
|
{
|
|
df::enums::tile_building_occ::tile_building_occ awk = block1->occupancy[pt1.x&0x0F][pt1.y&0x0F].bits.building;
|
|
building1 = awk == df::enums::tile_building_occ::Obstacle || awk == df::enums::tile_building_occ::Impassable;
|
|
awk = block2->occupancy[pt2.x&0x0F][pt2.y&0x0F].bits.building;
|
|
building2 = awk == df::enums::tile_building_occ::Obstacle || awk == df::enums::tile_building_occ::Impassable;
|
|
if ( building1 && building2 ) {
|
|
df::building* b1 = Buildings::findAtTile(pt1);
|
|
df::building* b2 = Buildings::findAtTile(pt2);
|
|
sameBuilding = b1 == b2;
|
|
}
|
|
}
|
|
|
|
if ( Maps::canStepBetween(pt1, pt2) ) {
|
|
if ( building2 && !sameBuilding ) {
|
|
cost += costWeight[CostDimension::DestroyBuilding];
|
|
}
|
|
return cost;
|
|
}
|
|
|
|
if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
|
|
return -1;
|
|
}
|
|
|
|
//cannot step between: find out why
|
|
if ( dz == 0 ) {
|
|
if ( passable2 && !passable1 ) {
|
|
return cost;
|
|
}
|
|
if ( passable1 && passable2 ) {
|
|
out << __FILE__ << ", line " << __LINE__ << ": WTF?" << endl;
|
|
return cost;
|
|
}
|
|
//pt2 is not passable. it must be a construction, a building, or a wall.
|
|
if ( building2 ) {
|
|
if ( sameBuilding ) {
|
|
//don't charge twice for destroying the same building
|
|
return cost;
|
|
}
|
|
cost += costWeight[CostDimension::DestroyBuilding];
|
|
return cost;
|
|
}
|
|
if ( construction2 ) {
|
|
//impassible constructions must be deconstructed
|
|
cost += costWeight[CostDimension::DestroyConstruction];
|
|
return cost;
|
|
}
|
|
|
|
if ( shape2 == df::enums::tiletype_shape::TREE ) {
|
|
return -1;
|
|
}
|
|
|
|
if ( shape2 == df::enums::tiletype_shape::RAMP_TOP ) {
|
|
return -1;
|
|
}
|
|
|
|
//it has to be a wall
|
|
if ( shape2 != df::enums::tiletype_shape::WALL ) {
|
|
out << "shape = " << (int32_t)shape2 << endl;
|
|
out << __FILE__ << ", line " << __LINE__ << ": WTF?" << endl;
|
|
return cost;
|
|
}
|
|
|
|
cost += costWeight[CostDimension::Dig];
|
|
return cost;
|
|
}
|
|
|
|
//dz != 0
|
|
if ( dx == 0 && dy == 0 ) {
|
|
if ( dz > 0 ) {
|
|
if ( passable_low2 )
|
|
return cost;
|
|
if ( building2 || construction2 ) {
|
|
return -1;
|
|
}
|
|
cost += costWeight[CostDimension::Dig];
|
|
return cost;
|
|
}
|
|
|
|
//descending
|
|
if ( passable_high2 )
|
|
return cost;
|
|
|
|
if ( building2 || construction2 ) {
|
|
return -1;
|
|
}
|
|
|
|
//must be a wall?
|
|
if ( shape2 != df::enums::tiletype_shape::WALL ) {
|
|
out.print("%s, line %n: WTF?\n", __FILE__, __LINE__);
|
|
return cost;
|
|
}
|
|
|
|
cost += costWeight[CostDimension::Dig];
|
|
return cost;
|
|
}
|
|
|
|
//moving diagonally
|
|
return -1;
|
|
}
|
|
|
|
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax) {
|
|
vector<Edge>* result = new vector<Edge>(26);
|
|
//result->reserve(26);
|
|
|
|
size_t count = 0;
|
|
for ( int32_t dx = -1; dx <= 1; dx++ ) {
|
|
for ( int32_t dy = -1; dy <= 1; dy++ ) {
|
|
for ( int32_t dz = -1; dz <= 1; dz++ ) {
|
|
df::coord neighbor(point.x+dx, point.y+dy, point.z+dz);
|
|
if ( neighbor.x < 0 || neighbor.x >= xMax || neighbor.y < 0 || neighbor.y >= yMax || neighbor.z < 0 || neighbor.z >= zMax )
|
|
continue;
|
|
if ( dz != 0 && /*(point.x == 0 || point.y == 0 || point.z == 0 || point.x == xMax-1 || point.y == yMax-1 || point.z == zMax-1) ||*/ (neighbor.x == 0 || neighbor.y == 0 || neighbor.z == 0 || neighbor.x == xMax-1 || neighbor.y == yMax-1 || neighbor.z == zMax-1) )
|
|
continue;
|
|
if ( dx == 0 && dy == 0 && dz == 0 )
|
|
continue;
|
|
int64_t cost = getEdgeCost(out, point, neighbor);
|
|
if ( cost == -1 )
|
|
continue;
|
|
Edge edge(point, neighbor, cost);
|
|
//result->push_back(edge);
|
|
(*result)[count] = edge;
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|