diff --git a/plugins/diggingInvaders/diggingInvaders.cpp b/plugins/diggingInvaders/diggingInvaders.cpp index 9899f0c96..de358399d 100644 --- a/plugins/diggingInvaders/diggingInvaders.cpp +++ b/plugins/diggingInvaders/diggingInvaders.cpp @@ -29,7 +29,7 @@ DFHACK_PLUGIN("diggingInvaders"); // Mandatory init function. If you have some global state, create it here. DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - //out.print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!\n\n\n\n\n"); + //out.print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!\n\n\n\n\n"); // Fill the command list with your commands. commands.push_back(PluginCommand( "diggingInvaders", "Makes invaders dig to your dwarves.", @@ -80,30 +80,30 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) */ /*class CompareEdge { - bool operator()(edge e1, edge e2) { - - } + bool operator()(edge e1, edge e2) { + + } };*/ class Edge { public: - //static map pointCost; - df::coord p1; - df::coord p2; - int cost; - Edge(df::coord p1In, df::coord p2In, int costIn): p1(p1In), p2(p2In), cost(costIn) { - - } - - /*bool operator<(const Edge e) const { - int pCost = max(pointCost[p1], pointCost[p2]) + cost; - int e_pCost = max(pointCost[e.p1], pointCost[e.p2]) + e.cost; - if ( pCost != e_pCost ) - return pCost < e_pCost; - if ( p1 != e.p1 ) - return p1 < e.p1; - return p2 < e.p2; - }*/ + //static map pointCost; + df::coord p1; + df::coord p2; + int cost; + Edge(df::coord p1In, df::coord p2In, int costIn): p1(p1In), p2(p2In), cost(costIn) { + + } + + /*bool operator<(const Edge e) const { + int pCost = max(pointCost[p1], pointCost[p2]) + cost; + int e_pCost = max(pointCost[e.p1], pointCost[e.p2]) + e.cost; + if ( pCost != e_pCost ) + return pCost < e_pCost; + if ( p1 != e.p1 ) + return p1 < e.p1; + return p2 < e.p2; + }*/ }; vector* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int xMax, int yMax, int zMax); @@ -111,26 +111,26 @@ df::coord getRoot(df::coord point, map& rootMap); class PointComp { public: - map *pointCost; - PointComp(map *p): pointCost(p) { - - } - - int operator()(df::coord p1, df::coord p2) { - map::iterator i1 = pointCost->find(p1); - map::iterator i2 = pointCost->find(p2); - if ( i1 == pointCost->end() && i2 == pointCost->end() ) - return p1 < p2; - if ( i1 == pointCost->end() ) - return 1; - if ( i2 == pointCost->end() ) - return -1; - int c1 = (*i1).second; - int c2 = (*i2).second; - if ( c1 != c2 ) - return c1 < c2; - return p1 < p2; - } + map *pointCost; + PointComp(map *p): pointCost(p) { + + } + + int operator()(df::coord p1, df::coord p2) { + map::iterator i1 = pointCost->find(p1); + map::iterator i2 = pointCost->find(p2); + if ( i1 == pointCost->end() && i2 == pointCost->end() ) + return p1 < p2; + if ( i1 == pointCost->end() ) + return 1; + if ( i2 == pointCost->end() ) + return -1; + int c1 = (*i1).second; + int c2 = (*i2).second; + if ( c1 != c2 ) + return c1 < c2; + return p1 < p2; + } }; // A command! It sits around and looks pretty. And it's nice and friendly. @@ -140,353 +140,353 @@ command_result diggingInvadersFunc(color_ostream &out, std::vector return CR_WRONG_USAGE; CoreSuspender suspend; - //eventually we're going to want a path from each surviving invader to each dwarf, but for now, let's just do from each dwarf to each dwarf - int32_t race_id = df::global::ui->race_id; - int32_t civ_id = df::global::ui->civ_id; - - uint32_t xMax, yMax, zMax; - Maps::getSize(xMax,yMax,zMax); - xMax *= 16; - yMax *= 16; - MapExtras::MapCache cache; - - //TODO: consider whether to pursue hidden dwarf diplomats and merchants - vector locals; - vector invaders; - map dwarfCount; - //map*> edgeSet; - map rootMap; - map parentMap; - map pointCost; - PointComp comp(&pointCost); - set fringe(comp); - for ( size_t a = 0; a < df::global::world->units.all.size(); a++ ) { - df::unit* unit = df::global::world->units.all[a]; - bool isInvader = false; - if ( df::global::ui->invasions.next_id > 0 && unit->invasion_id+1 == df::global::ui->invasions.next_id ) { - invaders.push_back(unit); - //dwarfCount[unit->pos]++; - isInvader = true; - } - - if ( (!isInvader && (unit->race != race_id || unit->civ_id != civ_id)) || unit->flags1.bits.dead ) - continue; - - if ( !isInvader ) - locals.push_back(unit); - dwarfCount[unit->pos]++; - //edgeSet[unit->pos] = getEdgeSet(unit->pos, cache, xMax, yMax, zMax); - rootMap[unit->pos] = unit->pos; - parentMap[unit->pos] = unit->pos; - pointCost[unit->pos] = 0; - fringe.insert(unit->pos); - } - - //TODO: if only one connectivity group, return - if ( invaders.size() == 0 ) { - return CR_OK; //no invaders, no problem! - } - set importantPoints; - int a=0; - int dwarvesFound = 1; - while(dwarvesFound < invaders.size()+locals.size() && fringe.size() > 0) { - df::coord point = *fringe.begin(); - //out.print("%d: (%d,%d,%d); dwarvesFound = %d\n", a++, (int)point.x, (int)point.y, (int)point.z, dwarvesFound); - //if ( a > 10000 ) break; - fringe.erase(fringe.begin()); - //dwarfCount[getRoot(point, rootMap)] += dwarfCount[point]; - - if ( getRoot(point, rootMap) != point && dwarfCount[point] != 0 ) { - dwarfCount[getRoot(point, rootMap)] += dwarfCount[point]; - } - - int costSoFar = pointCost[point]; - vector* neighbors = getEdgeSet(out, point, cache, xMax, yMax, zMax); - for ( size_t a = 0; a < neighbors->size(); a++ ) { - df::coord neighbor = (*neighbors)[a].p2; - int neighborCost; - if ( pointCost.find(neighbor) == pointCost.end() ) - neighborCost = -1; - else - neighborCost = pointCost[neighbor]; - if ( neighborCost == -1 || neighborCost > costSoFar + (*neighbors)[a].cost ) { - fringe.erase(neighbor); - pointCost[neighbor] = costSoFar + (*neighbors)[a].cost; - parentMap[neighbor] = point; - //if ( getRoot(neighbor, rootMap) == neighbor ) - rootMap[neighbor] = rootMap[point]; - fringe.insert(neighbor); - } - df::coord pointRoot = getRoot(point, rootMap); - df::coord neighborRoot = getRoot(neighbor, rootMap); - //check for unified sections of the map - if ( neighborRoot != neighbor && neighborRoot != pointRoot ) { - //dwarvesFound++; - dwarfCount[pointRoot] += dwarfCount[neighborRoot]; - dwarfCount[neighborRoot] = 0; - dwarvesFound = max(dwarvesFound, dwarfCount[pointRoot]); - rootMap[neighborRoot] = rootMap[pointRoot]; - - df::coord temp = point; - while(true) { - importantPoints.insert(temp); - if ( parentMap[temp] != temp ) - temp = parentMap[temp]; - else break; - } - temp = neighbor; - while(true) { - importantPoints.insert(temp); - if ( parentMap[temp] != temp ) - temp = parentMap[temp]; - else break; - } - } - } - delete neighbors; - } - out.print("dwarves found: %d\n", dwarvesFound); - - out.print("Important points:\n"); - for ( set::iterator i = importantPoints.begin(); i != importantPoints.end(); i++ ) { - df::coord point = *i; - out.print(" (%d, %d, %d)\n", (int)point.x, (int)point.y, (int)point.z); - } - - //dig out all the important points - for ( set::iterator i = importantPoints.begin(); i != importantPoints.end(); i++ ) { - df::coord point = *i; - - //deal with buildings, hatches, and doors - { - df::map_block* block = cache.BlockAt(df::coord((point.x)/16, (point.y)/16, point.z))->getRaw(); - /*if ( block == NULL ) { - continue; - }*/ - df::tiletype type = cache.tiletypeAt(point); - df::tiletype_shape shape = tileShape(type); - df::tiletype_shape_basic basic = ENUM_ATTR(tiletype_shape, basic_shape, shape); - df::tile_building_occ building_occ = block->occupancy[point.x%16][point.y%16].bits.building; - int z = point.z; - if ( basic == df::tiletype_shape_basic::Ramp && building_occ == df::tile_building_occ::None ) { - df::map_block* block2 = cache.BlockAt(df::coord(point.x/16, point.y/16, point.z+1))->getRaw(); - if ( block2 != NULL ) { - building_occ = block2->occupancy[point.x%16][point.y%16].bits.building; - z = z+1; - if ( building_occ != df::tile_building_occ::None ) { - //if it doesn't block pathing, don't destroy it - - } - } - } - if ( building_occ != df::tile_building_occ::None ) { - //find the building there - bool foundIt = false; - for( size_t a = 0; a < df::global::world->buildings.all.size(); a++ ) { - df::building* building = df::global::world->buildings.all[a]; - if ( z != building->z ) - continue; - if ( building->x1 < point.x || building->x2 > point.x ) - continue; - if ( building->y1 < point.y || building->y2 > point.y ) - continue; - //found it! - foundIt = true; - //destroy it - building->deconstructItems(false, false); - //building->removeUses(false, false); - break; - } - if ( !foundIt ) { - out.print("Error: could not find building at (%d,%d,%d).\n", point.x, point.y, point.z); - } - } - } - - df::tiletype type = cache.tiletypeAt(point); - df::tiletype_shape shape = tileShape(type); - if ( shape == df::tiletype_shape::STAIR_UPDOWN ) - continue; - df::tiletype_shape_basic basicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); - bool uppyDowny; - { - //only needs to change if we need uppy-downiness - df::coord up = df::coord(point.x, point.y, point.z+1); - df::coord down = df::coord(point.x, point.y, point.z-1); - uppyDowny = !(importantPoints.find(up) == importantPoints.end() && importantPoints.find(down) == importantPoints.end()); - } - if ( (basicShape == df::tiletype_shape_basic::Floor || basicShape == df::tiletype_shape_basic::Ramp) && !uppyDowny ) { - continue; - } - - if ( uppyDowny ) { - cache.setTiletypeAt(point, df::tiletype::StoneStairUD); - } else { - cache.setTiletypeAt(point, df::tiletype::StoneFloor1); - } - } - - cache.WriteAll(); + //eventually we're going to want a path from each surviving invader to each dwarf, but for now, let's just do from each dwarf to each dwarf + int32_t race_id = df::global::ui->race_id; + int32_t civ_id = df::global::ui->civ_id; + + uint32_t xMax, yMax, zMax; + Maps::getSize(xMax,yMax,zMax); + xMax *= 16; + yMax *= 16; + MapExtras::MapCache cache; + + //TODO: consider whether to pursue hidden dwarf diplomats and merchants + vector locals; + vector invaders; + map dwarfCount; + //map*> edgeSet; + map rootMap; + map parentMap; + map pointCost; + PointComp comp(&pointCost); + set fringe(comp); + for ( size_t a = 0; a < df::global::world->units.all.size(); a++ ) { + df::unit* unit = df::global::world->units.all[a]; + bool isInvader = false; + if ( df::global::ui->invasions.next_id > 0 && unit->invasion_id+1 == df::global::ui->invasions.next_id ) { + invaders.push_back(unit); + //dwarfCount[unit->pos]++; + isInvader = true; + } + + if ( (!isInvader && (unit->race != race_id || unit->civ_id != civ_id)) || unit->flags1.bits.dead ) + continue; + + if ( !isInvader ) + locals.push_back(unit); + dwarfCount[unit->pos]++; + //edgeSet[unit->pos] = getEdgeSet(unit->pos, cache, xMax, yMax, zMax); + rootMap[unit->pos] = unit->pos; + parentMap[unit->pos] = unit->pos; + pointCost[unit->pos] = 0; + fringe.insert(unit->pos); + } + + //TODO: if only one connectivity group, return + if ( invaders.size() == 0 ) { + return CR_OK; //no invaders, no problem! + } + set importantPoints; + int a=0; + int dwarvesFound = 1; + while(dwarvesFound < invaders.size()+locals.size() && fringe.size() > 0) { + df::coord point = *fringe.begin(); + //out.print("%d: (%d,%d,%d); dwarvesFound = %d\n", a++, (int)point.x, (int)point.y, (int)point.z, dwarvesFound); + //if ( a > 10000 ) break; + fringe.erase(fringe.begin()); + //dwarfCount[getRoot(point, rootMap)] += dwarfCount[point]; + + if ( getRoot(point, rootMap) != point && dwarfCount[point] != 0 ) { + dwarfCount[getRoot(point, rootMap)] += dwarfCount[point]; + } + + int costSoFar = pointCost[point]; + vector* neighbors = getEdgeSet(out, point, cache, xMax, yMax, zMax); + for ( size_t a = 0; a < neighbors->size(); a++ ) { + df::coord neighbor = (*neighbors)[a].p2; + int neighborCost; + if ( pointCost.find(neighbor) == pointCost.end() ) + neighborCost = -1; + else + neighborCost = pointCost[neighbor]; + if ( neighborCost == -1 || neighborCost > costSoFar + (*neighbors)[a].cost ) { + fringe.erase(neighbor); + pointCost[neighbor] = costSoFar + (*neighbors)[a].cost; + parentMap[neighbor] = point; + //if ( getRoot(neighbor, rootMap) == neighbor ) + rootMap[neighbor] = rootMap[point]; + fringe.insert(neighbor); + } + df::coord pointRoot = getRoot(point, rootMap); + df::coord neighborRoot = getRoot(neighbor, rootMap); + //check for unified sections of the map + if ( neighborRoot != neighbor && neighborRoot != pointRoot ) { + //dwarvesFound++; + dwarfCount[pointRoot] += dwarfCount[neighborRoot]; + dwarfCount[neighborRoot] = 0; + dwarvesFound = max(dwarvesFound, dwarfCount[pointRoot]); + rootMap[neighborRoot] = rootMap[pointRoot]; + + df::coord temp = point; + while(true) { + importantPoints.insert(temp); + if ( parentMap[temp] != temp ) + temp = parentMap[temp]; + else break; + } + temp = neighbor; + while(true) { + importantPoints.insert(temp); + if ( parentMap[temp] != temp ) + temp = parentMap[temp]; + else break; + } + } + } + delete neighbors; + } + out.print("dwarves found: %d\n", dwarvesFound); + + out.print("Important points:\n"); + for ( set::iterator i = importantPoints.begin(); i != importantPoints.end(); i++ ) { + df::coord point = *i; + out.print(" (%d, %d, %d)\n", (int)point.x, (int)point.y, (int)point.z); + } + + //dig out all the important points + for ( set::iterator i = importantPoints.begin(); i != importantPoints.end(); i++ ) { + df::coord point = *i; + + //deal with buildings, hatches, and doors + { + df::map_block* block = cache.BlockAt(df::coord((point.x)/16, (point.y)/16, point.z))->getRaw(); + /*if ( block == NULL ) { + continue; + }*/ + df::tiletype type = cache.tiletypeAt(point); + df::tiletype_shape shape = tileShape(type); + df::tiletype_shape_basic basic = ENUM_ATTR(tiletype_shape, basic_shape, shape); + df::tile_building_occ building_occ = block->occupancy[point.x%16][point.y%16].bits.building; + int z = point.z; + if ( basic == df::tiletype_shape_basic::Ramp && building_occ == df::tile_building_occ::None ) { + df::map_block* block2 = cache.BlockAt(df::coord(point.x/16, point.y/16, point.z+1))->getRaw(); + if ( block2 != NULL ) { + building_occ = block2->occupancy[point.x%16][point.y%16].bits.building; + z = z+1; + if ( building_occ != df::tile_building_occ::None ) { + //if it doesn't block pathing, don't destroy it + + } + } + } + if ( building_occ != df::tile_building_occ::None ) { + //find the building there + bool foundIt = false; + for( size_t a = 0; a < df::global::world->buildings.all.size(); a++ ) { + df::building* building = df::global::world->buildings.all[a]; + if ( z != building->z ) + continue; + if ( building->x1 < point.x || building->x2 > point.x ) + continue; + if ( building->y1 < point.y || building->y2 > point.y ) + continue; + //found it! + foundIt = true; + //destroy it + building->deconstructItems(false, false); + //building->removeUses(false, false); + break; + } + if ( !foundIt ) { + out.print("Error: could not find building at (%d,%d,%d).\n", point.x, point.y, point.z); + } + } + } + + df::tiletype type = cache.tiletypeAt(point); + df::tiletype_shape shape = tileShape(type); + if ( shape == df::tiletype_shape::STAIR_UPDOWN ) + continue; + df::tiletype_shape_basic basicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); + bool uppyDowny; + { + //only needs to change if we need uppy-downiness + df::coord up = df::coord(point.x, point.y, point.z+1); + df::coord down = df::coord(point.x, point.y, point.z-1); + uppyDowny = !(importantPoints.find(up) == importantPoints.end() && importantPoints.find(down) == importantPoints.end()); + } + if ( (basicShape == df::tiletype_shape_basic::Floor || basicShape == df::tiletype_shape_basic::Ramp) && !uppyDowny ) { + continue; + } + + if ( uppyDowny ) { + cache.setTiletypeAt(point, df::tiletype::StoneStairUD); + } else { + cache.setTiletypeAt(point, df::tiletype::StoneFloor1); + } + } + + cache.WriteAll(); return CR_OK; } vector* getEdgeSet(color_ostream &out, df::coord point, MapExtras::MapCache& cache, int xMax, int yMax, int zMax) { - vector candidates; - for ( int dx = -1; dx <= 1; dx++ ) { - if ( point.x + dx < 0 ) continue; - for ( int dy = -1; dy <= 1; dy++ ) { - if ( point.y + dy < 0 ) continue; - if ( dx == 0 && dy == 0) - continue; - candidates.push_back(df::coord(point.x+dx,point.y+dy,point.z)); - } - } - for ( int dz = -1; dz <= 1; dz++ ) { - if ( point.z + dz < 0 ) continue; - if ( dz == 0 ) continue; - candidates.push_back(df::coord(point.x, point.y, point.z+dz)); - } - int connectivityType; - { - df::map_block* block = cache.BlockAt(df::coord(point.x/16, point.y/16, point.z))->getRaw(); - if ( block == NULL ) { - return new vector; - } - connectivityType = block->walkable[point.x%16][point.y%16]; - } - if ( connectivityType == 0 ) - return new vector; - for ( int dx = -1; dx <= 1; dx++ ) { - if ( point.x + dx < 0 ) - continue; - for ( int dy = -1; dy <= 1; dy++ ) { - if ( point.y + dy < 0 ) - continue; - for ( int dz = -1; dz <= 1; dz++ ) { - if ( dz == 0 ) continue; - if ( point.z + dz < 0 ) - continue; - if ( dx == 0 && dy == 0 ) - continue; - df::map_block* block = cache.BlockAt(df::coord((point.x+dx)/16, (point.y+dy)/16, point.z+dz))->getRaw(); - if ( block == NULL ) { - continue; - } - if ( block->walkable[(point.x+dx)%16][(point.y+dy)%16] != connectivityType ) { - continue; - } - candidates.push_back(df::coord(point.x+dx, point.y+dy, point.z+dz)); - } - } - } - - //TODO: ramps, buildings - - vector* result = new vector; - df::tiletype_shape_basic basePointBasicShape; - bool basePointIsWall; - { - df::tiletype type = cache.tiletypeAt(point); - df::tiletype_shape shape = tileShape(type); - if ( shape == df::tiletype_shape::EMPTY ) - return result; - basePointBasicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); - //TODO: worry about up stairs vs down stairs vs updown stairs - } - - if ( basePointBasicShape == df::tiletype_shape_basic::Wall && cache.hasConstructionAt(point) ) - return result; - - /*if ( point.z < zMax-1 ) { - //ramps part 1: going up - //if I'm a ramp, and there's a wall in some direction, and there's nothing above me, and that tile is open, I can go there. - df::tiletype_shape_basic upBasicShape; - { - df::tiletype type = cache.tiletypeAt(df::coord(point.x, point.y, point.z+1)); - df::tiletype_shape shape = tileShape(type); - upBasicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); - } - if ( upBasicShape == df::tiletype_shape_basic::Ramp ) { - for ( int dx = -1; dx <= 1; dx++ ) { - for ( int dy = -1; dy <= 1; dy++ ) { - if ( dx == 0 && dy == 0 ) - continue; - df::tiletype type = cache.tiletypeAt(df::coord(point.x+dx, point.y+dy, point.z+1)); - df::tiletype_shape shape = tileShape(type); - df::tiletype_shape_basic basicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); - if ( basicShape == df::tiletype_shape_basic::Floor || - basicShape == df::tiletype_shape_basic::Stair || - basicShape == df::tiletype_shape_basic::Ramp ) { - candidates.push_back(df::coord(point.x+dx, point.y+dy, point.z+1)); - } - } - } - } - } - - if ( point.z >= 1 ) { - //ramps part 2: going down - - }*/ - - for ( size_t a = 0; a < candidates.size(); a++ ) { - if ( candidates[a].x <= 1 || candidates[a].x >= xMax-1 - || candidates[a].y <= 1 || candidates[a].y >= yMax-1 - || candidates[a].z <= 1 || candidates[a].z >= zMax-1 - ) { - continue; - } - df::tiletype type = cache.tiletypeAt(candidates[a]); - df::tiletype_shape shape = tileShape(type); //what namespace? - if ( shape == df::tiletype_shape::EMPTY ) - continue; - df::tiletype_shape_basic basicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); - if ( basicShape == df::tiletype_shape_basic::Wall && cache.hasConstructionAt(candidates[a]) ) { - continue; - } - - //if it's a forbidden door, continue - df::map_block* block = cache.BlockAt(df::coord(candidates[a].x/16, candidates[a].y/16, candidates[a].z))->getRaw(); - if ( block == NULL ) { - continue; - } else { - df::tile_building_occ building_occ = block->occupancy[candidates[a].x%16][candidates[a].y%16].bits.building; - if ( building_occ == df::tile_building_occ::Obstacle ) - continue; - if ( building_occ == df::tile_building_occ::Impassable ) - continue; - if ( building_occ == df::tile_building_occ::Well ) - continue; - if ( building_occ == df::tile_building_occ::Dynamic ) { - //continue; //TODO: check df.map.xml.walkable - } - } - - int cost = 1; - if ( basePointIsWall || basicShape == df::tiletype_shape_basic::Wall ) { - cost += 1000000; //TODO: fancy cost - } - //if ( candidates[a] < point ) { - // result->push_back(Edge(candidates[a], point, cost)); - //} else { - result->push_back(Edge(point, candidates[a], cost)); - //} - } - return result; + vector candidates; + for ( int dx = -1; dx <= 1; dx++ ) { + if ( point.x + dx < 0 ) continue; + for ( int dy = -1; dy <= 1; dy++ ) { + if ( point.y + dy < 0 ) continue; + if ( dx == 0 && dy == 0) + continue; + candidates.push_back(df::coord(point.x+dx,point.y+dy,point.z)); + } + } + for ( int dz = -1; dz <= 1; dz++ ) { + if ( point.z + dz < 0 ) continue; + if ( dz == 0 ) continue; + candidates.push_back(df::coord(point.x, point.y, point.z+dz)); + } + int connectivityType; + { + df::map_block* block = cache.BlockAt(df::coord(point.x/16, point.y/16, point.z))->getRaw(); + if ( block == NULL ) { + return new vector; + } + connectivityType = block->walkable[point.x%16][point.y%16]; + } + if ( connectivityType == 0 ) + return new vector; + for ( int dx = -1; dx <= 1; dx++ ) { + if ( point.x + dx < 0 ) + continue; + for ( int dy = -1; dy <= 1; dy++ ) { + if ( point.y + dy < 0 ) + continue; + for ( int dz = -1; dz <= 1; dz++ ) { + if ( dz == 0 ) continue; + if ( point.z + dz < 0 ) + continue; + if ( dx == 0 && dy == 0 ) + continue; + df::map_block* block = cache.BlockAt(df::coord((point.x+dx)/16, (point.y+dy)/16, point.z+dz))->getRaw(); + if ( block == NULL ) { + continue; + } + if ( block->walkable[(point.x+dx)%16][(point.y+dy)%16] != connectivityType ) { + continue; + } + candidates.push_back(df::coord(point.x+dx, point.y+dy, point.z+dz)); + } + } + } + + //TODO: ramps, buildings + + vector* result = new vector; + df::tiletype_shape_basic basePointBasicShape; + bool basePointIsWall; + { + df::tiletype type = cache.tiletypeAt(point); + df::tiletype_shape shape = tileShape(type); + if ( shape == df::tiletype_shape::EMPTY ) + return result; + basePointBasicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); + //TODO: worry about up stairs vs down stairs vs updown stairs + } + + if ( basePointBasicShape == df::tiletype_shape_basic::Wall && cache.hasConstructionAt(point) ) + return result; + + /*if ( point.z < zMax-1 ) { + //ramps part 1: going up + //if I'm a ramp, and there's a wall in some direction, and there's nothing above me, and that tile is open, I can go there. + df::tiletype_shape_basic upBasicShape; + { + df::tiletype type = cache.tiletypeAt(df::coord(point.x, point.y, point.z+1)); + df::tiletype_shape shape = tileShape(type); + upBasicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); + } + if ( upBasicShape == df::tiletype_shape_basic::Ramp ) { + for ( int dx = -1; dx <= 1; dx++ ) { + for ( int dy = -1; dy <= 1; dy++ ) { + if ( dx == 0 && dy == 0 ) + continue; + df::tiletype type = cache.tiletypeAt(df::coord(point.x+dx, point.y+dy, point.z+1)); + df::tiletype_shape shape = tileShape(type); + df::tiletype_shape_basic basicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); + if ( basicShape == df::tiletype_shape_basic::Floor || + basicShape == df::tiletype_shape_basic::Stair || + basicShape == df::tiletype_shape_basic::Ramp ) { + candidates.push_back(df::coord(point.x+dx, point.y+dy, point.z+1)); + } + } + } + } + } + + if ( point.z >= 1 ) { + //ramps part 2: going down + + }*/ + + for ( size_t a = 0; a < candidates.size(); a++ ) { + if ( candidates[a].x <= 1 || candidates[a].x >= xMax-1 + || candidates[a].y <= 1 || candidates[a].y >= yMax-1 + || candidates[a].z <= 1 || candidates[a].z >= zMax-1 + ) { + continue; + } + df::tiletype type = cache.tiletypeAt(candidates[a]); + df::tiletype_shape shape = tileShape(type); //what namespace? + if ( shape == df::tiletype_shape::EMPTY ) + continue; + df::tiletype_shape_basic basicShape = ENUM_ATTR(tiletype_shape, basic_shape, shape); + if ( basicShape == df::tiletype_shape_basic::Wall && cache.hasConstructionAt(candidates[a]) ) { + continue; + } + + //if it's a forbidden door, continue + df::map_block* block = cache.BlockAt(df::coord(candidates[a].x/16, candidates[a].y/16, candidates[a].z))->getRaw(); + if ( block == NULL ) { + continue; + } else { + df::tile_building_occ building_occ = block->occupancy[candidates[a].x%16][candidates[a].y%16].bits.building; + if ( building_occ == df::tile_building_occ::Obstacle ) + continue; + if ( building_occ == df::tile_building_occ::Impassable ) + continue; + if ( building_occ == df::tile_building_occ::Well ) + continue; + if ( building_occ == df::tile_building_occ::Dynamic ) { + //continue; //TODO: check df.map.xml.walkable + } + } + + int cost = 1; + if ( basePointIsWall || basicShape == df::tiletype_shape_basic::Wall ) { + cost += 1000000; //TODO: fancy cost + } + //if ( candidates[a] < point ) { + // result->push_back(Edge(candidates[a], point, cost)); + //} else { + result->push_back(Edge(point, candidates[a], cost)); + //} + } + return result; } df::coord getRoot(df::coord point, map& rootMap) { - map::iterator i = rootMap.find(point); - if ( i == rootMap.end() ) { - rootMap[point] = point; - return point; - } - df::coord parent = (*i).second; - if ( parent == point ) - return parent; - df::coord root = getRoot(parent, rootMap); - rootMap[point] = root; - return root; + map::iterator i = rootMap.find(point); + if ( i == rootMap.end() ) { + rootMap[point] = point; + return point; + } + df::coord parent = (*i).second; + if ( parent == point ) + return parent; + df::coord root = getRoot(parent, rootMap); + rootMap[point] = root; + return root; }