port depot finder change from Wyrmgus that searches from outside mine

This commit is contained in:
Tim Felgentreff 2022-02-20 08:39:10 +01:00
parent f454ad3227
commit 02b70a362b
6 changed files with 69 additions and 41 deletions

View file

@ -910,20 +910,19 @@ int COrder_Resource::StopGathering(CUnit &unit)
// Find and send to resource deposit.
CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource);
// There's a bug in the traversal that leads to workers "sometimes" not finding their way to the old depot
// TODO: once we figure out that bug, this workaround can probably be removed.
// There's a bug in the traversal that leads to workers "sometimes" not finding their way to the old depot.
// timfel: of course, maybe it's actually nice that workers drop out towards their last depot...
if (!depot && (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) && Depot && Depot->IsAlive()) {
CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource);
Assert(unit.Container);
DropOutNearest(unit, Depot->tilePos + depot->Type->GetHalfTileSize(), source);
// try to path again
depot = FindDeposit(unit, 1000, unit.CurrentResource);
DropOutNearest(unit, Depot->tilePos + Depot->Type->GetHalfTileSize(), source);
}
Depot = depot;
if (!depot || !unit.ResourcesHeld || this->Finished) {
if (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) {
Assert(unit.Container);
DropOutOnSide(unit, LookingW, source);
if (unit.Container) {
DropOutOnSide(unit, LookingW, source);
}
}
CUnit *mine = this->Resource.Mine;

View file

@ -926,7 +926,7 @@ void AiCanNotMove(CUnit &unit)
const int gh = unit.pathFinderData->input.GetGoalSize().y;
AiPlayer = unit.Player->Ai;
if (PlaceReachable(unit, goalPos, gw, gh, 0, 255)) {
if (PlaceReachable(unit, goalPos, gw, gh, 0, 255, false)) {
// Path probably closed by unit here
AiMoveUnitInTheWay(unit);
}

View file

@ -219,13 +219,13 @@ extern void FreePathfinder();
/// Returns the next element of the path
extern int NextPathElement(CUnit &unit, short int *xdp, short int *ydp);
/// Return path length to unit 'dst'.
extern int UnitReachable(const CUnit &src, const CUnit &dst, int range);
extern int UnitReachable(const CUnit &src, const CUnit &dst, int range, bool from_outside_container);
/// Return path length to unit 'dst' or error code.
extern int CalcPathLengthToUnit(const CUnit &src, const CUnit &dst,
const int minrange, const int range);
/// Can the unit 'src' reach the place x,y
extern int PlaceReachable(const CUnit &src, const Vec2i &pos, int w, int h,
int minrange, int maxrange);
int minrange, int maxrange, bool from_outside_container);
//
// in astar.cpp

View file

@ -183,33 +183,68 @@ void FreePathfinder()
**
** @return Distance to place.
*/
int PlaceReachable(const CUnit &src, const Vec2i &goalPos, int w, int h, int minrange, int range)
int PlaceReachable(const CUnit &src, const Vec2i &goalPos, int w, int h, int minrange, int range, bool from_outside_container)
{
SetAStarFixedEnemyUnitsUnpassable(true); /// change Path Finder setting to don't count tiles with enemy units as passable
int i = AStarFindPath(src.tilePos, goalPos, w, h,
src.Type->TileWidth, src.Type->TileHeight,
minrange, range, NULL, 0, src);
int i;
Vec2i srcTilePos = src.tilePos;
int srcTW = src.Type->TileWidth;
int srcTH = src.Type->TileHeight;
if (!from_outside_container || !src.Container) {
i = AStarFindPath(srcTilePos, goalPos, w, h,
srcTW, srcTH,
minrange, range, nullptr, 0, src);
} else {
const CUnit *first_container = GetFirstContainer(src);
const Vec2i offset(1, 1);
int containerW = first_container->Type->TileWidth;
int containerH = first_container->Type->TileHeight;
Vec2i containerTilePos = first_container->tilePos;
// check top and bottom rows and left and right columns around the container
for (int x = -1; x <= containerW; x++) {
for (int y = -1; y <= containerH; y++) {
if (x >= 0 && x < containerW && y >= 0 && y < containerH) {
// inside the container, no need to check
continue;
}
Vec2i tile_pos = containerTilePos + Vec2i(x, y);
if (!Map.Info.IsPointOnMap(tile_pos)) {
continue;
}
if (!CanMoveToMask(tile_pos, src.Type->MovementMask)) {
//ignore tiles to which the unit cannot be dropped from its container
continue;
}
i = AStarFindPath(tile_pos, goalPos, w, h,
srcTW, srcTH,
minrange, range, nullptr, 0, src);
switch (i) {
case PF_FAILED:
case PF_UNREACHABLE:
case PF_WAIT:
continue;
}
goto finished;
}
}
}
finished:
SetAStarFixedEnemyUnitsUnpassable(false); /// restore Path Finder setting
switch (i) {
case PF_FAILED:
case PF_UNREACHABLE:
i = 0;
break;
case PF_WAIT:
return 0;
case PF_REACHED:
/* since most of this function usage check return value as bool
* then reached state should be track as true value */
i = 1;
break;
case PF_WAIT:
Assert(0);
i = 0;
break;
case PF_MOVE:
break;
* then reached state should be track as true value */
return std::max(i, 1);
default:
break;
return i;
}
return i;
}
/**
@ -221,14 +256,14 @@ int PlaceReachable(const CUnit &src, const Vec2i &goalPos, int w, int h, int min
**
** @return Distance to place.
*/
int UnitReachable(const CUnit &src, const CUnit &dst, int range)
int UnitReachable(const CUnit &src, const CUnit &dst, int range, bool from_outside_container)
{
// Find a path to the goal.
if (src.Type->Building) {
return 0;
}
const int depth = PlaceReachable(src, dst.tilePos,
dst.Type->TileWidth, dst.Type->TileHeight, 0, range);
dst.Type->TileWidth, dst.Type->TileHeight, 0, range, from_outside_container);
if (depth <= 0) {
return 0;
}

View file

@ -2984,7 +2984,7 @@ static void HitUnit_AttackBack(CUnit &attacker, CUnit &target)
COrder_Attack &order = dynamic_cast<COrder_Attack &>(*target.CurrentOrder());
if (order.IsAutoTargeting() || target.Player->AiEnabled) {
if (attacker.IsVisibleAsGoal(*target.Player)) {
if (UnitReachable(target, attacker, target.Stats->Variables[ATTACKRANGE_INDEX].Max)) {
if (UnitReachable(target, attacker, target.Stats->Variables[ATTACKRANGE_INDEX].Max, false)) {
target.UnderAttack = underAttack; /// allow target to ignore non aggressive targets while searching attacker
order.OfferNewTarget(target, &attacker);
}
@ -3018,7 +3018,7 @@ static void HitUnit_AttackBack(CUnit &attacker, CUnit &target)
const Vec2i posToAttack = (attacker.IsVisibleAsGoal(*target.Player))
? attacker.tilePos
: GetRndPosInDirection(target.tilePos, attacker.tilePos, false, target.Type->ReactRangeComputer, 2);
if (!PlaceReachable(target, posToAttack, 1, 1, 0, target.Stats->Variables[ATTACKRANGE_INDEX].Max)) {
if (!PlaceReachable(target, posToAttack, 1, 1, 0, target.Stats->Variables[ATTACKRANGE_INDEX].Max, false)) {
return;
}
COrder *savedOrder = NULL;

View file

@ -213,14 +213,8 @@ class BestDepotFinder
return;
}
// calck real travel distance
if (worker->Container != nullptr) {
UnmarkUnitFieldFlags(*first_container);
}
const int travel_distance = UnitReachable(*worker, *dest, 1);
if (worker->Container != nullptr) {
MarkUnitFieldFlags(*first_container);
}
// calc real travel distance
const int travel_distance = UnitReachable(*worker, *dest, 1, worker->Container != nullptr);
//
// Take this depot?
//
@ -730,7 +724,7 @@ private:
// Unit in range ?
const int d = attacker->MapDistanceTo(*dest);
if (d > attackrange && !UnitReachable(*attacker, *dest, attackrange)) {
if (d > attackrange && !UnitReachable(*attacker, *dest, attackrange, false)) {
return INT_MAX;
}
@ -934,7 +928,7 @@ public:
int attackrange = attacker->Stats->Variables[ATTACKRANGE_INDEX].Max;
if (d <= attackrange ||
(d <= range && UnitReachable(*attacker, *dest, attackrange))) {
(d <= range && UnitReachable(*attacker, *dest, attackrange, false))) {
++enemy_count;
} else {
dest->CacheLock = 1;