Digging invaders. Temp commit. Unstable.

develop
expwnent 2012-12-19 18:46:46 -05:00
parent a09764e77b
commit fcbc5d1cb0
1 changed files with 402 additions and 87 deletions

@ -7,22 +7,41 @@
#include "modules/Buildings.h"
#include "modules/EventManager.h"
#include "modules/Job.h"
#include "modules/Maps.h"
#include "modules/MapCache.h"
#include "modules/Units.h"
#include "modules/World.h"
#include "df/body_part_raw_flags.h"
#include "df/building.h"
#include "df/building_type.h"
#include "df/caste_body_info.h"
#include "df/coord.h"
#include "df/general_ref.h"
#include "df/general_ref_building_holderst.h"
#include "df/general_ref_unit.h"
#include "df/general_ref_unit_holderst.h"
#include "df/general_ref_unit_workerst.h"
#include "df/item.h"
#include "df/itemdef_weaponst.h"
#include "df/item_quality.h"
#include "df/item_weaponst.h"
#include "df/inorganic_raw.h"
#include "df/job.h"
#include "df/job_skill.h"
#include "df/job_type.h"
#include "df/map_block.h"
#include "df/strain_type.h"
#include "df/ui.h"
#include "df/unit.h"
#include "df/tile_building_occ.h"
#include "df/tile_occupancy.h"
#include "df/tiletype.h"
#include "df/tiletype_material.h"
#include "df/tiletype_shape.h"
#include "df/tiletype_shape_basic.h"
#include "df/ui.h"
#include "df/unit.h"
#include "df/unit_inventory_item.h"
#include "df/world.h"
#include <algorithm>
@ -73,7 +92,25 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
}
//cost is [path cost, building destruction cost, dig cost, construct cost]. Minimize constructions, then minimize dig cost, then minimize path cost.
const size_t costDim = 3;
enum CostDimension {
Distance,
DestroyBuilding,
Dig,
DestroyConstruction,
//Construct,
costDim
};
const int32_t costBucket[] = {
//Distance
0,
//DestroyBuilding
1,
//Dig
2,
//DestroyConstruction
3,
};
struct Cost {
int32_t cost[costDim];
@ -88,39 +125,73 @@ struct Cost {
}
Cost( int32_t i ) {
memset(cost, 0, costDim*sizeof(int32_t));
cost[0] = i;
cost[CostDimension::Distance] = i;
}
/*
int32_t workNeeded() const {
int32_t result = 0;
for ( int32_t a = 1; a < costDim; a++ ) {
result += cost[a];
}
return result;
}
*/
int32_t compare(const Cost& c) const {
int32_t table[costDim];
memset(table, 0, costDim*sizeof(int32_t));
for ( size_t a = 0; a < costDim; a++ ) {
table[costBucket[a]] += cost[a] - c.cost[a];
}
for ( size_t a = 0; a < costDim; a++ ) {
if ( table[costDim-1-a] > 0 )
return 1;
if ( table[costDim-1-a] < 0 )
return -1;
}
return 0;
}
bool operator>(const Cost& c) const {
return compare(c) > 0;
/*
for ( size_t a = 0; a < costDim; a++ ) {
if ( cost[costDim-1-a] != c.cost[costDim-1-a] )
return cost[costDim-1-a] > c.cost[costDim-1-a];
}
return false;
*/
}
bool operator<(const Cost& c) const {
return compare(c) < 0;
/*
for ( size_t a = 0; a < costDim; a++ ) {
if ( cost[costDim-1-a] != c.cost[costDim-1-a] )
return cost[costDim-1-a] < c.cost[costDim-1-a];
}
return false;
*/
}
bool operator==(const Cost& c) const {
return compare(c) == 0;
/*
for ( size_t a = 0; a < costDim; a++ ) {
if ( cost[a] != c.cost[a] )
return false;
}
return true;
*/
}
bool operator<=(const Cost& c) const {
return *this == c || *this < c;
return compare(c) <= 0;
}
bool operator!=(const Cost& c) const {
return !( *this == c);
return compare(c) != 0;
}
Cost operator+(const Cost& c) const {
@ -245,6 +316,7 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
xMax *= 16;
yMax *= 16;
MapExtras::MapCache cache;
df::unit* firstInvader = NULL;
//TODO: look for invaders with buildingdestroyer:3
@ -263,10 +335,14 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
invaderPts.insert(unit->pos);
costMap[unit->pos] = 0;
fringe.insert(unit->pos);
if ( firstInvader == NULL )
firstInvader = unit;
} else {
continue;
}
}
out << firstInvader->id << endl;
out << firstInvader->pos.x << ", " << firstInvader->pos.y << ", " << firstInvader->pos.z << endl;
int32_t localPtsFound = 0;
#if HASHMAP
@ -285,13 +361,20 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
out.print("Double closure! Bad!\n");
break;
}
//closedSet.insert(pt);
closedSet.insert(pt);
if ( localPts.find(pt) != localPts.end() ) {
localPtsFound++;
if ( localPtsFound >= localPts.size() )
break;
if ( costMap[pt].cost[1] > 0 || costMap[pt].cost[2] > 0 /*|| costMap[pt].cost[3] > 0*/ )
bool doBreak = false;
for ( int32_t a = 1; a < costDim; a++ ) {
if ( costMap[pt].cost[a] > 0 ) {
doBreak = true;
break;
}
}
if ( doBreak )
break;
}
@ -323,6 +406,9 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
clock_t time = clock() - t0;
out.print("time = %d, totalEdgeTime = %d\n", time, totalEdgeTime);
unordered_set<df::coord, PointHash> requiresZNeg;
unordered_set<df::coord, PointHash> requiresZPos;
//find important edges
list<Edge> importantEdges;
for ( auto i = localPts.begin(); i != localPts.end(); i++ ) {
@ -331,12 +417,30 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
continue;
if ( parentMap.find(pt) == parentMap.end() )
continue;
if ( costMap[pt].cost[1] == 0 && costMap[pt].cost[2] == 0 )
bool requireAction = false;
for ( int32_t a = 1; a < costDim; a++ ) {
if ( costMap[pt].cost[a] != 0 ) {
requireAction = true;
break;
}
}
if ( !requireAction )
continue;
while ( parentMap.find(pt) != parentMap.end() ) {
//out.print("(%d,%d,%d)\n", pt.x, pt.y, pt.z);
df::coord parent = parentMap[pt];
if ( !Maps::canWalkBetween(pt, parent) ) {
if ( pt.z < parent.z ) {
requiresZNeg.insert(parent);
requiresZPos.insert(pt);
} else if ( pt.z > parent.z ) {
requiresZNeg.insert(pt);
requiresZPos.insert(parent);
}
Cost cost1 = costMap[pt];
Cost cost2 = costMap[parent];
cost1.cost[0] = 0;
cost2.cost[0] = 0;
if ( true || cost1 != cost2 ) {
importantEdges.push_front(Edge(pt,parent,0));
}
pt = parent;
@ -344,6 +448,28 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
break;
}
unordered_set<df::coord,PointHash> toDelete;
for ( auto a = requiresZNeg.begin(); a != requiresZNeg.end(); a++ ) {
df::coord pos = *a;
df::tiletype* type = Maps::getTileType(pos);
df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, *type);
if ( ENUM_ATTR(tiletype_shape, passable_low, shape) ) {
toDelete.insert(pos);
}
}
requiresZNeg.erase(toDelete.begin(), toDelete.end());
toDelete.clear();
for ( auto a = requiresZPos.begin(); a != requiresZPos.end(); a++ ) {
df::coord pos = *a;
df::tiletype* type = Maps::getTileType(pos);
df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, *type);
if ( ENUM_ATTR(tiletype_shape, passable_high, shape) ) {
toDelete.insert(pos);
}
}
requiresZPos.erase(toDelete.begin(), toDelete.end());
toDelete.clear();
bool didSomething = false;
df::coord where;
for ( auto i = importantEdges.begin(); i != importantEdges.end(); i++ ) {
@ -354,54 +480,199 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
pt1 = e.p2;
pt2 = e.p1;
}
bool important = //requireZNeg.find(pt1) != requireZNeg.end() ||
//requireZPos.find(pt1) != requireZPos.end() ||
requiresZNeg.find(pt2) != requiresZNeg.end() ||
requiresZPos.find(pt2) != requiresZPos.end();
if ( !important ) {
Cost c1 = costMap[pt1];
Cost c2 = costMap[pt2];
c1.cost[0] = 0;
c2.cost[0] = 0;
if ( c1 == c2 ) {
//definitely not important
continue;
}
}
df::map_block* block1 = Maps::getTileBlock(pt1);
df::map_block* block2 = Maps::getTileBlock(pt2);
bool passable1 = block1->walkable[pt1.x&0x0F][pt1.y&0x0F];
bool passable2 = block2->walkable[pt2.x&0x0F][pt2.y&0x0F];
//TODO: if actions required > 1, continue
df::building* building = Buildings::findAtTile(pt2);
if ( building != NULL && passable2 ) {
building = NULL;
}
if ( building != NULL ) {
building->flags.bits.almost_deleted = true;
out.print("%s, line %d: Destroying building %d\n", __FILE__, __LINE__, building->id);
//building->flags.bits.almost_deleted = true;
df::job* job = new df::job;
job->job_type = df::enums::job_type::DestroyBuilding;
job->flags.bits.special = 1;
df::general_ref_building_holderst* buildingRef = new df::general_ref_building_holderst;
buildingRef->building_id = building->id;
job->references.push_back(buildingRef);
df::general_ref_unit_workerst* workerRef = new df::general_ref_unit_workerst;
workerRef->unit_id = firstInvader->id;
job->references.push_back(workerRef);
firstInvader->job.current_job = job;
firstInvader->path.path.x.clear();
firstInvader->path.path.y.clear();
firstInvader->path.path.z.clear();
firstInvader->path.dest = pt1;
firstInvader->job.hunt_target = NULL;
firstInvader->job.destroy_target = NULL;
building->jobs.clear();
building->jobs.push_back(job);
Job::linkIntoWorld(job);
didSomething = true;
where = pt2;
break;
continue;
} else {
df::map_block* block1 = Maps::getTileBlock(pt1);
df::map_block* block2 = Maps::getTileBlock(pt2);
df::tiletype* type1 = Maps::getTileType(pt1);
df::tiletype* type2 = Maps::getTileType(pt2);
df::tiletype_shape shape1 = ENUM_ATTR(tiletype, shape, *type1);
df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2);
if ( pt1.z != pt2.z && shape1 != df::enums::tiletype_shape::STAIR_DOWN && shape1 != df::enums::tiletype_shape::STAIR_UPDOWN ) {
block1->tiletype[pt2.x&0x0F][pt2.y&0x0F] = df::enums::tiletype::ConstructedStairUD;
where = pt2;
bool construction2 = ENUM_ATTR(tiletype, material, *type1) == df::enums::tiletype_material::CONSTRUCTION;
if ( construction2 ) {
out.print("%s, line %d. Removing construction (%d,%d,%d)\n", __FILE__, __LINE__, pt2.x,pt2.y,pt2.z);
df::job* job = new df::job();
job->job_type = df::enums::job_type::RemoveConstruction;
df::general_ref_unit_workerst* workerRef = new df::general_ref_unit_workerst;
workerRef->unit_id = firstInvader->id;
job->references.push_back(workerRef);
job->pos = pt2;
firstInvader->job.current_job = job;
firstInvader->path.path.x.clear();
firstInvader->path.path.y.clear();
firstInvader->path.path.z.clear();
firstInvader->path.dest = pt1;
firstInvader->job.hunt_target = NULL;
firstInvader->job.destroy_target = NULL;
Job::linkIntoWorld(job);
didSomething = true;
where = pt2;
break;
}
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) {
block2->tiletype[pt2.x&0x0F][pt2.y&0x0F] = df::enums::tiletype::ConstructedStairUD;
didSomething = true;
/*if ( pt1.z != pt2.z && shape1 != df::enums::tiletype_shape::STAIR_DOWN && shape1 != df::enums::tiletype_shape::STAIR_UPDOWN ) {
block1->tiletype[pt2.x&0x0F][pt2.y&0x0F] = df::enums::tiletype::ConstructedStairUD;
where = pt2;
didSomething = true;
break;
}*/
bool up = requiresZPos.find(pt2) != requiresZPos.end();
bool down = requiresZNeg.find(pt2) != requiresZNeg.end();
df::job* job = new df::job;
if ( up && down ) {
job->job_type = df::enums::job_type::CarveUpDownStaircase;
job->pos = pt2;
} else if ( up && !down ) {
job->job_type = df::enums::job_type::CarveUpwardStaircase;
job->pos = pt2;
} else if ( !up && down ) {
job->job_type = df::enums::job_type::CarveDownwardStaircase;
job->pos = pt2;
} else {
job->job_type = df::enums::job_type::Dig;
job->pos = pt1;
}
df::general_ref_unit_workerst* ref = new df::general_ref_unit_workerst;
ref->unit_id = firstInvader->id;
job->references.push_back(ref);
firstInvader->job.hunt_target = NULL;
firstInvader->job.destroy_target = NULL;
firstInvader->job.current_job = job;
firstInvader->path.path.x.clear();
firstInvader->path.path.y.clear();
firstInvader->path.path.z.clear();
firstInvader->path.dest = pt2;
Job::linkIntoWorld(job);
//create and give a pick
df::item_weaponst* pick = new df::item_weaponst;
pick->pos = firstInvader->pos;
pick->flags.bits.forbid = 1;
pick->flags.bits.on_ground = 1;
pick->id = (*df::global::item_next_id)++;
pick->ignite_point = -1;
pick->heatdam_point = -1;
pick->colddam_point = -1;
pick->boiling_point = 11000;
pick->melting_point = 10500;
pick->fixed_temp = -1;
pick->weight = 0;
pick->weight_fraction = 0;
pick->stack_size = 1;
pick->temperature = 10059;
pick->temperature_fraction = 0;
pick->mat_type = 0;
pick->mat_index = 5;
pick->maker_race = 0; //hehe
pick->quality = (df::enums::item_quality::item_quality)0;
pick->skill_used = (df::enums::job_skill::job_skill)0;
pick->maker = -1;
df::itemdef_weaponst* itemdef = NULL;
for ( size_t a = 0; a < df::global::world->raws.itemdefs.weapons.size(); a++ ) {
df::itemdef_weaponst* candidate = df::global::world->raws.itemdefs.weapons[a];
if ( candidate->id == "ITEM_WEAPON_PICK" ) {
itemdef = candidate;
break;
}
}
if ( itemdef == NULL ) {
out.print("%s, %d: null itemdef.\n", __FILE__, __LINE__);
return;
}
pick->subtype = itemdef;
pick->sharpness = 5000;
int32_t part = -1;
part = firstInvader->body.unk_3c8; //weapon_bp
if ( part == -1 ) {
out.print("%s, %d: no grasp part.\n", __FILE__, __LINE__);
return;
}
//check for existing item there
for ( size_t a = 0; a < firstInvader->inventory.size(); a++ ) {
df::unit_inventory_item* inv_item = firstInvader->inventory[a];
if ( false || inv_item->body_part_id == part ) {
//throw it on the GROUND
Items::moveToGround(cache, inv_item->item, firstInvader->pos);
}
}
Items::moveToInventory(cache, pick, firstInvader, df::unit_inventory_item::T_mode::Weapon, part);
didSomething = true;
where = pt2;
break;
}
}
out << "didSomething = " << didSomething << endl;
if ( !didSomething )
return;
Cost cost = costMap[where];
float cost_tick = 0;
cost_tick += cost.cost[0];
cost_tick += cost.cost[1] / (float)destroySpeed;
cost_tick += cost.cost[2] / (float)digSpeed;
cost_tick += cost.cost[CostDimension::Distance];
cost_tick += cost.cost[CostDimension::DestroyBuilding] / (float)destroySpeed;
cost_tick += cost.cost[CostDimension::Dig] / (float)digSpeed;
EventManager::EventHandler handle(doDiggingInvaders);
Plugin* me = Core::getInstance().getPluginManager()->getPluginByName("diggingInvaders");
EventManager::registerTick(handle, (int32_t)cost_tick, me);
//EventManager::registerTick(handle, (int32_t)cost_tick, me);
df::global::world->reindex_pathfinding = true;
}
int32_t getDestroyCost(df::building* building) {
return 10000;
return 1;
#if 0
if ( building->mat_type != 0 ) {
cerr << "Error " << __FILE__ << ", " << __LINE__ << endl;
@ -415,7 +686,7 @@ int32_t getDestroyCost(df::building* building) {
int32_t getDigCost(MapExtras::MapCache& cache, df::coord point) {
//TODO: check for constructions
return 1000000;
return 1;
#if 0
df::tiletype* type = Maps::getTileType(point);
df::enums::tiletype_material::tiletype_material ttmat = ENUM_ATTR(tiletype, material, *type);
@ -431,11 +702,11 @@ int32_t getDigCost(MapExtras::MapCache& cache, df::coord point) {
}
int32_t getDeconstructCost(df::coord point) {
return 1000000;
return 1;
}
int32_t getConstructCost(df::coord point) {
return 10000000;
return 1;
}
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax) {
@ -455,6 +726,18 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCach
Cost cost = 1;
//if ( dz != 0 ) cost++;
if ( Maps::canWalkBetween(point, neighbor) ) {
df::map_block* block2 = Maps::getTileBlock(neighbor);
bool building2 = block2->occupancy[point.x&0x0F][point.y&0x0F].bits.building == df::enums::tile_building_occ::Obstacle || block2->occupancy[point.x&0x0F][point.y&0x0F].bits.building == df::enums::tile_building_occ::Impassable;
if ( building2 ) {
df::building* building = Buildings::findAtTile(neighbor);
if ( building->getType() == df::enums::building_type::Hatch ) {
if ( building->isForbidden() ) {
//TODO: worry about destroying hatches with nowhere to stand
cost.cost[CostDimension::DestroyBuilding] += getDestroyCost(building);
}
}
}
Edge edge(point, neighbor, cost);
result->push_back(edge);
} else {
@ -474,86 +757,118 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCach
df::tiletype* type2 = Maps::getTileType(neighbor);
df::map_block* block1 = Maps::getTileBlock(point);
df::map_block* block2 = Maps::getTileBlock(neighbor);
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[point.x&0xF][point.y&0xF] != 0;
bool passable2 = block2->walkable[neighbor.x&0xF][neighbor.y&0xF] != 0;
bool building1, building2;
bool sameBuilding = false;
{
df::building* building1 = Buildings::findAtTile(point);
df::building* building2 = Buildings::findAtTile(neighbor);
if ( building2 != NULL && building2 != building1 ) {
cost.cost[1] += getDestroyCost(building2);
if ( dz != 0 )
continue;
df::enums::tile_building_occ::tile_building_occ awk = block1->occupancy[point.x&0x0F][point.y&0x0F].bits.building;
building1 = awk == df::enums::tile_building_occ::Obstacle || awk == df::enums::tile_building_occ::Impassable;
awk = block2->occupancy[neighbor.x&0x0F][neighbor.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(point);
df::building* b2 = Buildings::findAtTile(neighbor);
sameBuilding = b1 == b2;
}
}
if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
//cost.cost[3] += getConstructCost(neighbor);
continue;
if ( !passable2 && building2 && !sameBuilding ) {
df::building* b2 = Buildings::findAtTile(neighbor);
cost.cost[CostDimension::DestroyBuilding] += getDestroyCost(b2);
if ( dz != 0 )
continue;
} else {
if ( point.z == neighbor.z ) {
if ( ENUM_ATTR(tiletype_shape, walkable, shape2) ) {
if ( ENUM_ATTR(tiletype_shape, walkable, shape1 ) ) {
//exit(1);
//must be building impassible tile or something
//TODO: check
df::building* building = Buildings::findAtTile(neighbor);
if ( building != NULL )
cost.cost[1]+=getDestroyCost(building);
else {
building = Buildings::findAtTile(point);
if ( building == NULL ) {
//out.print("%s, %d: (%d,%d,%d), (%d,%d,%d)\n", __FILE__, __LINE__, point.x,point.y,point.z, neighbor.x,neighbor.y,neighbor.z);
//exit(1);
//TODO: deal with the silly RAMP_TOP condition
if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
//cost.cost[CostDimension::Construct] += getConstructCost(neighbor);
continue;
} else {
if ( dz == 0 ) {
if ( passable2 ) {
if ( passable1 ) {
out.print("%s, line %d: weirdness. (%d,%d,%d), (%d,%d,%d)\n", __FILE__, __LINE__, point.x,point.y,point.z, neighbor.x,neighbor.y,neighbor.z);
//exit(1);
//TODO: check
} else {
//this is fine: only charge once for digging through a wall, etc
}
} else {
//passable2 is false
if ( construction2 ) {
//must deconstruct orthogonally
if ( dx*dy != 0 )
continue;
}
cost.cost[CostDimension::DestroyConstruction] += getDeconstructCost(neighbor);
} else {
cost.cost[CostDimension::Dig] += getDigCost(cache, neighbor);
}
}
//this is fine: only charge once for digging through a wall
} else {
cost.cost[2] += getDigCost(cache, neighbor);
}
} else {
bool ascending = neighbor.z > point.z;
/*df::tiletype_shape temp;
if ( neighbor.z > point.z ) {
temp = shape1;
shape1 = shape2;
shape2 = temp;
}*/
if ( point.x == neighbor.x && point.y == neighbor.y ) {
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Stair ) {
if ( (ascending && ENUM_ATTR(tiletype_shape, passable_low, shape2)) || (!ascending && ENUM_ATTR(tiletype_shape, walkable_up, shape2)) ) {
//must be a forbidden hatch: TODO: check
df::building* building = Buildings::findAtTile(dz < 0 ? point : neighbor);
if ( building != NULL ) {
cost.cost[1] += getDestroyCost(building);
//dz is nonzero
bool ascending = dz > 0;
if ( dx == 0 && dy == 0 ) {
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Stair ) {
if ( (ascending && ENUM_ATTR(tiletype_shape, passable_low, shape2)) || (!ascending && ENUM_ATTR(tiletype_shape, walkable_up, shape2)) ) {
out.print("%s, line %d: weirdness. (%d,%d,%d), (%d,%d,%d)\n", __FILE__, __LINE__, point.x,point.y,point.z, neighbor.x,neighbor.y,neighbor.z);
//TODO: check for forbidden hatch
continue;
} else {
out.print("%s, line %d: Weirdness (%d,%d,%d), (%d,%d,%d).\n", __FILE__, __LINE__, point.x,point.y,point.z, neighbor.x,neighbor.y,neighbor.z);
//figure out if we can dig something in there
df::enums::tiletype_shape_basic::tiletype_shape_basic basic = ENUM_ATTR(tiletype_shape, basic_shape, shape2);
if ( ascending ) {
if ( construction2 )
continue; //technically possible: moving up, construction is up stair, hiding a floor with no down stair
if ( basic == df::enums::tiletype_shape_basic::Wall || basic == df::enums::tiletype_shape_basic::Stair || df::enums::tiletype_shape_basic::Floor ) {
cost.cost[CostDimension::Dig] += 1;
} else {
continue;
}
} else {
//descending
if ( construction2 )
continue;
if ( basic == df::enums::tiletype_shape_basic::Wall ) {
cost.cost[CostDimension::Dig] += 1;
} else {
continue;
}
}
}
} else {
//too complicated
continue;
//shape2 is not a stair
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) {
if ( construction2 )
continue;
cost.cost[CostDimension::Dig] += getDigCost(cache, neighbor);
} else if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Open ) {
continue;
//cost.cost[CostDimension::Construct] += getConstructCost(neighbor);
} else {
if ( ascending && ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Floor && !construction2 ) {
cost.cost[CostDimension::Dig] += 1;
}
continue;
}
}
} else {
//bad!
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) {
cost.cost[2] += getDigCost(cache, neighbor);
} else if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Open ) {
cost.cost[3] += getConstructCost(neighbor);
} else {
continue;
}
//now we're talking about moving up and down nonvertically, ie with ramps
continue;
}
} else {
//too complicated
continue;
}
}
}
if ( cost.cost[CostDimension::DestroyBuilding] != 0 ) {
//out.print("Line %d: Destroy building from (%d,%d,%d), (%d,%d,%d)\n", __LINE__, point.x,point.y,point.z, neighbor.x,neighbor.y,neighbor.z);
}
Edge edge(point, neighbor, cost);
result->push_back(edge);
}