diff --git a/source/glest_game/ai/path_finder.cpp b/source/glest_game/ai/path_finder.cpp index 4049498f..cb93738d 100644 --- a/source/glest_game/ai/path_finder.cpp +++ b/source/glest_game/ai/path_finder.cpp @@ -173,10 +173,18 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos) { throw runtime_error("unsupported or missing path finder detected!"); } } + else if(ts == tsArrived) { + ts = aStar(unit, finalPos); + break; + } } } } unit->setInBailOutAttempt(false); + + if(ts == tsArrived) { + ts = tsBlocked; + } } unit->setCurrSkill(scStop); break; @@ -230,17 +238,20 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ //if arrived if(finalPos == unit->getPos()) { - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { - string commandDesc = "none"; - Command *command= unit->getCurrCommand(); - if(command != NULL && command->getCommandType() != NULL) { - commandDesc = command->getCommandType()->toString(); + Command *command= unit->getCurrCommand(); + if(command == NULL || command->getPos() != unit->getPos()) { + if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { + string commandDesc = "none"; + Command *command= unit->getCurrCommand(); + if(command != NULL && command->getCommandType() != NULL) { + commandDesc = command->getCommandType()->toString(); + } + char szBuf[1024]=""; + sprintf(szBuf,"State: arrived#2 at pos: %s, command [%s]",targetPos.getString().c_str(),commandDesc.c_str()); + unit->setCurrentUnitTitle(szBuf); } - char szBuf[1024]=""; - sprintf(szBuf,"State: arrived#2 at pos: %s, command [%s]",targetPos.getString().c_str(),commandDesc.c_str()); - unit->setCurrentUnitTitle(szBuf); + return tsArrived; } - return tsArrived; } //path find algorithm @@ -338,8 +349,10 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){ commandDesc = command->getCommandType()->toString(); } + std::pair lastHarvest = unit->getLastHarvestResourceTarget(); + char szBuf[1024]=""; - sprintf(szBuf,"State: blocked, cmd [%s] pos: %s, dest pos: %s, reason A= %d, B= %d, C= %d, D= %d, E= %d, F = %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),pathFound,(lastNode == firstNode),path->getBlockCount(), path->isBlocked(), nodeLimitReached,path->isStuck()); + sprintf(szBuf,"State: blocked, cmd [%s] pos: [%s], dest pos: [%s], lastHarvest = [%s - %lld], reason A= %d, B= %d, C= %d, D= %d, E= %d, F = %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),lastHarvest.first.getString().c_str(),lastHarvest.second.getMillis(), pathFound,(lastNode == firstNode),path->getBlockCount(), path->isBlocked(), nodeLimitReached,path->isStuck()); unit->setCurrentUnitTitle(szBuf); } diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 42ee3d31..1583d2c9 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -183,6 +183,7 @@ Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType this->retryCurrCommandCount=0; this->screenPos = Vec3f(0.0); this->inBailOutAttempt = false; + this->lastHarvestResourceTarget.first = Vec2i(0); level= NULL; loadType= NULL; @@ -245,6 +246,8 @@ Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType Unit::~Unit(){ SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] delete unitid = %d\n",__FILE__,__FUNCTION__,__LINE__,id); + badHarvestPosList.clear(); + //Just to be sure, should already be removed if (livingUnits.erase(id)) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -1678,6 +1681,75 @@ void Unit::logSynchData(string source) { } } +void Unit::addBadHarvestPos(const Vec2i &value) { + Chrono chron; + chron.start(); + badHarvestPosList.push_back(std::pair(value,chron)); + cleanupOldBadHarvestPos(); +} + +void Unit::removeBadHarvestPos(const Vec2i &value) { + for(int i = 0; i < badHarvestPosList.size(); ++i) { + const std::pair &item = badHarvestPosList[i]; + if(item.first == value) { + badHarvestPosList.erase(badHarvestPosList.begin() + i); + break; + } + } + cleanupOldBadHarvestPos(); +} + +bool Unit::isBadHarvestPos(const Vec2i &value) { + cleanupOldBadHarvestPos(); + + bool result = false; + for(int i = 0; i < badHarvestPosList.size(); ++i) { + const std::pair &item = badHarvestPosList[i]; + if(item.first == value) { + result = true; + break; + } + } + + return result; +} + +void Unit::cleanupOldBadHarvestPos() { + for(int i = badHarvestPosList.size() - 1; i >= 0; --i) { + const std::pair &item = badHarvestPosList[i]; + + // If this position has been is the list for longer than 120 + // seconds remove it so the unit could potentially try it again + if(item.second.getMillis() >= 1200000) { + badHarvestPosList.erase(badHarvestPosList.begin() + i); + } + } +} + +void Unit::setLastHarvestResourceTarget(const Vec2i *pos) { + if(pos == NULL) { + lastHarvestResourceTarget.first = Vec2i(0); + //lastHarvestResourceTarget.second = 0; + } + else { + const Vec2i resourceLocation = *pos; + if(resourceLocation != lastHarvestResourceTarget.first) { + lastHarvestResourceTarget.first = resourceLocation; + + Chrono chron; + chron.start(); + lastHarvestResourceTarget.second = chron; + } + else { + // If we cannot harvest for > 10 seconds tag the position + // as a bad one + if(lastHarvestResourceTarget.second.getMillis() > 10000) { + addBadHarvestPos(resourceLocation); + } + } + } +} + std::string Unit::toString() const { std::string result = ""; diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index d168016b..1b58aff2 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -18,9 +18,10 @@ #include "skill_type.h" #include "game_constants.h" #include +#include "platform_common.h" #include "leak_dumper.h" -namespace Glest{ namespace Game{ +namespace Glest { namespace Game { using Shared::Graphics::ParticleSystem; using Shared::Graphics::UnitParticleSystem; @@ -29,6 +30,7 @@ using Shared::Graphics::Vec2f; using Shared::Graphics::Vec3f; using Shared::Graphics::Vec2i; using Shared::Graphics::Model; +using Shared::PlatformCommon::Chrono; using std::set; @@ -281,6 +283,13 @@ private: string currentUnitTitle; bool inBailOutAttempt; + // This buffer stores a list of bad harvest cells, along with the start + // time of when it was detected. Typically this may be due to a unit + // constantly getting blocked from getting to the resource so this + // list may be used to tell areas of the game to ignore those cells for a + // period of time + std::vector > badHarvestPosList; + std::pair lastHarvestResourceTarget; static Game *game; @@ -426,6 +435,16 @@ public: bool getInBailOutAttempt() const { return inBailOutAttempt; } void setInBailOutAttempt(bool value) { inBailOutAttempt = value; } + std::vector > getBadHarvestPosList() const { return badHarvestPosList; } + void setBadHarvestPosList(std::vector > value) { badHarvestPosList = value; } + void addBadHarvestPos(const Vec2i &value); + void removeBadHarvestPos(const Vec2i &value); + bool isBadHarvestPos(const Vec2i &value); + void cleanupOldBadHarvestPos(); + + void setLastHarvestResourceTarget(const Vec2i *pos); + std::pair getLastHarvestResourceTarget() const { return lastHarvestResourceTarget;} + std::string toString() const; private: diff --git a/source/glest_game/world/map.cpp b/source/glest_game/world/map.cpp index 2ee54c6a..7e50fa66 100644 --- a/source/glest_game/world/map.cpp +++ b/source/glest_game/world/map.cpp @@ -249,15 +249,18 @@ bool Map::isInsideSurface(const Vec2i &sPos) const{ } //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, const ResourceType *rt, Vec2i &resourcePos, int size) const{ - for(int i=-1; i<=size; ++i){ - for(int j=-1; j<=size; ++j){ - if(isInside(pos.x+i, pos.y+j)){ - Resource *r= getSurfaceCell(toSurfCoords(Vec2i(pos.x+i, pos.y+j)))->getResource(); - if(r!=NULL){ - if(r->getType()==rt){ +bool Map::isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit) const { + for(int i = -1; i <= size; ++i) { + for(int j = -1; j <= size; ++j) { + if(isInside(pos.x + i, pos.y + j)) { + Resource *r= getSurfaceCell(toSurfCoords(Vec2i(pos.x + i, pos.y + j)))->getResource(); + if(r != NULL){ + if(r->getType() == rt) { resourcePos= pos + Vec2i(i,j); - return true; + + if(unit == NULL || unit->isBadHarvestPos(resourcePos) == false) { + return true; + } } } } diff --git a/source/glest_game/world/map.h b/source/glest_game/world/map.h index 486f30ec..88b71918 100755 --- a/source/glest_game/world/map.h +++ b/source/glest_game/world/map.h @@ -197,7 +197,7 @@ public: bool isInside(const Vec2i &pos) const; bool isInsideSurface(int sx, int sy) const; bool isInsideSurface(const Vec2i &sPos) const; - bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size) const; + bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit=NULL) const; bool isResourceNear(const Vec2i &pos, int size, const ResourceType *rt, Vec2i &resourcePos) const; //free cells diff --git a/source/glest_game/world/unit_updater.cpp b/source/glest_game/world/unit_updater.cpp index 54b74ac2..63192a55 100644 --- a/source/glest_game/world/unit_updater.cpp +++ b/source/glest_game/world/unit_updater.cpp @@ -572,7 +572,7 @@ void UnitUpdater::updateBuild(Unit *unit) { // ==================== updateHarvest ==================== -void UnitUpdater::updateHarvest(Unit *unit){ +void UnitUpdater::updateHarvest(Unit *unit) { Chrono chrono; chrono.start(); @@ -585,17 +585,17 @@ void UnitUpdater::updateHarvest(Unit *unit){ if(unit->getCurrSkill()->getClass() != scHarvest) { //if not working - if(unit->getLoadCount()==0){ + if(unit->getLoadCount() == 0) { //if not loaded go for resources Resource *r= map->getSurfaceCell(Map::toSurfCoords(command->getPos()))->getResource(); - if(r!=NULL && hct->canHarvest(r->getType())){ + if(r != NULL && hct->canHarvest(r->getType())) { //if can harvest dest. pos bool canHarvestDestPos = false; switch(this->game->getGameSettings()->getPathFinderType()) { case pfBasic: - canHarvestDestPos = (unit->getPos().dist(command->getPos())isResourceNear(unit->getPos(), r->getType(), targetPos,unit->getType()->getSize())); + canHarvestDestPos = (unit->getPos().dist(command->getPos()) < harvestDistance && + map->isResourceNear(unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit)); break; case pfRoutePlanner: canHarvestDestPos = map->isResourceNear(unit->getPos(), unit->getType()->getSize(), r->getType(), targetPos); @@ -605,22 +605,24 @@ void UnitUpdater::updateHarvest(Unit *unit){ } if (canHarvestDestPos == true) { - //if it finds resources it starts harvesting - unit->setCurrSkill(hct->getHarvestSkillType()); - unit->setTargetPos(targetPos); - command->setPos(targetPos); - unit->setLoadCount(0); + unit->setLastHarvestResourceTarget(&targetPos); - switch(this->game->getGameSettings()->getPathFinderType()) { - case pfBasic: - unit->setLoadType(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->getType()); - break; - case pfRoutePlanner: - unit->setLoadType(r->getType()); - break; - default: - throw runtime_error("detected unsupported pathfinder type!"); - } + //if it finds resources it starts harvesting + unit->setCurrSkill(hct->getHarvestSkillType()); + unit->setTargetPos(targetPos); + command->setPos(targetPos); + unit->setLoadCount(0); + + switch(this->game->getGameSettings()->getPathFinderType()) { + case pfBasic: + unit->setLoadType(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->getType()); + break; + case pfRoutePlanner: + unit->setLoadType(r->getType()); + break; + default: + throw runtime_error("detected unsupported pathfinder type!"); + } } else { @@ -652,7 +654,7 @@ void UnitUpdater::updateHarvest(Unit *unit){ } } } - else{ + else { //if loaded, return to store Unit *store= world->nearestStore(unit->getPos(), unit->getFaction()->getIndex(), unit->getLoadType()); if(store!=NULL) { @@ -702,8 +704,10 @@ void UnitUpdater::updateHarvest(Unit *unit){ } } } - else{ + else { //if working + //unit->setLastHarvestResourceTarget(NULL); + SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos())); Resource *r= sc->getResource();