Find a more logical position to harvest giving a pos inside wood (but still ignore peon pos in computation).

This commit is contained in:
Joris 2012-06-13 11:43:42 +02:00
parent 28f4a213c3
commit 37b23caeb1
4 changed files with 74 additions and 78 deletions

View file

@ -71,22 +71,73 @@
-- Functions
----------------------------------------------------------------------------*/
class NearReachableTerrainFinder
{
public:
NearReachableTerrainFinder(const CPlayer &player, int maxDist, int movemask, int resmask, Vec2i* resPos) :
player(player), maxDist(maxDist), movemask(movemask), resmask(resmask), resPos(resPos) {}
VisitResult Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from);
private:
const CPlayer &player;
int maxDist;
int movemask;
int resmask;
Vec2i* resPos;
};
VisitResult NearReachableTerrainFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from)
{
if (!player.AiEnabled && !Map.IsFieldExplored(player, pos)) {
terrainTraversal.Get(pos) = -1;
return VisitResult_DeadEnd;
}
// Look if found what was required.
if (CanMoveToMask(pos, movemask)) {
if (resPos) {
*resPos = from;
}
return VisitResult_Finished;
}
if (Map.CheckMask(pos, resmask)) { // reachable
terrainTraversal.Get(pos) = terrainTraversal.Get(from) + 1;
if (terrainTraversal.Get(pos) <= maxDist) {
return VisitResult_Ok;
} else {
return VisitResult_DeadEnd;
}
} else { // unreachable
terrainTraversal.Get(pos) = -1;
return VisitResult_DeadEnd;
}
}
static bool FindNearestReachableTerrainType(int movemask, int resmask, int range,
const CPlayer &player, const Vec2i &startPos, Vec2i *terrainPos)
{
TerrainTraversal terrainTraversal;
terrainTraversal.SetSize(Map.Info.MapWidth, Map.Info.MapHeight);
terrainTraversal.Init(-1);
Assert(Map.CheckMask(startPos, resmask));
terrainTraversal.PushPos(startPos);
NearReachableTerrainFinder nearReachableTerrainFinder(player, range, movemask, resmask, terrainPos);
return terrainTraversal.Run(nearReachableTerrainFinder);
}
/* static */ COrder *COrder::NewActionResource(CUnit &harvester, const Vec2i &pos)
{
COrder_Resource *order = new COrder_Resource(harvester);
Vec2i ressourceLoc;
// Find the closest piece of wood next to a tile where the unit can move
if (!FindTerrainType(0, (harvester.Type->MovementMask), 1, 20, *harvester.Player, pos, &ressourceLoc)) {
if (!FindNearestReachableTerrainType(harvester.Type->MovementMask, MapFieldForest, 20, *harvester.Player, pos, &ressourceLoc)) {
DebugPrint("FIXME: Give up???\n");
}
// Max Value > 1
if ((MyAbs(ressourceLoc.x - pos.x) | MyAbs(ressourceLoc.y - pos.y)) > 1) {
if (!FindTerrainType(0, MapFieldForest, 0, 20, *harvester.Player, ressourceLoc, &ressourceLoc)) {
DebugPrint("FIXME: Give up???\n");
}
} else {
// The destination is next to a reachable tile.
ressourceLoc = pos;
}
order->goalPos = ressourceLoc;
@ -320,8 +371,7 @@ int COrder_Resource::MoveToResource_Terrain(CUnit &unit)
// Wood gone, look somewhere else.
if ((Map.Info.IsPointOnMap(pos) == false || Map.ForestOnMap(pos) == false) && (!unit.IX) && (!unit.IY)) {
if (!FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 16,
*unit.Player, this->goalPos, &pos)) {
if (!FindTerrainType(unit.Type->MovementMask, MapFieldForest, 16, *unit.Player, this->goalPos, &pos)) {
// no wood in range
return -1;
} else {
@ -331,8 +381,7 @@ int COrder_Resource::MoveToResource_Terrain(CUnit &unit)
switch (DoActionMove(unit)) {
case PF_UNREACHABLE:
unit.Wait = 10;
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 9999,
*unit.Player, unit.tilePos, &pos)) {
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 9999, *unit.Player, unit.tilePos, &pos)) {
this->goalPos = pos;
DebugPrint("Found a better place to harvest %d,%d\n" _C_ pos.x _C_ pos.y);
// FIXME: can't this overflow? It really shouldn't, since
@ -959,7 +1008,7 @@ bool COrder_Resource::WaitInDepot(CUnit &unit)
if (resinfo.TerrainHarvester) {
Vec2i pos = this->Resource.Pos;
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 10, *unit.Player, pos, &pos)) {
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 10, *unit.Player, pos, &pos)) {
if (depot) {
DropOutNearest(unit, pos, depot);
}

View file

@ -835,7 +835,7 @@ static int AiAssignHarvesterFromTerrain(CUnit &unit, int resource)
Vec2i forestPos;
// Code for terrain harvesters. Search for piece of terrain to mine.
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 1000, *unit.Player, unit.tilePos, &forestPos)) {
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 1000, *unit.Player, unit.tilePos, &forestPos)) {
CommandResourceLoc(unit, forestPos, FlushCommands);
return 1;
}

View file

@ -947,7 +947,7 @@ extern CUnit *FindDeposit(const CUnit &unit, int range, int resource);
extern CUnit *FindIdleWorker(const CPlayer &player, const CUnit *last);
/// Find the neareast piece of terrain with specific flags.
extern bool FindTerrainType(int movemask, int resmask, int rvresult, int range,
extern bool FindTerrainType(int movemask, int resmask, int range,
const CPlayer &player, const Vec2i &startPos, Vec2i *pos);
/// @todo more docu

View file

@ -2008,8 +2008,8 @@ void DropOutAll(const CUnit &source)
class TerrainFinder
{
public:
TerrainFinder(const CPlayer &player, int maxDist, int movemask, int resmask, Vec2i* resPos, Vec2i* lastPos) :
player(player), maxDist(maxDist), movemask(movemask), resmask(resmask), resPos(resPos), lastPos(lastPos) {}
TerrainFinder(const CPlayer &player, int maxDist, int movemask, int resmask, Vec2i* resPos) :
player(player), maxDist(maxDist), movemask(movemask), resmask(resmask), resPos(resPos) {}
VisitResult Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from);
private:
const CPlayer &player;
@ -2017,22 +2017,6 @@ private:
int movemask;
int resmask;
Vec2i* resPos;
Vec2i* lastPos;
};
class TerrainFinder_Inv
{
public:
TerrainFinder_Inv(const CPlayer &player, int maxDist, int movemask, int resmask, Vec2i* resPos, Vec2i* lastPos) :
player(player), maxDist(maxDist), movemask(movemask), resmask(resmask), resPos(resPos), lastPos(lastPos) {}
VisitResult Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from);
private:
const CPlayer &player;
int maxDist;
int movemask;
int resmask;
Vec2i* resPos;
Vec2i* lastPos;
};
VisitResult TerrainFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from)
@ -2042,11 +2026,9 @@ VisitResult TerrainFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i
return VisitResult_DeadEnd;
}
// Look if found what was required.
bool can_move_to = CanMoveToMask(pos, resmask);
if (!can_move_to) {
*resPos = pos;
if (lastPos) {
*lastPos = from;
if (Map.CheckMask(pos, resmask)) {
if (resPos) {
*resPos = pos;
}
return VisitResult_Finished;
}
@ -2063,53 +2045,24 @@ VisitResult TerrainFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i
}
}
VisitResult TerrainFinder_Inv::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from)
{
if (!player.AiEnabled && !Map.IsFieldExplored(player, pos)) {
terrainTraversal.Get(pos) = -1;
return VisitResult_DeadEnd;
}
// Look if found what was required.
bool can_move_to = CanMoveToMask(pos, resmask);
if (can_move_to) {
*resPos = pos;
return VisitResult_Finished;
}
if (CanMoveToMask(pos, movemask)) { // reachable
terrainTraversal.Get(pos) = terrainTraversal.Get(from) + 1;
if (terrainTraversal.Get(pos) <= maxDist) {
return VisitResult_Ok;
} else {
return VisitResult_DeadEnd;
}
} else { // unreachable
terrainTraversal.Get(pos) = -1;
return VisitResult_DeadEnd;
}
}
/**
** Find the closest piece of terrain with the given flags.
**
** @param movemask The movement mask to reach that location.
** @param resmask Result tile mask.
** @param rvresult Return a tile that doesn't match.
** @param range Maximum distance for the search.
** @param player Only search fields explored by player
** @param startPos Map start position for the search.
**
** @param pos OUT: Map position of tile.
** @param terrainPos OUT: Map position of tile.
**
** @note Movement mask can be 0xFFFFFFFF to have no effect
** Range is not circular, but square.
** Player is ignored if nil(search the entire map)
** Use rvresult if you search for a tile that doesn't
** match resmask. Like for a tile where an unit can go
** with it's movement mask.
**
** @return True if wood was found.
*/
bool FindTerrainType(int movemask, int resmask, int rvresult, int range,
bool FindTerrainType(int movemask, int resmask, int range,
const CPlayer &player, const Vec2i &startPos, Vec2i *terrainPos)
{
TerrainTraversal terrainTraversal;
@ -2119,15 +2072,9 @@ bool FindTerrainType(int movemask, int resmask, int rvresult, int range,
terrainTraversal.PushPos(startPos);
if (rvresult) {
TerrainFinder_Inv terrainFinder(player, range, movemask, resmask, terrainPos, NULL);
TerrainFinder terrainFinder(player, range, movemask, resmask, terrainPos);
return terrainTraversal.Run(terrainFinder);
} else {
TerrainFinder terrainFinder(player, range, movemask, resmask, terrainPos, NULL);
return terrainTraversal.Run(terrainFinder);
}
return terrainTraversal.Run(terrainFinder);
}