Digging Invaders: reorganized the files to make it easier to work with.
parent
84b8fae326
commit
1d6dec54c7
@ -0,0 +1,188 @@
|
||||
#include "assignJob.h"
|
||||
|
||||
#include "modules/Buildings.h"
|
||||
#include "modules/Items.h"
|
||||
#include "modules/Job.h"
|
||||
|
||||
#include "df/building.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/job.h"
|
||||
#include "df/job_type.h"
|
||||
#include "df/unit.h"
|
||||
#include "df/unit_inventory_item.h"
|
||||
|
||||
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,int64_t,PointHash>& costMap, vector<df::unit*>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache) {
|
||||
df::unit* firstInvader = invaders[0];
|
||||
|
||||
//do whatever you need to do at the first important edge
|
||||
df::coord pt1 = firstImportantEdge.p1;
|
||||
df::coord pt2 = firstImportantEdge.p2;
|
||||
if ( costMap[pt1] > costMap[pt2] ) {
|
||||
df::coord temp = pt1;
|
||||
pt1 = pt2;
|
||||
pt2 = temp;
|
||||
}
|
||||
out.print("first important edge: (%d,%d,%d) -> (%d,%d,%d)\n", pt1.x,pt1.y,pt1.z, pt2.x,pt2.y,pt2.z);
|
||||
|
||||
int32_t jobId = -1;
|
||||
|
||||
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];
|
||||
|
||||
df::building* building = Buildings::findAtTile(pt2);
|
||||
df::coord buildingPos = pt2;
|
||||
if ( pt1.z > pt2.z ) {
|
||||
building = Buildings::findAtTile(df::coord(pt2.x,pt2.y,pt2.z+1));
|
||||
buildingPos = df::coord(pt2.x,pt2.y,pt2.z+1);
|
||||
}
|
||||
if ( building != NULL ) {
|
||||
df::coord destroyFrom = parentMap[buildingPos];
|
||||
out.print("%s, line %d: Destroying building %d at (%d,%d,%d) from (%d,%d,%d).\n", __FILE__, __LINE__, building->id, buildingPos.x,buildingPos.y,buildingPos.z, destroyFrom.x,destroyFrom.y,destroyFrom.z);
|
||||
|
||||
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->general_refs.push_back(buildingRef);
|
||||
df::general_ref_unit_workerst* workerRef = new df::general_ref_unit_workerst;
|
||||
workerRef->unit_id = firstInvader->id;
|
||||
job->general_refs.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 = destroyFrom;
|
||||
firstInvader->job.hunt_target = NULL;
|
||||
firstInvader->job.destroy_target = NULL;
|
||||
|
||||
building->jobs.clear();
|
||||
building->jobs.push_back(job);
|
||||
Job::linkIntoWorld(job);
|
||||
jobId = job->id;
|
||||
} else {
|
||||
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);
|
||||
bool construction2 = ENUM_ATTR(tiletype, material, *type2) == df::enums::tiletype_material::CONSTRUCTION;
|
||||
if ( construction2 ) {
|
||||
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->general_refs.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);
|
||||
jobId = job->id;
|
||||
} else {
|
||||
//must be a dig job
|
||||
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;
|
||||
firstInvader->path.dest = pt2;
|
||||
} else if ( up && !down ) {
|
||||
job->job_type = df::enums::job_type::CarveUpwardStaircase;
|
||||
job->pos = pt2;
|
||||
firstInvader->path.dest = pt2;
|
||||
} else if ( !up && down ) {
|
||||
job->job_type = df::enums::job_type::CarveDownwardStaircase;
|
||||
job->pos = pt2;
|
||||
firstInvader->path.dest = pt2;
|
||||
} else {
|
||||
job->job_type = df::enums::job_type::Dig;
|
||||
job->pos = pt2;
|
||||
firstInvader->path.dest = pt1;
|
||||
}
|
||||
df::general_ref_unit_workerst* ref = new df::general_ref_unit_workerst;
|
||||
ref->unit_id = firstInvader->id;
|
||||
job->general_refs.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();
|
||||
Job::linkIntoWorld(job);
|
||||
jobId = job->id;
|
||||
|
||||
//TODO: test if he already has a pick
|
||||
|
||||
//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.whole = 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 -1;
|
||||
}
|
||||
pick->subtype = itemdef;
|
||||
pick->sharpness = 5000;
|
||||
|
||||
int32_t part = -1;
|
||||
part = firstInvader->body.weapon_bp; //weapon_bp
|
||||
if ( part == -1 ) {
|
||||
out.print("%s, %d: no grasp part.\n", __FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
//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);
|
||||
}
|
||||
}
|
||||
return jobId;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "edgeCost.h"
|
||||
|
||||
#include "modules/MapCache.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map<df::coord,df::coord,PointHash> parentMap, unordered_map<df::coord,int64_t,PointHash>& costMap, vector<df::unit*>& invaders, unordered_set<df::coord,PointHash>& requiresZNeg, unordered_set<df::coord,PointHash>& requiresZPos, MapExtras::MapCache& cache);
|
@ -0,0 +1,169 @@
|
||||
#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"
|
||||
|
||||
using namespace std;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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>;
|
||||
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;
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core.h"
|
||||
#include "Console.h"
|
||||
#include "DataDefs.h"
|
||||
|
||||
#include "modules/Maps.h"
|
||||
#include "modules/MapCache.h"
|
||||
|
||||
#include "df/coord.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
//cost is [path cost, building destruction cost, dig cost, construct cost]. Minimize constructions, then minimize dig cost, then minimize path cost.
|
||||
enum CostDimension {
|
||||
Distance,
|
||||
DestroyBuilding,
|
||||
Dig,
|
||||
DestroyConstruction,
|
||||
//Construct,
|
||||
costDim
|
||||
};
|
||||
|
||||
const int64_t costWeight[] = {
|
||||
//Distance
|
||||
1,
|
||||
//Destroy Building
|
||||
2,
|
||||
//Dig
|
||||
10000,
|
||||
//DestroyConstruction
|
||||
100,
|
||||
};
|
||||
|
||||
class Edge {
|
||||
public:
|
||||
//static map<df::coord, int32_t> pointCost;
|
||||
df::coord p1;
|
||||
df::coord p2;
|
||||
int64_t cost;
|
||||
Edge(df::coord p1In, df::coord p2In, int64_t costIn): cost(costIn) {
|
||||
if ( p2In < p1In ) {
|
||||
p1 = p2In;
|
||||
p2 = p1In;
|
||||
} else {
|
||||
p1 = p1In;
|
||||
p2 = p2In;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Edge& e) const {
|
||||
return (cost == e.cost && p1 == e.p1 && p2 == e.p2);
|
||||
}
|
||||
|
||||
bool operator<(const Edge& e) const {
|
||||
if ( cost != e.cost )
|
||||
return cost < e.cost;
|
||||
if ( p1.z != e.p1.z )
|
||||
return p1.z < e.p1.z;
|
||||
if ( p1 != e.p1 )
|
||||
return p1 < e.p1;
|
||||
if ( p2.z != e.p2.z )
|
||||
return p2.z < e.p2.z;
|
||||
if ( p2 != e.p2 )
|
||||
return p2 < e.p2;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct PointHash {
|
||||
size_t operator()(const df::coord c) const {
|
||||
return c.x * 65537 + c.y * 17 + c.z;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<Edge>* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int32_t xMax, int32_t yMax, int32_t zMax);
|
||||
|
Loading…
Reference in New Issue