Digging invaders: it still doesn't work, but now it's a lot simpler.

develop
expwnent 2012-12-20 00:35:45 -05:00
parent 9cb3f19630
commit 46b9148277
1 changed files with 323 additions and 347 deletions

@ -52,24 +52,14 @@
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#define HASHMAP 1
#if HASHMAP
#include <unordered_set> #include <unordered_set>
#include <unordered_map> #include <unordered_map>
#endif
using namespace std; using namespace std;
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
int32_t digSpeed = 100;
int32_t destroySpeed = 100;
int32_t deconstructSpeed = 100;
int32_t constructSpeed = 100;
command_result diggingInvadersFunc(color_ostream &out, std::vector <std::string> & parameters); command_result diggingInvadersFunc(color_ostream &out, std::vector <std::string> & parameters);
DFHACK_PLUGIN("diggingInvaders"); DFHACK_PLUGIN("diggingInvaders");
@ -101,106 +91,15 @@ enum CostDimension {
costDim costDim
}; };
const int32_t costBucket[] = { const int64_t costWeight[] = {
//Distance //Distance
0,
//DestroyBuilding
1, 1,
//Dig //Destroy Building
2, 2,
//Dig
100,
//DestroyConstruction //DestroyConstruction
3, 100,
};
struct Cost {
int32_t cost[costDim];
Cost() {
memset(cost, 0, costDim*sizeof(int32_t));
}
Cost( int32_t costIn[costDim] ) {
memcpy(cost, costIn, costDim*sizeof(int32_t));
}
Cost(const Cost& c) {
memcpy(cost, c.cost, costDim*sizeof(int32_t));
}
Cost( int32_t i ) {
memset(cost, 0, costDim*sizeof(int32_t));
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 compare(c) <= 0;
}
bool operator!=(const Cost& c) const {
return compare(c) != 0;
}
Cost operator+(const Cost& c) const {
Cost result(*this);
for ( size_t a = 0; a < costDim; a++ ) {
result.cost[a] += c.cost[a];
}
return result;
}
}; };
class Edge { class Edge {
@ -208,8 +107,8 @@ public:
//static map<df::coord, int32_t> pointCost; //static map<df::coord, int32_t> pointCost;
df::coord p1; df::coord p1;
df::coord p2; df::coord p2;
Cost cost; int64_t cost;
Edge(df::coord p1In, df::coord p2In, Cost costIn): cost(costIn) { Edge(df::coord p1In, df::coord p2In, int64_t costIn): cost(costIn) {
if ( p2In < p1In ) { if ( p2In < p1In ) {
p1 = p2In; p1 = p2In;
p2 = p1In; p2 = p1In;
@ -240,11 +139,7 @@ public:
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax); vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax);
#if HASHMAP
df::coord getRoot(df::coord point, unordered_map<df::coord, df::coord>& rootMap); df::coord getRoot(df::coord point, unordered_map<df::coord, df::coord>& rootMap);
#else
df::coord getRoot(df::coord point, map<df::coord, df::coord>& rootMap);
#endif
struct PointHash { struct PointHash {
size_t operator()(const df::coord c) const { size_t operator()(const df::coord c) const {
@ -254,17 +149,10 @@ struct PointHash {
class PointComp { class PointComp {
public: public:
#if HASHMAP unordered_map<df::coord, int64_t, PointHash> *pointCost;
unordered_map<df::coord, Cost, PointHash> *pointCost; PointComp(unordered_map<df::coord, int64_t, PointHash> *p): pointCost(p) {
PointComp(unordered_map<df::coord, Cost, PointHash> *p): pointCost(p) {
}
#else
map<df::coord, Cost> *pointCost;
PointComp(map<df::coord, Cost> *p): pointCost(p) {
} }
#endif
int32_t operator()(df::coord p1, df::coord p2) { int32_t operator()(df::coord p1, df::coord p2) {
if ( p1 == p2 ) return 0; if ( p1 == p2 ) return 0;
@ -276,8 +164,8 @@ public:
return true; return true;
if ( i2 == pointCost->end() ) if ( i2 == pointCost->end() )
return false; return false;
Cost c1 = (*i1).second; int64_t c1 = (*i1).second;
Cost c2 = (*i2).second; int64_t c2 = (*i2).second;
if ( c1 != c2 ) if ( c1 != c2 )
return c1 < c2; return c1 < c2;
return p1 < p2; return p1 < p2;
@ -297,17 +185,10 @@ command_result diggingInvadersFunc(color_ostream& out, std::vector<std::string>&
void doDiggingInvaders(color_ostream& out, void* ptr) { void doDiggingInvaders(color_ostream& out, void* ptr) {
CoreSuspender suspend; CoreSuspender suspend;
#if HASHMAP
unordered_set<df::coord, PointHash> invaderPts; unordered_set<df::coord, PointHash> invaderPts;
unordered_set<df::coord, PointHash> localPts; unordered_set<df::coord, PointHash> localPts;
unordered_map<df::coord,df::coord,PointHash> parentMap; unordered_map<df::coord,df::coord,PointHash> parentMap;
unordered_map<df::coord,Cost,PointHash> costMap; unordered_map<df::coord,int64_t,PointHash> costMap;
#else
set<df::coord> invaderPts;
set<df::coord> localPts;
map<df::coord, df::coord> parentMap;
map<df::coord, Cost> costMap;
#endif
PointComp comp(&costMap); PointComp comp(&costMap);
set<df::coord, PointComp> fringe(comp); set<df::coord, PointComp> fringe(comp);
@ -345,11 +226,8 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
out << firstInvader->pos.x << ", " << firstInvader->pos.y << ", " << firstInvader->pos.z << endl; out << firstInvader->pos.x << ", " << firstInvader->pos.y << ", " << firstInvader->pos.z << endl;
int32_t localPtsFound = 0; int32_t localPtsFound = 0;
#if HASHMAP
unordered_set<df::coord,PointHash> closedSet; unordered_set<df::coord,PointHash> closedSet;
#else unordered_map<df::coord,int32_t,PointHash> workNeeded; //non-walking work needed to get there
set<df::coord> closedSet;
#endif
clock_t t0 = clock(); clock_t t0 = clock();
clock_t totalEdgeTime = 0; clock_t totalEdgeTime = 0;
@ -367,18 +245,11 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
localPtsFound++; localPtsFound++;
if ( localPtsFound >= localPts.size() ) if ( localPtsFound >= localPts.size() )
break; break;
bool doBreak = false; if ( workNeeded.find(pt) != workNeeded.end() && workNeeded[pt] > 0 )
for ( int32_t a = 1; a < costDim; a++ ) {
if ( costMap[pt].cost[a] > 0 ) {
doBreak = true;
break;
}
}
if ( doBreak )
break; break;
} }
Cost& myCost = costMap[pt]; int64_t myCost = costMap[pt];
clock_t edgeTime = clock(); clock_t edgeTime = clock();
vector<Edge>* myEdges = getEdgeSet(out, pt, cache, xMax, yMax, zMax); vector<Edge>* myEdges = getEdgeSet(out, pt, cache, xMax, yMax, zMax);
totalEdgeTime += (clock() - edgeTime); totalEdgeTime += (clock() - edgeTime);
@ -391,7 +262,7 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
// continue; // continue;
auto i = costMap.find(other); auto i = costMap.find(other);
if ( i != costMap.end() ) { if ( i != costMap.end() ) {
Cost& cost = (*i).second; int64_t cost = (*i).second;
if ( cost <= myCost + e.cost ) { if ( cost <= myCost + e.cost ) {
continue; continue;
} }
@ -400,6 +271,7 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
costMap[other] = myCost + e.cost; costMap[other] = myCost + e.cost;
fringe.insert(other); fringe.insert(other);
parentMap[other] = pt; parentMap[other] = pt;
workNeeded[other] = (e.cost > 1 ? 1 : 0) + workNeeded[pt];
} }
delete myEdges; delete myEdges;
} }
@ -417,17 +289,10 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
continue; continue;
if ( parentMap.find(pt) == parentMap.end() ) if ( parentMap.find(pt) == parentMap.end() )
continue; continue;
bool requireAction = false; if ( workNeeded[pt] == 0 )
for ( int32_t a = 1; a < costDim; a++ ) {
if ( costMap[pt].cost[a] != 0 ) {
requireAction = true;
break;
}
}
if ( !requireAction )
continue; continue;
while ( parentMap.find(pt) != parentMap.end() ) { while ( parentMap.find(pt) != parentMap.end() ) {
//out.print("(%d,%d,%d)\n", pt.x, pt.y, pt.z); out.print("(%d,%d,%d)\n", pt.x, pt.y, pt.z);
df::coord parent = parentMap[pt]; df::coord parent = parentMap[pt];
if ( pt.z < parent.z ) { if ( pt.z < parent.z ) {
requiresZNeg.insert(parent); requiresZNeg.insert(parent);
@ -436,13 +301,9 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
requiresZNeg.insert(pt); requiresZNeg.insert(pt);
requiresZPos.insert(parent); requiresZPos.insert(parent);
} }
Cost cost1 = costMap[pt]; //if ( workNeeded[pt] > workNeeded[parent] ) {
Cost cost2 = costMap[parent];
cost1.cost[0] = 0;
cost2.cost[0] = 0;
if ( true || cost1 != cost2 ) {
importantEdges.push_front(Edge(pt,parent,0)); importantEdges.push_front(Edge(pt,parent,0));
} //}
pt = parent; pt = parent;
} }
break; break;
@ -472,41 +333,57 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
bool didSomething = false; bool didSomething = false;
df::coord where; df::coord where;
out << __LINE__ << endl;
for ( auto i = importantEdges.begin(); i != importantEdges.end(); i++ ) { for ( auto i = importantEdges.begin(); i != importantEdges.end(); i++ ) {
out << __LINE__ << endl;
Edge e = *i; Edge e = *i;
df::coord pt1 = e.p1; df::coord pt1 = e.p1;
df::coord pt2 = e.p2; df::coord pt2 = e.p2;
if ( costMap[e.p2] < costMap[e.p1] ) { if ( costMap[e.p2] < costMap[e.p1] ) {
out << __LINE__ << endl;
pt1 = e.p2; pt1 = e.p2;
pt2 = e.p1; pt2 = e.p1;
} }
out << __LINE__ << endl;
bool important = //requireZNeg.find(pt1) != requireZNeg.end() || bool important = //requireZNeg.find(pt1) != requireZNeg.end() ||
//requireZPos.find(pt1) != requireZPos.end() || //requireZPos.find(pt1) != requireZPos.end() ||
requiresZNeg.find(pt2) != requiresZNeg.end() || requiresZNeg.find(pt2) != requiresZNeg.end() ||
requiresZPos.find(pt2) != requiresZPos.end(); requiresZPos.find(pt2) != requiresZPos.end() ||
Buildings::findAtTile(pt2) != NULL;
if ( !important ) { if ( !important ) {
Cost c1 = costMap[pt1]; out << __LINE__ << endl;
Cost c2 = costMap[pt2]; if ( workNeeded[pt2] <= workNeeded[pt1] ) {
c1.cost[0] = 0; out << __LINE__ << endl;
c2.cost[0] = 0;
if ( c1 == c2 ) {
//definitely not important //definitely not important
continue; continue;
} }
} }
out << __LINE__ << endl;
if ( workNeeded[pt1] > 0 )
continue;
df::map_block* block1 = Maps::getTileBlock(pt1); df::map_block* block1 = Maps::getTileBlock(pt1);
out << __LINE__ << endl;
df::map_block* block2 = Maps::getTileBlock(pt2); df::map_block* block2 = Maps::getTileBlock(pt2);
bool passable1 = block1->walkable[pt1.x&0x0F][pt1.y&0x0F]; bool passable1 = block1->walkable[pt1.x&0x0F][pt1.y&0x0F];
bool passable2 = block2->walkable[pt2.x&0x0F][pt2.y&0x0F]; bool passable2 = block2->walkable[pt2.x&0x0F][pt2.y&0x0F];
//TODO: if actions required > 1, continue //TODO: if actions required > 1, continue
df::building* building = Buildings::findAtTile(pt2); df::building* building = Buildings::findAtTile(pt2);
out << __LINE__ << endl;
if ( building != NULL && building->getType() == df::enums::building_type::Stockpile ) {
out << __LINE__ << endl;
continue;
}
out << __LINE__ << endl;
if ( building != NULL && passable2 ) { if ( building != NULL && passable2 ) {
building = NULL; //building = NULL;
} }
out << __LINE__ << endl;
if ( building != NULL ) { if ( building != NULL ) {
out.print("%s, line %d: Destroying building %d\n", __FILE__, __LINE__, building->id); out << __LINE__ << endl;
out.print("%s, line %d: Destroying building %d at (%d,%d,%d)\n", __FILE__, __LINE__, building->id, pt2.x,pt2.y,pt2.z);
//building->flags.bits.almost_deleted = true; //building->flags.bits.almost_deleted = true;
df::job* job = new df::job; df::job* job = new df::job;
@ -532,14 +409,17 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
didSomething = true; didSomething = true;
where = pt2; where = pt2;
continue; out << __LINE__ << endl;
break;
} else { } else {
out << __LINE__ << endl;
df::tiletype* type1 = Maps::getTileType(pt1); df::tiletype* type1 = Maps::getTileType(pt1);
df::tiletype* type2 = Maps::getTileType(pt2); df::tiletype* type2 = Maps::getTileType(pt2);
df::tiletype_shape shape1 = ENUM_ATTR(tiletype, shape, *type1); df::tiletype_shape shape1 = ENUM_ATTR(tiletype, shape, *type1);
df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2); df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2);
bool construction2 = ENUM_ATTR(tiletype, material, *type1) == df::enums::tiletype_material::CONSTRUCTION; bool construction2 = ENUM_ATTR(tiletype, material, *type1) == df::enums::tiletype_material::CONSTRUCTION;
if ( construction2 ) { if ( construction2 ) {
out << __LINE__ << endl;
out.print("%s, line %d. Removing construction (%d,%d,%d)\n", __FILE__, __LINE__, pt2.x,pt2.y,pt2.z); 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(); df::job* job = new df::job();
job->job_type = df::enums::job_type::RemoveConstruction; job->job_type = df::enums::job_type::RemoveConstruction;
@ -557,6 +437,7 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
Job::linkIntoWorld(job); Job::linkIntoWorld(job);
didSomething = true; didSomething = true;
where = pt2; where = pt2;
out << __LINE__ << endl;
break; break;
} }
@ -567,6 +448,7 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
break; break;
}*/ }*/
out << __LINE__ << endl;
bool up = requiresZPos.find(pt2) != requiresZPos.end(); bool up = requiresZPos.find(pt2) != requiresZPos.end();
bool down = requiresZNeg.find(pt2) != requiresZNeg.end(); bool down = requiresZNeg.find(pt2) != requiresZNeg.end();
df::job* job = new df::job; df::job* job = new df::job;
@ -619,6 +501,7 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
pick->skill_used = (df::enums::job_skill::job_skill)0; pick->skill_used = (df::enums::job_skill::job_skill)0;
pick->maker = -1; pick->maker = -1;
df::itemdef_weaponst* itemdef = NULL; df::itemdef_weaponst* itemdef = NULL;
out << __LINE__ << endl;
for ( size_t a = 0; a < df::global::world->raws.itemdefs.weapons.size(); a++ ) { 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]; df::itemdef_weaponst* candidate = df::global::world->raws.itemdefs.weapons[a];
if ( candidate->id == "ITEM_WEAPON_PICK" ) { if ( candidate->id == "ITEM_WEAPON_PICK" ) {
@ -626,16 +509,20 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
break; break;
} }
} }
out << __LINE__ << endl;
if ( itemdef == NULL ) { if ( itemdef == NULL ) {
out.print("%s, %d: null itemdef.\n", __FILE__, __LINE__); out.print("%s, %d: null itemdef.\n", __FILE__, __LINE__);
return; return;
} }
out << __LINE__ << endl;
pick->subtype = itemdef; pick->subtype = itemdef;
pick->sharpness = 5000; pick->sharpness = 5000;
int32_t part = -1; int32_t part = -1;
part = firstInvader->body.unk_3c8; //weapon_bp part = firstInvader->body.unk_3c8; //weapon_bp
out << __LINE__ << endl;
if ( part == -1 ) { if ( part == -1 ) {
out << __LINE__ << endl;
out.print("%s, %d: no grasp part.\n", __FILE__, __LINE__); out.print("%s, %d: no grasp part.\n", __FILE__, __LINE__);
return; return;
} }
@ -650,14 +537,17 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
Items::moveToInventory(cache, pick, firstInvader, df::unit_inventory_item::T_mode::Weapon, part); Items::moveToInventory(cache, pick, firstInvader, df::unit_inventory_item::T_mode::Weapon, part);
didSomething = true; didSomething = true;
where = pt2; where = pt2;
out << __LINE__ << endl;
break; break;
} }
} }
out << __LINE__ << endl;
out << "didSomething = " << didSomething << endl; out << "didSomething = " << didSomething << endl;
if ( !didSomething ) if ( !didSomething )
return; return;
/*
Cost cost = costMap[where]; Cost cost = costMap[where];
float cost_tick = 0; float cost_tick = 0;
cost_tick += cost.cost[CostDimension::Distance]; cost_tick += cost.cost[CostDimension::Distance];
@ -668,212 +558,298 @@ void doDiggingInvaders(color_ostream& out, void* ptr) {
Plugin* me = Core::getInstance().getPluginManager()->getPluginByName("diggingInvaders"); 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; df::global::world->reindex_pathfinding = true;
*/
} }
int64_t getEdgeCost(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];
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;
}
}
int32_t getDestroyCost(df::building* building) { if ( Maps::canStepBetween(pt1, pt2) ) {
return 1; if ( building2 && !sameBuilding ) {
#if 0 cost += costWeight[CostDimension::DestroyBuilding];
if ( building->mat_type != 0 ) { }
cerr << "Error " << __FILE__ << ", " << __LINE__ << endl; return cost;
exit(1);
} }
df::inorganic_raw* mat = df::global::world->raws.inorganics[building->mat_index];
int32_t str = mat->material.strength.fracture[df::enums::strain_type::IMPACT];
return str / destroySpeed;
#endif
}
int32_t getDigCost(MapExtras::MapCache& cache, df::coord point) { if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
//TODO: check for constructions return -1;
return 1;
#if 0
df::tiletype* type = Maps::getTileType(point);
df::enums::tiletype_material::tiletype_material ttmat = ENUM_ATTR(tiletype, material, *type);
if ( ttmat == df::enums::tiletype_material::CONSTRUCTION ) {
//construction stuff
return 1;
} else if ( ttmat == df::enums::tiletype_material::SOIL ) {
} }
return 1;
#endif
}
int32_t getDeconstructCost(df::coord point) { //cannot step between: find out why
return 1; 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;
}
int32_t getConstructCost(df::coord point) { if ( shape2 == df::enums::tiletype_shape::TREE ) {
return 1; return -1;
} }
vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax) { if ( shape2 == df::enums::tiletype_shape::RAMP_TOP ) {
vector<Edge>* result = new vector<Edge>; return -1;
result->reserve(26); }
//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;
}
for ( int32_t dx = -1; dx <= 1; dx++ ) { //moving diagonally
for ( int32_t dy = -1; dy <= 1; dy++ ) { return -1;
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;
Cost cost = 1;
//if ( dz != 0 ) cost++;
if ( Maps::canStepBetween(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 {
#if 0 #if 0
{ //if ( dz != 0 ) cost++;
cost.cost[1] = 1; if ( Maps::canStepBetween(point, neighbor) ) {
result->push_back(Edge(point,neighbor,cost)); df::map_block* block2 = Maps::getTileBlock(neighbor);
continue; df::enums::tile_building_occ::tile_building_occ occ = block2->occupancy[neighbor.x&0x0F][neighbor.y&0x0F].bits.building;
} bool building2 = occ == df::enums::tile_building_occ::Obstacle || occ == df::enums::tile_building_occ::Impassable || occ == df::enums::tile_building_occ::Floored;
#endif if ( building2 ) {
//cost.cost[1] = 1; df::building* building = Buildings::findAtTile(neighbor);
//find out WHY we can't walk there if ( true || building->getType() == df::enums::building_type::Hatch ) {
//make it simple: don't deal with unallocated blocks if ( true || building->isForbidden() ) {
Maps::ensureTileBlock(point); //TODO: worry about destroying hatches with nowhere to stand
Maps::ensureTileBlock(neighbor); cost += costWeight[CostDimension::DestroyBuilding];
df::tiletype* type1 = Maps::getTileType(point); }
df::tiletype* type2 = Maps::getTileType(neighbor); }
df::map_block* block1 = Maps::getTileBlock(point); }
df::map_block* block2 = Maps::getTileBlock(neighbor);
Edge edge(point, neighbor, cost);
df::tiletype_shape shape1 = ENUM_ATTR(tiletype, shape, *type1); result->push_back(edge);
df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2); } else {
//find out WHY we can't walk there
bool construction1 = ENUM_ATTR(tiletype, material, *type1) == df::enums::tiletype_material::CONSTRUCTION; //make it simple: don't deal with unallocated blocks
bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION; Maps::ensureTileBlock(point);
bool passable1 = block1->walkable[point.x&0xF][point.y&0xF] != 0; Maps::ensureTileBlock(neighbor);
bool passable2 = block2->walkable[neighbor.x&0xF][neighbor.y&0xF] != 0; df::tiletype* type1 = Maps::getTileType(point);
df::tiletype* type2 = Maps::getTileType(neighbor);
bool building1, building2; df::map_block* block1 = Maps::getTileBlock(point);
bool sameBuilding = false; df::map_block* block2 = Maps::getTileBlock(neighbor);
{
df::enums::tile_building_occ::tile_building_occ awk = block1->occupancy[point.x&0x0F][point.y&0x0F].bits.building; df::tiletype_shape shape1 = ENUM_ATTR(tiletype, shape, *type1);
building1 = awk == df::enums::tile_building_occ::Obstacle || awk == df::enums::tile_building_occ::Impassable; df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2);
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; bool construction1 = ENUM_ATTR(tiletype, material, *type1) == df::enums::tiletype_material::CONSTRUCTION;
if ( building1 && building2 ) { bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION;
df::building* b1 = Buildings::findAtTile(point); bool passable1 = block1->walkable[point.x&0xF][point.y&0xF] != 0;
df::building* b2 = Buildings::findAtTile(neighbor); bool passable2 = block2->walkable[neighbor.x&0xF][neighbor.y&0xF] != 0;
sameBuilding = b1 == b2;
} bool building1, building2;
} bool sameBuilding = false;
{
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 ( !passable2 && building2 && !sameBuilding ) { if ( !passable2 && building2 && !sameBuilding ) {
df::building* b2 = Buildings::findAtTile(neighbor); df::building* b2 = Buildings::findAtTile(neighbor);
cost.cost[CostDimension::DestroyBuilding] += getDestroyCost(b2); cost += costWeight[CostDimension::DestroyBuilding];
if ( dz != 0 ) if ( dz != 0 )
continue; continue;
} else { } else {
if ( shape2 == df::enums::tiletype_shape::EMPTY ) { if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
//cost.cost[CostDimension::Construct] += getConstructCost(neighbor); //cost.cost[CostDimension::Construct] += getConstructCost(neighbor);
continue; 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 += costWeight[CostDimension::DestroyConstruction];
} else { } else {
if ( dz == 0 ) { cost += costWeight[CostDimension::Dig];
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); } else {
//exit(1); //dz is nonzero
//TODO: check 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 {
//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 += costWeight[CostDimension::Dig];
} else { } else {
//this is fine: only charge once for digging through a wall, etc continue;
} }
} else { } else {
//passable2 is false //descending
if ( construction2 ) { if ( construction2 )
//must deconstruct orthogonally continue;
if ( dx*dy != 0 ) if ( basic == df::enums::tiletype_shape_basic::Wall ) {
continue; cost += costWeight[CostDimension::Dig];
cost.cost[CostDimension::DestroyConstruction] += getDeconstructCost(neighbor); } else if ( basic == df::enums::tiletype_shape_basic::Ramp ) {
//do nothing
} else if ( basic == df::enums::tiletype_shape_basic::Floor ) {
//do nothing
} else { } else {
cost.cost[CostDimension::Dig] += getDigCost(cache, neighbor); continue;
} }
} }
} else { }
//dz is nonzero } else {
bool ascending = dz > 0; //shape2 is not a stair
if ( dx == 0 && dy == 0 ) { if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Wall ) {
if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Stair ) { if ( construction2 )
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 {
//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 {
//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 {
//now we're talking about moving up and down nonvertically, ie with ramps
continue; continue;
cost += costWeight[CostDimension::Dig];
} else if ( ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Open ) {
continue;
} else {
if ( ascending && ENUM_ATTR(tiletype_shape, basic_shape, shape2) == df::enums::tiletype_shape_basic::Floor && !construction2 ) {
cost += costWeight[CostDimension::Dig];
} }
continue;
} }
} }
} else {
//now we're talking about moving up and down nonvertically, ie with ramps
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);
} }
} }
} }
}
return cost;
#endif
}
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>;
result->reserve(26);
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);
}
}
} }
return result; return result;