Hooks
static bool BeforeIgnoreUnitsCost(CvAStarNode* parent, CvAStarNode* node, int data, const void* pointer, CvAStar* finder, int& result);static void AfterIgnoreUnitsCost(CvAStarNode* parent, CvAStarNode* node, int data, const void* pointer, CvAStar* finder, int& result);static int ReplaceIgnoreUnitsCost(int (*original)(CvAStarNode*, CvAStarNode*, int, const void*, CvAStar*), CvAStarNode* parent, CvAStarNode* node, int data, const void* pointer, CvAStar* finder);CivRegisterBefore<CivHooks::IgnoreUnitsCost>(host, &BeforeIgnoreUnitsCost);CivRegisterAfter<CivHooks::IgnoreUnitsCost>(host, &AfterIgnoreUnitsCost);CivRegisterReplace<CivHooks::IgnoreUnitsCost>(host, &ReplaceIgnoreUnitsCost);
Code
1704/// Ignore units path finder - compute cost of a path1705int IgnoreUnitsCost(CvAStarNode* parent, CvAStarNode* node, int data, const void* pointer, CvAStar* finder)1706{1707 CvUnit* pUnit;1708 int iCost;1709 int iMax;17101711 CvMap& kMap = GC.getMap();1712 int iFromPlotX = parent->m_iX;1713 int iFromPlotY = parent->m_iY;1714 CvPlot* pFromPlot = kMap.plotUnchecked(iFromPlotX, iFromPlotY);17151716 int iToPlotX = node->m_iX;1717 int iToPlotY = node->m_iY;1718 CvPlot* pToPlot = kMap.plotUnchecked(iToPlotX, iToPlotY);17191720 pUnit = ((CvUnit*)pointer);1721 const UnitPathCacheData* pCacheData = reinterpret_cast<const UnitPathCacheData*>(finder->GetScratchBuffer());17221723 CvAssertMsg(pUnit->getDomainType() != DOMAIN_AIR, "pUnit->getDomainType() is not expected to be equal with DOMAIN_AIR");17241725 if(parent->m_iData1 > 0)1726 {1727 iMax = parent->m_iData1;1728 }1729 else1730 {1731 iMax = pCacheData->baseMoves((pToPlot->isWater() && !pToPlot->IsAllowsWalkWater()) ? DOMAIN_SEA : DOMAIN_LAND) * GC.getMOVE_DENOMINATOR();1732 }17331734 // Get the cost of moving to the new plot, passing in our max moves or the moves we have left, in case the movementCost 1735 // method wants to burn all our remaining moves. This is needed because our remaining moves for this segment of the path1736 // may be larger or smaller than the baseMoves if some moves have already been used or if the starting domain (LAND/SEA)1737 // of the path segment is different from the destination plot.1738 iCost = CvUnitMovement::MovementCostNoZOC(pUnit, pFromPlot, pToPlot, pCacheData->baseMoves((pToPlot->isWater() || pCacheData->isEmbarked())?DOMAIN_SEA:pCacheData->getDomainType()), pCacheData->maxMoves(), iMax);17391740 TeamTypes eUnitTeam = pUnit->getTeam();17411742 int iMovesLeft = iMax - iCost;1743 // Is the cost greater than our max?1744 if (iMovesLeft < 0)1745 {1746 // Yes, we will still let the move happen, but that is the end of the turn.1747 iCost = iMax;1748 iMovesLeft = 0;1749 }17501751 if(iMovesLeft == 0)1752 {1753 iCost = (PATH_MOVEMENT_WEIGHT * iCost);17541755#if defined(MOD_PATHFINDER_TERRAFIRMA)1756 bool bFromTerraFirma = pFromPlot->isTerraFirma(pUnit);1757 bool bToWater = !pToPlot->isTerraFirma(pUnit);1758 if(bFromTerraFirma && bToWater && !pUnit->canEmbarkOnto(*pFromPlot, *pToPlot, true))1759#else1760 if(!pFromPlot->isWater() && pToPlot->isWater() && !pUnit->canEmbarkOnto(*pFromPlot, *pToPlot, true))1761#endif1762 {1763 iCost += PATH_INCORRECT_EMBARKING_WEIGHT;1764 }17651766 if(pToPlot->getTeam() != eUnitTeam)1767 {1768 iCost += PATH_TERRITORY_WEIGHT;1769 }17701771 if(finder->GetInfo() & MOVE_MAXIMIZE_EXPLORE)1772 {1773 if(!pToPlot->isHills())1774 {1775 iCost += PATH_EXPLORE_NON_HILL_WEIGHT;1776 }1777 }17781779 // Damage caused by features (mods)1780 if(0 != GC.getPATH_DAMAGE_WEIGHT())1781 {1782 if(pToPlot->getFeatureType() != NO_FEATURE)1783 {1784#if defined(MOD_UNITS_MAX_HP)1785 // We don't have the specific unit, so we'll just use the generic MAX_HIT_POINTS value1786#endif1787#if defined(MOD_API_PLOT_BASED_DAMAGE)1788 if (MOD_API_PLOT_BASED_DAMAGE) {1789 iCost += (GC.getPATH_DAMAGE_WEIGHT() * std::max(0, pToPlot->getTurnDamage(pUnit->ignoreTerrainDamage(), pUnit->ignoreFeatureDamage(), pUnit->extraTerrainDamage(), pUnit->extraFeatureDamage()))) / GC.getMAX_HIT_POINTS();1790 } else {1791#endif1792 iCost += (GC.getPATH_DAMAGE_WEIGHT() * std::max(0, GC.getFeatureInfo(pToPlot->getFeatureType())->getTurnDamage())) / GC.getMAX_HIT_POINTS();1793#if defined(MOD_API_PLOT_BASED_DAMAGE)1794 }1795#endif1796 }17971798 if(pToPlot->getExtraMovePathCost() > 0)1799 {1800 iCost += (PATH_MOVEMENT_WEIGHT * pToPlot->getExtraMovePathCost());1801 }1802 }18031804 if(pToPlot->getPlotCity() && !(pToPlot->getX() == finder->GetDestX() && pToPlot->getY() == finder->GetDestY()))1805 {1806 iCost += PATH_CITY_AVOID_WEIGHT; // slewis - this should be zeroed out currently1807 }1808 }1809 else1810 {1811 iCost = (PATH_MOVEMENT_WEIGHT * iCost);1812 }18131814 if(finder->GetInfo() & MOVE_MAXIMIZE_EXPLORE)1815 {1816 int iUnseenPlots = pToPlot->getNumAdjacentNonrevealed(eUnitTeam);1817 if(!pToPlot->isRevealed(eUnitTeam))1818 {1819 iUnseenPlots += 1;1820 }18211822 iCost += (7 - iUnseenPlots) * PATH_EXPLORE_NON_REVEAL_WEIGHT;1823 }18241825 // If we are a land unit and we are moving through the water, make the cost a little higher so that1826 // we favor staying on land or getting back to land as quickly as possible because it is dangerous to1827 // be on the water. Don't add this penalty if the unit is human controlled however, we will assume they want1828 // the best path, rather than the safest.1829 if(pCacheData->getDomainType() == DOMAIN_LAND && (pToPlot->isWater() && !pToPlot->IsAllowsWalkWater()) && (!pCacheData->isHuman() || pUnit->IsAutomated()))1830 {1831 iCost += PATH_THROUGH_WATER;1832 }18331834 if(pUnit->IsCombatUnit())1835 {1836 if(iMovesLeft == 0)1837 {1838 iCost += (PATH_DEFENSE_WEIGHT * std::max(0, (200 - ((pUnit->noDefensiveBonus()) ? 0 : pToPlot->defenseModifier(eUnitTeam, false)))));1839 }18401841 if(pCacheData->IsAutomated())1842 {1843 if(pCacheData->IsCanAttack())1844 {1845 if(finder->IsPathDest(pToPlot->getX(), pToPlot->getY()))1846 {1847 if(pToPlot->isVisibleEnemyDefender(pUnit))1848 {1849 iCost += (PATH_DEFENSE_WEIGHT * std::max(0, (200 - ((pUnit->noDefensiveBonus()) ? 0 : pFromPlot->defenseModifier(eUnitTeam, false)))));18501851 // I guess we may as well be the garrison1852 if(!(pFromPlot->isCity()))1853 {1854 iCost += PATH_CITY_WEIGHT;1855 }18561857 if(!(pUnit->isRiverCrossingNoPenalty()))1858 {1859 if(pFromPlot->isRiverCrossing(directionXY(pFromPlot, pToPlot)))1860 {1861 iCost += (PATH_RIVER_WEIGHT * -(GC.getRIVER_ATTACK_MODIFIER()));1862 iCost += (PATH_MOVEMENT_WEIGHT * iMovesLeft);1863 }1864 }1865 }1866 }1867 }1868 }1869 }18701871 FAssert(iCost != MAX_INT);18721873 iCost += PATH_STEP_WEIGHT;18741875 FAssert(iCost > 0);18761877 return iCost;1878}