diff --git a/.vscode/launch.json b/.vscode/launch.json index 528044c45..b85377ba2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "windows": { "type": "cppvsdbg", "program": "${workspaceFolder}/build/Debug/stratagus-dbg.exe", - "args": ["-W", "-p", "-a", "-d", "${workspaceFolder}\\..\\data.${input:game}"], + "args": ["-W", "-i", "-p", "-P", "${input:port}", "-a", "-d", "${workspaceFolder}\\..\\data.${input:game}"], "environment": [ {"name": "PATH", "value": "${workspaceFolder}\\..\\dependencies\\bin;${env:PATH}"}, {"name": "OMP_WAIT_POLICY", "value": "passive"} @@ -23,7 +23,7 @@ }, "stopAtEntry": false, "cwd": "${workspaceFolder}/../${input:game}", - } + }, ], "inputs": [ { @@ -37,5 +37,11 @@ ], "default": "wargus" }, + { + "type": "promptString", + "id": "port", + "description": "Network port?", + "default": "6600" + } ] } diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp index a1e735788..4d69479cc 100644 --- a/src/action/action_resource.cpp +++ b/src/action/action_resource.cpp @@ -221,6 +221,8 @@ COrder_Resource::~COrder_Resource() worker->DeAssignWorkerFromMine(*mine); } + Depot = NULL; + CUnit *goal = this->GetGoal(); if (goal) { // If mining decrease the active count on the resource. @@ -908,10 +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. + // 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); + } + 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; @@ -921,13 +932,15 @@ int COrder_Resource::StopGathering(CUnit &unit) } DebugPrint("%d: Worker %d report: Can't find a resource [%d] deposit.\n" - _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.CurrentResource); + _C_ unit.Player->Index _C_ UnitNumber(unit) _C_ unit.CurrentResource); this->Finished = true; return 0; } else { if (!(resinfo.HarvestFromOutside || resinfo.TerrainHarvester)) { - Assert(unit.Container); - DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(), source); + if (unit.Container) { + // may have dropped out above + DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(), source); + } } UnitGotoGoal(unit, depot, SUB_MOVE_TO_DEPOT); } diff --git a/src/action/actions.cpp b/src/action/actions.cpp index 6881e62c0..7d97e94a6 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -77,6 +77,14 @@ #include "unit_manager.h" #include "unittype.h" +#ifdef USE_STACKTRACE +#include <stdexcept> +#include <stacktrace/call_stack.hpp> +#include <stacktrace/stack_exception.hpp> +#else +#include "st_backtrace.h" +#endif + /*---------------------------------------------------------------------------- -- Variables ----------------------------------------------------------------------------*/ @@ -483,11 +491,38 @@ static void DumpUnitInfo(CUnit &unit) } fprintf(logf, "%lu: ", GameCycle); - fprintf(logf, "%d %s %d P%d Refs %d: %X %d,%d %d,%d\n", + + const char *currentAction; + switch (!unit.Orders.empty() ? unit.CurrentAction() : -1) { + case -1: currentAction = "No Orders"; break; + case UnitActionNone: currentAction = "None"; break; + case UnitActionStill: currentAction = "Still"; break; + case UnitActionStandGround: currentAction = "StandGround"; break; + case UnitActionFollow: currentAction = "Follow"; break; + case UnitActionDefend: currentAction = "Defend"; break; + case UnitActionMove: currentAction = "Move"; break; + case UnitActionAttack: currentAction = "Attack"; break; + case UnitActionAttackGround: currentAction = "AttackGround"; break; + case UnitActionDie: currentAction = "Die"; break; + case UnitActionSpellCast: currentAction = "SpellCast"; break; + case UnitActionTrain: currentAction = "Train"; break; + case UnitActionUpgradeTo: currentAction = "UpgradeTo"; break; + case UnitActionResearch: currentAction = "Research"; break; + case UnitActionBuilt: currentAction = "Built"; break; + case UnitActionBoard: currentAction = "Board"; break; + case UnitActionUnload: currentAction = "Unload"; break; + case UnitActionPatrol: currentAction = "Patrol"; break; + case UnitActionBuild: currentAction = "Build"; break; + case UnitActionExplore: currentAction = "Explore"; break; + case UnitActionRepair: currentAction = "Repair"; break; + case UnitActionResource: currentAction = "Resource"; break; + case UnitActionTransformInto: currentAction = "TransformInto"; break; + } + + fprintf(logf, "%d %s %s P%d Refs %d: Seed %X Hash %X %d@%d %d@%d\n", UnitNumber(unit), unit.Type ? unit.Type->Ident.c_str() : "unit-killed", - !unit.Orders.empty() ? unit.CurrentAction() : -1, - unit.Player ? unit.Player->Index : -1, unit.Refs, SyncRandSeed, - unit.tilePos.x, unit.tilePos.y, unit.IX, unit.IY); + currentAction, unit.Player ? unit.Player->Index : -1, unit.Refs, + SyncRandSeed, SyncHash, unit.tilePos.x, unit.tilePos.y, unit.IX, unit.IY); #if 0 SaveUnit(unit, logf); #endif @@ -532,10 +567,18 @@ static void UnitActionsEachCycle(UNITP_ITERATOR begin, UNITP_ITERATOR end) if (EnableUnitDebug) { DumpUnitInfo(unit); } + // Calculate some hash. SyncHash = (SyncHash << 5) | (SyncHash >> 27); SyncHash ^= unit.Orders.empty() == false ? unit.CurrentAction() << 18 : 0; SyncHash ^= unit.Refs << 3; + + if (EnableUnitDebug) { + fprintf(stderr, "GameCycle: %lud, new SyncHash: %x (unit: %d:%s, order: %d, refs: %d)\n", GameCycle, SyncHash, + UnitNumber(unit), unit.Type->Ident.c_str(), unit.Orders.empty() ? -1 : unit.CurrentAction(), unit.Refs); + print_backtrace(8); + fflush(stderr); + } } } diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 72aac91a6..274e25d36 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -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); } diff --git a/src/include/pathfinder.h b/src/include/pathfinder.h index cb1071f3e..1bdcb86e9 100644 --- a/src/include/pathfinder.h +++ b/src/include/pathfinder.h @@ -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 diff --git a/src/include/st_backtrace.h b/src/include/st_backtrace.h index 8e4709007..1dd4ec7b8 100644 --- a/src/include/st_backtrace.h +++ b/src/include/st_backtrace.h @@ -16,13 +16,12 @@ inline void print_backtrace(int sz = 100) { #elif defined(USE_WIN32) -#if 1 // the below would mean we give up XP support #include "windows.h" #include "winbase.h" #include "dbghelp.h" #include "process.h" -inline void print_backtrace(void) { +inline void print_backtrace(int sz = 100) { unsigned int i; void *stack[100]; unsigned short frames; @@ -34,7 +33,7 @@ inline void print_backtrace(void) { process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); - frames = CaptureStackBackTrace(0, 100, stack, NULL); + frames = CaptureStackBackTrace(0, sz, stack, NULL); fprintf(stderr, "backtrace returned %d addresses\n", frames); symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); symbol->MaxNameLen = 1024; @@ -58,17 +57,12 @@ inline void print_backtrace(void) { } free(symbol); } -#else -inline void print_backtrace(void) { -} -#endif #else -inline void print_backtrace(void) { +inline void print_backtrace(int sz = 100) { } #endif - #endif diff --git a/src/include/tile.h b/src/include/tile.h index ff9aee7c7..1166689ce 100644 --- a/src/include/tile.h +++ b/src/include/tile.h @@ -227,6 +227,9 @@ public: unsigned char getCost() const { return cost; } unsigned int getFlag() const { return Flags; } void setGraphicTile(unsigned int tile) { this->tile = tile; } +#ifdef DEBUG + int64_t lastAStarCost; /// debugging pathfinder +#endif private: #ifdef DEBUG unsigned int tilesetTile; /// tileset tile number diff --git a/src/map/map_draw.cpp b/src/map/map_draw.cpp index a58508db4..61b5b25e6 100644 --- a/src/map/map_draw.cpp +++ b/src/map/map_draw.cpp @@ -286,6 +286,38 @@ void CViewport::DrawMapBackgroundInViewport() const tile = mf.playerInfo.SeenTile; } Map.TileGraphic->DrawFrameClip(tile, dx, dy); +#if 0 + int64_t cost = mf.lastAStarCost; + int32_t alpha; + // we use the msb as marker, but only consider the lower 32-bits as numeric value + if (cost != 0) { + if (cost == -1) { + // non traversible tiles always start full red + alpha = -60; + } else if (cost > 0) { + // msb not set means this has not been scaled + // scale cost to be between 1 and 60 + cost <<= 3; + if (cost > 60) { + cost = 60; + } + alpha = static_cast<int32_t>(cost); + } else { + // consider only low 32-bits of already scaled value + alpha = static_cast<int32_t>(cost); + } + } + if (alpha > 0) { + Video.FillTransRectangleClip(ColorGreen, dx, dy, + dx + Map.TileGraphic->getWidth(), dy + dx + Map.TileGraphic->getWidth(), alpha * 200 / 60); + alpha--; + } else if (alpha < 0) { + Video.FillTransRectangleClip(ColorRed, dx, dy, + dx + Map.TileGraphic->getWidth(), dy + dx + Map.TileGraphic->getWidth(), -alpha * 200 / 60); + alpha++; + } + const_cast<CMapField &>(mf).lastAStarCost = alpha | ((uint64_t)1 << 63); +#endif ++sx; dx += PixelTileSize.x; } diff --git a/src/map/map_fog.cpp b/src/map/map_fog.cpp index c3879b3a7..8c30e2ce2 100644 --- a/src/map/map_fog.cpp +++ b/src/map/map_fog.cpp @@ -51,6 +51,13 @@ #include "video.h" #include "../video/intern_video.h" +#ifdef USE_STACKTRACE +#include <stdexcept> +#include <stacktrace/call_stack.hpp> +#include <stacktrace/stack_exception.hpp> +#else +#include "st_backtrace.h" +#endif /*---------------------------------------------------------------------------- -- Variables @@ -205,6 +212,7 @@ void MapMarkTileSight(const CPlayer &player, const unsigned int index) { CMapField &mf = *Map.Field(index); unsigned short *v = &(mf.playerInfo.Visible[player.Index]); + if (*v == 0 || *v == 1) { // Unexplored or unseen // When there is no fog only unexplored tiles are marked. if (!Map.NoFogOfWar || *v == 0) { @@ -214,10 +222,25 @@ void MapMarkTileSight(const CPlayer &player, const unsigned int index) if (mf.playerInfo.IsTeamVisible(*ThisPlayer)) { Map.MarkSeenTile(mf); } - return; + } else { + Assert(*v != 65535); + ++*v; } - Assert(*v != 65535); - ++*v; +#if 0 + if (EnableDebugPrint) { + fprintf(stderr, "Mapsight: GameCycle: %lud, SyncHash before: %x", GameCycle, SyncHash); + } + // Calculate some hash. + SyncHash = (SyncHash << 5) | (SyncHash >> 27); + SyncHash ^= (*v << 16) | *v; + + if (EnableDebugPrint) { + fprintf(stderr, ", after: %x (mapfield: %d, player: %d, sight: %d)\n", SyncHash, + index, player.Index, *v); + print_backtrace(8); + fflush(stderr); + } +#endif } void MapMarkTileSight(const CPlayer &player, const Vec2i &pos) diff --git a/src/network/network.cpp b/src/network/network.cpp index 4ac34d613..4519b93dc 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -250,6 +250,8 @@ // Declaration //---------------------------------------------------------------------------- +extern int SaveGame(const std::string &filename); /// Save game + /** ** Network command input/output queue. */ @@ -298,8 +300,8 @@ CUDPSocket NetworkFildes; /// Network file descriptor static unsigned long NetworkLastFrame[PlayerMax]; /// Last frame received packet static unsigned long NetworkLastCycle[PlayerMax]; /// Last cycle received packet -static int NetworkSyncSeeds[256]; /// Network sync seeds. -static int NetworkSyncHashs[256]; /// Network sync hashs. +static unsigned int NetworkSyncSeeds[256]; /// Network sync seeds. +static unsigned int NetworkSyncHashs[256]; /// Network sync hashs. static CNetworkCommandQueue NetworkIn[256][PlayerMax][MaxNetworkCommands]; /// Per-player network packet input queue static std::deque<CNetworkCommandQueue> CommandsIn; /// Network command input queue static std::deque<CNetworkCommandQueue> MsgCommandsIn; /// Network message input queue @@ -917,8 +919,8 @@ static void NetworkExecCommand_Sync(const CNetworkCommandQueue &ncq) CNetworkCommandSync nc; nc.Deserialize(&ncq.Data[0]); const unsigned long gameNetCycle = GameCycle; - const int syncSeed = nc.syncSeed; - const int syncHash = nc.syncHash; + const unsigned int syncSeed = nc.syncSeed; + const unsigned int syncHash = nc.syncHash; if (syncSeed != NetworkSyncSeeds[gameNetCycle & 0xFF] || syncHash != NetworkSyncHashs[gameNetCycle & 0xFF]) { @@ -929,10 +931,20 @@ static void NetworkExecCommand_Sync(const CNetworkCommandQueue &ncq) // only print this message circa every 5 seconds... SetMessage("%s", _("Network out of sync")); gameInSync = false; + SetGamePaused(true); + + time_t now; + time(&now); + std::string savefile = "desync_savegame_"; + savefile += std::to_string(ThisPlayer->Index); + savefile += "_"; + savefile += std::to_string((intmax_t)now); + savefile += ".sav"; + SaveGame(savefile); } - DebugPrint("\nNetwork out of sync %x!=%x! %d!=%d! Cycle %lu\n\n" _C_ + DebugPrint("\nNetwork out of sync seed: %X!=%X , hash: %X!=%X Cycle %lu\n\n" _C_ syncSeed _C_ NetworkSyncSeeds[gameNetCycle & 0xFF] _C_ - syncHash _C_ NetworkSyncHashs[gameNetCycle & 0xFF] _C_ GameCycle); + syncHash _C_ NetworkSyncHashs[gameNetCycle & 0xFF] _C_ GameCycle); } else { gameInSync = true; } diff --git a/src/pathfinder/astar.cpp b/src/pathfinder/astar.cpp index 996bbca12..5cbd52c3c 100644 --- a/src/pathfinder/astar.cpp +++ b/src/pathfinder/astar.cpp @@ -534,12 +534,18 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit) if (flag && (AStarKnowUnseenTerrain || mf->playerInfo.IsExplored(*unit.Player))) { if (flag & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)) { // we can't cross fixed units and other unpassable things +#ifdef DEBUG + const_cast<CMapField *>(mf)->lastAStarCost = -1; +#endif return -1; } CUnit *goal = mf->UnitCache.find(unit_finder); if (!goal) { // Shouldn't happen, mask says there is something on this tile Assert(0); +#ifdef DEBUG + const_cast<CMapField *>(mf)->lastAStarCost = -1; +#endif return -1; } if (goal->Moving) { @@ -549,6 +555,9 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit) // for non moving unit Always Fail unless goal is unit, or unit can attack the target if (&unit != goal) { if (GetAStarFixedEnemyUnitsUnpassable() == true) { +#ifdef DEBUG + const_cast<CMapField *>(mf)->lastAStarCost = -1; +#endif return -1; } if (goal->Player->IsEnemy(unit) && unit.IsAgressive() && CanTarget(*unit.Type, *goal->Type) @@ -556,6 +565,9 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit) cost += 2 * AStarMovingUnitCrossingCost; } else { // FIXME: Need support for moving a fixed unit to add cost +#ifdef DEBUG + const_cast<CMapField *>(mf)->lastAStarCost = -1; +#endif return -1; } //cost += AStarFixedUnitCrossingCost; @@ -569,6 +581,9 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit) } // Add tile movement cost cost += mf->getCost(); +#ifdef DEBUG + const_cast<CMapField *>(mf)->lastAStarCost = cost; +#endif ++mf; } while (--i); index += AStarMapWidth; diff --git a/src/pathfinder/pathfinder.cpp b/src/pathfinder/pathfinder.cpp index 46f47df25..a229396c2 100644 --- a/src/pathfinder/pathfinder.cpp +++ b/src/pathfinder/pathfinder.cpp @@ -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; } diff --git a/src/stratagus/util.cpp b/src/stratagus/util.cpp index 26c632d5d..3ec394514 100644 --- a/src/stratagus/util.cpp +++ b/src/stratagus/util.cpp @@ -87,7 +87,7 @@ int SyncRand() if (EnableDebugPrint) { fprintf(stderr, "GameCycle: %lud, seed: %x, Sync rand: %d\n", GameCycle, SyncRandSeed, val); - print_backtrace(); + print_backtrace(8); fflush(stderr); } return val; diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index cf7125c78..84eb4d0ad 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -430,43 +430,45 @@ void CUnit::Init() pathFinderData = new PathFinderData; pathFinderData->input.SetUnit(*this); + Frame = 0; Colors = -1; + memset(IndividualUpgrades, 0, sizeof(IndividualUpgrades)); IX = 0; IY = 0; - Frame = 0; Direction = 0; + CurrentResource = 0; + ResourcesHeld = 0; DamagedType = ANIMATIONS_DEATHTYPES; Attacked = 0; + Summoned = 0; + Blink = 0; + Moving = 0; + ReCast = 0; + AutoRepair = 0; Burning = 0; Destroyed = 0; Removed = 0; Selected = 0; - TeamSelected = 0; Constructed = 0; Active = 0; Boarded = 0; + CacheLock = 0; + Waiting = 0; + MineLow = 0; + TeamSelected = 0; RescuedFrom = NULL; memset(VisCount, 0, sizeof(VisCount)); memset(&Seen, 0, sizeof(Seen)); delete Variable; Variable = NULL; TTL = 0; - Threshold = 0; - UnderAttack = 0; GroupId = 0; LastGroup = 0; - ResourcesHeld = 0; Wait = 0; - Blink = 0; - Moving = 0; - ReCast = 0; - CacheLock = 0; - Summoned = 0; - Waiting = 0; - MineLow = 0; + Threshold = 0; + UnderAttack = 0; memset(&Anim, 0, sizeof(Anim)); memset(&WaitBackup, 0, sizeof(WaitBackup)); - CurrentResource = 0; Orders.clear(); delete SavedOrder; SavedOrder = NULL; @@ -478,9 +480,7 @@ void CUnit::Init() AutoCastSpell = NULL; delete SpellCoolDownTimers; SpellCoolDownTimers = NULL; - AutoRepair = 0; Goal = NULL; - memset(IndividualUpgrades, 0, sizeof(IndividualUpgrades)); } CUnit::~CUnit() { @@ -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; diff --git a/src/unit/unit_find.cpp b/src/unit/unit_find.cpp index 5cae1a2e8..b8b41e985 100644 --- a/src/unit/unit_find.cpp +++ b/src/unit/unit_find.cpp @@ -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;