diggingInvaders: added per-creature dig times and differentiated between smooth and rough constructions.

develop
expwnent 2013-06-15 23:04:15 -04:00
parent 776d088eb9
commit f459bfc4f1
5 changed files with 191 additions and 54 deletions

@ -6,6 +6,7 @@
#include "modules/Materials.h" #include "modules/Materials.h"
#include "df/building.h" #include "df/building.h"
#include "df/construction.h"
#include "df/coord.h" #include "df/coord.h"
#include "df/general_ref.h" #include "df/general_ref.h"
#include "df/general_ref_building_holderst.h" #include "df/general_ref_building_holderst.h"
@ -47,7 +48,7 @@ void getRidOfOldJob(df::unit* unit) {
//delete job; //delete job;
} }
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache) { int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache, DigAbilities& abilities ) {
df::unit* firstInvader = df::unit::find(invaders[0]); df::unit* firstInvader = df::unit::find(invaders[0]);
if ( !firstInvader ) { if ( !firstInvader ) {
return -1; return -1;
@ -69,7 +70,7 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df:
df::map_block* block2 = Maps::getTileBlock(pt2); df::map_block* block2 = Maps::getTileBlock(pt2);
bool passable1 = block1->walkable[pt1.x&0xF][pt1.y&0xF]; bool passable1 = block1->walkable[pt1.x&0xF][pt1.y&0xF];
bool passable2 = block2->walkable[pt2.x&0xF][pt2.y&0xF]; bool passable2 = block2->walkable[pt2.x&0xF][pt2.y&0xF];
df::coord location; df::coord location;
df::building* building = Buildings::findAtTile(pt2); df::building* building = Buildings::findAtTile(pt2);
df::coord buildingPos = pt2; df::coord buildingPos = pt2;
@ -107,7 +108,7 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df:
building->jobs.push_back(job); building->jobs.push_back(job);
Job::linkIntoWorld(job); Job::linkIntoWorld(job);
jobId = job->id; jobId = job->id;
job->completion_timer = jobDelay[DestroyBuilding]; job->completion_timer = abilities.jobDelay[CostDimension::DestroyBuilding];
} else { } else {
df::tiletype* type1 = Maps::getTileType(pt1); df::tiletype* type1 = Maps::getTileType(pt1);
df::tiletype* type2 = Maps::getTileType(pt2); df::tiletype* type2 = Maps::getTileType(pt2);
@ -132,7 +133,12 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df:
firstInvader->job.destroy_target = NULL; firstInvader->job.destroy_target = NULL;
Job::linkIntoWorld(job); Job::linkIntoWorld(job);
jobId = job->id; jobId = job->id;
job->completion_timer = jobDelay[DestroyConstruction]; df::construction* constr = df::construction::find(pt2);
bool smooth = constr != NULL && constr->item_type != df::enums::item_type::BOULDER;
if ( smooth )
job->completion_timer = abilities.jobDelay[CostDimension::DestroySmoothConstruction];
else
job->completion_timer = abilities.jobDelay[CostDimension::DestroyRoughConstruction];
} else { } else {
bool walkable_low1 = shape1 == df::tiletype_shape::STAIR_DOWN || shape1 == df::tiletype_shape::STAIR_UPDOWN; bool walkable_low1 = shape1 == df::tiletype_shape::STAIR_DOWN || shape1 == df::tiletype_shape::STAIR_UPDOWN;
bool walkable_low2 = shape2 == df::tiletype_shape::STAIR_DOWN || shape2 == df::tiletype_shape::STAIR_UPDOWN; bool walkable_low2 = shape2 == df::tiletype_shape::STAIR_DOWN || shape2 == df::tiletype_shape::STAIR_UPDOWN;
@ -195,7 +201,7 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df:
firstInvader->path.path.z.clear(); firstInvader->path.path.z.clear();
Job::linkIntoWorld(job); Job::linkIntoWorld(job);
jobId = job->id; jobId = job->id;
job->completion_timer = jobDelay[Dig]; job->completion_timer = abilities.jobDelay[CostDimension::Dig];
//TODO: test if he already has a pick //TODO: test if he already has a pick
bool hasPick = false; bool hasPick = false;

@ -9,5 +9,5 @@
using namespace std; using namespace std;
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache); int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,cost_t,PointHash>& costMap, vector<int32_t>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache, DigAbilities& abilities);

@ -87,33 +87,61 @@ static bool activeDigging=false;
static unordered_set<string> diggingRaces; static unordered_set<string> diggingRaces;
static unordered_set<int32_t> invaderJobs; static unordered_set<int32_t> invaderJobs;
static df::coord lastDebugEdgeCostPoint; static df::coord lastDebugEdgeCostPoint;
unordered_map<string, DigAbilities> digAbilities;
static cost_t costWeightDefault[] = {
//Distance
1,
//Destroy Building
2,
//Dig
10000,
//DestroyRoughConstruction
1000,
//DestroySmoothConstruction
100,
};
static int32_t jobDelayDefault[] = {
//Distance
-1,
//Destroy Building
1000,
//Dig
1000,
//DestroyRoughConstruction
1000,
//DestroySmoothConstruction
100,
};
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"diggingInvaders", "Makes invaders dig to your dwarves.", "diggingInvaders", "Makes invaders dig to your dwarves.",
diggingInvadersCommand, false, /* true means that the command can't be used from non-interactive user interface */ diggingInvadersCommand, false, /* true means that the command can't be used from non-interactive user interface */
"example usage:\n"
" diggingInvaders 0\n disables the plugin\n" " diggingInvaders 0\n disables the plugin\n"
" diggingInvaders 1\n enables the plugin\n" " diggingInvaders 1\n enables the plugin\n"
" diggingInvaders enable\n enables the plugin\n" " diggingInvaders enable\n enables the plugin\n"
" diggingInvaders disable\n disables the plugin\n" " diggingInvaders disable\n disables the plugin\n"
" diggingInvaders add GOBLIN\n registers the race GOBLIN as a digging invader. Case-sensitive.\n" " diggingInvaders add GOBLIN\n registers the race GOBLIN as a digging invader. Case-sensitive.\n"
" diggingInvaders remove GOBLIN\n unregisters the race GOBLIN as a digging invader. Case-sensitive.\n" " diggingInvaders remove GOBLIN\n unregisters the race GOBLIN as a digging invader. Case-sensitive.\n"
" diggingInvaders setCost walk n\n sets the walk cost in the path algorithm\n" " diggingInvaders setCost GOBLIN walk n\n sets the walk cost in the path algorithm for the race GOBLIN\n"
" diggingInvaders setCost destroyBuilding n\n" " diggingInvaders setCost GOBLIN destroyBuilding n\n"
" diggingInvaders setCost dig n\n" " diggingInvaders setCost GOBLIN dig n\n"
" diggingInvaders setCost destroyConstruction n\n" " diggingInvaders setCost GOBLIN destroyRoughConstruction n\n rough constructions are made from boulders\n"
" diggingInvaders setDelay destroyBuilding n\n adds to the job_completion_timer of destroy building jobs that are assigned to invaders\n" " diggingInvaders setCost GOBLIN destroySmoothConstruction n\n smooth constructions are made from blocks or bars instead of boulders\n"
" diggingInvaders setDelay dig n\n" " diggingInvaders setDelay GOBLIN destroyBuilding n\n adds to the job_completion_timer of destroy building jobs that are assigned to invaders\n"
" diggingInvaders setDelay destroyConstruction n\n" " diggingInvaders setDelay GOBLIN dig n\n"
" diggingInvaders setDelay GOBLIN destroyRoughConstruction n\n"
" diggingInvaders setDelay GOBLIN destroySmoothConstruction n\n"
" diggingInvaders now\n makes invaders try to dig now, if plugin is enabled\n" " diggingInvaders now\n makes invaders try to dig now, if plugin is enabled\n"
" diggingInvaders clear\n clears all digging invader races\n" " diggingInvaders clear\n clears all digging invader races\n"
" diggingInvaders edgesPerTick n\n makes the pathfinding algorithm work on at most n edges per tick. Set to 0 or lower to make it unlimited." " diggingInvaders edgesPerTick n\n makes the pathfinding algorithm work on at most n edges per tick. Set to 0 or lower to make it unlimited."
// " diggingInvaders\n Makes invaders try to dig now.\n" // " diggingInvaders\n Makes invaders try to dig now.\n"
)); ));
*df::global::debug_showambush = true; //*df::global::debug_showambush = true;
return CR_OK; return CR_OK;
} }
@ -135,6 +163,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
case DFHack::SC_WORLD_UNLOADED: case DFHack::SC_WORLD_UNLOADED:
// cleanup // cleanup
lastInvasionJob = lastInvasionDigger = -1; lastInvasionJob = lastInvasionDigger = -1;
enabled = false;
activeDigging = false; activeDigging = false;
clearDijkstra(); clearDijkstra();
invaderJobs.clear(); invaderJobs.clear();
@ -193,14 +222,28 @@ command_result diggingInvadersCommand(color_ostream& out, std::vector<std::strin
string race = parameters[a+1]; string race = parameters[a+1];
if ( parameters[a] == "add" ) { if ( parameters[a] == "add" ) {
diggingRaces.insert(race); diggingRaces.insert(race);
DigAbilities& abilities = digAbilities[race];
memcpy(abilities.costWeight, costWeightDefault, costDim*sizeof(cost_t));
memcpy(abilities.jobDelay, jobDelayDefault, costDim*sizeof(int32_t));
} else { } else {
diggingRaces.erase(race); diggingRaces.erase(race);
digAbilities.erase(race);
} }
a++; a++;
} else if ( parameters[a] == "setCost" || parameters[a] == "setDelay" ) { } else if ( parameters[a] == "setCost" || parameters[a] == "setDelay" ) {
if ( a+2 >= parameters.size() ) if ( a+3 >= parameters.size() )
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
string costStr = parameters[a+1];
string raceString = parameters[a+1];
if ( digAbilities.find(raceString) == digAbilities.end() ) {
DigAbilities bob;
memset(&bob, 0xFF, sizeof(bob));
digAbilities[raceString] = bob;
}
DigAbilities& abilities = digAbilities[raceString];
string costStr = parameters[a+2];
int32_t costDim = -1; int32_t costDim = -1;
if ( costStr == "walk" ) { if ( costStr == "walk" ) {
costDim = CostDimension::Walk; costDim = CostDimension::Walk;
@ -210,30 +253,47 @@ command_result diggingInvadersCommand(color_ostream& out, std::vector<std::strin
costDim = CostDimension::DestroyBuilding; costDim = CostDimension::DestroyBuilding;
} else if ( costStr == "dig" ) { } else if ( costStr == "dig" ) {
costDim = CostDimension::Dig; costDim = CostDimension::Dig;
} else if ( costStr == "destroyConstruction" ) { } else if ( costStr == "destroyRoughConstruction" ) {
costDim = CostDimension::DestroyConstruction; costDim = CostDimension::DestroyRoughConstruction;
} else if ( costStr == "destroySmoothConstruction" ) {
costDim = CostDimension::DestroySmoothConstruction;
} else { } else {
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
cost_t value; cost_t value;
stringstream asdf(parameters[a+2]); stringstream asdf(parameters[a+3]);
asdf >> value; asdf >> value;
if ( parameters[a] == "setCost" && value <= 0 ) //if ( parameters[a] == "setCost" && value <= 0 )
return CR_WRONG_USAGE; // return CR_WRONG_USAGE;
if ( parameters[a] == "setCost" ) if ( parameters[a] == "setCost" ) {
costWeight[costDim] = value; abilities.costWeight[costDim] = value;
else } else {
jobDelay[costDim] = value; abilities.jobDelay[costDim] = value;
a += 2; }
a += 3;
} else if ( parameters[a] == "edgeCost" ) { } else if ( parameters[a] == "edgeCost" ) {
if ( a+1 >= parameters.size() )
return CR_WRONG_USAGE;
string raceString = parameters[a+1];
if ( digAbilities.find(raceString) == digAbilities.end() ) {
out.print("Race %s does not have dig abilities assigned.\n", raceString.c_str());
return CR_WRONG_USAGE;
}
DigAbilities& abilities = digAbilities[raceString];
df::coord bob = Gui::getCursorPos(); df::coord bob = Gui::getCursorPos();
out.print("(%d,%d,%d), (%d,%d,%d): cost = %lld\n", lastDebugEdgeCostPoint.x, lastDebugEdgeCostPoint.y, lastDebugEdgeCostPoint.z, bob.x, bob.y, bob.z, getEdgeCost(out, lastDebugEdgeCostPoint, bob)); out.print("(%d,%d,%d), (%d,%d,%d): cost = %lld\n", lastDebugEdgeCostPoint.x, lastDebugEdgeCostPoint.y, lastDebugEdgeCostPoint.z, bob.x, bob.y, bob.z, getEdgeCost(out, lastDebugEdgeCostPoint, bob, abilities));
lastDebugEdgeCostPoint = bob; lastDebugEdgeCostPoint = bob;
a++;
} else if ( parameters[a] == "now" ) { } else if ( parameters[a] == "now" ) {
activeDigging = true; activeDigging = true;
findAndAssignInvasionJob(out, (void*)0); findAndAssignInvasionJob(out, (void*)0);
} else if ( parameters[a] == "clear" ) { } else if ( parameters[a] == "clear" ) {
diggingRaces.clear(); diggingRaces.clear();
digAbilities.clear();
} else if ( parameters[a] == "edgesPerTick" ) { } else if ( parameters[a] == "edgesPerTick" ) {
if ( a+1 >= parameters.size() ) if ( a+1 >= parameters.size() )
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
@ -335,8 +395,12 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
out.print("%s,%d: WTF? Couldn't find creature raw.\n", __FILE__, __LINE__); out.print("%s,%d: WTF? Couldn't find creature raw.\n", __FILE__, __LINE__);
continue; continue;
} }
/*
if ( diggingRaces.find(raw->creature_id) == diggingRaces.end() ) if ( diggingRaces.find(raw->creature_id) == diggingRaces.end() )
continue; continue;
*/
if ( digAbilities.find(raw->creature_id) == digAbilities.end() )
continue;
if ( invaderPts.find(unit->pos) != invaderPts.end() ) if ( invaderPts.find(unit->pos) != invaderPts.end() )
continue; continue;
//must be able to wield a pick: this is overly pessimistic //must be able to wield a pick: this is overly pessimistic
@ -380,6 +444,14 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
fringe.clear(); fringe.clear();
return; return;
} }
df::creature_raw* creature_raw = df::creature_raw::find(firstInvader->race);
if ( creature_raw == NULL || digAbilities.find(creature_raw->creature_id) == digAbilities.end() ) {
//inappropriate digger: no dig abilities
fringe.clear();
return;
}
DigAbilities& abilities = digAbilities[creature_raw->creature_id];
//TODO: check that firstInvader is an appropriate digger //TODO: check that firstInvader is an appropriate digger
//out << firstInvader->id << endl; //out << firstInvader->id << endl;
//out << firstInvader->pos.x << ", " << firstInvader->pos.y << ", " << firstInvader->pos.z << endl; //out << firstInvader->pos.x << ", " << firstInvader->pos.y << ", " << firstInvader->pos.z << endl;
@ -421,7 +493,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
cost_t myCost = costMap[pt]; cost_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, abilities);
totalEdgeTime += (clock() - edgeTime); totalEdgeTime += (clock() - edgeTime);
for ( auto a = myEdges->begin(); a != myEdges->end(); a++ ) { for ( auto a = myEdges->begin(); a != myEdges->end(); a++ ) {
Edge &e = *a; Edge &e = *a;
@ -476,7 +548,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
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];
cost_t cost = getEdgeCost(out, parent, pt); cost_t cost = getEdgeCost(out, parent, pt, abilities);
if ( cost < 0 ) { if ( cost < 0 ) {
//path invalidated //path invalidated
return; return;
@ -514,7 +586,7 @@ void findAndAssignInvasionJob(color_ostream& out, void* tickTime) {
} }
*/ */
assignJob(out, firstImportantEdge, parentMap, costMap, invaders, requiresZNeg, requiresZPos, cache); assignJob(out, firstImportantEdge, parentMap, costMap, invaders, requiresZNeg, requiresZPos, cache, abilities);
lastInvasionDigger = firstInvader->id; lastInvasionDigger = firstInvader->id;
lastInvasionJob = firstInvader->job.current_job ? firstInvader->job.current_job->id : -1; lastInvasionJob = firstInvader->job.current_job ? firstInvader->job.current_job->id : -1;
invaderJobs.erase(lastInvasionJob); invaderJobs.erase(lastInvasionJob);

@ -8,7 +8,9 @@
#include "df/building_bridgest.h" #include "df/building_bridgest.h"
#include "df/building_hatchst.h" #include "df/building_hatchst.h"
#include "df/building_type.h" #include "df/building_type.h"
#include "df/construction.h"
#include "df/coord.h" #include "df/coord.h"
#include "df/item_type.h"
#include "df/map_block.h" #include "df/map_block.h"
#include "df/tile_building_occ.h" #include "df/tile_building_occ.h"
#include "df/tiletype.h" #include "df/tiletype.h"
@ -17,6 +19,7 @@
#include <iostream> #include <iostream>
/*
cost_t costWeight[] = { cost_t costWeight[] = {
//Distance //Distance
1, 1,
@ -38,6 +41,7 @@ int32_t jobDelay[] = {
//DestroyConstruction //DestroyConstruction
1000 1000
}; };
*/
using namespace std; using namespace std;
@ -46,15 +50,17 @@ limitations
ramps ramps
cave-ins cave-ins
*/ */
cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) { cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2, DigAbilities& abilities) {
int32_t dx = pt2.x - pt1.x; int32_t dx = pt2.x - pt1.x;
int32_t dy = pt2.y - pt1.y; int32_t dy = pt2.y - pt1.y;
int32_t dz = pt2.z - pt1.z; int32_t dz = pt2.z - pt1.z;
cost_t cost = costWeight[CostDimension::Walk]; cost_t cost = abilities.costWeight[CostDimension::Walk];
if ( cost < 0 )
return -1;
if ( Maps::getTileBlock(pt1) == NULL || Maps::getTileBlock(pt2) == NULL ) if ( Maps::getTileBlock(pt1) == NULL || Maps::getTileBlock(pt2) == NULL )
return -1; return -1;
df::tiletype* type2 = Maps::getTileType(pt2); df::tiletype* type2 = Maps::getTileType(pt2);
df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2); df::tiletype_shape shape2 = ENUM_ATTR(tiletype, shape, *type2);
@ -66,7 +72,7 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
if ( shape2 == df::enums::tiletype_shape::EMPTY ) { if ( shape2 == df::enums::tiletype_shape::EMPTY ) {
return -1; return -1;
} }
if ( shape2 == df::enums::tiletype_shape::TREE ) if ( shape2 == df::enums::tiletype_shape::TREE )
return -1; return -1;
@ -83,14 +89,28 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
df::building* building2 = Buildings::findAtTile(pt2); df::building* building2 = Buildings::findAtTile(pt2);
if ( building2 ) { if ( building2 ) {
cost += costWeight[CostDimension::DestroyBuilding]; if ( abilities.costWeight[CostDimension::DestroyBuilding] < 0 )
return -1;
cost += abilities.costWeight[CostDimension::DestroyBuilding];
if ( dx*dx + dy*dy > 1 ) if ( dx*dx + dy*dy > 1 )
return -1; return -1;
} }
bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION; bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION;
if ( construction2 ) if ( construction2 ) {
cost += costWeight[CostDimension::DestroyConstruction]; //smooth or not?
df::construction* constr = df::construction::find(pt2);
bool smooth = constr != NULL && constr->item_type != df::enums::item_type::BOULDER;
if ( smooth ) {
if ( abilities.costWeight[CostDimension::DestroySmoothConstruction] < 0 )
return -1;
cost += abilities.costWeight[CostDimension::DestroySmoothConstruction];
} else {
if ( abilities.costWeight[CostDimension::DestroyRoughConstruction] < 0 )
return -1;
cost += abilities.costWeight[CostDimension::DestroyRoughConstruction];
}
}
if ( dz == 0 ) { if ( dz == 0 ) {
if ( !building2 && !construction2 ) { if ( !building2 && !construction2 ) {
@ -102,7 +122,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
//out << __FILE__ << ", line " << __LINE__ << ": WTF?" << endl; //out << __FILE__ << ", line " << __LINE__ << ": WTF?" << endl;
return cost; return cost;
} }
cost += costWeight[CostDimension::Dig]; if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
} }
} else { } else {
if ( dx == 0 && dy == 0 ) { if ( dx == 0 && dy == 0 ) {
@ -113,7 +136,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
if ( !walkable_low2 ) { if ( !walkable_low2 ) {
if ( building2 || construction2 ) if ( building2 || construction2 )
return -1; return -1;
cost += costWeight[CostDimension::Dig]; if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
} }
bool walkable_high1 = shape1 == df::tiletype_shape::STAIR_UP || shape1 == df::tiletype_shape::STAIR_UPDOWN; bool walkable_high1 = shape1 == df::tiletype_shape::STAIR_UP || shape1 == df::tiletype_shape::STAIR_UPDOWN;
@ -121,7 +147,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
if ( shape1 != df::enums::tiletype_shape::WALL ) { if ( shape1 != df::enums::tiletype_shape::WALL ) {
return -1; return -1;
} }
cost += costWeight[CostDimension::Dig]; if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
} }
if ( building2 ) { if ( building2 ) {
@ -174,7 +203,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
if ( shape2 != df::enums::tiletype_shape::WALL ) if ( shape2 != df::enums::tiletype_shape::WALL )
return -1; return -1;
cost += costWeight[CostDimension::Dig]; if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
} }
bool walkable_low1 = shape1 == df::tiletype_shape::STAIR_DOWN || shape1 == df::tiletype_shape::STAIR_UPDOWN; bool walkable_low1 = shape1 == df::tiletype_shape::STAIR_DOWN || shape1 == df::tiletype_shape::STAIR_UPDOWN;
if ( !walkable_low1 ) { if ( !walkable_low1 ) {
@ -183,7 +215,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
//TODO: consider ramps //TODO: consider ramps
if ( shape1 == df::tiletype_shape::RAMP ) if ( shape1 == df::tiletype_shape::RAMP )
return -1; return -1;
cost += costWeight[CostDimension::Dig]; if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
return -1;
}
cost += abilities.costWeight[CostDimension::Dig];
} }
df::building* building1 = Buildings::findAtTile(pt1); df::building* building1 = Buildings::findAtTile(pt1);
@ -213,13 +248,17 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
//you can deconstruct a hatch from the side //you can deconstruct a hatch from the side
if ( building1 && forbidden /*&& building1->getType() == df::building_type::Hatch*/ ) { if ( building1 && forbidden /*&& building1->getType() == df::building_type::Hatch*/ ) {
/*
df::coord support[] = {df::coord(pt1.x-1, pt1.y, pt1.z), df::coord(pt1.x+1,pt1.y,pt1.z), df::coord(pt1.x,pt1.y-1,pt1.z), df::coord(pt1.x,pt1.y+1,pt1.z)}; df::coord support[] = {df::coord(pt1.x-1, pt1.y, pt1.z), df::coord(pt1.x+1,pt1.y,pt1.z), df::coord(pt1.x,pt1.y-1,pt1.z), df::coord(pt1.x,pt1.y+1,pt1.z)};
if ( abilities.costWeight[CostDimension::DestroyBuilding] < 0 ) {
return -1;
}
cost_t minCost = -1; cost_t minCost = -1;
for ( size_t a = 0; a < 4; a++ ) { for ( size_t a = 0; a < 4; a++ ) {
df::tiletype* supportType = Maps::getTileType(support[a]); df::tiletype* supportType = Maps::getTileType(support[a]);
df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, *supportType); df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, *supportType);
df::tiletype_shape_basic basic = ENUM_ATTR(tiletype_shape, basic_shape, shape); df::tiletype_shape_basic basic = ENUM_ATTR(tiletype_shape, basic_shape, shape);
cost_t cost2 = 2*costWeight[CostDimension::Walk] + costWeight[CostDimension::DestroyBuilding]; cost_t cost2 = 2*abilities.costWeight[CostDimension::Walk] + abilities.costWeight[CostDimension::DestroyBuilding];
if ( !Maps::canStepBetween(pt1, support[a]) ) { if ( !Maps::canStepBetween(pt1, support[a]) ) {
switch(basic) { switch(basic) {
case tiletype_shape_basic::Open: case tiletype_shape_basic::Open:
@ -227,9 +266,15 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
continue; continue;
case tiletype_shape_basic::Wall: case tiletype_shape_basic::Wall:
if ( ENUM_ATTR(tiletype, material, *supportType) == df::enums::tiletype_material::CONSTRUCTION ) { if ( ENUM_ATTR(tiletype, material, *supportType) == df::enums::tiletype_material::CONSTRUCTION ) {
cost2 += costWeight[CostDimension::DestroyConstruction]; if ( abilities.costWeight[CostDimension::DestroyConstruction] < 0 ) {
continue;
}
cost2 += abilities.costWeight[CostDimension::DestroyConstruction];
} else { } else {
cost2 += costWeight[CostDimension::Dig]; if ( abilities.costWeight[CostDimension::Dig] < 0 ) {
continue;
}
cost2 += abilities.costWeight[CostDimension::Dig];
} }
case tiletype_shape_basic::Ramp: case tiletype_shape_basic::Ramp:
//TODO: check for a hatch or a bridge: that makes it ok //TODO: check for a hatch or a bridge: that makes it ok
@ -241,7 +286,10 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
break; break;
} }
if ( Buildings::findAtTile(support[a]) ) { if ( Buildings::findAtTile(support[a]) ) {
cost2 += costWeight[CostDimension::DestroyBuilding]; if ( abilities.costWeight[CostDimension::DestroyBuilding] < 0 ) {
continue;
}
cost2 += abilities.costWeight[CostDimension::DestroyBuilding];
} }
} }
if ( minCost == -1 || cost2 < minCost ) if ( minCost == -1 || cost2 < minCost )
@ -251,6 +299,7 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
return -1; return -1;
cost += minCost; cost += minCost;
*/
//note: assignJob is not ready for this level of sophistication, so don't allow it //note: assignJob is not ready for this level of sophistication, so don't allow it
return -1; return -1;
} }
@ -265,6 +314,7 @@ cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2) {
return cost; return cost;
} }
/*
cost_t getEdgeCostOld(color_ostream& out, df::coord pt1, df::coord pt2) { cost_t getEdgeCostOld(color_ostream& out, df::coord pt1, df::coord pt2) {
//first, list all the facts //first, list all the facts
int32_t dx = pt2.x - pt1.x; int32_t dx = pt2.x - pt1.x;
@ -397,8 +447,9 @@ cost_t getEdgeCostOld(color_ostream& out, df::coord pt1, df::coord pt2) {
//moving diagonally //moving diagonally
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) { vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax, DigAbilities& abilities) {
//vector<Edge>* result = new vector<Edge>(26); //vector<Edge>* result = new vector<Edge>(26);
vector<Edge>* result = new vector<Edge>(); vector<Edge>* result = new vector<Edge>();
result->reserve(26); result->reserve(26);
@ -414,7 +465,7 @@ vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCach
continue; continue;
if ( dx == 0 && dy == 0 && dz == 0 ) if ( dx == 0 && dy == 0 && dz == 0 )
continue; continue;
cost_t cost = getEdgeCost(out, point, neighbor); cost_t cost = getEdgeCost(out, point, neighbor, abilities);
if ( cost == -1 ) if ( cost == -1 )
continue; continue;
Edge edge(point, neighbor, cost); Edge edge(point, neighbor, cost);

@ -9,6 +9,7 @@
#include "df/coord.h" #include "df/coord.h"
#include <unordered_map>
#include <vector> #include <vector>
//cost is [path cost, building destruction cost, dig cost, construct cost]. Minimize constructions, then minimize dig cost, then minimize path cost. //cost is [path cost, building destruction cost, dig cost, construct cost]. Minimize constructions, then minimize dig cost, then minimize path cost.
@ -16,15 +17,22 @@ enum CostDimension {
Walk, Walk,
DestroyBuilding, DestroyBuilding,
Dig, Dig,
DestroyConstruction, DestroyRoughConstruction,
DestroySmoothConstruction,
//Construct, //Construct,
costDim costDim
}; };
typedef int64_t cost_t; typedef int64_t cost_t;
extern cost_t costWeight[costDim]; struct DigAbilities {
extern int32_t jobDelay[costDim]; cost_t costWeight[costDim];
int32_t jobDelay[costDim];
};
//extern cost_t costWeight[costDim];
//extern int32_t jobDelay[costDim];
extern std::unordered_map<std::string, DigAbilities> digAbilities;
/* /*
const cost_t costWeight[] = { const cost_t costWeight[] = {
//Distance //Distance
@ -85,6 +93,6 @@ struct PointHash {
} }
}; };
cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2); cost_t getEdgeCost(color_ostream& out, df::coord pt1, df::coord pt2, DigAbilities& abilities);
std::vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax); std::vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax, DigAbilities& abilities);