diff --git a/source/glest_game/ai/annotated_map.cpp b/source/glest_game/ai/annotated_map.cpp deleted file mode 100644 index 3141aa86..00000000 --- a/source/glest_game/ai/annotated_map.cpp +++ /dev/null @@ -1,379 +0,0 @@ -// ============================================================== -// This file is part of The Glest Advanced Engine -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ==============================================================// -// File: annotated_map.cpp -// -// Annotated Map, for use in pathfinding. -// - -#include "annotated_map.h" -#include "world.h" -#include "pos_iterator.h" -#include "cartographer.h" -#include "cluster_map.h" - -#include "profiler.h" - -namespace Glest { namespace Game { - -/** Construct AnnotatedMap object, 'g_map' must be constructed and loaded - * @param master true if this is the master map, false for a foggy map (default true) - */ -AnnotatedMap::AnnotatedMap(World *world) - : world(world) - , cellMap(NULL) { - //_PROFILE_FUNCTION(); - assert(world && world->getMap()); - cellMap = world->getMap(); - width = cellMap->getW(); - height = cellMap->getH(); - metrics.init(width, height); - for (int f = fLand; f < fieldCount; ++f) { - maxClearance[f] = 0; - } - const int &ftCount = world->getTechTree()->getTypeCount(); - const FactionType *factionType; - for (int i = 0; i < ftCount; ++i) { - factionType = world->getTechTree()->getType(i); - const UnitType *unitType; - for (int j = 0; j < factionType->getUnitTypeCount(); ++j) { - unitType = factionType->getUnitType(j); - if (unitType->isMobile()) { - if (unitType->getSize() > maxClearance[unitType->getField()]) { - maxClearance[unitType->getField()] = unitType->getSize(); - } - } - } - } - initMapMetrics(); -} - -AnnotatedMap::~AnnotatedMap() { -} - -/** Initialise clearance data for a master map. */ -void AnnotatedMap::initMapMetrics() { -// _PROFILE_FUNCTION(); - Util::ReverseRectIterator iter(Vec2i(0,0), Vec2i(width - 1, height - 1)); - while (iter.more()) { - computeClearances(iter.next()); - } -} - -#define LOG_CLUSTER_DIRTYING(x) {} -//#define LOG_CLUSTER_DIRTYING(x) {cout << x;} - -struct MudFlinger { - ClusterMap *cm; - - inline void setDirty(const Vec2i &pos) { - Vec2i cluster = ClusterMap::cellToCluster(pos); - cm->setClusterDirty(cluster); - LOG_CLUSTER_DIRTYING( "MapMetrics changed @ pos = " << pos << endl ) - LOG_CLUSTER_DIRTYING( cout << "\tCluster = " << cluster << " dirty\n" ) - int ymod = pos.y % GameConstants::clusterSize; - if (ymod == 0) { - cm->setNorthBorderDirty(cluster); - LOG_CLUSTER_DIRTYING( "\tNorth border dirty\n" ) - } else if (ymod == GameConstants::clusterSize - 1) { - cm->setNorthBorderDirty(Vec2i(cluster.x, cluster.y + 1)); - LOG_CLUSTER_DIRTYING( "\tSouth border dirty\n" ) - } - int xmod = pos.x % GameConstants::clusterSize; - if (xmod == 0) { - cm->setWestBorderDirty(cluster); - LOG_CLUSTER_DIRTYING( "\tWest border dirty\n" ) - } else if (xmod == GameConstants::clusterSize - 1) { - cm->setWestBorderDirty(Vec2i(cluster.x + 1, cluster.y)); - LOG_CLUSTER_DIRTYING( "\tEast border dirty\n" ) - } - } -} mudFlinger; - -/** Update clearance data, when an obstactle is placed or removed from the map * - * @param pos the cell co-ordinates of the obstacle added/removed * - * @param size the size of the obstacle */ -void AnnotatedMap::updateMapMetrics(const Vec2i &pos, const int size) { - assert(cellMap->isInside(pos)); - assert(cellMap->isInside(pos.x + size - 1, pos.y + size - 1)); - //_PROFILE_FUNCTION(); - - // need to throw mud on the ClusterMap - mudFlinger.cm = world->getCartographer()->getClusterMap(); - - // 1. re-evaluate the cells occupied (or formerly occupied) - for (int i = size - 1; i >= 0 ; --i) { - for (int j = size - 1; j >= 0; --j) { - Vec2i occPos = pos; - occPos.x += i; occPos.y += j; - CellMetrics old = metrics[occPos]; - computeClearances(occPos); - if (old != metrics[occPos]) { - mudFlinger.setDirty(occPos); - } - } - } - // 2. propegate changes... - cascadingUpdate(pos, size); -} - -/** Perform a 'cascading update' of clearance metrics having just changed clearances * - * @param pos the cell co-ordinates of the obstacle added/removed * - * @param size the size of the obstacle * - * @param field the field to update (temporary), or fieldCount to update all fields (permanent) */ -void AnnotatedMap::cascadingUpdate(const Vec2i &pos, const int size, const Field field) { - list *leftList, *aboveList, leftList1, leftList2, aboveList1, aboveList2; - leftList = &leftList1; - aboveList = &aboveList1; - // both the left and above lists need to be sorted, bigger values first (right->left, bottom->top) - for (int i = size - 1; i >= 0; --i) { - // Check if positions are on map, (the '+i' components are along the sides of the building/object, - // so we assume they are ok). If so, list them - if (pos.x-1 >= 0) { - leftList->push_back(Vec2i(pos.x-1,pos.y+i)); - } - if (pos.y-1 >= 0) { - aboveList->push_back(Vec2i(pos.x+i,pos.y-1)); - } - } - // the cell to the nothwest... - Vec2i *corner = NULL; - Vec2i cornerHolder(pos.x - 1, pos.y - 1); - if (pos.x - 1 >= 0 && pos.y - 1 >= 0) { - corner = &cornerHolder; - } - while (!leftList->empty() || !aboveList->empty() || corner) { - // the left and above lists for the next loop iteration - list *newLeftList, *newAboveList; - newLeftList = leftList == &leftList1 ? &leftList2 : &leftList1; - newAboveList = aboveList == &aboveList1 ? &aboveList2 : &aboveList1; - if (!leftList->empty()) { - for (VLIt it = leftList->begin(); it != leftList->end(); ++it) { - if (updateCell(*it, field) && it->x - 1 >= 0) { - // if we updated and there is a cell to the left, add it to - newLeftList->push_back(Vec2i(it->x-1,it->y)); // the new left list - } - } - } - if (!aboveList->empty()) { - for (VLIt it = aboveList->begin(); it != aboveList->end(); ++it) { - if (updateCell(*it, field) && it->y - 1 >= 0) { - newAboveList->push_back(Vec2i(it->x,it->y-1)); - } - } - } - if (corner) { - // Deal with the corner... - if (updateCell(*corner, field)) { - int x = corner->x, y = corner->y; - if (x - 1 >= 0) { - newLeftList->push_back(Vec2i(x-1,y)); - if (y - 1 >= 0) { - *corner = Vec2i(x-1,y-1); - } else { - corner = NULL; - } - } else { - corner = NULL; - } - if (y - 1 >= 0) { - newAboveList->push_back(Vec2i(x,y-1)); - } - } else { - corner = NULL; - } - } - leftList->clear(); - leftList = newLeftList; - aboveList->clear(); - aboveList = newAboveList; - }// end while -} - -/** cascadingUpdate() helper */ -bool AnnotatedMap::updateCell(const Vec2i &pos, const Field field) { - if (field == fieldCount) { // permanent annotation, update all - //if (eMap && !eMap->isExplored(Map::toTileCoords(pos))) { - // if not master map, stop if cells are unexplored - // return false; - //} - CellMetrics old = metrics[pos]; - computeClearances(pos); - if (old != metrics[pos]) { - mudFlinger.setDirty(pos); - return true; - } - } else { // local annotation, only check field, store original clearances - uint32 old = metrics[pos].get(field); - if (old) { - computeClearance(pos, field); - if (old > metrics[pos].get(field)) { - if (localAnnt.find(pos) == localAnnt.end()) { - localAnnt[pos] = old; // was original clearance - } - return true; - } - } - } - return false; -} - -/** Compute clearances (all fields) for a location - * @param pos the cell co-ordinates - */ -void AnnotatedMap::computeClearances(const Vec2i &pos) { - assert(cellMap->isInside(pos)); - if (pos.x >= cellMap->getW() - 2 || pos.y >= cellMap->getH() - 2) { - metrics[pos].setAll(0); - return; - } - Cell *cell = cellMap->getCell(pos); - // is there a building here, or an object on the tile ?? - bool surfaceBlocked = (cell->getUnit(fLand) && !cell->getUnit(fLand)->getType()->isMobile()) - || !cellMap->getSurfaceCell(cellMap->toSurfCoords(pos))->isFree(); - // Walkable - if (surfaceBlocked || cellMap->getDeepSubmerged(cell)) - metrics[pos].set(fLand, 0); - else - computeClearance(pos, fLand); -/* - // Any Water - if ( surfaceBlocked || !cell->isSubmerged() || !maxClearance[Field::ANY_WATER] ) - metrics[pos].set(Field::ANY_WATER, 0); - else - computeClearance(pos, Field::ANY_WATER); - - // Deep Water - if ( surfaceBlocked || !cell->isDeepSubmerged() || !maxClearance[Field::DEEP_WATER] ) - metrics[pos].set(Field::DEEP_WATER, 0); - else - computeClearance(pos, Field::DEEP_WATER); - - // Amphibious: - if ( surfaceBlocked || !maxClearance[Field::AMPHIBIOUS] ) - metrics[pos].set(Field::AMPHIBIOUS, 0); - else - computeClearance(pos, Field::AMPHIBIOUS); -*/ - // Air - computeClearance(pos, fAir); -} - -/** Computes clearance based on metrics to the south and east. - * Does NOT check if this cell is an obstactle, assumes metrics of cells to - * the south, south-east & east are correct - * @param pos the co-ordinates of the cell - * @param field the field to update - */ -uint32 AnnotatedMap::computeClearance( const Vec2i &pos, Field f ) { - uint32 clear = metrics[Vec2i(pos.x, pos.y + 1)].get(f); - if ( clear > metrics[Vec2i(pos.x + 1, pos.y + 1)].get(f) ) { - clear = metrics[Vec2i(pos.x + 1, pos.y + 1)].get(f); - } - if ( clear > metrics[Vec2i(pos.x + 1, pos.y)].get(f) ) { - clear = metrics[Vec2i(pos.x + 1, pos.y)].get(f); - } - clear ++; - if ( clear > maxClearance[f] ) { - clear = maxClearance[f]; - } - metrics[pos].set(f, clear); - return clear; -} -/** Perform 'local annotations', annotate the map to treat other mobile units in - * the vincinity of unit as obstacles - * @param unit the unit about to perform a search - * @param field the field that the unit is about to search in - */ -void AnnotatedMap::annotateLocal(const Unit *unit) { - //_PROFILE_FUNCTION(); - const Field &field = unit->getCurrField(); - const Vec2i &pos = unit->getPos(); - const int &size = unit->getType()->getSize(); - assert(cellMap->isInside(pos)); - assert(cellMap->isInside(pos.x + size - 1, pos.y + size - 1)); - const int dist = 3; - set annotate; - - // find surrounding units - for ( int y = pos.y - dist; y < pos.y + size + dist; ++y ) { - for ( int x = pos.x - dist; x < pos.x + size + dist; ++x ) { - if ( cellMap->isInside(x, y) && metrics[Vec2i(x, y)].get(field) ) { // clearance != 0 - Unit *u = cellMap->getCell(x, y)->getUnit(field); - if ( u && u != unit ) { // the set will take care of duplicates for us - annotate.insert(u); - } - } - } - } - // annotate map for each nearby unit - for ( set::iterator it = annotate.begin(); it != annotate.end(); ++it ) { - annotateUnit(*it, field); - } -} - -/** Temporarily annotate the map, to treat unit as an obstacle - * @param unit the unit to treat as an obstacle - * @param field the field to annotate - */ -void AnnotatedMap::annotateUnit(const Unit *unit, const Field field) { - const int size = unit->getType()->getSize(); - const Vec2i &pos = unit->getPos(); - assert(cellMap->isInside(pos)); - assert(cellMap->isInside(pos.x + size - 1, pos.y + size - 1)); - // first, re-evaluate the cells occupied - for (int i = size - 1; i >= 0 ; --i) { - for (int j = size - 1; j >= 0; --j) { - Vec2i occPos = pos; - occPos.x += i; occPos.y += j; - if (!unit->getType()->hasCellMap() || unit->getType()->getCellMapCell(i, j, unit->getModelFacing())) { - if (localAnnt.find(occPos) == localAnnt.end()) { - localAnnt[occPos] = metrics[occPos].get(field); - } - metrics[occPos].set(field, 0); - } else { - uint32 old = metrics[occPos].get(field); - computeClearance(occPos, field); - if (old != metrics[occPos].get(field) && localAnnt.find(occPos) == localAnnt.end()) { - localAnnt[occPos] = old; - } - } - } - } - // propegate changes to left and above - cascadingUpdate(pos, size, field); -} - -/** Clear all local annotations * - * @param field the field annotations were applied to */ -void AnnotatedMap::clearLocalAnnotations(const Unit *unit) { - //_PROFILE_FUNCTION(); - const Field &field = unit->getCurrField(); - for ( map::iterator it = localAnnt.begin(); it != localAnnt.end(); ++ it ) { - assert(it->second <= maxClearance[field]); - assert(cellMap->isInside(it->first)); - metrics[it->first].set(field, it->second); - } - localAnnt.clear(); -} - -#if _GAE_DEBUG_EDITION_ - -list >* AnnotatedMap::getLocalAnnotations() { - list > *ret = new list >(); - for ( map::iterator it = localAnnt.begin(); it != localAnnt.end(); ++ it ) - ret->push_back(pair(it->first,metrics[it->first].get(fLand))); - return ret; -} - -#endif - -}} - diff --git a/source/glest_game/ai/annotated_map.h b/source/glest_game/ai/annotated_map.h deleted file mode 100644 index e83106a8..00000000 --- a/source/glest_game/ai/annotated_map.h +++ /dev/null @@ -1,201 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== -// -// File: annotated_map.h -// -// Annotated Map, for use in pathfinding. -// - -#ifndef _GLEST_GAME_ANNOTATED_MAP_H_ -#define _GLEST_GAME_ANNOTATED_MAP_H_ - -#ifdef WIN32 - #include - #include -#endif - -#include "vec.h" -#include "map.h" - -namespace Glest { namespace Game { - -using Shared::Platform::int64; - -typedef list::iterator VLIt; -typedef list::const_iterator VLConIt; -typedef list::reverse_iterator VLRevIt; -typedef list::const_reverse_iterator VLConRevIt; - -class World; - -// ===================================================== -// struct CellMetrics -// ===================================================== -/** Stores clearance metrics for a cell. - * 3 bits are used per field, allowing for a maximum moveable unit size of 7. - * The left over bit is used for per team 'foggy' maps, the dirty bit is set when - * an obstacle has been placed or removed in an area the team cannot currently see. - * The team's annotated map is thus not updated until that cell becomes visible again. - */ -struct CellMetrics { - CellMetrics() { memset(this, 0, sizeof(*this)); } - - uint16 get(const Field field) const { /**< get metrics for field */ - switch (field) { - case fLand: return field0; - case fAir: return field1; - //case Field::ANY_WATER: return field2; - //case Field::DEEP_WATER: return field3; - //case Field::AMPHIBIOUS: return field4; - default: throw megaglest_runtime_error("Unknown Field passed to CellMetrics::get()"); - } - } - - void set(const Field field, uint16 val) { /**< set metrics for field */ - switch (field) { - case fLand: field0 = val; return; - case fAir: field1 = val; return; - //case Field::ANY_WATER: field2 = val; return; - //case Field::DEEP_WATER: field3 = val; return; - //case Field::AMPHIBIOUS: field4 = val; return; - default: throw megaglest_runtime_error("Unknown Field passed to CellMetrics::set()"); - } - } - - void setAll(uint16 val) { /**< set clearance of all fields to val */ - field0 = field1 = field2 = field3 = field4 = val; - } - - bool operator!=(CellMetrics &that) const { /**< comparison, ignoring dirty bit */ - if (field0 == that.field0 && field1 == that.field1 - && field2 == that.field2 && field3 == that.field3 && field4 == that.field4) { - return false; - } - return true; - } - - bool isDirty() const { return dirty; } /**< is this cell dirty */ - void setDirty(const bool val) { dirty = val; } /**< set dirty flag */ - -private: - uint16 field0 : 3; /**< fLand = land + shallow water */ - uint16 field1 : 3; /**< fAir = air */ - uint16 field2 : 3; /**< Field::ANY_WATER = shallow + deep water */ - uint16 field3 : 3; /**< Field::DEEP_WATER = deep water */ - uint16 field4 : 3; /**< Field::AMPHIBIOUS = land + shallow + deep water */ - - uint16 dirty : 1; /**< used in 'team' maps as a 'dirty bit' (clearances have changed - * but team hasn't seen that change yet). */ -}; - -// ===================================================== -// class MetricMap -// ===================================================== -/** A wrapper class for the array of CellMetrics - */ -class MetricMap { -private: - CellMetrics *metrics; - int width,height; - -public: - MetricMap() : metrics(NULL), width(0), height(0) { } - ~MetricMap() { delete [] metrics; } - - void init(int w, int h) { - assert ( w > 0 && h > 0); - width = w; - height = h; - metrics = new CellMetrics[w * h]; - } - - void zero() { memset(metrics, 0, sizeof(CellMetrics) * width * height); } - - CellMetrics& operator[](const Vec2i &pos) const { return metrics[pos.y * width + pos.x]; } -}; - -class PathFinderTextureCallback; - -// ===================================================== -// class AnnotatedMap -// ===================================================== -/** A 'search' map, annotated with clearance data and explored status - *

A compact representation of the map with clearance information for each cell. - * The clearance values are stored for each cell & field, and represent the - * clearance to the south and east of the cell. That is, the maximum size unit - * that can be 'positioned' in this cell (with units in Glest always using the - * north-west most cell they occupy as their 'position').

- */ -//TODO: pretty pictures for the doco... -class AnnotatedMap { - friend class ClusterMap; - friend class PathFinderTextureCallback; - -private: - int width, height; - World *world; - Map *cellMap; - -public: - AnnotatedMap(World *world); - ~AnnotatedMap(); - - int getWidth() { return width; } - int getHeight() { return height; } - - /** Maximum clearance allowed by the game. Hence, also maximum moveable unit size supported. */ - static const int maxClearanceValue = 7; // don't change me without also changing CellMetrics - - int maxClearance[fieldCount]; // maximum clearances needed for this world - - void initMapMetrics(); - - void revealTile(const Vec2i &pos); - - void updateMapMetrics(const Vec2i &pos, const int size); - - /** Interface to the clearance metrics, can a unit of size occupy a cell(s) - * @param pos position agent wishes to occupy - * @param size size of agent - * @param field field agent moves in - * @return true if position can be occupied, else false - */ - bool canOccupy(const Vec2i &pos, int size, Field field) const { - assert(cellMap->isInside(pos)); - return metrics[pos].get(field) >= size ? true : false; - } - - bool isDirty(const Vec2i &pos) const { return metrics[pos].isDirty(); } - void setDirty(const Vec2i &pos, const bool val) { metrics[pos].setDirty(val); } - - void annotateLocal(const Unit *unit); - void clearLocalAnnotations(const Unit *unit); - -private: - // for initMetrics() and updateMapMetrics () - void computeClearances(const Vec2i &); - uint32 computeClearance(const Vec2i &, Field); - - void cascadingUpdate(const Vec2i &pos, const int size, const Field field = fieldCount); - void annotateUnit(const Unit *unit, const Field field); - - bool updateCell(const Vec2i &pos, const Field field); - - - /** the original values of locations that have had local annotations applied */ - std::map localAnnt; - /** The metrics */ - MetricMap metrics; -}; - -}} - -#endif diff --git a/source/glest_game/ai/cartographer.cpp b/source/glest_game/ai/cartographer.cpp deleted file mode 100644 index f3eeee3f..00000000 --- a/source/glest_game/ai/cartographer.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#include "cartographer.h" -#include "game_constants.h" -#include "route_planner.h" - -#include "pos_iterator.h" - -#include "game.h" -#include "unit.h" -#include "unit_type.h" - -//#include "profiler.h" -//#include "leak_dumper.h" - -#include - -#if DEBUG_RENDERING_ENABLED -# include "debug_renderer.h" -#endif - -using namespace Shared::Graphics; -using namespace Shared::Util; - -namespace Glest { namespace Game { - -/** Construct Cartographer object. Requires game settings, factions & cell map to have been loaded. - */ -Cartographer::Cartographer(World *world) - : world(world), cellMap(0), routePlanner(0) { -// _PROFILE_FUNCTION(); - Logger::getInstance().add("Cartographer", true); - - cellMap = world->getMap(); - //int w = cellMap->getW(), h = cellMap->getH(); - - routePlanner = world->getRoutePlanner(); - masterMap = new AnnotatedMap(world); - clusterMap = new ClusterMap(masterMap, this); - - const TechTree *tt = world->getTechTree(); - vector harvestResourceTypes; - for (int i = 0; i < tt->getResourceTypeCount(); ++i) { - rt_ptr rt = tt->getResourceType(i); - if (rt->getClass() == rcTech || rt->getClass() == rcTileset) { - harvestResourceTypes.push_back(rt); - } - } - for (int i = 0; i < tt->getTypeCount(); ++i) { - const FactionType *ft = tt->getType(i); - for (int j = 0; j < ft->getUnitTypeCount(); ++j) { - const UnitType *ut = ft->getUnitType(j); - for (int k=0; k < ut->getCommandTypeCount(); ++k) { - const CommandType *ct = ut->getCommandType(k); - if (ct->getClass() == ccHarvest) { - const HarvestCommandType *hct = static_cast(ct); - for (vector::iterator it = harvestResourceTypes.begin(); - it != harvestResourceTypes.end(); ++it) { - if (hct->canHarvest(*it)) { - ResourceMapKey key(*it, ut->getField(), ut->getSize()); - resourceMapKeys.insert(key); - } - } - } - } - } - } - - // find and catalog all resources... - for (int x=0; x < cellMap->getSurfaceW() - 1; ++x) { - for (int y=0; y < cellMap->getSurfaceH() - 1; ++y) { - const Resource * const r = cellMap->getSurfaceCell(x,y)->getResource(); - if (r) { - resourceLocations[r->getType()].push_back(Vec2i(x,y)); - } - } - } - - Rectangle rect(0, 0, cellMap->getW() - 3, cellMap->getH() - 3); - for (set::iterator it = resourceMapKeys.begin(); it != resourceMapKeys.end(); ++it) { - PatchMap<1> *pMap = new PatchMap<1>(rect, 0); - initResourceMap(*it, pMap); - resourceMaps[*it] = pMap; - } -} - -/** Destruct */ -Cartographer::~Cartographer() { - delete masterMap; - delete clusterMap; - - // Goal Maps - deleteMapValues(resourceMaps.begin(), resourceMaps.end()); - resourceMaps.clear(); - deleteMapValues(storeMaps.begin(), storeMaps.end()); - storeMaps.clear(); - deleteMapValues(siteMaps.begin(), siteMaps.end()); - siteMaps.clear(); -} - -void Cartographer::initResourceMap(ResourceMapKey key, PatchMap<1> *pMap) { - const int &size = key.workerSize; - const Field &field = key.workerField; - const Map &map = *world->getMap(); - pMap->zeroMap(); - for (vector::iterator it = resourceLocations[key.resourceType].begin(); - it != resourceLocations[key.resourceType].end(); ++it) { - Resource *r = world->getMap()->getSurfaceCell(*it)->getResource(); - assert(r); - - Vec2i tl = *it * GameConstants::cellScale + OrdinalOffsets[odNorthWest] * size; - Vec2i br(tl.x + size + 2, tl.y + size + 2); - - Util::PerimeterIterator iter(tl, br); - while (iter.more()) { - Vec2i pos = iter.next(); - if (map.isInside(pos) && masterMap->canOccupy(pos, size, field)) { - pMap->setInfluence(pos, 1); - } - } - } -} - -void Cartographer::onResourceDepleted(Vec2i pos, const ResourceType *rt) { - PF_TRACE(); - pos = Map::toUnitCoords(pos); - updateMapMetrics(pos, GameConstants::cellScale); - resDirtyAreas[rt].push_back(pos); -} - -void Cartographer::fixupResourceMaps(const ResourceType *rt, const Vec2i &pos) { - PF_TRACE(); - const Map &map = *world->getMap(); - Vec2i junk; - for (set::iterator it = resourceMapKeys.begin(); it != resourceMapKeys.end(); ++it) { - if (it->resourceType == rt) { - PatchMap<1> *pMap = resourceMaps[*it]; - const int &size = it->workerSize; - const Field &field = it->workerField; - - Vec2i tl = pos + OrdinalOffsets[odNorthWest] * size; - Vec2i br(tl.x + size + 2, tl.y + size + 2); - - Util::RectIterator iter(tl, br); - while (iter.more()) { - Vec2i cur = iter.next(); - if (map.isInside(cur) && masterMap->canOccupy(cur, size, field) - && map.isResourceNear(cur, size, rt, junk)) { - pMap->setInfluence(cur, 1); - } else { - pMap->setInfluence(cur, 0); - } - } - } - } -} - -PatchMap<1>* Cartographer::buildSiteMap(BuildSiteMapKey key) { - PF_TRACE(); - PatchMap<1> *sMap = siteMaps[key] = buildAdjacencyMap(key.buildingType, key.buildingPosition, - key.buildingFacing, key.workerField, key.workerSize); -# ifdef DEBUG_RENDERING_ENABLED - debugAddBuildSiteMap(sMap); -# endif - return sMap; -} - -PatchMap<1>* Cartographer::getResourceMap(ResourceMapKey key) { - PF_TRACE(); - return resourceMaps[key]; -} - -PatchMap<1>* Cartographer::getStoreMap(StoreMapKey key, bool build) { - PF_TRACE(); - StoreMaps::iterator it = storeMaps.find(key); - if (it != storeMaps.end()) { - return it->second; - } - if (build) { - return buildStoreMap(key); - } else { - return 0; - } -} - -PatchMap<1>* Cartographer::getStoreMap(const Unit *store, const Unit *worker) { - PF_TRACE(); - StoreMapKey key(store, worker->getCurrField(), worker->getType()->getSize()); - return getStoreMap(key); -} - -PatchMap<1>* Cartographer::getSiteMap(BuildSiteMapKey key) { - PF_TRACE(); - SiteMaps::iterator it = siteMaps.find(key); - if (it != siteMaps.end()) { - return it->second; - } - return buildSiteMap(key); - -} - -PatchMap<1>* Cartographer::getSiteMap(const UnitType *ut, const Vec2i &pos, - CardinalDir facing, Unit *worker) { - PF_TRACE(); - BuildSiteMapKey key(ut, pos, facing, worker->getCurrField(), worker->getType()->getSize()); - return getSiteMap(key); -} - -void Cartographer::onStoreDestroyed(Unit *unit) { - ///@todo fixme -// delete storeMaps[unit]; -// storeMaps.erase(unit); -} - -PatchMap<1>* Cartographer::buildAdjacencyMap(const UnitType *uType, const Vec2i &pos, - CardinalDir facing, Field f, int size) { - PF_TRACE(); - const Vec2i mapPos = pos + (OrdinalOffsets[odNorthWest] * size); - const int sx = pos.x; - const int sy = pos.y; - - Rectangle rect(mapPos.x, mapPos.y, uType->getSize() + 2 + size, uType->getSize() + 2 + size); - PatchMap<1> *pMap = new PatchMap<1>(rect, 0); - pMap->zeroMap(); - - PatchMap<1> tmpMap(rect, 0); - tmpMap.zeroMap(); - - // mark cells occupied by unitType at pos (on tmpMap) - Util::RectIterator rIter(pos, pos + Vec2i(uType->getSize() - 1)); - while (rIter.more()) { - Vec2i gpos = rIter.next(); - if (!uType->hasCellMap() || uType->getCellMapCell(gpos.x - sx, gpos.y - sy, facing)) { - tmpMap.setInfluence(gpos, 1); - } - } - - // mark goal cells on result map - rIter = Util::RectIterator(mapPos, pos + Vec2i(uType->getSize())); - while (rIter.more()) { - Vec2i gpos = rIter.next(); - if (tmpMap.getInfluence(gpos) || !masterMap->canOccupy(gpos, size, f)) { - continue; // building or obstacle - } - Util::PerimeterIterator pIter(gpos - Vec2i(1), gpos + Vec2i(size)); - while (pIter.more()) { - if (tmpMap.getInfluence(pIter.next())) { - pMap->setInfluence(gpos, 1); - break; - } - } - } - return pMap; -} - -#ifdef DEBUG_RENDERING_ENABLED - - void Cartographer::debugAddBuildSiteMap(PatchMap<1> *siteMap) { - Rectangle mapBounds = siteMap->getBounds(); - for (int ly = 0; ly < mapBounds.h; ++ly) { - int y = mapBounds.y + ly; - for (int lx = 0; lx < mapBounds.w; ++lx) { - Vec2i pos(mapBounds.x + lx, y); - if (siteMap->getInfluence(pos)) { - getDebugRenderer().addBuildSiteCell(pos); - } - } - } - } - -#endif - -void Cartographer::tick() { - PF_TRACE(); - if (clusterMap->isDirty()) { - clusterMap->update(); - } - for (ResourcePosMap::iterator it = resDirtyAreas.begin(); it != resDirtyAreas.end(); ++it) { - if (!it->second.empty()) { - for (V2iList::iterator posIt = it->second.begin(); posIt != it->second.end(); ++posIt) { - fixupResourceMaps(it->first, *posIt); - } - it->second.clear(); - } - } -} - -}} diff --git a/source/glest_game/ai/cartographer.h b/source/glest_game/ai/cartographer.h deleted file mode 100644 index 26f32dd6..00000000 --- a/source/glest_game/ai/cartographer.h +++ /dev/null @@ -1,173 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifndef _GLEST_GAME_CARTOGRAPHER_H_ -#define _GLEST_GAME_CARTOGRAPHER_H_ - -#ifdef WIN32 - #include - #include -#endif - -#include "game_constants.h" -#include "influence_map.h" -#include "annotated_map.h" -#include "cluster_map.h" - -#include "world.h" -#include "config.h" - -#include "search_engine.h" -#include "resource_type.h" - -namespace Glest { namespace Game { - -using std::make_pair; - -class RoutePlanner; - -struct ResourceMapKey { - const ResourceType *resourceType; - Field workerField; - int workerSize; - - ResourceMapKey(const ResourceType *type, Field f, int s) - : resourceType(type), workerField(f), workerSize(s) {} - - bool operator<(const ResourceMapKey &that) const { - return (memcmp(this, &that, sizeof(ResourceMapKey)) < 0); - } -}; - -struct StoreMapKey { - const Unit *storeUnit; - Field workerField; - int workerSize; - - StoreMapKey(const Unit *store, Field f, int s) - : storeUnit(store), workerField(f), workerSize(s) {} - - bool operator<(const StoreMapKey &that) const { - return (memcmp(this, &that, sizeof(StoreMapKey)) < 0); - } -}; - -struct BuildSiteMapKey { - const UnitType *buildingType; - Vec2i buildingPosition; - CardinalDir buildingFacing; - Field workerField; - int workerSize; - - BuildSiteMapKey(const UnitType *type, const Vec2i &pos, CardinalDir facing, Field f, int s) - : buildingType(type), buildingPosition(pos), buildingFacing(facing) - , workerField(f), workerSize(s) {} - - bool operator<(const BuildSiteMapKey &that) const { - return (memcmp(this, &that, sizeof(BuildSiteMapKey)) < 0); - } -}; - -// -// Cartographer: 'Map' Manager -// -class Cartographer { -private: - /** Master annotated map, always correct */ - AnnotatedMap *masterMap; - - /** The ClusterMap (Hierarchical map abstraction) */ - ClusterMap *clusterMap; - - typedef const ResourceType* rt_ptr; - typedef vector V2iList; - - typedef map*> ResourceMaps; // goal maps for harvester path searches to resourecs - typedef map*> StoreMaps; // goal maps for harvester path searches to store - typedef map*> SiteMaps; // goal maps for building sites. - - typedef list > ResourcePosList; - typedef map ResourcePosMap; - - // Resources - /** The locations of each and every resource on the map */ - ResourcePosMap resourceLocations; - - set resourceMapKeys; - - /** areas where resources have been depleted and updates are required */ - ResourcePosMap resDirtyAreas; - - ResourceMaps resourceMaps; /**< Goal Maps for each tech & tileset resource */ - StoreMaps storeMaps; /**< goal maps for resource stores */ - SiteMaps siteMaps; /**< goal maps for building sites */ - - World *world; - Map *cellMap; - RoutePlanner *routePlanner; - - void initResourceMap(ResourceMapKey key, PatchMap<1> *pMap); - void fixupResourceMaps(const ResourceType *rt, const Vec2i &pos); - - PatchMap<1>* buildAdjacencyMap(const UnitType *uType, const Vec2i &pos, CardinalDir facing, Field f, int sz); - - PatchMap<1>* buildStoreMap(StoreMapKey key) { - return (storeMaps[key] = - buildAdjacencyMap(key.storeUnit->getType(), key.storeUnit->getPos(), - key.storeUnit->getModelFacing(), key.workerField, key.workerSize)); - } - - PatchMap<1>* buildSiteMap(BuildSiteMapKey key); - -# ifdef DEBUG_RENDERING_ENABLED - void debugAddBuildSiteMap(PatchMap<1>*); -# endif - -public: - Cartographer(World *world); - virtual ~Cartographer(); - - RoutePlanner* getRoutePlanner() { return routePlanner; } - - /** Update the annotated maps when an obstacle has been added or removed from the map. - * @param pos position (north-west most cell) of obstacle - * @param size size of obstacle */ - void updateMapMetrics(const Vec2i &pos, const int size) { - masterMap->updateMapMetrics(pos, size); - } - - void onResourceDepleted(Vec2i pos, const ResourceType *rt); - void onStoreDestroyed(Unit *unit); - - void tick(); - - PatchMap<1>* getResourceMap(ResourceMapKey key); - - PatchMap<1>* getStoreMap(StoreMapKey key, bool build=true); - PatchMap<1>* getStoreMap(const Unit *store, const Unit *worker); - - PatchMap<1>* getSiteMap(BuildSiteMapKey key); - PatchMap<1>* getSiteMap(const UnitType *ut, const Vec2i &pos, CardinalDir facing, Unit *worker); - - void adjustGlestimalMap(Field f, TypeMap &iMap, const Vec2i &pos, float range); - void buildGlestimalMap(Field f, V2iList &positions); - - ClusterMap* getClusterMap() const { return clusterMap; } - - AnnotatedMap* getMasterMap() const { return masterMap; } - AnnotatedMap* getAnnotatedMap(int team ) { return masterMap;/*teamMaps[team];*/ } - AnnotatedMap* getAnnotatedMap(const Faction *faction) { return getAnnotatedMap(faction->getTeam()); } - AnnotatedMap* getAnnotatedMap(const Unit *unit) { return getAnnotatedMap(unit->getTeam()); } -}; - -}} - -#endif diff --git a/source/glest_game/ai/cluster_map.cpp b/source/glest_game/ai/cluster_map.cpp deleted file mode 100644 index 4f78a7b4..00000000 --- a/source/glest_game/ai/cluster_map.cpp +++ /dev/null @@ -1,670 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#include - -#include "cluster_map.h" -#include "node_pool.h" -#include "route_planner.h" - -#include "line.h" - -using std::min; -using Shared::Util::line; - -#define _USE_LINE_PATH_ 1 - -#if DEBUG_RENDERING_ENABLED -# include "debug_renderer.h" -#endif - -namespace Glest { namespace Game { - -int Edge::numEdges[fieldCount]; -int Transition::numTransitions[fieldCount]; - -void Edge::zeroCounters() { - for (int f = 0; f < fieldCount; ++f) { - numEdges[f] = 0; - } -} - -void Transition::zeroCounters() { - for (int f = 0; f < fieldCount; ++f) { - numTransitions[f] = 0; - } -} - -ClusterMap::ClusterMap(AnnotatedMap *aMap, Cartographer *carto) - : carto(carto), aMap(aMap), dirty(false) { - //_PROFILE_FUNCTION(); - w = aMap->getWidth() / GameConstants::clusterSize; - h = aMap->getHeight() / GameConstants::clusterSize; - vertBorders = new ClusterBorder[(w-1)*h]; - horizBorders = new ClusterBorder[w*(h-1)]; - - Edge::zeroCounters(); - Transition::zeroCounters(); - - // init Borders (and hence inter-cluster edges) & evaluate clusters (intra-cluster edges) - for (int i = h - 1; i >= 0; --i) { - for (int j = w - 1; j >= 0; --j) { - Vec2i cluster(j, i); - initCluster(cluster); - evalCluster(cluster); - //g_logger.clusterInit(); - } - } -} - -ClusterMap::~ClusterMap() { - delete [] vertBorders; - delete [] horizBorders; - for (int f = 0; f < fieldCount; ++f) { - assert(Edge::NumEdges(Field(f)) == 0); - assert(Transition::NumTransitions(Field(f)) == 0); - if (Edge::NumEdges(Field(f)) != 0 || Transition::NumTransitions(Field(f)) != 0) { - throw megaglest_runtime_error("memory leak"); - } - } -} - -#define LOG(x) {} - -void ClusterMap::assertValid() { - //bool valid[fieldCount]; - bool inUse[fieldCount]; - int numNodes[fieldCount]; - int numEdges[fieldCount]; - - for (int f = 0; f < fieldCount; ++f) { - typedef set TSet; - TSet tSet; - - typedef pair TKey; - typedef map TKMap; - - TKMap tkMap; - - //valid[f] = true; - numNodes[f] = 0; - numEdges[f] = 0; - inUse[f] = aMap->maxClearance[f] != 0; - if (f == fAir) inUse[f] = false; - if (!inUse[f]) { - continue; - } - - // collect all transitions, checking for membership in tSet and tkMap (indicating an error) - // and filling tSet and tkMap - for (int i=0; i < (w - 1) * h; ++i) { // vertical borders - ClusterBorder *b = &vertBorders[i]; - for (int j=0; j < b->transitions[f].n; ++j) { - const Transition *t = b->transitions[f].transitions[j]; - if (tSet.find(t) != tSet.end()) { - LOG("single transition on multiple borders.\n"); - //valid[f] = false; - } else { - tSet.insert(t); - TKey key(t->nwPos, t->vertical); - if (tkMap.find(key) != tkMap.end()) { - LOG("seperate transitions of same orientation on same cell.\n"); - //valid[f] = false; - } else { - tkMap[key] = t; - } - } - ++numNodes[f]; - } - } - for (int i=0; i < w * (h - 1); ++i) { // horizontal borders - ClusterBorder *b = &horizBorders[i]; - for (int j=0; j < b->transitions[f].n; ++j) { - const Transition *t = b->transitions[f].transitions[j]; - if (tSet.find(t) != tSet.end()) { - LOG("single transition on multiple borders.\n"); - //valid[f] = false; - } else { - tSet.insert(t); - TKey key(t->nwPos, t->vertical); - if (tkMap.find(key) != tkMap.end()) { - LOG("seperate transitions of same orientation on same cell.\n"); - //valid[f] = false; - } else { - tkMap[key] = t; - } - } - ++numNodes[f]; - } - } - - // with a complete collection, iterate, check all dest transitions - for (TSet::iterator it = tSet.begin(); it != tSet.end(); ++it) { - const Edges &edges = (*it)->edges; - for (Edges::const_iterator eit = edges.begin(); eit != edges.end(); ++eit) { - TSet::iterator it2 = tSet.find((*eit)->transition()); - if (it2 == tSet.end()) { - LOG("Invalid edge.\n"); - //valid[f] = false; - } else { - if (*it == *it2) { - LOG("self referential transition.\n"); - //valid[f] = false; - } - } - ++numEdges[f]; - } - } - } - LOG("\nClusterMap::assertValid()"); - LOG("\n=========================\n"); - for (int f = 0; f < fieldCount; ++f) { - if (!inUse[f]) { - LOG("Field::" << FieldNames[f] << " not in use.\n"); - } else { - LOG("Field::" << FieldNames[f] << " in use and " << (!valid[f]? "NOT " : "") << "valid.\n"); - LOG("\t" << numNodes[f] << " transitions inspected.\n"); - LOG("\t" << numEdges[f] << " edges inspected.\n"); - } - } -} - -/** Entrance init helper class */ -class InsideOutIterator { -private: - int centre, incr, end; - bool flip; - -public: - InsideOutIterator(int low, int high) - : flip(false) { - centre = low + (high - low) / 2; - incr = 0; - end = ((high - low) % 2 != 0) ? low - 1 : high + 1; - } - - int operator*() const { - return centre + (flip ? incr : -incr); - } - - void operator++() { - flip = !flip; - if (flip) ++incr; - } - - bool more() { - return **this != end; - } -}; - -void ClusterMap::addBorderTransition(EntranceInfo &info) { - assert(info.max_clear > 0 && info.startPos != -1 && info.endPos != -1); - if (info.run < 12) { - // find central most pos with max clearance - InsideOutIterator it(info.endPos, info.startPos); - while (it.more()) { - if (eClear[info.startPos - *it] == info.max_clear) { - Transition *t; - if (info.vert) { - t = new Transition(Vec2i(info.pos, *it), info.max_clear, true, info.f); - } else { - t = new Transition(Vec2i(*it, info.pos), info.max_clear, false, info.f); - } - info.cb->transitions[info.f].add(t); - return; - } - ++it; - } - assert(false); - } else { - // look for two, as close as possible to 1/4 and 3/4 accross - int l1 = info.endPos; - int h1 = info.endPos + (info.startPos - info.endPos) / 2 - 1; - int l2 = info.endPos + (info.startPos - info.endPos) / 2; - int h2 = info.startPos; - InsideOutIterator it(l1, h1); - int first_at = -1; - while (it.more()) { - if (eClear[info.startPos - *it] == info.max_clear) { - first_at = *it; - break; - } - ++it; - } - if (first_at != -1) { - it = InsideOutIterator(l2, h2); - int next_at = -1; - while (it.more()) { - if (eClear[info.startPos - *it] == info.max_clear) { - next_at = *it; - break; - } - ++it; - } - if (next_at != -1) { - Transition *t1, *t2; - if (info.vert) { - t1 = new Transition(Vec2i(info.pos, first_at), info.max_clear, true, info.f); - t2 = new Transition(Vec2i(info.pos, next_at), info.max_clear, true, info.f); - } else { - t1 = new Transition(Vec2i(first_at, info.pos), info.max_clear, false, info.f); - t2 = new Transition(Vec2i(next_at, info.pos), info.max_clear, false, info.f); - } - info.cb->transitions[info.f].add(t1); - info.cb->transitions[info.f].add(t2); - return; - } - } - // failed to find two, just add one... - it = InsideOutIterator(info.endPos, info.startPos); - while (it.more()) { - if (eClear[info.startPos - *it] == info.max_clear) { - Transition *t; - if (info.vert) { - t = new Transition(Vec2i(info.pos, *it), info.max_clear, true, info.f); - } else { - t = new Transition(Vec2i(*it, info.pos), info.max_clear, false, info.f); - } - info.cb->transitions[info.f].add(t); - return; - } - ++it; - } - assert(false); - } -} - -void ClusterMap::initClusterBorder(const Vec2i &cluster, bool north) { - //_PROFILE_FUNCTION(); - ClusterBorder *cb = north ? getNorthBorder(cluster) : getWestBorder(cluster); - EntranceInfo inf; - inf.cb = cb; - inf.vert = !north; - if (cb != &sentinel) { - int pos = north ? cluster.y * GameConstants::clusterSize - 1 - : cluster.x * GameConstants::clusterSize - 1; - inf.pos = pos; - int pos2 = pos + 1; - bool clear = false; // true while evaluating a Transition, false when obstacle hit - inf.max_clear = -1; // max clearance seen for current Transition - inf.startPos = -1; // start position of entrance - inf.endPos = -1; // end position of entrance - inf.run = 0; // to count entrance 'width' - for (int f = 0; f < fieldCount; ++f) { - if (!aMap->maxClearance[f] || f == fAir) continue; - -# if DEBUG_RENDERING_ENABLED - if (f == fLand) { - for (int i=0; i < cb->transitions[f].n; ++i) { - getDebugRenderer().getCMOverlay().entranceCells.erase( - cb->transitions[f].transitions[i]->nwPos - ); - } - } -# endif - - cb->transitions[f].clear(); - clear = false; - inf.f = Field(f); - inf.max_clear = -1; - for (int i=0; i < GameConstants::clusterSize; ++i) { - int clear1, clear2; - if (north) { - clear1 = aMap->metrics[Vec2i(POS_X,pos)].get(inf.f); - clear2 = aMap->metrics[Vec2i(POS_X,pos2)].get(inf.f); - } else { - clear1 = aMap->metrics[Vec2i(pos, POS_Y)].get(Field(f)); - clear2 = aMap->metrics[Vec2i(pos2, POS_Y)].get(Field(f)); - } - int local = min(clear1, clear2); - if (local) { - if (!clear) { - clear = true; - inf.startPos = north ? POS_X : POS_Y; - } - eClear[inf.run++] = local; - inf.endPos = north ? POS_X : POS_Y; - if (local > inf.max_clear) { - inf.max_clear = local; - } - } else { - if (clear) { - addBorderTransition(inf); - inf.run = 0; - inf.startPos = inf.endPos = inf.max_clear = -1; - clear = false; - } - } - } // for i < clusterSize - if (clear) { - addBorderTransition(inf); - inf.run = 0; - inf.startPos = inf.endPos = inf.max_clear = -1; - clear = false; - } - }// for each Field - -# if DEBUG_RENDERING_ENABLED - for (int i=0; i < cb->transitions[fLand].n; ++i) { - getDebugRenderer().getCMOverlay().entranceCells.insert( - cb->transitions[fLand].transitions[i]->nwPos - ); - } -# endif - - } // if not sentinel -} - -/** function object for line alg. 'visit' */ -struct Visitor { - vector &results; - Visitor(vector &res) : results(res) {} - - void operator()(int x, int y) { - results.push_back(Vec2i(x, y)); - } -}; - -/** compute path length using midpoint line algorithm, @return infinite if path not possible, else cost */ -float ClusterMap::linePathLength(Field f, int size, const Vec2i &start, const Vec2i &dest) { - //_PROFILE_FUNCTION(); - if (start == dest) { - return 0.f; - } - vector linePath; - Visitor visitor(linePath); - line(start.x, start.y, dest.x, dest.y, visitor); - assert(linePath.size() >= 2); - MoveCost costFunc(f, size, aMap); - vector::iterator it = linePath.begin(); - vector::iterator nIt = it + 1; - float cost = 0.f; - while (nIt != linePath.end()) { - float add = costFunc(*it++, *nIt++); - if (add != -1.f) { - cost += add; - } else { - return -1.f; - } - } - return cost; -} - -/** compute path length using A* (with node limit), @return infinite if path not possible, else cost */ -float ClusterMap::aStarPathLength(Field f, int size, const Vec2i &start, const Vec2i &dest) { - //_PROFILE_FUNCTION(); - if (start == dest) { - return 0.f; - } - SearchEngine *se = carto->getRoutePlanner()->getSearchEngine(); - MoveCost costFunc(f, size, aMap); - DiagonalDistance dd(dest); - se->setNodeLimit(GameConstants::clusterSize * GameConstants::clusterSize); - se->setStart(start, dd(start)); - PosGoal goal(dest); - AStarResult res = se->aStar(goal, costFunc, dd); - Vec2i goalPos = se->getGoalPos(); - if (res != asrComplete || goalPos != dest) { - return -1.f; - } - return se->getCostTo(goalPos); -} - -void ClusterMap::getTransitions(const Vec2i &cluster, Field f, Transitions &t) { - ClusterBorder *b = getNorthBorder(cluster); - for (int i=0; i < b->transitions[f].n; ++i) { - t.push_back(b->transitions[f].transitions[i]); - } - b = getEastBorder(cluster); - for (int i=0; i < b->transitions[f].n; ++i) { - t.push_back(b->transitions[f].transitions[i]); - } - b = getSouthBorder(cluster); - for (int i=0; i < b->transitions[f].n; ++i) { - t.push_back(b->transitions[f].transitions[i]); - } - b = getWestBorder(cluster); - for (int i=0; i < b->transitions[f].n; ++i) { - t.push_back(b->transitions[f].transitions[i]); - } -} - -void ClusterMap::disconnectCluster(const Vec2i &cluster) { - //cout << "Disconnecting cluster " << cluster << endl; - for (int f = 0; f < fieldCount; ++f) { - if (!aMap->maxClearance[f] || f == fAir) continue; - Transitions t; - getTransitions(cluster, Field(f), t); - set tset; - for (Transitions::iterator it = t.begin(); it != t.end(); ++it) { - tset.insert(*it); - } - //int del = 0; - for (Transitions::iterator it = t.begin(); it != t.end(); ++it) { - Transition *t = const_cast(*it); - Edges::iterator eit = t->edges.begin(); - while (eit != t->edges.end()) { - if (tset.find((*eit)->transition()) != tset.end()) { - delete *eit; - eit = t->edges.erase(eit); - //++del; - } else { - ++eit; - } - } - } - //cout << "\tDeleted " << del << " edges in Field = " << FieldNames[f] << ".\n"; - } - -} - -void ClusterMap::update() { - //_PROFILE_FUNCTION(); - //cout << "ClusterMap::update()" << endl; - for (set::iterator it = dirtyNorthBorders.begin(); it != dirtyNorthBorders.end(); ++it) { - if (it->y > 0 && it->y < h) { - dirtyClusters.insert(Vec2i(it->x, it->y)); - dirtyClusters.insert(Vec2i(it->x, it->y - 1)); - } - } - for (set::iterator it = dirtyWestBorders.begin(); it != dirtyWestBorders.end(); ++it) { - if (it->x > 0 && it->x < w) { - dirtyClusters.insert(Vec2i(it->x, it->y)); - dirtyClusters.insert(Vec2i(it->x - 1, it->y)); - } - } - for (set::iterator it = dirtyClusters.begin(); it != dirtyClusters.end(); ++it) { - //cout << "cluster " << *it << " dirty." << endl; - disconnectCluster(*it); - } - for (set::iterator it = dirtyNorthBorders.begin(); it != dirtyNorthBorders.end(); ++it) { - //cout << "cluster " << *it << " north border dirty." << endl; - initClusterBorder(*it, true); - } - for (set::iterator it = dirtyWestBorders.begin(); it != dirtyWestBorders.end(); ++it) { - //cout << "cluster " << *it << " west border dirty." << endl; - initClusterBorder(*it, false); - } - for (set::iterator it = dirtyClusters.begin(); it != dirtyClusters.end(); ++it) { - evalCluster(*it); - } - - dirtyClusters.clear(); - dirtyNorthBorders.clear(); - dirtyWestBorders.clear(); - dirty = false; -} - - -/** compute intra-cluster path lengths */ -void ClusterMap::evalCluster(const Vec2i &cluster) { - //_PROFILE_FUNCTION(); - //int linePathSuccess = 0, linePathFail = 0; - SearchEngine *se = carto->getRoutePlanner()->getSearchEngine(); - se->getNeighbourFunc().setSearchCluster(cluster); - Transitions transitions; - for (int f = 0; f < fieldCount; ++f) { - if (!aMap->maxClearance[f] || f == fAir) continue; - transitions.clear(); - getTransitions(cluster, Field(f), transitions); - Transitions::iterator it = transitions.begin(); - for ( ; it != transitions.end(); ++it) { // foreach transition - Transition *t = const_cast(*it); - Vec2i start = t->nwPos; - Transitions::iterator it2 = transitions.begin(); - for ( ; it2 != transitions.end(); ++it2) { // foreach other transition - const Transition* &t2 = *it2; - if (t == t2) continue; - Vec2i dest = t2->nwPos; -# if _USE_LINE_PATH_ - float cost = linePathLength(Field(f), 1, start, dest); - if (cost == -1.f) { - cost = aStarPathLength(Field(f), 1, start, dest); - } -# else - float cost = aStarPathLength(Field(f), 1, start, dest); -# endif - if (cost == -1.f) continue; - Edge *e = new Edge(t2, Field(f)); - t->edges.push_back(e); - e->addWeight(cost); - int size = 2; - int maxClear = t->clearance > t2->clearance ? t2->clearance : t->clearance; - while (size <= maxClear) { -# if _USE_LINE_PATH_ - cost = linePathLength(Field(f), 1, start, dest); - if (cost == -1.f) { - cost = aStarPathLength(Field(f), size, start, dest); - } -# else - float cost = aStarPathLength(Field(f), size, start, dest); -# endif - if (cost == -1.f) { - break; - } - e->addWeight(cost); - assert(size == e->maxClear()); - ++size; - } - } // for each other transition - } // for each transition - } // for each Field - se->getNeighbourFunc().setSearchSpace(ssCellMap); -} - -// ======================================================== -// class TransitionNodeStorage -// ======================================================== - -TransitionAStarNode* TransitionNodeStore::getNode() { - if (nodeCount == size) { - //assert(false); - return NULL; - } - return &stock[nodeCount++]; -} - -void TransitionNodeStore::insertIntoOpen(TransitionAStarNode *node) { - if (openList.empty()) { - openList.push_front(node); - return; - } - list::iterator it = openList.begin(); - while (it != openList.end() && (*it)->est() <= node->est()) { - ++it; - } - openList.insert(it, node); -} - -bool TransitionNodeStore::assertOpen() { - if (openList.size() < 2) { - return true; - } - set seen; - list::iterator it1, it2 = openList.begin(); - it1 = it2; - seen.insert((*it1)->pos); - for (++it2; it2 != openList.end(); ++it2) { - if (seen.find((*it2)->pos) != seen.end()) { - LOG("open list has cycle... that's bad."); - return false; - } - seen.insert((*it2)->pos); - if ((*it1)->est() > (*it2)->est() + 0.0001f) { // stupid inaccurate fp - LOG("Open list corrupt: it1.est() == " << (*it1)->est() - << " > it2.est() == " << (*it2)->est()); - return false; - } - } - set::iterator it = open.begin(); - for ( ; it != open.end(); ++it) { - if (seen.find(*it) == seen.end()) { - LOG("node marked open not on open list."); - return false; - } - } - it = seen.begin(); - for ( ; it != seen.end(); ++it) { - if (open.find(*it) == open.end()) { - LOG("node on open list not marked open."); - return false; - } - } - return true; -} - -Transition* TransitionNodeStore::getBestSeen() { - assert(false); - return NULL; -} - -bool TransitionNodeStore::setOpen(const Transition* pos, const Transition* prev, float h, float d) { - assert(open.find(pos) == open.end()); - assert(closed.find(pos) == closed.end()); - - TransitionAStarNode *node = getNode(); - if (!node) return false; - node->pos = pos; - node->prev = prev; - node->distToHere = d; - node->heuristic = h; - open.insert(pos); - insertIntoOpen(node); - listed[pos] = node; - - return true; -} - -void TransitionNodeStore::updateOpen(const Transition* pos, const Transition* &prev, const float cost) { - assert(open.find(pos) != open.end()); - assert(closed.find(prev) != closed.end()); - - TransitionAStarNode *prevNode = listed[prev]; - TransitionAStarNode *posNode = listed[pos]; - if (prevNode->distToHere + cost < posNode->distToHere) { - openList.remove(posNode); - posNode->prev = prev; - posNode->distToHere = prevNode->distToHere + cost; - insertIntoOpen(posNode); - } -} - -const Transition* TransitionNodeStore::getBestCandidate() { - if (openList.empty()) return NULL; - TransitionAStarNode *node = openList.front(); - const Transition *best = node->pos; - openList.pop_front(); - open.erase(open.find(best)); - closed.insert(best); - return best; -} - -}} diff --git a/source/glest_game/ai/cluster_map.h b/source/glest_game/ai/cluster_map.h deleted file mode 100644 index 2ef2688c..00000000 --- a/source/glest_game/ai/cluster_map.h +++ /dev/null @@ -1,324 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifndef _GLEST_GAME_CLUSTER_MAP_H_ -#define _GLEST_GAME_CLUSTER_MAP_H_ - -#ifdef WIN32 - #include - #include -#endif - -#include "util.h" -#include "game_constants.h" -#include "skill_type.h" -#include "math_util.h" - -#include -#include -#include - -namespace Glest { namespace Game { - -using std::set; -using std::map; -using std::list; -using Shared::Util::deleteValues; - -class AnnotatedMap; -class Cartographer; -struct Transition; - -/** uni-directional edge, is owned by the source transition, contains pointer to dest */ -struct Edge { -private: - static int numEdges[fieldCount]; - - const Transition *dest; - vector weights; - - Field f; // for diagnostics... remove this one day - -public: - Edge(const Transition *t, Field f) : f(f) { - dest = t; - ++numEdges[f]; - } - - ~Edge() { - --numEdges[f]; - } - - void addWeight(const float w) { weights.push_back(w); } - const Transition* transition() const { return dest; } - float cost(int size) const { return weights[size-1]; } - int maxClear() { return weights.size(); } - - static int NumEdges(Field f) { return numEdges[f]; } - static void zeroCounters(); -}; -typedef list Edges; - -/** */ -struct Transition { -private: - static int numTransitions[fieldCount]; - Field f; - -public: - int clearance; - Vec2i nwPos; - bool vertical; - Edges edges; - - Transition(Vec2i pos, int clear, bool vert, Field f) - : f(f), clearance(clear), nwPos(pos), vertical(vert) { - ++numTransitions[f]; - } - ~Transition() { - deleteValues(edges.begin(), edges.end()); - --numTransitions[f]; - } - - static int NumTransitions(Field f) { return numTransitions[f]; } - static void zeroCounters(); -}; - -typedef vector Transitions; - -struct TransitionCollection { - Transition *transitions[GameConstants::clusterSize / 2]; - unsigned n; - - TransitionCollection() { - n = 0; - memset(transitions, 0, sizeof(Transition*) * GameConstants::clusterSize / 2); - } - - void add(Transition *t) { - assert(n < GameConstants::clusterSize / 2); - transitions[n++] = t; - } - - void clear() { - for (int i=0; i < n; ++i) { - delete transitions[i]; - } - n = 0; - } - -}; - -struct ClusterBorder { - TransitionCollection transitions[fieldCount]; - - ~ClusterBorder() { - for (int f = 0; f < fieldCount; ++f) { - transitions[f].clear(); - } - } -}; - -/** NeighbourFunc, describes abstract search space */ -class TransitionNeighbours { -public: - void operator()(const Transition* pos, vector &neighbours) const { - for (Edges::const_iterator it = pos->edges.begin(); it != pos->edges.end(); ++it) { - neighbours.push_back((*it)->transition()); - } - } -}; - -/** cost function for searching cluster map */ -class TransitionCost { - Field field; - int size; - -public: - TransitionCost(Field f, int s) : field(f), size(s) {} - float operator()(const Transition *t, const Transition *t2) const { - Edges::const_iterator it = t->edges.begin(); - for ( ; it != t->edges.end(); ++it) { - if ((*it)->transition() == t2) { - break; - } - } - if (it == t->edges.end()) { - throw megaglest_runtime_error("bad connection in ClusterMap."); - } - if ((*it)->maxClear() >= size) { - return (*it)->cost(size); - } - return -1.f; - } -}; - -/** goal function for search on cluster map */ -class TransitionGoal { - set goals; -public: - TransitionGoal() {} - set& goalTransitions() {return goals;} - bool operator()(const Transition *t, const float d) const { - return goals.find(t) != goals.end(); - } -}; - -#define POS_X ((cluster.x + 1) * GameConstants::clusterSize - i - 1) -#define POS_Y ((cluster.y + 1) * GameConstants::clusterSize - i - 1) - -class ClusterMap { -#if _GAE_DEBUG_EDITION_ - friend class DebugRenderer; -#endif -private: - int w, h; - ClusterBorder *vertBorders, *horizBorders, sentinel; - Cartographer *carto; - AnnotatedMap *aMap; - - set dirtyClusters; - set dirtyNorthBorders; - set dirtyWestBorders; - bool dirty; - - int eClear[GameConstants::clusterSize]; - -public: - ClusterMap(AnnotatedMap *aMap, Cartographer *carto); - ~ClusterMap(); - - int getWidth() const { return w; } - int getHeight() const { return h; } - - static Vec2i cellToCluster (const Vec2i &cellPos) { - return Vec2i(cellPos.x / GameConstants::clusterSize, cellPos.y / GameConstants::clusterSize); - } - // ClusterBorder getters - ClusterBorder* getNorthBorder(Vec2i cluster) { - return ( cluster.y == 0 ) ? &sentinel : &horizBorders[(cluster.y - 1) * w + cluster.x ]; - } - ClusterBorder* getEastBorder(Vec2i cluster) { - return ( cluster.x == w - 1 ) ? &sentinel : &vertBorders[cluster.y * (w - 1) + cluster.x ]; - } - ClusterBorder* getSouthBorder(Vec2i cluster) { - return ( cluster.y == h - 1 ) ? &sentinel : &horizBorders[cluster.y * w + cluster.x]; - } - ClusterBorder* getWestBorder(Vec2i cluster) { - return ( cluster.x == 0 ) ? &sentinel : &vertBorders[cluster.y * (w - 1) + cluster.x - 1]; - } - ClusterBorder* getBorder(Vec2i cluster, CardinalDir dir) { - switch (dir) { - case CardinalDir::NORTH: - return getNorthBorder(cluster); - case CardinalDir::EAST: - return getEastBorder(cluster); - case CardinalDir::SOUTH: - return getSouthBorder(cluster); - case CardinalDir::WEST: - return getWestBorder(cluster); - default: - throw megaglest_runtime_error("ClusterMap::getBorder() passed dodgey direction"); - } - return 0; // keep compiler quiet - } - void getTransitions(const Vec2i &cluster, Field f, Transitions &t); - - bool isDirty() { return dirty; } - void update(); - - void setClusterDirty(const Vec2i &cluster) { dirty = true; dirtyClusters.insert(cluster); } - void setNorthBorderDirty(const Vec2i &cluster) { dirty = true; dirtyNorthBorders.insert(cluster); } - void setWestBorderDirty(const Vec2i &cluster) { dirty = true; dirtyWestBorders.insert(cluster); } - - void assertValid(); - -private: - struct EntranceInfo { - ClusterBorder *cb; - Field f; - bool vert; - int pos, max_clear, startPos, endPos, run; - }; - void addBorderTransition(EntranceInfo &info); - void initClusterBorder(const Vec2i &cluster, bool north); - - /** initialise/re-initialise cluster (evaluates north and west borders) */ - void initCluster(const Vec2i &cluster) { - initClusterBorder(cluster, true); - initClusterBorder(cluster, false); - } - - void evalCluster(const Vec2i &cluster); - - float linePathLength(Field f, int size, const Vec2i &start, const Vec2i &dest); - float aStarPathLength(Field f, int size, const Vec2i &start, const Vec2i &dest); - - void disconnectCluster(const Vec2i &cluster); -}; - -struct TransitionAStarNode { - const Transition *pos, *prev; - float heuristic; /**< estimate of distance to goal */ - float distToHere; /**< cost from origin to this node */ - float est() const { /**< estimate, costToHere + heuristic */ - return distToHere + heuristic; - } -}; - -// ======================================================== -// class TransitionNodeStorage -// ======================================================== -// NodeStorage template interface -class TransitionNodeStore { -private: - list openList; - set open; - set closed; - map listed; - - int size, nodeCount; - TransitionAStarNode *stock; - - TransitionAStarNode* getNode(); - void insertIntoOpen(TransitionAStarNode *node); - bool assertOpen(); - -public: - TransitionNodeStore(int size) : size(size), stock(NULL) { - stock = new TransitionAStarNode[size]; - reset(); - } - ~TransitionNodeStore() { - delete [] stock; - } - - void reset() { nodeCount = 0; open.clear(); closed.clear(); openList.clear(); listed.clear(); } - void setMaxNodes(int limit) { } - - bool isOpen(const Transition* pos) { return open.find(pos) != open.end(); } - bool isClosed(const Transition* pos) { return closed.find(pos) != closed.end(); } - - bool setOpen(const Transition* pos, const Transition* prev, float h, float d); - void updateOpen(const Transition* pos, const Transition* &prev, const float cost); - const Transition* getBestCandidate(); - Transition* getBestSeen(); - - float getHeuristicAt(const Transition* &pos) { return listed[pos]->heuristic; } - float getCostTo(const Transition* pos) { return listed[pos]->distToHere; } - float getEstimateFor(const Transition* pos) { return listed[pos]->est(); } - const Transition* getBestTo(const Transition* pos) { return listed[pos]->prev; } -}; - - -}} - -#endif diff --git a/source/glest_game/ai/influence_map.h b/source/glest_game/ai/influence_map.h deleted file mode 100644 index ec96fa90..00000000 --- a/source/glest_game/ai/influence_map.h +++ /dev/null @@ -1,257 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - - -#ifndef _GAME_SEARCH_INLUENCE_MAP_H_ -#define _GAME_SEARCH_INLUENCE_MAP_H_ - -#include "vec.h" -#include "data_types.h" - -#include - -namespace Glest { namespace Game { - -using Shared::Platform::uint32; - -typedef Shared::Graphics::Vec2i Point; - -struct Rectangle { - Rectangle() : x(0), y(0), w(0), h(0) {} - Rectangle(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {} - int x, y, w, h; -}; - -const Point invalidPos(-1,-1); - -// ===================================================== -// class InfluenceMap -// ===================================================== -template class InfluenceMap { -public: - InfluenceMap(Rectangle b, iType def) : def(def), x(b.x), y(b.y), w(b.w), h(b.h) {} - - iType getInfluence(Point pos) { - pos = translate(pos); - if (pos != invalidPos) { - return static_cast(this)->get(pos); - } - return def; - } - bool setInfluence(Point pos, iType val) { - pos = translate(pos); - if (pos != invalidPos) { - static_cast(this)->set(pos, val); - return true; - } - return false; - } - Point translate(Point p) { - const int nx = p.x - x; - const int ny = p.y - y; - if (nx >= 0 && ny >=0 && nx < w && ny < h) { - return Point(nx, ny); - } - return invalidPos; - } - Point getPos() const { return Point(x, y); } - Rectangle getBounds() const { return Rectangle(x, y, w, h); } - -protected: - iType def; // defualt value for positions not within (this) maps dimensions - int x , y, w, h; // Dimensions of this map. -}; - -// ===================================================== -// class TypeMap -// ===================================================== -template class TypeMap : public InfluenceMap > { - friend class InfluenceMap >; -public: - TypeMap(Rectangle b, type def) : InfluenceMap >(b,def) { - data = new type[b.w*b.h]; - } - ~TypeMap() { delete [] data; } - void zeroMap() { memset(data, 0, sizeof(type) * this->w * this->h); } - void clearMap(type val) { std::fill_n(data, this->w * this->h, val); } - -private: - type get(Point p) { return data[p.y * this->w + p.x]; } - void set(Point p, type v) { data[p.y * this->w + p.x] = v; } - type *data; -}; - -// ===================================================== -// class PatchMap -// ===================================================== -/** bit packed InfluenceMap, values are bit packed into 32 bit 'sections' (possibly padded) - * Not usefull for bits >= 7, just use TypeMap, TypeMap etc... - * bit wastage: - * bits == 1, 2 or 4: no wastage in full sections - * bits == 3, 5 or 6: 2 bits wasted per full section - */ -template class PatchMap : public InfluenceMap > { - friend class InfluenceMap >; -public: - PatchMap(Rectangle b, uint32 def) : InfluenceMap >(b,def) { - //cout << "PatchMap<" << bits << "> max_value = "<< max_value <<", [width = " << b.w << " height = " << b.h << "]\n"; - sectionsPerRow = b.w / sectionSize + 1; - //cout << "section size = " << sectionSize << ", sections per row = " << sectionsPerRow << endl; - data = new uint32[b.h * sectionsPerRow]; - } - //only for infuence_map_test.cpp:249 - PatchMap &operator=(const PatchMap &op){ - if(&op != this) { - //FIXME: better when moved to InfluenceMap::operator=... - this->def = op.def; - this->x = op.x; this->y = op.y; this->w = op.w; this->h = op.h; - // - - sectionsPerRow = op.sectionsPerRow; - delete[] data; - data = new uint32[op.h * sectionsPerRow]; - memcpy(data, op.data, op.h * sectionsPerRow); - } - return *this; - } - ~PatchMap() { delete [] data; } - void zeroMap() { memset(data, 0, sizeof(uint32) * sectionsPerRow * this->h); } - void clearMap(uint32 val) { -// assert(val < max_value); - data[0] = 0; - for ( int i=0; i < sectionSize - 1; ++i) { - data[0] |= val; - data[0] <<= bits; - } - data[0] |= val; - for ( int i=1; i < sectionsPerRow; ++i ) { - data[i] = data[0]; - } - const int rowSize = sectionsPerRow * sizeof(uint32); - for ( int i=1; i < this->h; ++i ) { - uint32 *ptr = &data[i * sectionsPerRow]; - memcpy(ptr, data, rowSize); - } - } -private: - uint32 get(Point p) { - int sectionNdx = p.y * sectionsPerRow + p.x / sectionSize; - int subSectionNdx = p.x % sectionSize; - uint32 val = (data[sectionNdx] >> (subSectionNdx * bits)) & max_value; - //cout << "get(" << p.x << "," << p.y << "). section=" << sectionNdx - // << ", subsection=" << subSectionNdx << " = " << val < max_value) { //clamp? - v = max_value; - } - int sectionNdx = p.y * sectionsPerRow + p.x / sectionSize; - int subSectionNdx = p.x % sectionSize; - uint32 val = v << bits * subSectionNdx; - uint32 mask = max_value << bits * subSectionNdx; - data[sectionNdx] &= ~mask; // blot out old value - data[sectionNdx] |= val; // put in the new value - }/* - void logSection(int s) { - cout << "["; - for ( int j = 31; j >= 0; --j ) { - uint32 bitmask = 1 << j; - if ( data[s] & bitmask ) cout << "1"; - else cout << "0"; - if ( j && j % bits == 0 ) cout << " "; - } - cout << "]" << endl; - }*/ - static const uint32 max_value = (1 << bits) - 1; - static const int sectionSize = 32 / bits; - int sectionsPerRow; - uint32 *data; -}; - -// ===================================================== -// class FlowMap -// ===================================================== -/** bit packed 'offset' map, where offset is of the form -1 <= x <= 1 && -1 <= y <= 1 */ -class FlowMap : public InfluenceMap { - friend class InfluenceMap; -private: - Point expand(uint32 v) { - Point res(0,0); - if ( v & 8 ) { res.x = -1; } - else if ( v & 4 ) { res.x = 1; } - if ( v & 2 ) { res.y = -1; } - else if ( v & 1 ) { res.y = 1; } - return res; - } - uint32 pack(Point v) { - uint32 res = 0; - if ( v.x ) { res = 1 << (v.x > 0 ? 2 : 3); } - if ( v.y ) { res |= 1 << (v.y > 0 ? 0 : 1); } - return res; - } -public: - FlowMap(Rectangle b, Point def) : InfluenceMap(b,def) { - blocksPerRow = b.w / 8 + 1; - data = new uint32[b.h * blocksPerRow]; - } - ~FlowMap() { delete [] data; } - void zeroMap() { memset(data, 0, sizeof(uint32) * blocksPerRow * h); } - void clearMap(Point val) { - uint32 v = pack(val); - data[0] = 0; - for ( int i=0; i < 7; ++i ) { - data[0] |= v; - data[0] <<= 4; - } - data[0] |= v; - for ( int i=1; i < blocksPerRow; ++i ) { - data[i] = data[0]; - } - const int rowSize = blocksPerRow * sizeof(uint32); - for ( int i=1; i < h; ++i ) { - uint32 *ptr = &data[i * blocksPerRow]; - memcpy(ptr, data, rowSize); - } - } - -private: - Point get(Point p) { - const int blockNdx = p.y * blocksPerRow + p.x / 8; - const int subBlockNdx = p.x % 8; - uint32 val = (data[blockNdx] >> (subBlockNdx * 4)) & 15; - return expand(val); - } - void set(Point p, Point v) { - int blockNdx = p.y * blocksPerRow + p.x / 8; - int subBlockNdx = p.x % 8; - uint32 val = pack(v) << 4 * subBlockNdx; - uint32 mask = 15 << 4 * subBlockNdx; - data[blockNdx] &= ~mask; // blot out old value - data[blockNdx] |= val; // put in the new value - }/* - void logSection(int s) { - cout << "["; - for ( int j = 31; j >= 0; --j ) { - uint32 bitmask = 1 << j; - if ( data[s] & bitmask ) cout << "1"; - else cout << "0"; - if ( j && j % 4 == 0 ) cout << " "; - } - cout << "]" << endl; - }*/ - int blocksPerRow; - uint32 *data; // 8 values each -}; - -}} - -#endif diff --git a/source/glest_game/ai/node_pool.cpp b/source/glest_game/ai/node_pool.cpp deleted file mode 100644 index 13a1e019..00000000 --- a/source/glest_game/ai/node_pool.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== -// -// File: node_pool.cpp -// -#include "node_pool.h" -#include "world.h" -#include "map.h" - -namespace Glest { namespace Game { - -// ===================================================== -// class NodePool -// ===================================================== - -NodePool::NodePool(int w, int h) - : counter(0) - , leastH(NULL) - , numNodes(0) - , tmpMaxNodes(size) - , markerArray(w, h) { - stock = new AStarNode[size]; -} - -NodePool::~NodePool() { - delete [] stock; -} - -/** reset the node pool for a new search (resets tmpMaxNodes too) */ -void NodePool::reset() { - numNodes = 0; - counter = 0; - tmpMaxNodes = size; - leastH = NULL; - markerArray.newSearch(); - openHeap.clear(); - //IF_DEBUG_EDITION( listedNodes.clear(); ) -} -/** set a maximum number of nodes to expand */ -void NodePool::setMaxNodes(const int max) { - assert(max >= 32 && max <= size); // reasonable number ? - assert(!numNodes); // can't do this after we've started using it. - tmpMaxNodes = max; -} - -/** marks an unvisited position as open - * @param pos the position to open - * @param prev the best known path to pos is from - * @param h the heuristic for pos - * @param d the costSoFar for pos - * @return true if added, false if node limit reached */ -bool NodePool::setOpen(const Vec2i &pos, const Vec2i &prev, float h, float d) { - assert(!isOpen(pos)); - AStarNode *node = newNode(); - if (!node) { // NodePool exhausted - return false; - } - //IF_DEBUG_EDITION( listedNodes.push_back(pos); ) - node->posOff = pos; - if (prev.x >= 0) { - node->posOff.ox = prev.x - pos.x; - node->posOff.oy = prev.y - pos.y; - } else { - node->posOff.ox = 0; - node->posOff.oy = 0; - } - node->distToHere = d; - node->heuristic = h; - addOpenNode(node); - if (!numNodes || h < leastH->heuristic) { - leastH = node; - } - numNodes++; - return true; -} - -/** add a new node to the open list @param node pointer to the node to add */ -void NodePool::addOpenNode(AStarNode *node) { - assert(!isOpen(node->pos())); - markerArray.setOpen(node->pos()); - markerArray.set(node->pos(), node); - openHeap.insert(node); -} - -/** conditionally update a node on the open list. Tests if a path through a new nieghbour - * is better than the existing known best path to pos, updates if so. - * @param pos the open postion to test - * @param prev the new path from - * @param cost the cost to here from prev */ -void NodePool::updateOpen(const Vec2i &pos, const Vec2i &prev, const float cost) { - assert(isClosed(prev)); - assert(isOpen(pos)); - AStarNode *posNode, *prevNode; - posNode = markerArray.get(pos); - prevNode = markerArray.get(prev); - if (prevNode->distToHere + cost < posNode->distToHere) { - posNode->posOff.ox = prev.x - pos.x; - posNode->posOff.oy = prev.y - pos.y; - posNode->distToHere = prevNode->distToHere + cost; - openHeap.promote(posNode); - } -} - -#if _GAE_DEBUG_EDITION_ - -list* NodePool::getOpenNodes() { - list *ret = new list(); - list::iterator it = listedNodes.begin(); - for ( ; it != listedNodes.end (); ++it) { - if (isOpen(*it)) ret->push_back(*it); - } - return ret; -} - -list* NodePool::getClosedNodes() { - list *ret = new list(); - list::iterator it = listedNodes.begin(); - for ( ; it != listedNodes.end(); ++it) { - if (isClosed(*it)) ret->push_back(*it); - } - return ret; -} - -#endif // _GAE_DEBUG_EDITION_ - -}} diff --git a/source/glest_game/ai/node_pool.h b/source/glest_game/ai/node_pool.h deleted file mode 100644 index 900c37b0..00000000 --- a/source/glest_game/ai/node_pool.h +++ /dev/null @@ -1,198 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== -// -// File: node_pool.h -// - -#ifndef _GLEST_GAME_PATHFINDER_NODE_POOL_H_ -#define _GLEST_GAME_PATHFINDER_NODE_POOL_H_ - -#ifdef WIN32 - #include - #include -#endif - -#include "vec.h" -#include "game_constants.h" -#include "heap.h" -#include "data_types.h" -#include -#include -#include -//#include - -namespace Glest { namespace Game { - -using Shared::Util::MinHeap; -using Shared::Graphics::Vec2i; -using namespace Shared::Platform; - -#pragma pack(push, 4) -struct PosOff { /**< A bit packed position (Vec2i) and offset (direction) pair */ - PosOff() : x(0), y(0), ox(0), oy(0) {} /**< Construct a PosOff [0,0] */ - PosOff(Vec2i pos) : ox(0),oy(0) { *this = pos; } /**< Construct a PosOff [pos.x, pos.y] */ - PosOff(int x, int y) : x(x) ,y(y) ,ox(0), oy(0) {} /**< Construct a PosOff [x,y] */ - PosOff& operator=(Vec2i pos) { /**< Assign from Vec2i */ - assert(pos.x <= 8191 && pos.y <= 8191); - x = pos.x; y = pos.y; return *this; - } - bool operator==(PosOff &p) const - { return x == p.x && y == p.y; } /**< compare position components only */ - Vec2i getPos() const { return Vec2i(x, y); } /**< this packed pos as Vec2i */ - Vec2i getPrev() const { return Vec2i(x + ox, y + oy); } /**< return pos + offset */ - Vec2i getOffset() const { return Vec2i(ox, oy); } /**< return offset */ - bool hasOffset() const { return ox || oy; } /**< has an offset */ - bool valid() const { return x >= 0 && y >= 0; } /**< is this position valid */ - - int32 x : 14; /**< x coordinate */ - int32 y : 14; /**< y coordinate */ - int32 ox : 2; /**< x offset */ - int32 oy : 2; /**< y offset */ -}; -#pragma pack(pop) - -// ===================================================== -// struct AStarNode -// ===================================================== -#pragma pack(push, 2) -struct AStarNode { /**< A node structure for A* with NodePool */ - PosOff posOff; /**< position of this node, and direction of best path to it */ - float heuristic; /**< estimate of distance to goal */ - float distToHere; /**< cost from origin to this node */ - - float est() const { return distToHere + heuristic;} /**< estimate, costToHere + heuristic */ - Vec2i pos() const { return posOff.getPos(); } /**< position of this node */ - Vec2i prev() const { return posOff.getPrev(); } /**< best path to this node is from */ - bool hasPrev() const{ return posOff.hasOffset(); } /**< has valid previous 'pointer' */ - - int32 heap_ndx; - void setHeapIndex(int ndx) { heap_ndx = ndx; } - int getHeapIndex() const { return heap_ndx; } - - bool operator<(const AStarNode &that) const { - const float diff = est() - that.est(); - if (diff < 0.f) return true; - if (diff > 0.f) return false; - // tie, prefer closer to goal... - const float h_diff = heuristic - that.heuristic; - if (h_diff < 0.f) return true; - if (h_diff > 0.f) return false; - // still tied... just distinguish them somehow... - return pos() < that.pos(); - } -}; // == 128 bits (16 bytes) -#pragma pack(pop) - -// ======================================================== -// class NodePool -// ======================================================== -class NodePool { /**< A NodeStorage class (template interface) for A* */ -private: - static const int size = 512; /**< total number of AStarNodes in each pool */ - AStarNode *stock; /**< The block of nodes */ - int counter; /**< current counter */ - - // ===================================================== - // struct MarkerArray - // ===================================================== - /** An Marker & Pointer Array supporting two mark types, open and closed. */ - ///@todo replace pointers with indices, interleave mark and index arrays - struct MarkerArray { - private: - int stride; /**< stride of array */ - unsigned int counter; /**< the counter */ - unsigned int *marker; /**< the mark array */ - AStarNode **pArray; /**< the pointer array */ - public: - MarkerArray(int w, int h) : stride(w), counter(0) { - marker = new unsigned int[w * h]; - memset(marker, 0, w * h * sizeof(unsigned int)); - pArray = new AStarNode*[w * h]; - memset(pArray, 0, w * h * sizeof(AStarNode*)); - } - ~MarkerArray() { delete [] marker; delete [] pArray; } - inline void newSearch() { counter += 2; } - inline void setOpen(const Vec2i &pos) { marker[pos.y * stride + pos.x] = counter; } - inline void setClosed(const Vec2i &pos) { marker[pos.y * stride + pos.x] = counter + 1; } - inline bool isOpen(const Vec2i &pos) { return marker[pos.y * stride + pos.x] == counter; } - inline bool isClosed(const Vec2i &pos) { return marker[pos.y * stride + pos.x] == counter + 1; } - inline bool isListed(const Vec2i &pos) { return marker[pos.y * stride + pos.x] >= counter; } /**< @deprecated not needed? */ - inline void setNeither(const Vec2i &pos){ marker[pos.y * stride + pos.x] = 0; } /**< @deprecated not needed? */ - - inline void set(const Vec2i &pos, AStarNode *ptr) { pArray[pos.y * stride + pos.x] = ptr; } /**< set the pointer for pos to ptr */ - inline AStarNode* get(const Vec2i &pos) { return pArray[pos.y * stride + pos.x]; } /**< get the pointer for pos */ - }; - -private: - AStarNode *leastH; /**< The 'best' node seen so far this search */ - int numNodes; /**< number of nodes used so far this search */ - int tmpMaxNodes; /**< a temporary maximum number of nodes to use */ - - MarkerArray markerArray; /**< An array the size of the map, indicating node status (unvisited, open, closed) */ - MinHeap openHeap; /**< the open list, binary heap with index aware nodes */ - -public: - NodePool(int w, int h); - ~NodePool(); - - // NodeStorage template interface - // - void setMaxNodes(const int max); - void reset(); - - bool isOpen(const Vec2i &pos) { return markerArray.isOpen(pos); } /**< test if a position is open */ - bool isClosed(const Vec2i &pos) { return markerArray.isClosed(pos); } /**< test if a position is closed */ - bool isListed(const Vec2i &pos) { return markerArray.isListed(pos); } /**< @deprecated needed for canPathOut() */ - - bool setOpen(const Vec2i &pos, const Vec2i &prev, float h, float d); - void updateOpen(const Vec2i &pos, const Vec2i &prev, const float cost); - - /** get the best candidate from the open list, and close it. - * @return the lowest estimate node from the open list, or -1,-1 if open list empty */ - Vec2i getBestCandidate() { - if (openHeap.empty()) { - return Vec2i(-1); - } - AStarNode *ptr = openHeap.extract(); - markerArray.setClosed(ptr->pos()); - return ptr->pos(); - } - /** get the best heuristic node seen this search */ - Vec2i getBestSeen() { return leastH->pos(); } - /** get the heuristic of the node at pos [known to be visited] */ - float getHeuristicAt(const Vec2i &pos) { return markerArray.get(pos)->heuristic; } - /** get the cost to the node at pos [known to be visited] */ - float getCostTo(const Vec2i &pos) { return markerArray.get(pos)->distToHere; } - /** get the estimate for the node at pos [known to be visited] */ - float getEstimateFor(const Vec2i &pos) { return markerArray.get(pos)->est(); } - /** get the best path to the node at pos [known to be closed] */ - Vec2i getBestTo(const Vec2i &pos) { - AStarNode *ptr = markerArray.get(pos); - assert(ptr); - return ptr->hasPrev() ? ptr->prev() : Vec2i(-1); - } - -private: - void addOpenNode(AStarNode *node); - AStarNode* newNode() { return ( counter < size ? &stock[counter++] : NULL ); } - -#if _GAE_DEBUG_EDITION_ -public: - // interface to support debugging textures - list* getOpenNodes(); - list* getClosedNodes(); - list listedNodes; -#endif -}; - -}} - -#endif diff --git a/source/glest_game/ai/route_planner.cpp b/source/glest_game/ai/route_planner.cpp deleted file mode 100644 index 297ec68b..00000000 --- a/source/glest_game/ai/route_planner.cpp +++ /dev/null @@ -1,1152 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2001-2008 Martiño Figueroa -// 2009-2010 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#include "route_planner.h" -#include "node_pool.h" - -#include "config.h" -#include "map.h" -#include "game.h" -#include "unit.h" -#include "unit_type.h" - -#include "leak_dumper.h" -#include - -#define PF_DEBUG(x) { \ - stringstream _ss; \ - _ss << x << endl; \ - SystemFlags::OutputDebug(SystemFlags::debugPathFinder, _ss.str().c_str()); \ -} -//#define PF_DEBUG(x) std::cout << x << endl - - -#if _GAE_DEBUG_EDITION_ -# include "debug_renderer.h" -#endif - -#ifndef PATHFINDER_DEBUG_MESSAGES -# define PATHFINDER_DEBUG_MESSAGES 0 -#endif - -#if PATHFINDER_DEBUG_MESSAGES -# define CONSOLE_LOG(x) {g_console.addLine(x); g_logger.add(x);} -#else -# define CONSOLE_LOG(x) {} -#endif - -#define _PROFILE_PATHFINDER() -//#define _PROFILE_PATHFINDER() _PROFILE_FUNCTION() - -using namespace Shared::Graphics; -using namespace Shared::Util; - -namespace Glest { namespace Game { - -#if _GAE_DEBUG_EDITION_ - template - void collectOpenClosed(NodeStorage *ns) { - list *nodes = ns->getOpenNodes(); - list::iterator nit = nodes->begin(); - for ( ; nit != nodes->end(); ++nit ) - g_debugRenderer.getPFCallback().openSet.insert(*nit); - delete nodes; - nodes = ns->getClosedNodes(); - for ( nit = nodes->begin(); nit != nodes->end(); ++nit ) - g_debugRenderer.getPFCallback().closedSet.insert(*nit); - delete nodes; - } - - void collectPath(const Unit *unit) { - const UnitPath &path = *unit->getPath(); - for (UnitPath::const_iterator pit = path.begin(); pit != path.end(); ++pit) - g_debugRenderer.getPFCallback().pathSet.insert(*pit); - } - - void collectWaypointPath(const Unit *unit) { - const WaypointPath &path = *unit->getWaypointPath(); - g_debugRenderer.clearWaypoints(); - WaypointPath::const_iterator it = path.begin(); - for ( ; it != path.end(); ++it) { - Vec3f vert = g_world.getMap()->getTile(Map::toTileCoords(*it))->getVertex(); - vert.x += it->x % GameConstants::cellScale + 0.5f; - vert.z += it->y % GameConstants::cellScale + 0.5f; - vert.y += 0.15f; - g_debugRenderer.addWaypoint(vert); - } - } - - void clearOpenClosed(const Vec2i &start, const Vec2i &target) { - g_debugRenderer.getPFCallback().pathStart = start; - g_debugRenderer.getPFCallback().pathDest = target; - g_debugRenderer.getPFCallback().pathSet.clear(); - g_debugRenderer.getPFCallback().openSet.clear(); - g_debugRenderer.getPFCallback().closedSet.clear(); - } -#endif // _GAE_DEBUG_EDITION_ - -// ===================================================== -// class RoutePlanner -// ===================================================== - -// ===================== PUBLIC ======================== - -/** Construct RoutePlanner object */ -RoutePlanner::RoutePlanner(World *world) - : world(world) - , nsgSearchEngine(NULL) - , nodeStore(NULL) - , tSearchEngine(NULL) - , tNodeStore(NULL) { -#ifdef DEBUG_SEARCH_TEXTURES - debug_texture_action=SHOW_PATH_ONLY; -#endif - const int &w = world->getMap()->getW(); - const int &h = world->getMap()->getH(); - - nodeStore = new NodePool(w, h); - GridNeighbours gNeighbours(w, h); - nsgSearchEngine = new SearchEngine(gNeighbours, nodeStore, true); - nsgSearchEngine->setInvalidKey(Vec2i(-1)); - nsgSearchEngine->getNeighbourFunc().setSearchSpace(ssCellMap); - - int numNodes = w * h / 4096 * 250; // 250 nodes for every 16 clusters - tNodeStore = new TransitionNodeStore(numNodes); - TransitionNeighbours tNeighbours; - tSearchEngine = new TransitionSearchEngine(tNeighbours, tNodeStore, true); - tSearchEngine->setInvalidKey(NULL); -} - -/** delete SearchEngine objects */ -RoutePlanner::~RoutePlanner() { - delete nsgSearchEngine; - delete tSearchEngine; -} - -/** Determine legality of a proposed move for a unit. This function is the absolute last say - * in such matters. - * @param unit the unit attempting to move - * @param pos2 the position unit desires to move to - * @return true if move may proceed, false if not legal. - */ -bool RoutePlanner::isLegalMove(Unit *unit, const Vec2i &pos2) const { - assert(world->getMap()->isInside(pos2)); - assert(unit->getPos().dist(pos2) < 1.5); - - float d = unit->getPos().dist(pos2); - if (d > 1.5 || d < 0.9f) { - // path is invalid, this shouldn't happen... but it does. - static_cast(unit->getPath())->clear(); - unit->getWaypointPath()->clear(); - return false; - } - - const Vec2i &pos1 = unit->getPos(); - const int &size = unit->getType()->getSize(); - const Field &field = unit->getCurrField(); - - AnnotatedMap *annotatedMap = world->getCartographer()->getMasterMap(); - if (!annotatedMap->canOccupy(pos2, size, field)) { - return false; // obstruction in field - } - if ( pos1.x != pos2.x && pos1.y != pos2.y ) { - // Proposed move is diagonal, check if cells either 'side' are free. - // eg.. XXXX - // X1FX The Cells marked 'F' must both be free - // XF2X for the move 1->2 to be legit - // XXXX - Vec2i diag1, diag2; - getDiags(pos1, pos2, size, diag1, diag2); - if (!annotatedMap->canOccupy(diag1, 1, field) || !annotatedMap->canOccupy(diag2, 1, field) - || !world->getMap()->getCell(diag1)->isFree(field) - || !world->getMap()->getCell(diag2)->isFree(field)) { - return false; // obstruction, can not move to pos2 - } - } - for (int i = pos2.x; i < unit->getType()->getSize() + pos2.x; ++i) { - for (int j = pos2.y; j < unit->getType()->getSize() + pos2.y; ++j) { - if (world->getMap()->getCell(i,j)->getUnit(field) != unit - && !world->getMap()->isFreeCell(Vec2i(i, j), field)) { - return false; // blocked by another unit - } - } - } - // pos2 is free, and nothing is in the way - return true; -} - -string log_prelude(World *w, Unit *u) { - stringstream ss; - ss << "Frame: " << w->getFrameCount() << ", Unit: " << u->getId() << ", "; - return ss.str(); -} - -ostream& operator<<(ostream &stream, const list &posList) { - list::const_iterator itBegin = posList.begin(); - list::const_iterator itEnd = posList.end(); - list::const_iterator it = itBegin; - stream << " [ "; - for ( ; it != itEnd; ++it) { - if (it != itBegin) { - stream << ", "; - } - stream << *it; - } - stream << " ] "; - return stream; -} - -TravelState RoutePlanner::findPathToResource(Unit *unit, const Vec2i &targetPos, const ResourceType *rt) { - PF_TRACE(); - assert(rt && (rt->getClass() == rcTech || rt->getClass() == rcTileset)); - ResourceMapKey mapKey(rt, unit->getCurrField(), unit->getType()->getSize()); - PMap1Goal goal(world->getCartographer()->getResourceMap(mapKey)); - - PF_DEBUG(log_prelude(world, unit) << "findPathToResource() targetPos: " << targetPos - << ", resource type: " << rt->getName()); - - return findPathToGoal(unit, goal, targetPos); -} - -TravelState RoutePlanner::findPathToStore(Unit *unit, const Unit *store) { - PF_TRACE(); - Vec2i target = store->getCenteredPos(); - PMap1Goal goal(world->getCartographer()->getStoreMap(store, unit)); - - PF_DEBUG(log_prelude(world, unit) << "findPathToStore() store: " << store->getId()); - - return findPathToGoal(unit, goal, target); -} - -TravelState RoutePlanner::findPathToBuildSite(Unit *unit, const UnitType *bType, - const Vec2i &bPos, CardinalDir bFacing) { - PF_TRACE(); - PatchMap<1> *pMap = world->getCartographer()->getSiteMap(bType, bPos, bFacing, unit); - PMap1Goal goal(pMap); - - PF_DEBUG(log_prelude(world, unit) << "findPathToBuildSite() " << "building type: " << bType->getName() - << ", building pos: " << bPos << ", building facing = " << bFacing); - - return findPathToGoal(unit, goal, bPos + Vec2i(bType->getSize() / 2)); -} - - -float RoutePlanner::quickSearch(Field field, int size, const Vec2i &start, const Vec2i &dest) { - PF_TRACE(); - // setup search - MoveCost moveCost(field, size, world->getCartographer()->getMasterMap()); - DiagonalDistance heuristic(dest); - nsgSearchEngine->setStart(start, heuristic(start)); - - PosGoal goal(dest); - AStarResult r = nsgSearchEngine->aStar(goal, moveCost, heuristic); - if (r == asrComplete && nsgSearchEngine->getGoalPos() == dest) { - return nsgSearchEngine->getCostTo(dest); - } - return -1.f; -} - -HAAStarResult RoutePlanner::setupHierarchicalOpenList(Unit *unit, const Vec2i &target) { - // get Transitions for start cluster - Transitions transitions; - Vec2i startCluster = ClusterMap::cellToCluster(unit->getPos()); - ClusterMap *clusterMap = world->getCartographer()->getClusterMap(); - clusterMap->getTransitions(startCluster, unit->getCurrField(), transitions); - - DiagonalDistance dd(target); - nsgSearchEngine->getNeighbourFunc().setSearchCluster(startCluster); - - bool startTrap = true; - // attempt quick path from unit->pos to each transition, - // if successful add transition to open list - - AnnotatedMap *aMap = world->getCartographer()->getMasterMap(); - aMap->annotateLocal(unit); - for (Transitions::iterator it = transitions.begin(); it != transitions.end(); ++it) { - float cost = quickSearch(unit->getCurrField(), unit->getType()->getSize(), unit->getPos(), (*it)->nwPos); - if (cost != -1.f) { - tSearchEngine->setOpen(*it, dd((*it)->nwPos), cost); - startTrap = false; - } - } - aMap->clearLocalAnnotations(unit); - if (startTrap) { - // do again, without annnotations, return TRAPPED if all else goes well - bool locked = true; - for (Transitions::iterator it = transitions.begin(); it != transitions.end(); ++it) { - float cost = quickSearch(unit->getCurrField(), unit->getType()->getSize(), unit->getPos(), (*it)->nwPos); - if (cost != -1.f) { - tSearchEngine->setOpen(*it, dd((*it)->nwPos), cost); - locked = false; - } - } - if (locked) { - return hsrFailed; - } - return hsrStartTrap; - } - return hsrComplete; -} - -HAAStarResult RoutePlanner::setupHierarchicalSearch(Unit *unit, const Vec2i &dest, TransitionGoal &goalFunc) { - PF_TRACE(); - - // set-up open list - HAAStarResult res = setupHierarchicalOpenList(unit, dest); - if (res == hsrFailed) { - return hsrFailed; - } - bool startTrap = res == hsrStartTrap; - - // transitions to goal - Transitions transitions; - Vec2i cluster = ClusterMap::cellToCluster(dest); - world->getCartographer()->getClusterMap()->getTransitions(cluster, unit->getCurrField(), transitions); - nsgSearchEngine->getNeighbourFunc().setSearchCluster(cluster); - - bool goalTrap = true; - // attempt quick path from dest to each transition, - // if successful add transition to goal set - for (Transitions::iterator it = transitions.begin(); it != transitions.end(); ++it) { - float cost = quickSearch(unit->getCurrField(), unit->getType()->getSize(), dest, (*it)->nwPos); - if (cost != -1.f) { - goalFunc.goalTransitions().insert(*it); - goalTrap = false; - } - } - return startTrap ? hsrStartTrap - : goalTrap ? hsrGoalTrap - : hsrComplete; -} - -HAAStarResult RoutePlanner::findWaypointPath(Unit *unit, const Vec2i &dest, WaypointPath &waypoints) { - PF_TRACE(); - TransitionGoal goal; - HAAStarResult setupResult = setupHierarchicalSearch(unit, dest, goal); - nsgSearchEngine->getNeighbourFunc().setSearchSpace(ssCellMap); - if (setupResult == hsrFailed) { - return hsrFailed; - } - TransitionCost cost(unit->getCurrField(), unit->getType()->getSize()); - TransitionHeuristic heuristic(dest); - AStarResult res = tSearchEngine->aStar(goal,cost,heuristic); - if (res == asrComplete) { - WaypointPath &wpPath = *unit->getWaypointPath(); - wpPath.clear(); - waypoints.push(dest); - const Transition *t = tSearchEngine->getGoalPos(); - while (t) { - waypoints.push(t->nwPos); - t = tSearchEngine->getPreviousPos(t); - } - return setupResult; - } - return hsrFailed; -} - -/** goal function for search on cluster map when goal position is unexplored */ -class UnexploredGoal { -private: - set potentialGoals; - int team; - Map *map; - -public: - UnexploredGoal(Map *map, int teamIndex) : team(teamIndex), map(map) {} - bool operator()(const Transition *t, const float d) const { - Edges::const_iterator it = t->edges.begin(); - for ( ; it != t->edges.end(); ++it) { - if (!map->getSurfaceCell(Map::toSurfCoords((*it)->transition()->nwPos))->isExplored(team)) { - // leads to unexplored area, is a potential goal - const_cast(this)->potentialGoals.insert(t); - return false; - } - } - // always 'fails', is used to build a list of possible 'avenues of exploration' - return false; - } - - /** returns the best 'potential goal' transition found, or null if no potential goals */ - const Transition* getBestSeen(const Vec2i &currPos, const Vec2i &target) { - const Transition *best = 0; - float distToBest = Shared::Graphics::infinity;//1e6f//numeric_limits::infinity(); - set::iterator itEnd = potentialGoals.end(); - for (set::iterator it = potentialGoals.begin(); it != itEnd; ++it) { - float myDist = (*it)->nwPos.dist(target) + (*it)->nwPos.dist(currPos); - if (myDist < distToBest) { - best = *it; - distToBest = myDist; - } - } - return best; - } -}; - -/** cost function for searching cluster map with an unexplored target */ -class UnexploredCost { - Field field; - int size; - int team; - Map *map; - -public: - UnexploredCost(Field f, int s, int team, Map *map) : field(f), size(s), team(team), map(map) {} - float operator()(const Transition *t, const Transition *t2) const { - Edges::const_iterator it = t->edges.begin(); - for ( ; it != t->edges.end(); ++it) { - if ((*it)->transition() == t2) { - break; - } - } - assert(it != t->edges.end()); - if ((*it)->maxClear() >= size - && map->getSurfaceCell(Map::toSurfCoords((*it)->transition()->nwPos))->isExplored(team)) { - return (*it)->cost(size); - } - return -1.f; - } -}; - -HAAStarResult RoutePlanner::findWaypointPathUnExplored(Unit *unit, const Vec2i &dest, WaypointPath &waypoints) { - // set-up open list - HAAStarResult res = setupHierarchicalOpenList(unit, dest); - nsgSearchEngine->getNeighbourFunc().setSearchSpace(ssCellMap); - if (res == hsrFailed) { - return hsrFailed; - } - //bool startTrap = res == hsrStartTrap; - UnexploredGoal goal(world->getMap(), unit->getTeam()); - UnexploredCost cost(unit->getCurrField(), unit->getType()->getSize(), unit->getTeam(), world->getMap()); - TransitionHeuristic heuristic(dest); - tSearchEngine->aStar(goal, cost, heuristic); - const Transition *t = goal.getBestSeen(unit->getPos(), dest); - if (!t) { - return hsrFailed; - } - WaypointPath &wpPath = *unit->getWaypointPath(); - wpPath.clear(); - while (t) { - waypoints.push(t->nwPos); - t = tSearchEngine->getPreviousPos(t); - } - return res; // return setup res (in case of start trap) -} - - -/** refine waypoint path, extend low level path to next waypoint. - * @return true if successful, in which case waypoint will have been popped. - * false on failure, in which case waypoint will not be popped. */ -bool RoutePlanner::refinePath(Unit *unit) { - PF_TRACE(); - WaypointPath &wpPath = *unit->getWaypointPath(); - - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; - assert(!wpPath.empty()); - - const Vec2i &startPos = path.empty() ? unit->getPos() : path.back(); - const Vec2i &destPos = wpPath.front(); - AnnotatedMap *aMap = world->getCartographer()->getAnnotatedMap(unit); - - MoveCost cost(unit, aMap); - DiagonalDistance dd(destPos); - PosGoal posGoal(destPos); - - nsgSearchEngine->setStart(startPos, dd(startPos)); - AStarResult res = nsgSearchEngine->aStar(posGoal, cost, dd); - if (res != asrComplete) { - return false; - } -// IF_DEBUG_EDITION( collectOpenClosed(nsgSearchEngine->getStorage()); ) - // extract path - Vec2i pos = nsgSearchEngine->getGoalPos(); - assert(pos == destPos); - list::iterator it = path.end(); - while (pos.x != -1) { - it = path.insert(it, pos); - pos = nsgSearchEngine->getPreviousPos(pos); - } - // erase start point (already on path or is start pos) - it = path.erase(it); - // pop waypoint - wpPath.pop(); - return true; -} - -#undef max - -void RoutePlanner::smoothPath(Unit *unit) { - PF_TRACE(); - UnitPathInterface *path = unit->getPath(); - UnitPath *advPath = dynamic_cast(path); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - if (advPath->size() < 3) { - return; - } - AnnotatedMap* const &aMap = world->getCartographer()->getMasterMap(); - int min_x = 1 << 17, - max_x = -1, - min_y = 1 << 17, - max_y = -1; - set onPath; - UnitPath::iterator it = advPath->begin(); - for ( ; it != advPath->end(); ++it) { - if (it->x < min_x) min_x = it->x; - if (it->x > max_x) max_x = it->x; - if (it->y < min_y) min_y = it->y; - if (it->y > max_y) max_y = it->y; - onPath.insert(*it); - } - Rect2i bounds(min_x, min_y, max_x + 1, max_y + 1); - - it = advPath->begin(); - UnitPath::iterator nit = it; - ++nit; - - while (nit != advPath->end()) { - onPath.erase(*it); - Vec2i sp = *it; - for (int d = 0; d < odCount; ++d) { - Vec2i p = *it + OrdinalOffsets[d]; - if (p == *nit) continue; - Vec2i intersect(-1); - while (bounds.isInside(p)) { - if (!aMap->canOccupy(p, unit->getType()->getSize(), unit->getCurrField())) { - break; - } - if (d % 2 == 1) { // diagonal - Vec2i off1, off2; - getDiags(p - OrdinalOffsets[d], p, unit->getType()->getSize(), off1, off2); - if (!aMap->canOccupy(off1, 1, unit->getCurrField()) - || !aMap->canOccupy(off2, 1, unit->getCurrField())) { - break; - } - } - if (onPath.find(p) != onPath.end()) { - intersect = p; - break; - } - p += OrdinalOffsets[d]; - } - if (intersect != Vec2i(-1)) { - UnitPath::iterator eit = nit; - while (*eit != intersect) { - onPath.erase(*eit++); - } - nit = advPath->erase(nit, eit); - sp += OrdinalOffsets[d]; - while (sp != intersect) { - advPath->insert(nit, sp); - onPath.insert(sp); // do we need this? Can these get us further hits ?? - sp += OrdinalOffsets[d]; - } - break; // break foreach direction - } // if shortcut - } // foreach direction - nit = ++it; - ++nit; - } -} - -TravelState RoutePlanner::doRouteCache(Unit *unit) { - PF_TRACE(); - - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; - WaypointPath &wpPath = *unit->getWaypointPath(); - assert(unit->getPos().dist(path.front()) < 1.5f); - if (attemptMove(unit)) { - if (!wpPath.empty() && path.size() < 12) { - // if there are less than 12 steps left on this path, and there are more waypoints -// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), wpPath.back()); ) - while (!wpPath.empty() && path.size() < 24) { - // refine path to at least 24 steps (or end of path) - if (!refinePath(unit)) { - CONSOLE_LOG( "refinePath() failed. [route cache]" ) - wpPath.clear(); // path has become invalid - break; - } - } - smoothPath(unit); - PF_DEBUG(log_prelude(world, unit) << " MOVING [route cahce hit] from " << unit->getPos() - << " to " << unit->getTargetPos()); - PF_DEBUG(log_prelude(world, unit) << "[low-level path further refined]"); - if (!wpPath.empty()) { - PF_DEBUG("Waypoint Path: " << wpPath); - } - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } -// IF_DEBUG_EDITION( collectPath(unit); ) - } else { - PF_DEBUG(log_prelude(world, unit) << " MOVING [route cahce hit] from " << unit->getPos() - << " to " << unit->getTargetPos()); - } - - return tsMoving; - } - // path blocked, quickSearch to next waypoint... -// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), wpPath.empty() ? path.back() : wpPath.front()); ) - if (repairPath(unit) && attemptMove(unit)) { -// IF_DEBUG_EDITION( collectPath(unit); ) - PF_DEBUG(log_prelude(world, unit) << " MOVING [cached path repaired] from " << unit->getPos() - << " to " << unit->getTargetPos()); - if (!wpPath.empty()) { - PF_DEBUG("Waypoint Path: " << wpPath); - } - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - return tsMoving; - } - unit->setCurrSkill(scStop); - return tsBlocked; -} - -TravelState RoutePlanner::doQuickPathSearch(Unit *unit, const Vec2i &target) { - PF_TRACE(); - AnnotatedMap *aMap = world->getCartographer()->getAnnotatedMap(unit); - - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; -// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), target); ) - aMap->annotateLocal(unit); - float cost = quickSearch(unit->getCurrField(), unit->getType()->getSize(), unit->getPos(), target); - aMap->clearLocalAnnotations(unit); -// IF_DEBUG_EDITION( collectOpenClosed(nodeStore); ) - if (cost != -1.f) { - Vec2i pos = nsgSearchEngine->getGoalPos(); - while (pos.x != -1) { - path.push_front(pos); - pos = nsgSearchEngine->getPreviousPos(pos); - } - if (path.size() > 1) { - path.pop(); - if (attemptMove(unit)) { -// IF_DEBUG_EDITION( collectPath(unit); ) - PF_DEBUG(log_prelude(world, unit) << " MOVING [doQuickPathSearch() Ok.] from " << unit->getPos() - << " to " << unit->getTargetPos()); - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - return tsMoving; - } - } - path.clear(); - } - PF_DEBUG(log_prelude(world, unit) << "doQuickPathSearch() : Failed."); - return tsBlocked; -} - -TravelState RoutePlanner::findAerialPath(Unit *unit, const Vec2i &targetPos) { - PF_TRACE(); - AnnotatedMap *aMap = world->getCartographer()->getMasterMap(); - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; - PosGoal goal(targetPos); - MoveCost cost(unit, aMap); - DiagonalDistance dd(targetPos); - - nsgSearchEngine->setNodeLimit(256); - nsgSearchEngine->setStart(unit->getPos(), dd(unit->getPos())); - - aMap->annotateLocal(unit); - AStarResult res = nsgSearchEngine->aStar(goal, cost, dd); - aMap->clearLocalAnnotations(unit); - if (res == asrComplete || res == asrNodeLimit) { - Vec2i pos = nsgSearchEngine->getGoalPos(); - while (pos.x != -1) { - path.push_front(pos); - pos = nsgSearchEngine->getPreviousPos(pos); - } - if (path.size() > 1) { - path.pop(); - if (attemptMove(unit)) { - PF_DEBUG(log_prelude(world, unit) << " MOVING [aerial path search Ok.] from " << unit->getPos() - << " to " << unit->getTargetPos()); - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - return tsMoving; - } - } else { - path.clear(); - } - } - PF_DEBUG(log_prelude(world, unit) << " BLOCKED [aerial path search failed.]"); - path.incBlockCount(); - unit->setCurrSkill(scStop); - return tsBlocked; -} - -/** Find a path to a location. - * @param unit the unit requesting the path - * @param finalPos the position the unit desires to go to - * @return ARRIVED, MOVING, BLOCKED or IMPOSSIBLE - */ -TravelState RoutePlanner::findPathToLocation(Unit *unit, const Vec2i &finalPos) { - PF_TRACE(); - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; - WaypointPath &wpPath = *unit->getWaypointPath(); - - // if arrived (where we wanted to go) - if(finalPos == unit->getPos()) { - unit->setCurrSkill(scStop); - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() : ARRIVED [1]"); - return tsArrived; - } - // route cache - if (!path.empty()) { - if (doRouteCache(unit) == tsMoving) { - return tsMoving; - } - } - // route cache miss or blocked - const Vec2i &target = computeNearestFreePos(unit, finalPos); - - // if arrived (as close as we can get to it) - if (target == unit->getPos()) { - unit->setCurrSkill(scStop); - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() : ARRIVED [2]"); - return tsArrived; - } - path.clear(); - wpPath.clear(); - - if (unit->getCurrField() == fAir) { - return findAerialPath(unit, target); - } - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() " << "target pos: " << finalPos); - - // QuickSearch if close to target - Vec2i startCluster = ClusterMap::cellToCluster(unit->getPos()); - Vec2i destCluster = ClusterMap::cellToCluster(target); - if (startCluster.dist(destCluster) < 3.f) { - if (doQuickPathSearch(unit, target) == tsMoving) { - return tsMoving; - } - } - PF_TRACE(); - - // Hierarchical Search - tSearchEngine->reset(); - Map *map = world->getMap(); - HAAStarResult res; - if (map->getSurfaceCell(Map::toSurfCoords(target))->isExplored(unit->getTeam())) { - res = findWaypointPath(unit, target, wpPath); - } else { - res = findWaypointPathUnExplored(unit, target, wpPath); - } - if (res == hsrFailed) { - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() IMPOSSIBLE"); - if (unit->getFaction()->getThisFaction()) { - world->getGame()->getConsole()->addLine(Lang::getInstance().get("InvalidPosition")); - } - return tsImpossible; - } else if (res == hsrStartTrap) { - if (wpPath.size() < 2) { - unit->setCurrSkill(scStop); - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() BLOCKED [START_TRAP]"); - return tsBlocked; - } - } - PF_TRACE(); - - // IF_DEBUG_EDITION( collectWaypointPath(unit); ) - if (wpPath.size() > 1) { - wpPath.pop(); - } - assert(!wpPath.empty()); - - // IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), target); ) - // refine path, to at least 20 steps (or end of path) - AnnotatedMap *aMap = world->getCartographer()->getMasterMap(); - aMap->annotateLocal(unit); - wpPath.condense(); - while (!wpPath.empty() && path.size() < 20) { - if (!refinePath(unit)) { - aMap->clearLocalAnnotations(unit); - path.incBlockCount(); - unit->setCurrSkill(scStop); - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() BLOCKED [refinePath() failed]"); - return tsBlocked; - } - } - smoothPath(unit); - aMap->clearLocalAnnotations(unit); -// IF_DEBUG_EDITION( collectPath(unit); ) - if (path.empty()) { - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() : BLOCKED ... [post hierarchical search failure, path empty.]" ); - unit->setCurrSkill(scStop); - return tsBlocked; - } - if (attemptMove(unit)) { - PF_DEBUG(log_prelude(world, unit) << " MOVING [Hierarchical Search Ok.] from " << unit->getPos() - << " to " << unit->getTargetPos()); - if (!wpPath.empty()) { - PF_DEBUG("Waypoint Path: " << wpPath); - } - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - return tsMoving; - } - PF_DEBUG(log_prelude(world, unit) << "findPathToLocation() : BLOCKED ... [possible invalid path?]"); - if (!wpPath.empty()) { - PF_DEBUG("Waypoint Path: " << wpPath); - } - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - unit->setCurrSkill(scStop); - path.incBlockCount(); - return tsBlocked; -} - -TravelState RoutePlanner::customGoalSearch(PMap1Goal &goal, Unit *unit, const Vec2i &target) { - PF_TRACE(); - - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; - //WaypointPath &wpPath = *unit->getWaypointPath(); - const Vec2i &start = unit->getPos(); - - // setup search - AnnotatedMap *aMap = world->getCartographer()->getMasterMap(); - MoveCost moveCost(unit->getCurrField(), unit->getType()->getSize(), aMap); - DiagonalDistance heuristic(target); - nsgSearchEngine->setNodeLimit(512); - nsgSearchEngine->setStart(start, heuristic(start)); - - aMap->annotateLocal(unit); - AStarResult r = nsgSearchEngine->aStar(goal, moveCost, heuristic); - aMap->clearLocalAnnotations(unit); - - PF_TRACE(); - if (r == asrComplete) { - Vec2i pos = nsgSearchEngine->getGoalPos(); -// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), pos); ) -// IF_DEBUG_EDITION( collectOpenClosed(nsgSearchEngine->getStorage()); ) - while (pos.x != -1) { - path.push_front(pos); - pos = nsgSearchEngine->getPreviousPos(pos); - } - if (!path.empty()) path.pop(); -// IF_DEBUG_EDITION( collectPath(unit); ) - if (!path.empty() && attemptMove(unit)) { - return tsMoving; - } - path.clear(); - } - return tsBlocked; -} - -TravelState RoutePlanner::findPathToGoal(Unit *unit, PMap1Goal &goal, const Vec2i &target) { - PF_TRACE(); - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; - WaypointPath &wpPath = *unit->getWaypointPath(); - - // if at goal - if (goal(unit->getPos(), 0.f)) { - unit->setCurrSkill(scStop); - PF_DEBUG(log_prelude(world, unit) << "ARRIVED."); - return tsArrived; - } - // route chache - if (!path.empty()) { - if (doRouteCache(unit) == tsMoving) { - return tsMoving; - } - path.clear(); - wpPath.clear(); - } - // try customGoalSearch if close to target - if (unit->getPos().dist(target) < 50.f) { - if (customGoalSearch(goal, unit, target) == tsMoving) { - PF_DEBUG(log_prelude(world, unit) << " MOVING [customGoalSearch() Ok.] from " << unit->getPos() - << " to " << unit->getTargetPos()); - if (!wpPath.empty()) { - PF_DEBUG("Waypoint Path: " << wpPath); - } - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - return tsMoving; - } else { - PF_DEBUG(log_prelude(world, unit) << "BLOCKED. [customGoalSearch() Failed.]"); - unit->setCurrSkill(scStop); - return tsBlocked; - } - } - - PF_TRACE(); - // Hierarchical Search - tSearchEngine->reset(); - if (!findWaypointPath(unit, target, wpPath)) { - PF_DEBUG(log_prelude(world, unit) << "IMPOSSIBLE."); - if (unit->getFaction()->getThisFaction()) { - //console.add(lang.get("Unreachable")); - } - return tsImpossible; - } -// IF_DEBUG_EDITION( collectWaypointPath(unit); ) - assert(wpPath.size() > 1); - wpPath.pop(); -// IF_DEBUG_EDITION( clearOpenClosed(unit->getPos(), target); ) - // cull destination and waypoints close to it, when we get to the last remaining - // waypoint we'll do a 'customGoalSearch' to the target - while (wpPath.size() > 1 && wpPath.back().dist(target) < 32.f) { - wpPath.pop_back(); - } - // refine path, to at least 20 steps (or end of path) - AnnotatedMap *aMap = world->getCartographer()->getMasterMap(); - aMap->annotateLocal(unit); - while (!wpPath.empty() && path.size() < 20) { - if (!refinePath(unit)) { - aMap->clearLocalAnnotations(unit); - unit->setCurrSkill(scStop); - PF_DEBUG(log_prelude(world, unit) << "BLOCKED [refinePath() failed]."); - return tsBlocked; - } - } - smoothPath(unit); - aMap->clearLocalAnnotations(unit); -// IF_DEBUG_EDITION( collectPath(unit); ) - if (attemptMove(unit)) { - PF_DEBUG(log_prelude(world, unit) << " MOVING [Hierarchical Search Ok.] from " << unit->getPos() - << " to " << unit->getTargetPos()); - if (!wpPath.empty()) { - PF_DEBUG("Waypoint Path: " << wpPath); - } - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - return tsMoving; - } - PF_DEBUG(log_prelude(world, unit) << "BLOCKED [hierarchical search, possible invalid path]."); - CONSOLE_LOG( "Hierarchical refined path blocked ? valid ?!? [Custom Goal Search]" ) - if (!wpPath.empty()) { - PF_DEBUG("Waypoint Path: " << wpPath); - } - if (!path.empty()) { - PF_DEBUG("LowLevel Path: " << path); - } - unit->setCurrSkill(scStop); - return tsBlocked; -} - -/** repair a blocked path - * @param unit unit whose path is blocked - * @return true if repair succeeded */ -bool RoutePlanner::repairPath(Unit *unit) { - PF_TRACE(); - UnitPathInterface *unitpath = unit->getPath(); - UnitPath *advPath = dynamic_cast(unitpath); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - UnitPath &path = *advPath; - WaypointPath &wpPath = *unit->getWaypointPath(); - - Vec2i dest; - if (path.size() < 10 && !wpPath.empty()) { - dest = wpPath.front(); - } else { - dest = path.back(); - } - path.clear(); - - AnnotatedMap *aMap = world->getCartographer()->getAnnotatedMap(unit); - aMap->annotateLocal(unit); - if (quickSearch(unit->getCurrField(), unit->getType()->getSize(), unit->getPos(), dest) != -1.f) { - Vec2i pos = nsgSearchEngine->getGoalPos(); - while (pos.x != -1) { - path.push_front(pos); - pos = nsgSearchEngine->getPreviousPos(pos); - } - if (path.size() > 2) { - path.pop(); - if (!wpPath.empty() && wpPath.front() == path.back()) { - wpPath.pop(); - } - } else { - path.clear(); - } - } - aMap->clearLocalAnnotations(unit); - if (!path.empty()) { -// IF_DEBUG_EDITION ( -// collectOpenClosed(nsgSearchEngine->getStorage()); -// collectPath(unit); -// ) - return true; - } - return false; -} - -#if _GAE_DEBUG_EDITION_ - -TravelState RoutePlanner::doFullLowLevelAStar(Unit *unit, const Vec2i &dest) { - UnitPath &path = *unit->getPath(); - WaypointPath &wpPath = *unit->getWaypointPath(); - const Vec2i &target = computeNearestFreePos(unit, dest); - // if arrived (as close as we can get to it) - if (target == unit->getPos()) { - unit->setCurrSkill(scStop); - return tsArrived; - } - path.clear(); - wpPath.clear(); - - // Low Level Search with NodeMap (this is for testing purposes only, not node limited) - - // this is the 'straight' A* using the NodeMap (no node limit) - AnnotatedMap *aMap = g_world.getCartographer()->getAnnotatedMap(unit); - SearchEngine *se = g_world.getCartographer()->getSearchEngine(); - DiagonalDistance dd(target); - MoveCost cost(unit, aMap); - PosGoal goal(target); - se->setNodeLimit(-1); - se->setStart(unit->getPos(), dd(unit->getPos())); - AStarResult res = se->aStar(goal,cost,dd); - list::iterator it; - IF_DEBUG_EDITION ( - list *nodes = NULL; - NodeMap* nm = se->getStorage(); - ) - Vec2i goalPos, pos; - switch (res) { - case asrComplete: - goalPos = se->getGoalPos(); - pos = goalPos; - while (pos.x != -1) { - path.push(pos); - pos = se->getPreviousPos(pos); - } - if (!path.empty()) path.pop(); - IF_DEBUG_EDITION ( - collectOpenClosed(se->getStorage()); - collectPath(unit); - ) - break; // case asrComplete - - case AStarResult::FAILURE: - return tsImpossible; - - default: - throw megaglest_runtime_error("Something that shouldn't have happened, did happen :("); - } - if (path.empty()) { - unit->setCurrSkill(scStop); - return tsArrived; - } - if (attemptMove(unit)) return tsMoving; // should always succeed (if local annotations were applied) - unit->setCurrSkill(scStop); - path.incBlockCount(); - return tsBlocked; -} - -#endif // _GAE_DEBUG_EDITION_ - -// ==================== PRIVATE ==================== - -// return finalPos if free, else a nearest free pos within maxFreeSearchRadius -// cells, or unit's current position if none found -// -/** find nearest free position a unit can occupy - * @param unit the unit in question - * @param finalPos the position unit wishes to be - * @return finalPos if free and occupyable by unit, else the closest such position, or the unit's - * current position if none found - * @todo reimplement with Dijkstra search - */ -Vec2i RoutePlanner::computeNearestFreePos(const Unit *unit, const Vec2i &finalPos) { - PF_TRACE(); - //unit data - Vec2i unitPos= unit->getPos(); - int size= unit->getType()->getSize(); - Field field = unit->getCurrField(); - int teamIndex= unit->getTeam(); - - //if finalPos is free return it - if (world->getMap()->isAproxFreeCells(finalPos, size, field, teamIndex)) { - return finalPos; - } - - //find nearest pos - Vec2i nearestPos = unitPos; - float nearestDist = unitPos.dist(finalPos); - for (int i = -maxFreeSearchRadius; i <= maxFreeSearchRadius; ++i) { - for (int j = -maxFreeSearchRadius; j <= maxFreeSearchRadius; ++j) { - Vec2i currPos = finalPos + Vec2i(i, j); - if (world->getMap()->isAproxFreeCells(currPos, size, field, teamIndex)) { - float dist = currPos.dist(finalPos); - - //if nearer from finalPos - if (dist < nearestDist) { - nearestPos = currPos; - nearestDist = dist; - //if the distance is the same compare distance to unit - } else if (dist == nearestDist) { - if (currPos.dist(unitPos) < nearestPos.dist(unitPos)) { - nearestPos = currPos; - } - } - } - } - } - return nearestPos; -} - -}} // end namespace Glest::Game::Search - diff --git a/source/glest_game/ai/route_planner.h b/source/glest_game/ai/route_planner.h deleted file mode 100644 index cbb55d45..00000000 --- a/source/glest_game/ai/route_planner.h +++ /dev/null @@ -1,290 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2001-2008 Martiño Figueroa -// 2009-2010 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifndef _GLEST_GAME_ROUTEPLANNER_H_ -#define _GLEST_GAME_ROUTEPLANNER_H_ - -#ifdef WIN32 - #include - #include -#endif - -#include "game_constants.h" -#include "influence_map.h" -#include "annotated_map.h" -#include "cluster_map.h" -#include "config.h" -#include "profiler.h" - -#include "search_engine.h" -#include "cartographer.h" -#include "node_pool.h" - -#include "world.h" -#include "data_types.h" - -#define PF_TRACE() SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__) - -using Shared::Graphics::Vec2i; -using Shared::Platform::uint32; - -namespace Glest { namespace Game { - -/** maximum radius to search for a free position from a target position */ -const int maxFreeSearchRadius = 10; -/** @deprecated not in use */ -const int pathFindNodesMax = 2048; - -typedef SearchEngine TransitionSearchEngine; - -class PMap1Goal { -protected: - PatchMap<1> *pMap; - -public: - PMap1Goal(PatchMap<1> *pMap) : pMap(pMap) {} - - bool operator()(const Vec2i &pos, const float) const { - if (pMap->getInfluence(pos)) { - return true; - } - return false; - } -}; - -/** gets the two 'diagonal' cells to check for obstacles when a unit is moving diagonally - * @param s start pos - * @param d destination pos - * @param size size of unit - * @return d1 & d2, the two cells to check - * @warning assumes s & d are indeed diagonal, abs(s.x - d.x) == 1 && abs(s.y - d.y) == 1 - */ -__inline void getDiags(const Vec2i &s, const Vec2i &d, const int size, Vec2i &d1, Vec2i &d2) { -# define _SEARCH_ENGINE_GET_DIAGS_DEFINED_ - assert(abs(s.x - d.x) == 1 && abs(s.y - d.y) == 1); - if (size == 1) { - d1.x = s.x; d1.y = d.y; - d2.x = d.x; d2.y = s.y; - return; - } - if (d.x > s.x) { // travelling east - if (d.y > s.y) { // se - d1.x = d.x + size - 1; d1.y = s.y; - d2.x = s.x; d2.y = d.y + size - 1; - } else { // ne - d1.x = s.x; d1.y = d.y; - d2.x = d.x + size - 1; d2.y = s.y + size - 1; - } - } else { // travelling west - if (d.y > s.y) { // sw - d1.x = d.x; d1.y = s.y; - d2.x = s.x + size - 1; d2.y = d.y + size - 1; - } else { // nw - d1.x = d.x; d1.y = s.y + size - 1; - d2.x = s.x + size - 1; d2.y = d.y; - } - } -} - -/** The movement cost function */ -class MoveCost { -private: - const int size; /**< size of agent */ - const Field field; /**< field to search in */ - const AnnotatedMap *aMap; /**< map to search on */ - -public: - MoveCost(const Unit *unit, const AnnotatedMap *aMap) - : size(unit->getType()->getSize()), field(unit->getCurrField()), aMap(aMap) {} - MoveCost(const Field field, const int size, const AnnotatedMap *aMap ) - : size(size), field(field), aMap(aMap) {} - - /** The cost function @param p1 position 1 @param p2 position 2 ('adjacent' p1) - * @return cost of move, possibly infinite */ - float operator()(const Vec2i &p1, const Vec2i &p2) const { - assert(p1.dist(p2) < 1.5 && p1 != p2); - //assert(g_map.isInside(p2)); - if (!aMap->canOccupy(p2, size, field)) { - return -1.f; - } - if (p1.x != p2.x && p1.y != p2.y) { - Vec2i d1, d2; - getDiags(p1, p2, size, d1, d2); - //assert(g_map.isInside(d1) && g_map.isInside(d2)); - if (!aMap->canOccupy(d1, 1, field) || !aMap->canOccupy(d2, 1, field) ) { - return -1.f; - } - return SQRT2; - } - return 1.f; - // todo... height - } -}; - -enum HAAStarResult { - hsrFailed, - hsrComplete, - hsrStartTrap, - hsrGoalTrap -}; - -// ===================================================== -// class RoutePlanner -// ===================================================== -/** Finds paths for units using SearchEngine<>::aStar<>() */ -class RoutePlanner { -public: - RoutePlanner(World *world); - ~RoutePlanner(); - - TravelState findPathToLocation(Unit *unit, const Vec2i &finalPos); - - /** @see findPathToLocation() */ - TravelState findPath(Unit *unit, const Vec2i &finalPos) { - return findPathToLocation(unit, finalPos); - } - - TravelState findPathToResource(Unit *unit, const Vec2i &targetPos, const ResourceType *rt); - - TravelState findPathToStore(Unit *unit, const Unit *store); - - TravelState findPathToBuildSite(Unit *unit, const UnitType *bType, const Vec2i &bPos, CardinalDir bFacing); - - bool isLegalMove(Unit *unit, const Vec2i &pos) const; - - SearchEngine* getSearchEngine() { return nsgSearchEngine; } - -private: - bool repairPath(Unit *unit); - - TravelState findAerialPath(Unit *unit, const Vec2i &targetPos); - - TravelState doRouteCache(Unit *unit); - TravelState doQuickPathSearch(Unit *unit, const Vec2i &target); - - TravelState findPathToGoal(Unit *unit, PMap1Goal &goal, const Vec2i &targetPos); - TravelState customGoalSearch(PMap1Goal &goal, Unit *unit, const Vec2i &target); - - float quickSearch(Field field, int Size, const Vec2i &start, const Vec2i &dest); - bool refinePath(Unit *unit); - void smoothPath(Unit *unit); - - HAAStarResult setupHierarchicalOpenList(Unit *unit, const Vec2i &target); - HAAStarResult setupHierarchicalSearch(Unit *unit, const Vec2i &dest, TransitionGoal &goalFunc); - HAAStarResult findWaypointPath(Unit *unit, const Vec2i &dest, WaypointPath &waypoints); - HAAStarResult findWaypointPathUnExplored(Unit *unit, const Vec2i &dest, WaypointPath &waypoints); - - World *world; - SearchEngine *nsgSearchEngine; - NodePool *nodeStore; - TransitionSearchEngine *tSearchEngine; - TransitionNodeStore *tNodeStore; - - Vec2i computeNearestFreePos(const Unit *unit, const Vec2i &targetPos); - - bool attemptMove(Unit *unit) const { - UnitPathInterface *path = unit->getPath(); - UnitPath *advPath = dynamic_cast(path); - if(advPath == NULL) { - throw megaglest_runtime_error("Invalid or NULL unit path pointer!"); - } - - assert(advPath->isEmpty() == false); - Vec2i pos = advPath->peek(); - if (isLegalMove(unit, pos)) { - unit->setTargetPos(pos); - advPath->pop(); - return true; - } - return false; - } -#if _GAE_DEBUG_EDITION_ - TravelState doFullLowLevelAStar(Unit *unit, const Vec2i &dest); -#endif -#if DEBUG_SEARCH_TEXTURES -public: - enum { SHOW_PATH_ONLY, SHOW_OPEN_CLOSED_SETS, SHOW_LOCAL_ANNOTATIONS } debug_texture_action; -#endif -}; // class RoutePlanner - - -/** Diaginal Distance Heuristic */ -class DiagonalDistance { -public: - DiagonalDistance(const Vec2i &target) : target(target) {} - /** search target */ - Vec2i target; - /** The heuristic function. @param pos the position to calculate the heuristic for - * @return an estimate of the cost to target */ - float operator()(const Vec2i &pos) const { - float dx = (float)abs(pos.x - target.x), - dy = (float)abs(pos.y - target.y); - float diag = dx < dy ? dx : dy; - float straight = dx + dy - 2 * diag; - return 1.4 * diag + straight; - } -}; - -/** Goal function for 'normal' search */ -class PosGoal { -private: - Vec2i target; /**< search target */ - -public: - PosGoal(const Vec2i &target) : target(target) {} - - /** The goal function @param pos position to test - * @param costSoFar the cost of the shortest path to pos - * @return true if pos is target, else false */ - bool operator()(const Vec2i &pos, const float costSoFar) const { - return pos == target; - } -}; - -//TODO: put these somewhere sensible -class TransitionHeuristic { - DiagonalDistance dd; -public: - TransitionHeuristic(const Vec2i &target) : dd(target) {} - bool operator()(const Transition *t) const { - return (dd(t->nwPos) != 0); - } -}; - -#if 0 == 1 -// -// just use DiagonalDistance to waypoint ?? -class AbstractAssistedHeuristic { -public: - AbstractAssistedHeuristic(const Vec2i &target, const Vec2i &waypoint, float wpCost) - : target(target), waypoint(waypoint), wpCost(wpCost) {} - /** search target */ - Vec2i target, waypoint; - float wpCost; - /** The heuristic function. - * @param pos the position to calculate the heuristic for - * @return an estimate of the cost to target - */ - float operator()(const Vec2i &pos) const { - float dx = (float)abs(pos.x - waypoint.x), - dy = (float)abs(pos.y - waypoint.y); - float diag = dx < dy ? dx : dy; - float straight = dx + dy - 2 * diag; - return 1.4 * diag + straight + wpCost; - - } -}; -#endif - -}} // namespace - -#endif diff --git a/source/glest_game/ai/search_engine.h b/source/glest_game/ai/search_engine.h deleted file mode 100644 index 77fa5c0b..00000000 --- a/source/glest_game/ai/search_engine.h +++ /dev/null @@ -1,290 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== -// -// search_engine.h - -#ifndef _GLEST_GAME_SEARCH_ENGINE_ -#define _GLEST_GAME_SEARCH_ENGINE_ - -#ifdef WIN32 - #include - #include -#endif - -#include "math_util.h" -#include "game_constants.h" - -/** Home of the templated A* algorithm and some of the bits that plug into it.*/ -namespace Glest { namespace Game { - -using Shared::Graphics::Vec2i; - -static const float SQRT2 = Shared::Graphics::sqrt2; - -enum OrdinalDir { - odNorth, odNorthEast, odEast, odSouthEast, odSouth, odSouthWest, odWest, odNorthWest, odCount -}; - -const Vec2i OrdinalOffsets[odCount] = { - Vec2i( 0, -1), // n - Vec2i( 1, -1), // ne - Vec2i( 1, 0), // e - Vec2i( 1, 1), // se - Vec2i( 0, 1), // s - Vec2i(-1, 1), // sw - Vec2i(-1, 0), // w - Vec2i(-1, -1) // nw -}; - -/* - // NodeStorage template interface - // - class NodeStorage { - public: - void reset(); - void setMaxNode( int limit ); - - bool isOpen( const Vec2i &pos ); - bool isClosed( const Vec2i &pos ); - - bool setOpen( const Vec2i &pos, const Vec2i &prev, float h, float d ); - void updateOpen( const Vec2i &pos, const Vec2i &prev, const float cost ); - Vec2i getBestCandidate(); - Vec2i getBestSeen(); - - float getHeuristicAt( const Vec2i &pos ); - float getCostTo( const Vec2i &pos ); - float getEstimateFor( const Vec2i &pos ); - Vec2i getBestTo( const Vec2i &pos ); - }; -*/ - -enum SearchSpace { ssCellMap, ssTileMap }; - -/** Neighbour function for 'octile grid map' as search domain */ -class GridNeighbours { -private: - int x, y; - int width, height; - const int cellWidth, cellHeight; - -public: - GridNeighbours(int cellWidth, int cellHeight) - : x(0), y(0) - , width(cellWidth) - , height(cellHeight) - , cellWidth(cellWidth) - , cellHeight(cellHeight) { - assert(cellWidth % GameConstants::cellScale == 0); - assert(cellHeight % GameConstants::cellScale == 0); - } - - void operator()(Vec2i &pos, vector &neighbours) const { - for (int i = 0; i < odCount; ++i) { - Vec2i nPos = pos + OrdinalOffsets[i]; - if (nPos.x >= x && nPos.x < x + width && nPos.y >= y && nPos.y < y + height) { - neighbours.push_back(nPos); - } - } - } - /** Kludge to search on Cellmap or Tilemap... templated search domain should deprecate this */ - void setSearchSpace(SearchSpace s) { - if (s == ssCellMap) { - x = y = 0; - width = cellWidth; - height = cellHeight; - } else if (s == ssTileMap) { - x = y = 0; - width = cellWidth / GameConstants::cellScale; - height= cellHeight / GameConstants::cellScale; - } - } - - /** more kludgy search restriction stuff... */ - void setSearchCluster(Vec2i cluster) { - x = cluster.x * GameConstants::clusterSize - 1; - if (x < 0) x = 0; - y = cluster.y * GameConstants::clusterSize - 1; - if (y < 0) y = 0; - width = GameConstants::clusterSize + 1; - height = GameConstants::clusterSize + 1; - } -}; - -enum AStarResult { - asrFailed, asrComplete, asrNodeLimit, asrTimeLimit -}; - -// ======================================================== -// class SearchEngine -// ======================================================== -/** Generic (template) A* - * @param NodeStorage NodeStorage class to use, must conform to implicit interface, see elsewhere - * @param NeighbourFunc the function to generate neighbours for a search domain - * @param DomainKey the key type of the search domain - */ -template< typename NodeStorage, typename NeighbourFunc = GridNeighbours, typename DomainKey = Vec2i > -class SearchEngine { -private: - NodeStorage *nodeStorage;/**< NodeStorage for this SearchEngine */ - DomainKey goalPos; /**< The goal pos (the 'result') from the last A* search */ - DomainKey invalidKey; /**< The DomainKey value indicating an invalid 'position' */ - int expandLimit, /**< limit on number of nodes to expand */ - nodeLimit, /**< limit on number of nodes to use */ - expanded; /**< number of nodes expanded this/last run */ - bool ownStore; /**< wether or not this SearchEngine 'owns' its storage */ - NeighbourFunc neighbourFunc; - -public: - /** construct & initialise NodeStorage - * @param store NodeStorage to use - * @param own wether the SearchEngine should own the storage - */ - SearchEngine(NeighbourFunc neighbourFunc, NodeStorage *store = 0, bool own=false) - : nodeStorage(store) - , expandLimit(-1) - , nodeLimit(-1) - , expanded(0) - , ownStore(own) - , neighbourFunc(neighbourFunc) { - } - - /** Detruct, will delete storage if ownStore was set true */ - ~SearchEngine() { - if (ownStore) { - delete nodeStorage; - } - } - - /** Attach NodeStorage - * @param store NodeStorage to use - * @param own wether the SearchEngine should own the storage - */ - void setStorage(NodeStorage *store, bool own=false) { - nodeStorage = store; - ownStore = own; - } - - /** Set the DomainKey value indicating an invalid position, this must be set before use! - * @param key the invalid DomainKey value - */ - void setInvalidKey(DomainKey key) { invalidKey = key; } - - /** @return a pointer to this engine's node storage */ - NodeStorage* getStorage() { return nodeStorage; } - - NeighbourFunc& getNeighbourFunc() { return neighbourFunc; } - - /** Reset the node storage */ - void reset() { nodeStorage->reset(); nodeStorage->setMaxNodes(nodeLimit > 0 ? nodeLimit : -1); } - - /** Add a position to the open set with 'd' cost to here and invalid prev (a start position) - * @param pos position to set as open - * @param h heuristc, estimate to goal from pos - * @param d distance or cost to node (optional, defaults to 0) - */ - void setOpen(DomainKey pos, float h, float d = 0.f) { - nodeStorage->setOpen(pos, invalidKey, h, d); - } - - /** Reset the node storage and add pos to open - * @param pos position to set as open - * @param h heuristc, estimate to goal from pos - * @param d distance or cost to node (optional, defaults to 0) - */ - void setStart(DomainKey pos, float h, float d = 0.f) { - nodeStorage->reset(); - if ( nodeLimit > 0 ) { - nodeStorage->setMaxNodes(nodeLimit); - } - nodeStorage->setOpen(pos, invalidKey, h, d); - } - - /** Retrieve the goal of last search, position of last goal reached */ - DomainKey getGoalPos() { return goalPos; } - - /** Best path to pos is from */ - DomainKey getPreviousPos(const DomainKey &pos) { return nodeStorage->getBestTo(pos); } - - /** limit search to use at most limit nodes */ - void setNodeLimit(int limit) { nodeLimit = limit > 0 ? limit : -1; } - - /** set an 'expanded nodes' limit, for a resumable search */ - void setTimeLimit(int limit) { expandLimit = limit > 0 ? limit : -1; } - - /** How many nodes were expanded last search */ - int getExpandedLastRun() { return expanded; } - - /** Retrieves cost to the node at pos (known to be visited) */ - float getCostTo(const DomainKey &pos) { - assert(nodeStorage->isOpen(pos) || nodeStorage->isClosed(pos)); - return nodeStorage->getCostTo(pos); - } - - /** A* Algorithm (Just the loop, does not do any setup or post-processing) - * @param GoalFunc template parameter Goal function class - * @param CostFunc template parameter Cost function class - * @param Heuristic template parameter Heuristic function class - * @param goalFunc goal function object - * @param costFunc cost function object - * @param heuristic heuristic function object - */ - template< typename GoalFunc, typename CostFunc, typename Heuristic > - AStarResult aStar(GoalFunc &goalFunc, CostFunc &costFunc, Heuristic &heuristic) { - expanded = 0; - DomainKey minPos(invalidKey); - vector neighbours; - while (true) { - // get best open - minPos = nodeStorage->getBestCandidate(); - if (minPos == invalidKey) { // failure - goalPos = invalidKey; - return asrFailed; - } - if (goalFunc(minPos, nodeStorage->getCostTo(minPos))) { // success - goalPos = minPos; - return asrComplete; - } - // expand it... - neighbourFunc(minPos, neighbours); - while (!neighbours.empty()) { - DomainKey nPos = neighbours.back(); - neighbours.pop_back(); - if (nodeStorage->isClosed(nPos)) { - continue; - } - float cost = costFunc(minPos, nPos); - if (cost == -1.f) { - continue; - } - if (nodeStorage->isOpen(nPos)) { - nodeStorage->updateOpen(nPos, minPos, cost); - } else { - const float &costToMin = nodeStorage->getCostTo(minPos); - if (!nodeStorage->setOpen(nPos, minPos, heuristic(nPos), costToMin + cost)) { - goalPos = nodeStorage->getBestSeen(); - return asrNodeLimit; - } - } - } - expanded++; - if (expanded == expandLimit) { // run limit - goalPos = invalidKey; - return asrTimeLimit; - } - } - return asrFailed; // impossible... just keeping the compiler from complaining - } -}; - -}} - -#endif diff --git a/source/glest_game/facilities/pos_iterator.cpp b/source/glest_game/facilities/pos_iterator.cpp deleted file mode 100644 index 60638ff5..00000000 --- a/source/glest_game/facilities/pos_iterator.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009-2010 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#include "pos_iterator.h" - -#include "leak_dumper.h" - -namespace Glest { namespace Util { - -Vec2i PerimeterIterator::next() { - Vec2i n(cx, cy); - switch (state) { - case 0: // top edge, left->right - if (cx == ex) { - state = 1; - ++cy; - } else { - ++cx; - } - break; - case 1: // right edge, top->bottom - if (cy == sy) { - state = 2; - --cx; - } else { - ++cy; - } - break; - case 2: - if (cx == wx) { - state = 3; - --cy; - } else { - --cx; - } - break; - case 3: - if (cy == ny + 1) { - state = 4; - } else { - --cy; - } - break; - } - return n; -} - -}}//end namespace - diff --git a/source/glest_game/facilities/pos_iterator.h b/source/glest_game/facilities/pos_iterator.h deleted file mode 100644 index 67f36fe1..00000000 --- a/source/glest_game/facilities/pos_iterator.h +++ /dev/null @@ -1,125 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2009-2010 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifndef _GLEST_GAME_UTIL_POSITERATOR_H_ -#define _GLEST_GAME_UTIL_POSITERATOR_H_ - -#ifdef WIN32 - #include - #include -#endif - -#include -#include -#include "math_util.h" - -namespace Glest { namespace Util { - -using std::runtime_error; -using Shared::Graphics::Vec2i; -using Shared::Graphics::Rect2i; - -class RectIteratorBase { -protected: - int ex, wx, sy, ny; - -public: - RectIteratorBase(const Vec2i &p1, const Vec2i &p2) { - if (p1.x > p2.x) { - ex = p1.x; wx = p2.x; - } else { - ex = p2.x; wx = p1.x; - } - if (p1.y > p2.y) { - sy = p1.y; ny = p2.y; - } else { - sy = p2.y; ny = p1.y; - } - } -}; - -/** An iterator over a rectangular region that starts at the 'top-left' and proceeds left - * to right, top to bottom. */ -class RectIterator : public RectIteratorBase { -private: - int cx, cy; - -public: - RectIterator(const Rect2i &rect) - : RectIteratorBase(rect.p[0], rect.p[1]) { - cx = wx; - cy = ny; - } - - RectIterator(const Vec2i &p1, const Vec2i &p2) - : RectIteratorBase(p1, p2) { - cx = wx; - cy = ny; - } - - bool more() const { return cy <= sy; } - - Vec2i next() { - Vec2i n(cx, cy); - if (cx == ex) { - cx = wx; ++cy; - } else { - ++cx; - } - return n; - } -}; - -/** An iterator over a rectangular region that starts at the 'bottom-right' and proceeds right - * to left, bottom to top. */ -class ReverseRectIterator : public RectIteratorBase { -private: - int cx, cy; - -public: - ReverseRectIterator(const Vec2i &p1, const Vec2i &p2) - : RectIteratorBase(p1, p2) { - cx = ex; - cy = sy; - } - - bool more() const { return cy >= ny; } - - Vec2i next() { - Vec2i n(cx,cy); - if (cx == wx) { - cx = ex; cy--; - } else { - cx--; - } - return n; - } -}; - -class PerimeterIterator : public RectIteratorBase { -private: - int cx, cy; - int state; - -public: - PerimeterIterator(const Vec2i &p1, const Vec2i &p2) - : RectIteratorBase(p1, p2), state(0) { - cx = wx; - cy = ny; - } - - bool more() const { return state != 4; } - Vec2i next(); -}; - -}} // namespace Glest::Util - -#endif // _GLEST_GAME_UTIL_POSITERATOR_H_ diff --git a/source/glest_game/game/game.cpp b/source/glest_game/game/game.cpp index de3e4f6e..7cab9ade 100644 --- a/source/glest_game/game/game.cpp +++ b/source/glest_game/game/game.cpp @@ -1241,8 +1241,6 @@ void Game::init(bool initForPreviewOnly) { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"================ STARTING GAME ================\n"); if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled) SystemFlags::OutputDebug(SystemFlags::debugPathFinder,"================ STARTING GAME ================\n"); - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled) SystemFlags::OutputDebug(SystemFlags::debugPathFinder,"PathFinderType: %s\n", (getGameSettings()->getPathFinderType() ? "RoutePlanner" : "PathFinder")); - setupPopupMenus(false); for(int i=0; i < world.getFactionCount(); ++i) { diff --git a/source/glest_game/game/game_constants.h b/source/glest_game/game/game_constants.h index 4eac4060..d6d0aa90 100644 --- a/source/glest_game/game/game_constants.h +++ b/source/glest_game/game/game_constants.h @@ -73,8 +73,7 @@ const Vec4f WHITE(1.0f, 1.0f, 1.0f, 1.0f); const Vec4f ORANGE(1.0f, 0.7f, 0.0f, 1.0f); enum PathFinderType { - pfBasic, - pfRoutePlanner + pfBasic }; enum TravelState { diff --git a/source/glest_game/graphics/debug_renderer.cpp b/source/glest_game/graphics/debug_renderer.cpp deleted file mode 100644 index 529bf2c7..00000000 --- a/source/glest_game/graphics/debug_renderer.cpp +++ /dev/null @@ -1,577 +0,0 @@ -// ============================================================== -// This file is part of The Glest Advanced Engine -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifdef DEBUG_RENDERING_ENABLED - -#include "debug_renderer.h" -#include "route_planner.h" -#include "influence_map.h" -#include "cartographer.h" - -#include "renderer.h" - -using namespace Shared::Graphics; -using namespace Shared::Graphics::Gl; -using namespace Shared::Util; - -namespace Glest { namespace Game { - -// texture loading helper -void _load_debug_tex(Texture2D* &texPtr, const char *fileName) { - texPtr = g_renderer.newTexture2D(rsGame); - texPtr->setMipmap(false); - texPtr->getPixmap()->load(fileName); -} - -// ===================================================== -// class PathFinderTextureCallback -// ===================================================== - -PathFinderTextureCallback::PathFinderTextureCallback() - : debugField(fLand) { - reset(); -} - -void PathFinderTextureCallback::reset() { - pathSet.clear(); - openSet.clear(); - closedSet.clear(); - pathStart = Vec2i(-1); - pathDest = Vec2i(-1); - localAnnotations.clear(); - debugField = fLand; - memset(PFDebugTextures, 0, sizeof(PFDebugTextures)); -} - -void PathFinderTextureCallback::loadTextures() { -# define _load_tex(i,f) _load_debug_tex(PFDebugTextures[i],f) - char buff[128]; - for (int i=0; i < 8; ++i) { - sprintf(buff, "data/core/misc_textures/g%02d.bmp", i); - _load_tex(i, buff); - } - _load_tex(9, "data/core/misc_textures/path_start.bmp"); - _load_tex(10, "data/core/misc_textures/path_dest.bmp"); - //_load_tex(11, "data/core/misc_textures/path_both.bmp"); - //_load_tex(12, "data/core/misc_textures/path_return.bmp"); - //_load_tex(13, "data/core/misc_textures/path.bmp"); - - _load_tex(14, "data/core/misc_textures/path_node.bmp"); - _load_tex(15, "data/core/misc_textures/open_node.bmp"); - _load_tex(16, "data/core/misc_textures/closed_node.bmp"); - - for (int i=17; i < 17+8; ++i) { - sprintf(buff, "data/core/misc_textures/l%02d.bmp", i-17); - _load_tex(i, buff); - } -# undef _load_tex -} - -Texture2DGl* PathFinderTextureCallback::operator()(const Vec2i &cell) { - int ndx = -1; - if (pathStart == cell) ndx = 9; - else if (pathDest == cell) ndx = 10; - else if (pathSet.find(cell) != pathSet.end()) ndx = 14; // on path - else if (closedSet.find(cell) != closedSet.end()) ndx = 16; // closed nodes - else if (openSet.find(cell) != openSet.end()) ndx = 15; // open nodes - else if (localAnnotations.find(cell) != localAnnotations.end()) // local annotation - ndx = 17 + localAnnotations.find(cell)->second; - else ndx = g_world.getCartographer()->getMasterMap()->metrics[cell].get(debugField); // else use cell metric for debug field - return (Texture2DGl*)PFDebugTextures[ndx]; -} - -// ===================================================== -// class GridTextureCallback -// ===================================================== - -void GridTextureCallback::loadTextures() { - _load_debug_tex(tex, "data/core/misc_textures/grid.bmp"); -} - -bool ResourceMapOverlay::operator()(const Vec2i &cell, Vec4f &colour) { - ResourceMapKey mapKey(rt, fLand, 1); - PatchMap<1> *pMap = g_world.getCartographer()->getResourceMap(mapKey); - if (pMap && pMap->getInfluence(cell)) { - colour = Vec4f(1.f, 1.f, 0.f, 0.7f); - return true; - } - return false; -} - -bool StoreMapOverlay::operator()(const Vec2i &cell, Vec4f &colour) { - for (KeyList::iterator it = storeMaps.begin(); it != storeMaps.end(); ++it) { - PatchMap<1> *pMap = g_world.getCartographer()->getStoreMap(*it, false); - if (pMap && pMap->getInfluence(cell)) { - colour = Vec4f(0.f, 1.f, 0.3f, 0.7f); - return true; - } - } - return false; -} - -// ===================================================== -// class DebugRender -// ===================================================== - -DebugRenderer::DebugRenderer() { - // defaults, listed for ease of maintenance. [Note: these can be set from Lua now, use debugSet()] - showVisibleQuad = - captureVisibleQuad = - regionHilights = - storeMapOverlay = - showFrustum = - captureFrustum = - gridTextures = - influenceMap = - buildSiteMaps = - resourceMapOverlay = - false; - - AAStarTextures = - HAAStarOverlay = - true; -} - -const ResourceType* findResourceMapRes(const string &res) { - const int &n = g_world.getTechTree()->getResourceTypeCount(); - for (int i=0; i < n; ++i) { - const ResourceType *rt = g_world.getTechTree()->getResourceType(i); - if (rt->getName() == res) { - return rt; - } - } - return 0; -} - -void DebugRenderer::init() { - - pfCallback.reset(); - pfCallback.loadTextures(); - - gtCallback.reset(); - gtCallback.loadTextures(); - - rhCallback.reset(); - vqCallback.reset(); - cmOverlay.reset(); - rmOverlay.reset(); - smOverlay.reset(); - bsOverlay.reset(); - - if (resourceMapOverlay) { - rmOverlay.rt = findResourceMapRes(string("gold")); - } else { - rmOverlay.reset(); - } -} - -void DebugRenderer::commandLine(string &line) { - string key, val; - size_t n = line.find('='); - if ( n != string::npos ) { - key = line.substr(0, n); - val = line.substr(n+1); - } else { - key = line; - } - if ( key == "AStarTextures" ) { - if ( val == "" ) { // no val supplied, toggle - AAStarTextures = !AAStarTextures; - } else { - if ( val == "on" || val == "On" ) { - AAStarTextures = true; - } else { - AAStarTextures = false; - } - } - } else if ( key == "GridTextures" ) { - if ( val == "" ) { // no val supplied, toggle - gridTextures = !gridTextures; - } else { - if ( val == "on" || val == "On" ) { - gridTextures = true; - } else { - gridTextures = false; - } - } - } else if ( key == "ClusterOverlay" ) { - if ( val == "" ) { // no val supplied, toggle - HAAStarOverlay = !HAAStarOverlay; - } else { - if ( val == "on" || val == "On" ) { - HAAStarOverlay = true; - } else { - HAAStarOverlay = false; - } - } - } else if ( key == "CaptuereQuad" ) { - captureVisibleQuad = true; - } else if ( key == "RegionColouring" ) { - if ( val == "" ) { // no val supplied, toggle - regionHilights = !regionHilights; - } else { - if ( val == "on" || val == "On" ) { - regionHilights = true; - } else { - regionHilights = false; - } - } - } else if ( key == "DebugField" ) { - Field f = fLand; - if (val == "air") { - f = fAir; - } - pfCallback.debugField = f; - } else if (key == "Frustum") { - if (val == "capture" || val == "Capture") { - captureFrustum = true; - } else if (val == "off" || val == "Off") { - showFrustum = false; - } - } else if (key == "ResourceMap") { - if ( val == "" ) { // no val supplied, toggle - resourceMapOverlay = !resourceMapOverlay; - } else { - const ResourceType *rt = 0; - if ( val == "on" || val == "On" ) { - resourceMapOverlay = true; - } else if (val == "off" || val == "Off") { - resourceMapOverlay = false; - } else { - // else find resource - if (!( rt = findResourceMapRes(val))) { - g_console.addLine("Error: value='" + val + "' not valid."); - resourceMapOverlay = false; - } - resourceMapOverlay = true; - rmOverlay.rt = rt; - } - } - } else if (key == "StoreMap") { - n = val.find(','); - if (n == string::npos) { - g_console.addLine("Error: value='" + val + "' not valid"); - return; - } - storeMapOverlay = false; - string idString = val.substr(0, n); - ++n; - while (val[n] == ' ') ++n; - string szString = val.substr(n); - int id, sz; - try { - id = strToInt(idString); - sz = strToInt(szString); - } catch (runtime_error &e) { - g_console.addLine("Error: value='" + val + "' not valid: expected id, size (two integers)"); - return; - } - Unit *store = g_world.findUnitById(id); - if (!store) { - g_console.addLine("Error: unit id " + idString + " not found"); - return; - } - StoreMapKey smkey(store, fLand, sz); - PatchMap<1> *pMap = g_world.getCartographer()->getStoreMap(smkey, false); - if (pMap) { - smOverlay.storeMaps.push_back(smkey); - storeMapOverlay = true; - } else { - g_console.addLine("Error: no StoreMap found for unit " + idString - + " in fLand with size " + szString); - } - } else if (key == "AssertClusterMap") { - g_world.getCartographer()->getClusterMap()->assertValid(); - } else if (key == "TransitionEdges") { - if (val == "clear") { - clusterEdgesNorth.clear(); - clusterEdgesWest.clear(); - } else { - n = val.find(','); - if (n == string::npos) { - g_console.addLine("Error: value=" + val + "not valid"); - return; - } - string xs = val.substr(0, n); - val = val.substr(n + 1); - int x = atoi(xs.c_str()); - n = val.find(':'); - if (n == string::npos) { - g_console.addLine("Error: value=" + val + "not valid"); - return; - } - string ys = val.substr(0, n); - val = val.substr(n + 1); - int y = atoi(ys.c_str()); - if (val == "north") { - clusterEdgesNorth.insert(Vec2i(x, y)); - } else if ( val == "west") { - clusterEdgesWest.insert(Vec2i(x, y)); - } else if ( val == "south") { - clusterEdgesNorth.insert(Vec2i(x, y + 1)); - } else if ( val == "east") { - clusterEdgesWest.insert(Vec2i(x + 1, y)); - } else if ( val == "all") { - clusterEdgesNorth.insert(Vec2i(x, y)); - clusterEdgesNorth.insert(Vec2i(x, y + 1)); - clusterEdgesWest.insert(Vec2i(x, y)); - clusterEdgesWest.insert(Vec2i(x + 1, y)); - } else { - g_console.addLine("Error: value=" + val + "not valid"); - } - } - } -} - -void DebugRenderer::renderCellTextured(const Texture2DGl *tex, const Vec3f &norm, const Vec3f &v0, - const Vec3f &v1, const Vec3f &v2, const Vec3f &v3) { - glBindTexture( GL_TEXTURE_2D, tex->getHandle() ); - glBegin( GL_TRIANGLE_FAN ); - glTexCoord2f( 0.f, 1.f ); - glNormal3fv( norm.ptr() ); - glVertex3fv( v0.ptr() ); - - glTexCoord2f( 1.f, 1.f ); - glNormal3fv( norm.ptr() ); - glVertex3fv( v1.ptr() ); - - glTexCoord2f( 1.f, 0.f ); - glNormal3fv( norm.ptr() ); - glVertex3fv( v2.ptr() ); - - glTexCoord2f( 0.f, 0.f ); - glNormal3fv( norm.ptr() ); - glVertex3fv( v3.ptr() ); - glEnd (); -} - -void DebugRenderer::renderCellOverlay(const Vec4f colour, const Vec3f &norm, - const Vec3f &v0, const Vec3f &v1, const Vec3f &v2, const Vec3f &v3) { - glBegin ( GL_TRIANGLE_FAN ); - glNormal3fv(norm.ptr()); - glColor4fv( colour.ptr() ); - glVertex3fv(v0.ptr()); - glNormal3fv(norm.ptr()); - glColor4fv( colour.ptr() ); - glVertex3fv(v1.ptr()); - glNormal3fv(norm.ptr()); - glColor4fv( colour.ptr() ); - glVertex3fv(v2.ptr()); - glNormal3fv(norm.ptr()); - glColor4fv( colour.ptr() ); - glVertex3fv(v3.ptr()); - glEnd (); -} - -void DebugRenderer::renderArrow( - const Vec3f &pos1, const Vec3f &_pos2, const Vec3f &color, float width) { - const int tesselation = 3; - const float arrowEndSize = 0.5f; - - Vec3f dir = Vec3f(_pos2 - pos1); - //float len = dir.length(); - float alphaFactor = 0.3f; - - dir.normalize(); - Vec3f pos2 = _pos2 - dir; - Vec3f normal = dir.cross(Vec3f(0, 1, 0)); - - Vec3f pos2Left = pos2 + normal * (width - 0.05f) - dir * arrowEndSize * width; - Vec3f pos2Right = pos2 - normal * (width - 0.05f) - dir * arrowEndSize * width; - Vec3f pos1Left = pos1 + normal * (width + 0.02f); - Vec3f pos1Right = pos1 - normal * (width + 0.02f); - - //arrow body - glBegin(GL_TRIANGLE_STRIP); - for(int i=0; i<=tesselation; ++i){ - float t= static_cast(i)/tesselation; - Vec3f a= pos1Left.lerp(t, pos2Left); - Vec3f b= pos1Right.lerp(t, pos2Right); - Vec4f c= Vec4f(color, t*0.25f*alphaFactor); - - glColor4fv(c.ptr()); - glVertex3fv(a.ptr()); - glVertex3fv(b.ptr()); - } - glEnd(); - - //arrow end - glBegin(GL_TRIANGLES); - glVertex3fv((pos2Left + normal*(arrowEndSize-0.1f)).ptr()); - glVertex3fv((pos2Right - normal*(arrowEndSize-0.1f)).ptr()); - glVertex3fv((pos2 + dir*(arrowEndSize-0.1f)).ptr()); - glEnd(); -} - -void DebugRenderer::renderPathOverlay() { - //return; - Vec3f one, two; - if ( waypoints.size() < 2 ) return; - - assertGl(); - glPushAttrib( GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT ); - glEnable( GL_COLOR_MATERIAL ); - glDisable( GL_ALPHA_TEST ); - glDepthFunc(GL_ALWAYS); - glDisable(GL_STENCIL_TEST); - glDisable(GL_CULL_FACE); - glLineWidth(2.f); - glActiveTexture( GL_TEXTURE0 ); - glDisable( GL_TEXTURE_2D ); - - list::iterator it = waypoints.begin(); - one = *it; - ++it; - two = *it; - while ( true ) { - renderArrow(one,two,Vec3f(1.0f, 1.0f, 0.f), 0.15f); - one = two; - ++it; - if ( it == waypoints.end() ) break; - two = *it; - } - //Restore - glPopAttrib(); -} - -void DebugRenderer::renderIntraClusterEdges(const Vec2i &cluster, CardinalDir dir) { - ClusterMap *cm = g_world.getCartographer()->getClusterMap(); - const Map *map = g_world.getMap(); - - if (cluster.x < 0 || cluster.x >= cm->getWidth() - || cluster.y < 0 || cluster.y >= cm->getHeight()) { - return; - } - - Transitions transitions; - if (dir != CardinalDir::COUNT) { - TransitionCollection &tc = cm->getBorder(cluster, dir)->transitions[fLand]; - for (int i=0; i < tc.n; ++i) { - transitions.push_back(tc.transitions[i]); - } - } else { - cm->getTransitions(cluster, fLand, transitions); - } - assertGl(); - glPushAttrib( GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT | GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT ); - glEnable( GL_COLOR_MATERIAL ); - glDisable( GL_ALPHA_TEST ); - glDepthFunc(GL_ALWAYS); - glDisable(GL_STENCIL_TEST); - glDisable(GL_CULL_FACE); - glLineWidth(2.f); - glActiveTexture( GL_TEXTURE0 ); - glDisable( GL_TEXTURE_2D ); - - for (Transitions::iterator ti = transitions.begin(); ti != transitions.end(); ++ti) { - const Transition* &t = *ti; - float h = map->getCell(t->nwPos)->getHeight(); - Vec3f t1Pos(t->nwPos.x + 0.5f, h + 0.1f, t->nwPos.y + 0.5f); - for (Edges::const_iterator ei = t->edges.begin(); ei != t->edges.end(); ++ei) { - Edge * const &e = *ei; - //if (e->cost(1) != numeric_limits::infinity()) { - const Transition* t2 = e->transition(); - h = map->getCell(t2->nwPos)->getHeight(); - Vec3f t2Pos(t2->nwPos.x + 0.5f, h + 0.1f, t2->nwPos.y + 0.5f); - renderArrow(t1Pos, t2Pos, Vec3f(1.f, 0.f, 1.f), 0.2f); - //} - } - } - //Restore - glPopAttrib(); -} - -void DebugRenderer::renderFrustum() const { - glPushAttrib( GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT ); - glEnable( GL_BLEND ); - glEnable( GL_COLOR_MATERIAL ); - glDisable( GL_ALPHA_TEST ); - glActiveTexture( GL_TEXTURE0 ); - glDisable( GL_TEXTURE_2D ); - - glPointSize(5); - glColor3f(1.f, 0.2f, 0.2f); - glBegin(GL_POINTS); - for (int i=0; i < 8; ++i) glVertex3fv(frstmPoints[i].ptr()); - glEnd(); - - glLineWidth(2); - glColor3f(0.1f, 0.5f, 0.1f); // near - glBegin(GL_LINE_LOOP); - for (int i=0; i < 4; ++i) glVertex3fv(frstmPoints[i].ptr()); - glEnd(); - - glColor3f(0.1f, 0.1f, 0.5f); // far - glBegin(GL_LINE_LOOP); - for (int i=4; i < 8; ++i) glVertex3fv(frstmPoints[i].ptr()); - glEnd(); - - glColor3f(0.1f, 0.5f, 0.5f); - glBegin(GL_LINES); - for (int i=0; i < 4; ++i) { - glVertex3fv(frstmPoints[i].ptr()); // near - glVertex3fv(frstmPoints[i+4].ptr()); // far - } - glEnd(); - - glPopAttrib(); -} - -void DebugRenderer::setInfluenceMap(TypeMap *iMap, Vec3f colour, float max) { - imOverlay.iMap = iMap; - imOverlay.baseColour = colour; - imOverlay.max = max; - influenceMap = true; -} - -void DebugRenderer::renderEffects(Quad2i &quad) { - if (regionHilights && !rhCallback.empty()) { - renderCellOverlay(quad, rhCallback); - } - if (showVisibleQuad) { - renderCellOverlay(quad, vqCallback); - } - if (HAAStarOverlay) { - renderCellOverlay(quad, cmOverlay); - renderPathOverlay(); - set::iterator it; - for (it = clusterEdgesWest.begin(); it != clusterEdgesWest.end(); ++it) { - renderIntraClusterEdges(*it, CardinalDir::WEST); - } - for (it = clusterEdgesNorth.begin(); it != clusterEdgesNorth.end(); ++it) { - renderIntraClusterEdges(*it, CardinalDir::NORTH); - } - } - if (resourceMapOverlay && rmOverlay.rt) { - renderCellOverlay(quad, rmOverlay); - } - if (storeMapOverlay && !smOverlay.storeMaps.empty()) { - renderCellOverlay(quad, smOverlay); - } - if (buildSiteMaps && !bsOverlay.cells.empty()) { - renderCellOverlay(quad, bsOverlay); - } - //if (showFrustum) { - // renderFrustum(); - //} - if (influenceMap) { - renderCellOverlay(quad, imOverlay); - } -} - -DebugRenderer& getDebugRenderer() { - static DebugRenderer debugRenderer; - return debugRenderer; -} - -}} // end namespace Glest::Debug - -#endif // _GAE_DEBUG_EDITION_ diff --git a/source/glest_game/graphics/debug_renderer.h b/source/glest_game/graphics/debug_renderer.h deleted file mode 100644 index 2c3269c3..00000000 --- a/source/glest_game/graphics/debug_renderer.h +++ /dev/null @@ -1,408 +0,0 @@ -// ============================================================== -// This file is part of The Glest Advanced Engine -// -// Copyright (C) 2009 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifndef DEBUG_RENDERING_ENABLED -# error debug_renderer.h included without DEBUG_RENDERING_ENABLED defined -#endif - -#ifndef _GLEST_GAME_DEBUG_RENDERER_ -#define _GLEST_GAME_DEBUG_RENDERER_ - -#ifdef WIN32 - #include - #include -#endif - -#include "vec.h" -#include "math_util.h" -#include "pixmap.h" -#include "texture.h" -#include "graphics_factory_gl.h" - -#include "route_planner.h" -#include "influence_map.h" -#include "cartographer.h" -#include "cluster_map.h" - -#include "game.h" - -#define g_renderer (Renderer::getInstance()) -#define g_world (*static_cast(Program::getInstance()->getState())->getWorld()) -#define g_console (*static_cast(Program::getInstance()->getState())->getConsole()) - -using namespace Shared::Graphics; -using namespace Shared::Graphics::Gl; -using namespace Shared::Util; - -namespace Glest { namespace Game { - -class PathFinderTextureCallback { -public: - set pathSet, openSet, closedSet; - Vec2i pathStart, pathDest; - map localAnnotations; - Field debugField; - Texture2D *PFDebugTextures[26]; - - PathFinderTextureCallback(); - - void reset(); - void loadTextures(); - Texture2DGl* operator()(const Vec2i &cell); -}; - -class GridTextureCallback { -public: - Texture2D *tex; - - void reset() { tex = 0; } - void loadTextures(); - - GridTextureCallback() : tex(0) {} - - Texture2DGl* operator()(const Vec2i &cell) { - return (Texture2DGl*)tex; - } -}; - -enum HighlightColour { hcBlue, hcGreen, hcCount }; - -class CellHighlightOverlay { -public: - typedef map CellColours; - CellColours cells; - - Vec4f highlightColours[hcCount]; - - CellHighlightOverlay() { - highlightColours[hcBlue] = Vec4f(0.f, 0.f, 1.f, 0.6f); - highlightColours[hcGreen] = Vec4f(0.f, 1.f, 0.f, 0.6f); - } - - void reset() { - cells.clear(); - } - - bool empty() const { return cells.empty(); } - - bool operator()(const Vec2i &cell, Vec4f &colour) { - CellColours::iterator it = cells.find(cell); - if (it != cells.end()) { - colour = highlightColours[it->second]; - return true; - } - return false; - } -}; - -class InfluenceMapOverlay { -public: - TypeMap *iMap; - Vec3f baseColour; - float max; - - bool operator()(const Vec2i &cell, Vec4f &colour) { - const float influence = iMap->getInfluence(cell); - if (influence != 0.f) { - colour = Vec4f(baseColour, clamp(influence / max, 0.f, 1.f)); - return true; - } - return false; - } -}; - -class VisibleAreaOverlay { -public: - set quadSet; - Vec4f colour; - - void reset() { - colour = Vec4f(0.f, 1.f, 0.f, 0.5f); - quadSet.clear(); - } - - bool operator()(const Vec2i &cell, Vec4f &colour) { - if (quadSet.find(cell) == quadSet.end()) { - return false; - } - colour = this->colour; - return true; - } -}; - -class TeamSightOverlay { -public: - bool operator()(const Vec2i &cell, Vec4f &colour); -}; - -class ClusterMapOverlay { -public: - set entranceCells; - set pathCells; - - void reset() { - entranceCells.clear(); - pathCells.clear(); - } - - bool operator()(const Vec2i &cell, Vec4f &colour) { - const int &clusterSize = GameConstants::clusterSize; - if ( cell.x % clusterSize == clusterSize - 1 - || cell.y % clusterSize == clusterSize - 1 ) { - if ( entranceCells.find(cell) != entranceCells.end() ) { - colour = Vec4f(0.f, 1.f, 0.f, 0.7f); // entrance - } else { - colour = Vec4f(1.f, 0.f, 0.f, 0.7f); // border - } - } else if ( pathCells.find(cell) != pathCells.end() ) { // intra-cluster edge - colour = Vec4f(0.f, 0.f, 1.f, 0.7f); - } else { - return false; // nothing interesting - } - return true; - } -}; - -class ResourceMapOverlay { -public: - const ResourceType *rt; - - ResourceMapOverlay() : rt(0) {} - void reset() { rt = 0; } - - bool operator()(const Vec2i &cell, Vec4f &colour); -}; - -class StoreMapOverlay { -public: - typedef vector KeyList; - KeyList storeMaps; - - void reset() { storeMaps.clear(); } - - bool operator()(const Vec2i &cell, Vec4f &colour); -}; - -class BuildSiteMapOverlay { -public: - set cells; - - void reset() { cells.clear(); } - - bool operator()(const Vec2i &cell, Vec4f &colour) { - if (cells.find(cell) != cells.end()) { - colour = Vec4f(0.f, 1.f, 0.3f, 0.7f); - return true; - } - return false; - } -}; - -// ===================================================== -// class DebugRender -// -/// Helper class compiled with _GAE_DEBUG_EDITION_ only -// ===================================================== -class DebugRenderer { -private: - set clusterEdgesWest; - set clusterEdgesNorth; - Vec3f frstmPoints[8]; - - PathFinderTextureCallback pfCallback; - GridTextureCallback gtCallback; - CellHighlightOverlay rhCallback; - VisibleAreaOverlay vqCallback; - ClusterMapOverlay cmOverlay; - ResourceMapOverlay rmOverlay; - StoreMapOverlay smOverlay; - BuildSiteMapOverlay bsOverlay; - InfluenceMapOverlay imOverlay; - -public: - DebugRenderer(); - void init(); - void commandLine(string &line); - - bool gridTextures, // show cell grid - AAStarTextures, // AA* search space and results of last low-level search - HAAStarOverlay, // HAA* search space and results of last hierarchical search - showVisibleQuad, // set to show visualisation of last captured scene cull - captureVisibleQuad, // set to trigger a capture of the next scene cull - captureFrustum, // set to trigger a capture of the view frustum - showFrustum, // set to show visualisation of captured view frustum - regionHilights, // show hilighted cells, are, and can further be, used for various things - resourceMapOverlay, // show resource goal map overlay - storeMapOverlay, // show store goal map overlay - buildSiteMaps, // show building site goal maps - influenceMap; // visualise an inluence map, [TypeMap only] - - void addCellHighlight(const Vec2i &pos, HighlightColour c = hcBlue) { - rhCallback.cells[pos] = c; - } - - void clearCellHilights() { - rhCallback.cells.clear(); - } - - void addBuildSiteCell(const Vec2i &pos) { - bsOverlay.cells.insert(pos); - } - - void setInfluenceMap(TypeMap *iMap, Vec3f colour, float max); - - PathFinderTextureCallback& getPFCallback() { return pfCallback; } - ClusterMapOverlay& getCMOverlay() { return cmOverlay; } - -private: - /***/ - template - void renderCellTextures(Quad2i &quad, TextureCallback callback) { - const Map *map = g_world.getMap(); - const Rect2i mapBounds(0, 0, map->getSurfaceW() - 1, map->getSurfaceH() - 1); - float coordStep = g_world.getTileset()->getSurfaceAtlas()->getCoordStep(); - assertGl(); - - glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT); - glEnable(GL_BLEND); - glEnable(GL_COLOR_MATERIAL); - glDisable(GL_ALPHA_TEST); - glActiveTexture( GL_TEXTURE0 ); - - PosQuadIterator pqi(map, quad); - while (pqi.next()) { - const Vec2i &pos = pqi.getPos(); - int cx, cy; - cx = pos.x * 2; - cy = pos.y * 2; - if (mapBounds.isInside(pos)) { - SurfaceCell *tc00 = map->getSurfaceCell(pos.x, pos.y), *tc10 = map->getSurfaceCell(pos.x+1, pos.y), - *tc01 = map->getSurfaceCell(pos.x, pos.y+1), *tc11 = map->getSurfaceCell(pos.x+1, pos.y+1); - Vec3f tl = tc00->getVertex (), tr = tc10->getVertex (), - bl = tc01->getVertex (), br = tc11->getVertex (); - Vec3f tc = tl + (tr - tl) / 2, ml = tl + (bl - tl) / 2, - mr = tr + (br - tr) / 2, mc = ml + (mr - ml) / 2, bc = bl + (br - bl) / 2; - Vec2i cPos(cx, cy); - const Texture2DGl *tex = callback(cPos); - renderCellTextured(tex, tc00->getNormal(), tl, tc, mc, ml); - cPos = Vec2i(cx + 1, cy); - tex = callback(cPos); - renderCellTextured(tex, tc00->getNormal(), tc, tr, mr, mc); - cPos = Vec2i(cx, cy + 1 ); - tex = callback(cPos); - renderCellTextured(tex, tc00->getNormal(), ml, mc, bc, bl); - cPos = Vec2i(cx + 1, cy + 1); - tex = callback(cPos); - renderCellTextured(tex, tc00->getNormal(), mc, mr, br, bc); - } - } - //Restore - glPopAttrib(); - //assert - glGetError(); //remove when first mtex problem solved - assertGl(); - - } // renderCellTextures () - - - /***/ - template< typename ColourCallback > - void renderCellOverlay(Quad2i &quad, ColourCallback callback) { - const Map *map = g_world.getMap(); - const Rect2i mapBounds(0, 0, map->getSurfaceW() - 1, map->getSurfaceH() - 1); - float coordStep = g_world.getTileset()->getSurfaceAtlas()->getCoordStep(); - Vec4f colour; - assertGl(); - glPushAttrib( GL_LIGHTING_BIT | GL_ENABLE_BIT | GL_FOG_BIT | GL_TEXTURE_BIT ); - glEnable( GL_BLEND ); - glEnable( GL_COLOR_MATERIAL ); - glDisable( GL_ALPHA_TEST ); - glActiveTexture( GL_TEXTURE0 ); - glDisable( GL_TEXTURE_2D ); - - PosQuadIterator pqi(map, quad); - while(pqi.next()){ - const Vec2i &pos= pqi.getPos(); - int cx, cy; - cx = pos.x * 2; - cy = pos.y * 2; - if ( mapBounds.isInside( pos ) ) { - SurfaceCell *tc00= map->getSurfaceCell(pos.x, pos.y), *tc10= map->getSurfaceCell(pos.x+1, pos.y), - *tc01= map->getSurfaceCell(pos.x, pos.y+1), *tc11= map->getSurfaceCell(pos.x+1, pos.y+1); - Vec3f tl = tc00->getVertex(), tr = tc10->getVertex(), - bl = tc01->getVertex(), br = tc11->getVertex(); - tl.y += 0.1f; tr.y += 0.1f; bl.y += 0.1f; br.y += 0.1f; - Vec3f tc = tl + (tr - tl) / 2, ml = tl + (bl - tl) / 2, mr = tr + (br - tr) / 2, - mc = ml + (mr - ml) / 2, bc = bl + (br - bl) / 2; - - if (callback(Vec2i(cx,cy), colour)) { - renderCellOverlay(colour, tc00->getNormal(), tl, tc, mc, ml); - } - if (callback(Vec2i(cx+1, cy), colour)) { - renderCellOverlay(colour, tc00->getNormal(), tc, tr, mr, mc); - } - if (callback(Vec2i(cx, cy + 1), colour)) { - renderCellOverlay(colour, tc00->getNormal(), ml, mc, bc, bl); - } - if (callback(Vec2i(cx + 1, cy + 1), colour)) { - renderCellOverlay(colour, tc00->getNormal(), mc, mr, br, bc); - } - } - } - //Restore - glPopAttrib(); - assertGl(); - } - - /***/ - void renderCellTextured(const Texture2DGl *tex, const Vec3f &norm, const Vec3f &v0, - const Vec3f &v1, const Vec3f &v2, const Vec3f &v3); - - /***/ - void renderCellOverlay(const Vec4f colour, const Vec3f &norm, const Vec3f &v0, - const Vec3f &v1, const Vec3f &v2, const Vec3f &v3); - - /***/ - void renderArrow(const Vec3f &pos1, const Vec3f &pos2, const Vec3f &color, float width); - - /***/ - void renderPathOverlay(); - - /***/ - void renderIntraClusterEdges(const Vec2i &cluster, CardinalDir dir = CardinalDir::COUNT); - - /***/ - void renderFrustum() const; - - list waypoints; - -public: - void clearWaypoints() { waypoints.clear(); } - void addWaypoint(Vec3f v) { waypoints.push_back(v); } - - bool willRenderSurface() const { return AAStarTextures || gridTextures; } - - void renderSurface(Quad2i &quad) { - if (AAStarTextures) { - if (gridTextures) gridTextures = false; - renderCellTextures(quad, pfCallback); - } else if (gridTextures) { - renderCellTextures(quad, gtCallback); - } - } - void renderEffects(Quad2i &quad); -}; - -DebugRenderer& getDebugRenderer(); - -}} - -#endif diff --git a/source/glest_game/menu/menu_state_connected_game.cpp b/source/glest_game/menu/menu_state_connected_game.cpp index 7efc90ea..6e9bcf7f 100644 --- a/source/glest_game/menu/menu_state_connected_game.cpp +++ b/source/glest_game/menu/menu_state_connected_game.cpp @@ -233,9 +233,6 @@ MenuStateConnectedGame::MenuStateConnectedGame(Program *program, MainMenu *mainM listBoxPathFinderType.registerGraphicComponent(containerName,"listBoxPathFinderType"); listBoxPathFinderType.init(xoffset+650, aPos, 150); listBoxPathFinderType.pushBackItem(lang.get("PathFinderTypeRegular")); - if(config.getBool("EnableRoutePlannerPathfinder","false") == true) { - listBoxPathFinderType.pushBackItem(lang.get("PathFinderTypeRoutePlanner")); - } listBoxPathFinderType.setSelectedItemIndex(0); listBoxPathFinderType.setEditable(false); @@ -598,9 +595,6 @@ void MenuStateConnectedGame::reloadUI() { vector pathfinderItems; pathfinderItems.push_back(lang.get("PathFinderTypeRegular")); - if(config.getBool("EnableRoutePlannerPathfinder","false") == true) { - pathfinderItems.push_back(lang.get("PathFinderTypeRoutePlanner")); - } listBoxPathFinderType.setItems(pathfinderItems); labelMap.setText(lang.get("Map")); diff --git a/source/glest_game/menu/menu_state_custom_game.cpp b/source/glest_game/menu/menu_state_custom_game.cpp index 937361ec..8755b9c3 100644 --- a/source/glest_game/menu/menu_state_custom_game.cpp +++ b/source/glest_game/menu/menu_state_custom_game.cpp @@ -345,9 +345,6 @@ MenuStateCustomGame::MenuStateCustomGame(Program *program, MainMenu *mainMenu, listBoxPathFinderType.registerGraphicComponent(containerName,"listBoxPathFinderType"); listBoxPathFinderType.init(xoffset+650, aPos, 150); listBoxPathFinderType.pushBackItem(lang.get("PathFinderTypeRegular")); - if(config.getBool("EnableRoutePlannerPathfinder","false") == true) { - listBoxPathFinderType.pushBackItem(lang.get("PathFinderTypeRoutePlanner")); - } listBoxPathFinderType.setSelectedItemIndex(0); // Advanced Options @@ -781,9 +778,6 @@ void MenuStateCustomGame::reloadUI() { listBoxData.clear(); listBoxData.push_back(lang.get("PathFinderTypeRegular")); - if(config.getBool("EnableRoutePlannerPathfinder","false") == true) { - listBoxData.push_back(lang.get("PathFinderTypeRoutePlanner")); - } listBoxPathFinderType.setItems(listBoxData); // Advanced Options diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 2b7cdaad..45dca7c8 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -3876,9 +3876,6 @@ Unit * Unit::loadGame(const XmlNode *rootNode, GameSettings *settings, Faction * case pfBasic: newpath = new UnitPathBasic(); break; - case pfRoutePlanner: - newpath = new UnitPath(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index efa885bd..2c610df6 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -245,7 +245,7 @@ public: Vec2i peek() {return back();} /**< peek at the next position */ void pop() {this->pop_back();} /**< pop the next position off the path */ #else - // new style, for the new RoutePlanner + // new style Vec2i peek() {return front();} /**< peek at the next position */ //virtual Vec2i pop() { Vec2i p= front(); erase(begin()); return p; } /**< pop the next position off the path */ void pop() { erase(begin()); } /**< pop the next position off the path */ diff --git a/source/glest_game/world/map.cpp b/source/glest_game/world/map.cpp index f474ddc2..a25cb6f2 100644 --- a/source/glest_game/world/map.cpp +++ b/source/glest_game/world/map.cpp @@ -23,7 +23,6 @@ #include "util.h" #include "game_settings.h" #include "platform_util.h" -#include "pos_iterator.h" #include "faction.h" #include "command.h" #include "map_preview.h" @@ -661,24 +660,6 @@ bool Map::isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resour return resourceNear; } -//returns if there is a resource next to a unit, in "resourcePos" is stored the relative position of the resource -bool Map::isResourceNear(const Vec2i &pos, int size, const ResourceType *rt, Vec2i &resourcePos) const { - Vec2i p1 = pos + Vec2i(-size); - Vec2i p2 = pos + Vec2i(size); - Util::PerimeterIterator iter(p1, p2); - while (iter.more()) { - Vec2i cur = iter.next(); - if (isInside(cur) && isInsideSurface(toSurfCoords(cur))) { - Resource *r = getSurfaceCell(toSurfCoords(cur))->getResource(); - if (r && r->getType() == rt) { - resourcePos = cur; - return true; - } - } - } - return false; -} - // ==================== free cells ==================== bool Map::isFreeCell(const Vec2i &pos, Field field) const { diff --git a/source/glest_game/world/map.h b/source/glest_game/world/map.h index c27be678..15007e15 100644 --- a/source/glest_game/world/map.h +++ b/source/glest_game/world/map.h @@ -316,7 +316,6 @@ public: return isInsideSurface(sPos.x, sPos.y); } bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit=NULL,bool fallbackToPeersHarvestingSameResource=false,Vec2i *resourceClickPos=NULL) const; - bool isResourceNear(const Vec2i &pos, int size, const ResourceType *rt, Vec2i &resourcePos) const; //free cells bool isFreeCell(const Vec2i &pos, Field field) const; diff --git a/source/glest_game/world/unit_updater.cpp b/source/glest_game/world/unit_updater.cpp index 2d7d6173..a2876fd7 100644 --- a/source/glest_game/world/unit_updater.cpp +++ b/source/glest_game/world/unit_updater.cpp @@ -14,7 +14,6 @@ #include #include -#include "cartographer.h" #include "core_data.h" #include "config.h" #include "game.h" @@ -24,7 +23,6 @@ #include "particle_type.h" #include "path_finder.h" #include "renderer.h" -#include "route_planner.h" #include "sound.h" #include "sound_renderer.h" #include "upgrade.h" @@ -51,7 +49,6 @@ UnitUpdater::UnitUpdater() { this->map= NULL; this->console= NULL; this->scriptManager= NULL; - this->routePlanner = NULL; this->pathFinder = NULL; //UnitRangeCellsLookupItemCacheTimerCount = 0; attackWarnRange=0; @@ -66,7 +63,6 @@ void UnitUpdater::init(Game *game){ this->map= world->getMap(); this->console= game->getConsole(); this->scriptManager= game->getScriptManager(); - this->routePlanner = NULL; this->pathFinder = NULL; attackWarnRange=Config::getInstance().getFloat("AttackWarnRange","50.0"); //UnitRangeCellsLookupItemCacheTimerCount = 0; @@ -76,9 +72,6 @@ void UnitUpdater::init(Game *game){ pathFinder = new PathFinder(); pathFinder->init(map); break; - case pfRoutePlanner: - routePlanner = world->getRoutePlanner(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -226,9 +219,6 @@ void UnitUpdater::updateUnit(Unit *unit) { case pfBasic: newpath = new UnitPathBasic(); break; - case pfRoutePlanner: - newpath = new UnitPath(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -440,9 +430,6 @@ void UnitUpdater::updateMove(Unit *unit, int frameIndex) { case pfBasic: tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex); break; - case pfRoutePlanner: - tsValue = routePlanner->findPath(unit, pos); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -531,9 +518,6 @@ void UnitUpdater::updateAttack(Unit *unit, int frameIndex) { case pfBasic: tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex); break; - case pfRoutePlanner: - tsValue = routePlanner->findPath(unit, pos); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -740,9 +724,6 @@ void UnitUpdater::updateBuild(Unit *unit, int frameIndex) { tsValue = pathFinder->findPath(unit, buildPos, NULL, frameIndex); } break; - case pfRoutePlanner: - tsValue = routePlanner->findPathToBuildSite(unit, ut, command->getPos(), command->getFacing()); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -773,9 +754,6 @@ void UnitUpdater::updateBuild(Unit *unit, int frameIndex) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] tsArrived about to call map->isFreeCells() for command->getPos() = %s, ut->getSize() = %d\n",__FILE__,__FUNCTION__,__LINE__,command->getPos().getString().c_str(),ut->getSize()); canOccupyCell = map->isFreeCells(command->getPos(), ut->getSize(), fLand); break; - case pfRoutePlanner: - canOccupyCell = map->canOccupy(command->getPos(), ut->getField(), ut, command->getFacing()); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -791,9 +769,6 @@ void UnitUpdater::updateBuild(Unit *unit, int frameIndex) { case pfBasic: newpath = new UnitPathBasic(); break; - case pfRoutePlanner: - newpath = new UnitPath(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -820,9 +795,6 @@ void UnitUpdater::updateBuild(Unit *unit, int frameIndex) { switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; - case pfRoutePlanner: - world->getCartographer()->updateMapMetrics(builtUnit->getPos(), builtUnit->getType()->getSight()); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -973,9 +945,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { } } break; - case pfRoutePlanner: - canHarvestDestPos = map->isResourceNear(unit->getPos(), unit->getType()->getSize(), r->getType(), targetPos); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1002,9 +971,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { case pfBasic: unit->setLoadType(r->getType()); break; - case pfRoutePlanner: - unit->setLoadType(r->getType()); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1036,12 +1002,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { unit->setCurrSkill(hct->getMoveSkillType()); } break; - case pfRoutePlanner: - tsValue = routePlanner->findPathToResource(unit, command->getPos(), r->getType()); - if (tsValue == tsMoving && frameIndex < 0) { - unit->setCurrSkill(hct->getMoveSkillType()); - } - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1062,9 +1022,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { } } break; - case pfRoutePlanner: - canHarvestDestPos = map->isResourceNear(unit->getPos(), unit->getType()->getSize(), r->getType(), targetPos); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1088,9 +1045,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { case pfBasic: unit->setLoadType(r->getType()); break; - case pfRoutePlanner: - unit->setLoadType(r->getType()); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1125,13 +1079,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { command->setPos(targetPos); } break; - case pfRoutePlanner: - tsValue = routePlanner->findPathToResource(unit, targetPos, r->getType()); - if (tsValue == tsMoving && frameIndex < 0) { - unit->setCurrSkill(hct->getMoveSkillType()); - command->setPos(targetPos); - } - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1181,9 +1128,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { case pfBasic: tsValue = pathFinder->findPath(unit, store->getCenteredPos(), NULL, frameIndex); break; - case pfRoutePlanner: - tsValue = routePlanner->findPathToStore(unit, store); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1310,9 +1254,6 @@ void UnitUpdater::updateHarvest(Unit *unit, int frameIndex) { switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; - case pfRoutePlanner: - world->getCartographer()->onResourceDepleted(Map::toSurfCoords(unit->getTargetPos()), rt); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1669,16 +1610,6 @@ void UnitUpdater::updateRepair(Unit *unit, int frameIndex) { ts = pathFinder->findPath(unit, repairPos, NULL, frameIndex); break; - case pfRoutePlanner: - if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - - if (repaired && !repaired->getType()->isMobile()) { - ts = routePlanner->findPathToBuildSite(unit, repaired->getType(), repaired->getPos(), repaired->getModelFacing()); - } - else { - ts = routePlanner->findPath(unit, repairPos); - } - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1812,9 +1743,6 @@ void UnitUpdater::updateProduce(Unit *unit, int frameIndex) { case pfBasic: newpath = new UnitPathBasic(); break; - case pfRoutePlanner: - newpath = new UnitPath(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1921,10 +1849,6 @@ void UnitUpdater::updateMorph(Unit *unit, int frameIndex) { switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; - case pfRoutePlanner: - oldSize = unit->getType()->getSize(); - needMapUpdate = unit->getType()->isMobile() != mct->getMorphUnit()->isMobile(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1938,12 +1862,6 @@ void UnitUpdater::updateMorph(Unit *unit, int frameIndex) { switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; - case pfRoutePlanner: - if (needMapUpdate) { - int size = max(oldSize, unit->getType()->getSize()); - world->getCartographer()->updateMapMetrics(unit->getPos(), size); - } - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1967,57 +1885,8 @@ void UnitUpdater::updateMorph(Unit *unit, int frameIndex) { // ==================== updateMove ==================== void UnitUpdater::updateSwitchTeam(Unit *unit, int frameIndex) { -// Chrono chrono; -// if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); -// -// Command *command= unit->getCurrCommand(); -// const MoveCommandType *mct= static_cast(command->getCommandType()); -// -// Vec2i pos= command->getUnit()!=NULL? command->getUnit()->getCenteredPos(): command->getPos(); -// -// if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { -// char szBuf[4096]=""; -// sprintf(szBuf,"[updateMove] pos [%s] unit [%d - %s] cmd [%s]",pos.getString().c_str(),unit->getId(),unit->getFullName().c_str(),command->toString().c_str()); -// unit->logSynchData(__FILE__,__LINE__,szBuf); -// } -// -// if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); -// -// TravelState tsValue = tsImpossible; -// switch(this->game->getGameSettings()->getPathFinderType()) { -// case pfBasic: -// tsValue = pathFinder->findPath(unit, pos, NULL, frameIndex); -// break; -// case pfRoutePlanner: -// tsValue = routePlanner->findPath(unit, pos); -// break; -// default: -// throw megaglest_runtime_error("detected unsupported pathfinder type!"); -// } -// -// if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); -// -// if(frameIndex < 0) { -// switch (tsValue) { -// case tsMoving: -// unit->setCurrSkill(mct->getMoveSkillType()); -// break; -// -// case tsBlocked: -// unit->setCurrSkill(scStop); -// if(unit->getPath()->isBlocked()){ -// unit->finishCommand(); -// } -// break; -// -// default: -// unit->finishCommand(); -// } -// } -// if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } - // ==================== updateAttack ==================== // ==================== PRIVATE ==================== @@ -2094,11 +1963,6 @@ void UnitUpdater::damage(Unit *attacker, const AttackSkillType* ast, Unit *attac switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: break; - case pfRoutePlanner: - if (!attacked->getType()->isMobile()) { - world->getCartographer()->updateMapMetrics(attacked->getPos(), attacked->getType()->getSize()); - } - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -2627,7 +2491,6 @@ void UnitUpdater::saveGame(XmlNode *rootNode) { // ScriptManager *scriptManager; // PathFinder *pathFinder; pathFinder->saveGame(unitupdaterNode); -// RoutePlanner *routePlanner; // Game *game; // RandomGen random; //unitupdaterNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements); diff --git a/source/glest_game/world/unit_updater.h b/source/glest_game/world/unit_updater.h index 4af2b948..82527040 100644 --- a/source/glest_game/world/unit_updater.h +++ b/source/glest_game/world/unit_updater.h @@ -32,7 +32,6 @@ class Unit; class Map; class ScriptManager; class PathFinder; -class RoutePlanner; // ===================================================== // class UnitUpdater @@ -79,7 +78,6 @@ private: Console *console; ScriptManager *scriptManager; PathFinder *pathFinder; - RoutePlanner *routePlanner; Game *game; //RandomGen random; float attackWarnRange; diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index 0d87b9ce..34c685c0 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -22,7 +22,6 @@ #include "sound_renderer.h" #include "game_settings.h" #include "cache_manager.h" -#include "route_planner.h" #include #include "sound.h" #include "sound_renderer.h" @@ -69,9 +68,6 @@ World::World() { MaxExploredCellsLookupItemCache= config.getInt("MaxExploredCellsLookupItemCache",intToStr(MaxExploredCellsLookupItemCache).c_str()); //MaxExploredCellsLookupItemCache = 0; - routePlanner = 0; - cartographer = 0; - frameCount= 0; //nextUnitId= 0; @@ -122,9 +118,6 @@ void World::cleanup() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - delete routePlanner; - routePlanner = 0; - for(std::map::iterator iterMap = staticSoundList.begin(); iterMap != staticSoundList.end(); ++iterMap) { delete iterMap->second; @@ -139,8 +132,6 @@ void World::cleanup() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - delete cartographer; - cartographer = 0; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } @@ -244,12 +235,6 @@ void World::init(Game *game, bool createUnits, bool initFactions){ initMap(); initSplattedTextures(); - // must be done after initMap() - if(gs->getPathFinderType() != pfBasic) { - routePlanner = new RoutePlanner(this); - cartographer = new Cartographer(this); - } - unitUpdater.init(game); if(loadWorldNode != NULL) { unitUpdater.loadGame(loadWorldNode); @@ -709,10 +694,6 @@ void World::tick() { } } } - - if(cartographer != NULL) { - cartographer->tick(); - } } Unit* World::findUnitById(int id) const { @@ -941,9 +922,6 @@ void World::createUnit(const string &unitName, int factionIndex, const Vec2i &po case pfBasic: newpath = new UnitPathBasic(); break; - case pfRoutePlanner: - newpath = new UnitPath(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -1605,9 +1583,6 @@ void World::initUnitsForScenario() { if (unit->getType()->hasSkillClass(scBeBuilt)) { map.flatternTerrain(unit); - if(cartographer != NULL) { - cartographer->updateMapMetrics(unit->getPos(), unit->getType()->getSize()); - } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); } @@ -1640,9 +1615,6 @@ void World::placeUnitAtLocation(const Vec2i &location, int radius, Unit *unit, b } if (unit->getType()->hasSkillClass(scBeBuilt)) { map.flatternTerrain(unit); - if(cartographer != NULL) { - cartographer->updateMapMetrics(unit->getPos(), unit->getType()->getSize()); - } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); @@ -1673,9 +1645,6 @@ void World::initUnits() { case pfBasic: newpath = new UnitPathBasic(); break; - case pfRoutePlanner: - newpath = new UnitPath(); - break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } @@ -2325,8 +2294,6 @@ void World::saveGame(XmlNode *rootNode) { // RandomGen random; worldNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements); // ScriptManager* scriptManager; -// Cartographer *cartographer; -// RoutePlanner *routePlanner; // // int thisFactionIndex; worldNode->addAttribute("thisFactionIndex",intToStr(thisFactionIndex), mapTagReplacements); diff --git a/source/glest_game/world/world.h b/source/glest_game/world/world.h index 2affebaa..5c49679a 100644 --- a/source/glest_game/world/world.h +++ b/source/glest_game/world/world.h @@ -49,8 +49,6 @@ class Config; class Game; class GameSettings; class ScriptManager; -class Cartographer; -class RoutePlanner; class StaticSound; class StrSound; @@ -123,8 +121,6 @@ private: RandomGen random; ScriptManager* scriptManager; - Cartographer *cartographer; - RoutePlanner *routePlanner; int thisFactionIndex; int thisTeamIndex; @@ -181,8 +177,6 @@ public: inline const TimeFlow *getTimeFlow() const {return &timeFlow;} inline Tileset *getTileset() {return &tileset;} inline Map *getMap() {return ↦} - Cartographer* getCartographer() {return cartographer;} - RoutePlanner* getRoutePlanner() {return routePlanner;} inline const Faction *getFaction(int i) const {return factions[i];} inline Faction *getFaction(int i) {return factions[i];} inline const Minimap *getMinimap() const {return &minimap;} diff --git a/source/shared_lib/include/util/heap.h b/source/shared_lib/include/util/heap.h deleted file mode 100644 index eee1f2cb..00000000 --- a/source/shared_lib/include/util/heap.h +++ /dev/null @@ -1,119 +0,0 @@ -// ============================================================== -// This file is part of the Glest Advanced Engine -// -// Copyright (C) 2010 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== -#ifndef _MIN_HEAP_INCLUDED_ -#define _MIN_HEAP_INCLUDED_ - -#include - -namespace Shared { namespace Util { - -/** 'Nodes' nead to implement this implicit interface: - -struct SomeNode { - - void setHeapIndex(int ndx); // typically, { heap_ndx = ndx; } - int getHeapIndex() const; // typically, { return heap_ndx; } - - bool operator<(const SomeNode &that) const; -}; -*/ - -/** (Min) Heap, supporting node 'index awareness'. - * stores pointers to Nodes, user needs to supply the actual nodes, preferably in single block - * of memory, and preferably with as compact a node structure as is possible (to the point that the - * int 'heap_ndx' should be a bitfield using as few bits as you can get away with). - */ -template class MinHeap { -private: - Node** data; - int counter; - int capacity; - -public: - /** Construct MinHeap with a given capacity */ - MinHeap(int capacity = 1024) : counter(0), capacity(capacity) { - data = new Node*[capacity]; - } - - ~MinHeap() { - delete [] data; - } - - /** add a new node to the min heap */ - bool insert(Node *node) { - if (counter == capacity) { - return false; - } - data[counter] = node; - data[counter]->setHeapIndex(counter); - promoteNode(counter++); - return true; - } - - /** pop the best node off the min heap */ - Node* extract() { - assert(counter); - Node *res = data[0]; - if (--counter) { - data[0] = data[counter]; - data[0]->setHeapIndex(0); - demoteNode(); - } - return res; - } - - /** indicate a node has had its key decreased */ - void promote(Node *node) { - assert(data[node->getHeapIndex()] == node); - promoteNode(node->getHeapIndex()); - } - - int size() const { return counter; } - void clear() { counter = 0; } - bool empty() const { return !counter; } - -private: - inline int parent(int ndx) const { return (ndx - 1) / 2; } - inline int left(int ndx) const { return (ndx * 2) + 1; } - - void promoteNode(int ndx) { - assert(ndx >= 0 && ndx < counter); - while (ndx > 0 && *data[ndx] < *data[parent(ndx)]) { - Node *tmp = data[parent(ndx)]; - data[parent(ndx)] = data[ndx]; - data[ndx] = tmp; - data[ndx]->setHeapIndex(ndx); - ndx = parent(ndx); - data[ndx]->setHeapIndex(ndx); - } - } - - void demoteNode(int ndx = 0) { - assert(counter); - while (true) { - int cndx = left(ndx); // child index - int sndx = ndx; // smallest (priority) of data[ndx] and any children - if (cndx < counter && *data[cndx] < *data[ndx]) sndx = cndx; - if (++cndx < counter && *data[cndx] < *data[sndx]) sndx = cndx; - if (sndx == ndx) return; - Node *tmp = data[sndx]; - data[sndx] = data[ndx]; - data[ndx] = tmp; - data[ndx]->setHeapIndex(ndx); - ndx = sndx; - data[ndx]->setHeapIndex(ndx); - } - } -}; - -}} // end namespace Shared::Util - -#endif // _MIN_HEAP_INCLUDED_ diff --git a/source/shared_lib/include/util/line.h b/source/shared_lib/include/util/line.h deleted file mode 100644 index 061cac26..00000000 --- a/source/shared_lib/include/util/line.h +++ /dev/null @@ -1,83 +0,0 @@ -// ============================================================== -// This file is part of the Glest Advanced Engine -// -// Copyright (C) 2010 James McCulloch -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== -#ifndef _LINE_ALGORITHM_INCLUDED_ -#define _LINE_ALGORITHM_INCLUDED_ - -#include - -namespace Shared { namespace Util { - -/** midpoint line algorithm, 'Visit' specifies the 'pixel visit' function, * - * and must take two int params (x & y co-ords) */ -template void line(int x0, int y0, int x1, int y1, VisitFunc visitor) { - bool mirror_x, mirror_y; - int pivot_x, pivot_y; - if (x0 > x1) { - mirror_x = true; - pivot_x = x0; - x1 = (x0 << 1) - x1; - } else { - mirror_x = false; - } - if (y0 > y1) { - mirror_y = true; - pivot_y = y0; - y1 = (y0 << 1) - y1; - } else { - mirror_y = false; - } - // Visit(x,y) => Visit(mirror_x ? (pivot_x << 1) - x : x, mirror_y ? (pivot_y << 1) - y : y); - assert(y0 <= y1 && x0 <= x1); - int dx = x1 - x0, - dy = y1 - y0; - int x = x0, - y = y0; - - if (dx == 0) { - while (y <= y1) { - visitor(mirror_x ? (pivot_x << 1) - x : x, mirror_y ? (pivot_y << 1) - y : y); - ++y; - } - } else if (dy == 0) { - while (x <= x1) { - visitor(mirror_x ? (pivot_x << 1) - x : x, mirror_y ? (pivot_y << 1) - y : y); - ++x; - } - } else if (dy > dx) { - int d = 2 * dx - dy; - int incrS = 2 * dx; - int incrSE = 2 * (dx - dy); - do { - visitor(mirror_x ? (pivot_x << 1) - x : x, mirror_y ? (pivot_y << 1) - y : y); - if (d <= 0) { - d += incrS; ++y; - } else { - d += incrSE; ++x; ++y; - } - } while (y <= y1); - } else { - int d = 2 * dy - dx; - int incrE = 2 * dy; - int incrSE = 2 * (dy - dx); - do { - visitor(mirror_x ? (pivot_x << 1) - x : x, mirror_y ? (pivot_y << 1) - y : y); - if (d <= 0) { - d += incrE; ++x; - } else { - d += incrSE; ++x; ++y; - } - } while (x <= x1); - } -} - -}} // end namespace Shared::Util - -#endif // !def _LINE_ALGORITHM_INCLUDED_