/** * Test the availability and value of a square, * and possibly add it to the queue of open squares. */ bool CPathFinder::TestSquare( const MoveData& moveData, const CPathFinderDef& pfDef, const PathNode* parentOpenSquare, unsigned int enterDirection, int ownerId, bool synced ) { testedNodes++; // Calculate the new square. int2 square; square.x = parentOpenSquare->nodePos.x + directionVector[enterDirection].x; square.y = parentOpenSquare->nodePos.y + directionVector[enterDirection].y; // Inside map? if (square.x < 0 || square.y < 0 || square.x >= gs->mapx || square.y >= gs->mapy) { return false; } const int sqrIdx = square.x + square.y * gs->mapx; const int sqrStatus = squareStates[sqrIdx].nodeMask; // Check if the square is unaccessable or used. if (sqrStatus & (PATHOPT_CLOSED | PATHOPT_FORBIDDEN | PATHOPT_BLOCKED)) { return false; } const int blockStatus = moveData.moveMath->IsBlocked2(moveData, square.x, square.y); int blockBits = (CMoveMath::BLOCK_STRUCTURE | CMoveMath::BLOCK_TERRAIN); // Check if square are out of constraints or blocked by something. // Doesn't need to be done on open squares, as those are already tested. if ((!pfDef.WithinConstraints(square.x, square.y) || (blockStatus & blockBits)) && !(sqrStatus & PATHOPT_OPEN)) { squareStates[sqrIdx].nodeMask |= PATHOPT_BLOCKED; dirtySquares.push_back(sqrIdx); return false; } // Evaluate this square. float squareSpeedMod = moveData.moveMath->SpeedMod(moveData, square.x, square.y); blockBits = (CMoveMath::BLOCK_MOBILE | CMoveMath::BLOCK_MOVING | CMoveMath::BLOCK_MOBILE_BUSY); if (squareSpeedMod == 0) { squareStates[sqrIdx].nodeMask |= PATHOPT_FORBIDDEN; dirtySquares.push_back(sqrIdx); return false; } if (testMobile && (blockStatus & blockBits)) { if (blockStatus & CMoveMath::BLOCK_MOVING) squareSpeedMod *= 0.65f; else if (blockStatus & CMoveMath::BLOCK_MOBILE) squareSpeedMod *= 0.35f; else squareSpeedMod *= 0.10f; } // Include heatmap cost adjustment. float heatCostMod = 1.0f; if (heatMapping && moveData.heatMapping && GetHeatOwner(square.x, square.y) != ownerId) { heatCostMod += (moveData.heatMod * GetHeatValue(square.x,square.y)); } const float dirMoveCost = (heatCostMod * moveCost[enterDirection]); const float extraCost = squareStates.GetNodeExtraCost(square.x, square.y, synced); const float nodeCost = (dirMoveCost / squareSpeedMod) + extraCost; const float gCost = parentOpenSquare->gCost + nodeCost; // g const float hCost = pfDef.Heuristic(square.x, square.y); // h const float fCost = gCost + hCost; // f if (squareStates[sqrIdx].nodeMask & PATHOPT_OPEN) { // already in the open set if (squareStates[sqrIdx].fCost <= fCost) return true; squareStates[sqrIdx].nodeMask &= ~PATHOPT_DIRECTION; } // Look for improvements. if (!exactPath && hCost < goalHeuristic) { goalSquare = sqrIdx; goalHeuristic = hCost; } // Store this square as open. openSquareBuffer.SetSize(openSquareBuffer.GetSize() + 1); assert(openSquareBuffer.GetSize() < MAX_SEARCHED_NODES_PF); PathNode* os = openSquareBuffer.GetNode(openSquareBuffer.GetSize()); os->fCost = fCost; os->gCost = gCost; os->nodePos = square; os->nodeNum = sqrIdx; openSquares.push(os); squareStates.SetMaxFCost(std::max(squareStates.GetMaxFCost(), fCost)); squareStates.SetMaxGCost(std::max(squareStates.GetMaxGCost(), gCost)); // mark this square as open squareStates[sqrIdx].fCost = os->fCost; squareStates[sqrIdx].gCost = os->gCost; squareStates[sqrIdx].nodeMask |= (PATHOPT_OPEN | enterDirection); dirtySquares.push_back(sqrIdx); return true; }
bool CPathFinder::TestSquare( const MoveDef& moveDef, const CPathFinderDef& pfDef, const PathNode* parentOpenSquare, unsigned int enterDirection, int ownerId, bool synced ) { testedNodes++; const int2& dirVec2D = dirVectors2D[enterDirection]; const float3& dirVec3D = dirVectors3D[enterDirection]; // Calculate the new square. int2 square; square.x = parentOpenSquare->nodePos.x + dirVec2D.x; square.y = parentOpenSquare->nodePos.y + dirVec2D.y; // Inside map? if (square.x < 0 || square.y < 0 || square.x >= gs->mapx || square.y >= gs->mapy) { return false; } const int sqrIdx = square.x + square.y * gs->mapx; const int sqrStatus = squareStates.nodeMask[sqrIdx]; // Check if the square is unaccessable or used. if (sqrStatus & (PATHOPT_CLOSED | PATHOPT_FORBIDDEN | PATHOPT_BLOCKED)) { return false; } const CMoveMath::BlockType blockStatus = moveDef.moveMath->IsBlocked(moveDef, square.x, square.y); // Check if square are out of constraints or blocked by something. // Doesn't need to be done on open squares, as those are already tested. if (!(sqrStatus & PATHOPT_OPEN) && ((blockStatus & CMoveMath::BLOCK_STRUCTURE) || !pfDef.WithinConstraints(square.x, square.y)) ) { squareStates.nodeMask[sqrIdx] |= PATHOPT_BLOCKED; dirtySquares.push_back(sqrIdx); return false; } // Evaluate this square. float squareSpeedMod = moveDef.moveMath->GetPosSpeedMod(moveDef, square.x, square.y, dirVec3D); float heatCostMod = 1.0f; if (squareSpeedMod == 0.0f) { squareStates.nodeMask[sqrIdx] |= PATHOPT_FORBIDDEN; dirtySquares.push_back(sqrIdx); return false; } if (testMobile && moveDef.avoidMobilesOnPath && (blockStatus & squareMobileBlockBits)) { if (blockStatus & CMoveMath::BLOCK_MOBILE_BUSY) { squareSpeedMod *= moveDef.speedModMults[MoveDef::SPEEDMOD_MOBILE_BUSY_MULT]; } else if (blockStatus & CMoveMath::BLOCK_MOBILE) { squareSpeedMod *= moveDef.speedModMults[MoveDef::SPEEDMOD_MOBILE_IDLE_MULT]; } else { // (blockStatus & CMoveMath::BLOCK_MOVING) squareSpeedMod *= moveDef.speedModMults[MoveDef::SPEEDMOD_MOBILE_MOVE_MULT]; } } // Include heatmap cost adjustment. if (heatMapping && moveDef.heatMapping && GetHeatOwner(square.x, square.y) != ownerId) { heatCostMod += (moveDef.heatMod * GetHeatValue(square.x, square.y)); } const float dirMoveCost = (heatCostMod * moveCost[enterDirection]); const float extraCost = squareStates.GetNodeExtraCost(square.x, square.y, synced); const float nodeCost = (dirMoveCost / squareSpeedMod) + extraCost; const float gCost = parentOpenSquare->gCost + nodeCost; // g const float hCost = pfDef.Heuristic(square.x, square.y); // h const float fCost = gCost + hCost; // f if (squareStates.nodeMask[sqrIdx] & PATHOPT_OPEN) { // already in the open set if (squareStates.fCost[sqrIdx] <= fCost) return true; squareStates.nodeMask[sqrIdx] &= ~PATHOPT_DIRECTION; } // Look for improvements. if (!exactPath && hCost < goalHeuristic) { goalSquare = sqrIdx; goalHeuristic = hCost; } // Store this square as open. openSquareBuffer.SetSize(openSquareBuffer.GetSize() + 1); assert(openSquareBuffer.GetSize() < MAX_SEARCHED_NODES_PF); PathNode* os = openSquareBuffer.GetNode(openSquareBuffer.GetSize()); os->fCost = fCost; os->gCost = gCost; os->nodePos = square; os->nodeNum = sqrIdx; openSquares.push(os); squareStates.SetMaxFCost(std::max(squareStates.GetMaxFCost(), fCost)); squareStates.SetMaxGCost(std::max(squareStates.GetMaxGCost(), gCost)); // mark this square as open squareStates.fCost[sqrIdx] = os->fCost; squareStates.gCost[sqrIdx] = os->gCost; squareStates.nodeMask[sqrIdx] |= (PATHOPT_OPEN | enterDirection); dirtySquares.push_back(sqrIdx); return true; }