Hooks
static bool BeforeCvAIOperation_FindBestFitReserveUnit(CvAIOperation* self, OperationSlot thisOperationSlot, CvPlot* pMusterPlot, CvPlot* pTargetPlot, bool* bRequired, bool& result);static void AfterCvAIOperation_FindBestFitReserveUnit(CvAIOperation* self, OperationSlot thisOperationSlot, CvPlot* pMusterPlot, CvPlot* pTargetPlot, bool* bRequired, bool& result);static bool ReplaceCvAIOperation_FindBestFitReserveUnit(bool (*original)(CvAIOperation*, OperationSlot, CvPlot*, CvPlot*, bool*), CvAIOperation* self, OperationSlot thisOperationSlot, CvPlot* pMusterPlot, CvPlot* pTargetPlot, bool* bRequired);CivRegisterBefore<CivHooks::CvAIOperation_FindBestFitReserveUnit>(host, &BeforeCvAIOperation_FindBestFitReserveUnit);CivRegisterAfter<CivHooks::CvAIOperation_FindBestFitReserveUnit>(host, &AfterCvAIOperation_FindBestFitReserveUnit);CivRegisterReplace<CivHooks::CvAIOperation_FindBestFitReserveUnit>(host, &ReplaceCvAIOperation_FindBestFitReserveUnit);
Code
1648/// Find a unit from our reserves that could serve in this operation1649bool CvAIOperation::FindBestFitReserveUnit(OperationSlot thisOperationSlot, CvPlot* pMusterPlot, CvPlot* pTargetPlot, bool* bRequired)1650{1651 CvUnit* pBestUnit = NULL;1652 CvPlayerAI& ownerPlayer = GET_PLAYER(m_eOwner);1653 CvArmyAI* pThisArmy = ownerPlayer.getArmyAI(thisOperationSlot.m_iArmyID);1654 CvString strMsg;1655 CvPlot *pTargetToUse = pTargetPlot;16561657 CvOperationSearchUnitList kSearchList;16581659 *bRequired = true;16601661 // All naval operation targeting a city? Change target1662 if (pTargetToUse && !pTargetToUse->isWater() && IsAllNavalOperation())1663 {1664 pTargetToUse = ownerPlayer.GetMilitaryAI()->GetCoastalPlotAdjacentToTarget(pTargetToUse, pThisArmy);1665 }16661667 int iThisFormationIndex = pThisArmy->GetFormationIndex();1668 if(iThisFormationIndex != NO_MUFORMATION)1669 {1670 CvMultiUnitFormationInfo* thisFormation = GC.getMultiUnitFormationInfo(iThisFormationIndex);1671 if(thisFormation)1672 {1673 const CvFormationSlotEntry& thisSlotEntry = thisFormation->getFormationSlotEntry(thisOperationSlot.m_iSlotID);1674 bool bMustBeDeepWaterNaval = GET_TEAM(ownerPlayer.getTeam()).canEmbarkAllWaterPassage() && thisFormation->IsRequiresNavalUnitConsistency();16751676 int iLoop = 0;1677 for(CvUnit* pLoopUnit = ownerPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = ownerPlayer.nextUnit(&iLoop))1678 {1679 const UnitAITypes eLoopUnitAIType = pLoopUnit->AI_getUnitAIType();16801681 // Make sure he's not needed by the tactical AI or already in an army or scouting1682 if(pLoopUnit->canRecruitFromTacticalAI() && pLoopUnit->getArmyID() == FFreeList::INVALID_INDEX &&1683 eLoopUnitAIType != UNITAI_EXPLORE && eLoopUnitAIType != UNITAI_EXPLORE_SEA && pLoopUnit->getDropRange() == 0 /* no paratroopers */)1684 {1685 // Is this unit one of the requested types?1686 CvUnitEntry* unitInfo = GC.getUnitInfo(pLoopUnit->getUnitType());1687 if(unitInfo == NULL)1688 continue;16891690 // PRIMARY UNIT TYPE (ONLY)16911692 if(unitInfo->GetUnitAIType((UnitAITypes)thisSlotEntry.m_primaryUnitType))1693 {1694 // Is his health okay?1695 if(!pLoopUnit->IsCombatUnit() || pLoopUnit->GetCurrHitPoints() >= pLoopUnit->GetMaxHitPoints() * GC.getAI_OPERATIONAL_PERCENT_HEALTH_FOR_OPERATION() / 100)1696 {1697 // Not finishing up an operation?1698 if(pLoopUnit->GetDeployFromOperationTurn() + GC.getAI_TACTICAL_MAP_TEMP_ZONE_TURNS() < GC.getGame().getGameTurn())1699 {1700 if((!IsAllNavalOperation() && !IsMixedLandNavalOperation()) || pLoopUnit->getDomainType() == DOMAIN_SEA || pLoopUnit->CanEverEmbark())1701 {1702 if (!bMustBeDeepWaterNaval || pLoopUnit->getDomainType() != DOMAIN_SEA || !pLoopUnit->isTerrainImpassable(TERRAIN_OCEAN))1703 {1704 // Get raw distance to the muster point or target1705 CvPlot* pkLoopUnitPlot = pLoopUnit->plot();1706 int iDistance;1707 if(pMusterPlot != NULL)1708 {1709 iDistance = plotDistance(pkLoopUnitPlot->getX(), pkLoopUnitPlot->getY(), pMusterPlot->getX(), pMusterPlot->getY());1710 // Double the distance if this is a land unit on a different landmass (it's dangerous to go over water!)1711 if(pMusterPlot != NULL && pLoopUnit->getDomainType() == DOMAIN_LAND && pkLoopUnitPlot->getArea() != pMusterPlot->getArea())1712 {1713 iDistance *= 2;1714 }1715 }1716 else1717 {1718 if (pTargetToUse != NULL)1719 iDistance = plotDistance(pkLoopUnitPlot->getX(), pkLoopUnitPlot->getY(), pTargetToUse->getX(), pTargetToUse->getY());1720 else1721 {1722 CvAssertMsg(0, "No muster or target!");1723 iDistance = MAX_INT;1724 }1725 }17261727 kSearchList.push_back(CvOperationSearchUnit(pLoopUnit, iDistance));1728 }1729 }1730 }1731 }1732 }1733 }1734 }17351736 pBestUnit = GetClosestUnit(kSearchList, pMusterPlot, pTargetToUse, NeedToCheckPathToTarget());17371738 // Did we find one?1739 if(pBestUnit != NULL)1740 {1741 pThisArmy->AddUnit(pBestUnit->GetID(), thisOperationSlot.m_iSlotID);1742 return true;1743 }1744 else1745 {1746 if(GC.getLogging() && GC.getAILogging())1747 {1748 strMsg.Format("Could not recruit from primary units for muster at x=%d y=%d, target of x=%d y=%d", (pMusterPlot)?pMusterPlot->getX():-1, (pMusterPlot)?pMusterPlot->getY():-1, (pTargetToUse)?pTargetToUse->getX():-1, (pTargetToUse)?pTargetToUse->getY():-1);1749 LogOperationSpecialMessage(strMsg);1750 }1751 }17521753 kSearchList.clear();1754 // Loop again this time through secondary units1755 for(CvUnit* pLoopUnit = ownerPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = ownerPlayer.nextUnit(&iLoop))1756 {1757 const UnitAITypes eLoopUnitAIType = pLoopUnit->AI_getUnitAIType();17581759 // Make sure he's not needed by the tactical AI or already in an army or scouting1760 if(pLoopUnit->canRecruitFromTacticalAI() && pLoopUnit->getArmyID() == FFreeList::INVALID_INDEX &&1761 eLoopUnitAIType != UNITAI_EXPLORE && eLoopUnitAIType != UNITAI_EXPLORE_SEA && pLoopUnit->getDropRange() == 0 /* no paratroopers */)1762 {1763 // Is this unit one of the requested types?1764 CvUnitEntry* unitInfo = GC.getUnitInfo(pLoopUnit->getUnitType());1765 if(unitInfo == NULL)1766 continue;17671768 // SECONDARY UNIT TYPE (ONLY)17691770 if(unitInfo->GetUnitAIType((UnitAITypes)thisSlotEntry.m_secondaryUnitType))1771 {1772 // Is his health okay?1773 if(!pLoopUnit->IsCombatUnit() || pLoopUnit->GetCurrHitPoints() >= pLoopUnit->GetMaxHitPoints() * GC.getAI_OPERATIONAL_PERCENT_HEALTH_FOR_OPERATION() / 100)1774 {1775 // Not finishing up an operation?1776 if(pLoopUnit->GetDeployFromOperationTurn() + GC.getAI_TACTICAL_MAP_TEMP_ZONE_TURNS() < GC.getGame().getGameTurn())1777 {1778 if((!IsAllNavalOperation() && !IsMixedLandNavalOperation()) || pLoopUnit->getDomainType() == DOMAIN_SEA || pLoopUnit->CanEverEmbark())1779 {1780 if (!bMustBeDeepWaterNaval || pLoopUnit->getDomainType() != DOMAIN_SEA || !pLoopUnit->isTerrainImpassable(TERRAIN_OCEAN))1781 {1782 // Get raw distance to the muster point or target1783 CvPlot* pkLoopUnitPlot = pLoopUnit->plot();1784 int iDistance;1785 if(pMusterPlot != NULL)1786 {1787 iDistance = plotDistance(pkLoopUnitPlot->getX(), pkLoopUnitPlot->getY(), pMusterPlot->getX(), pMusterPlot->getY());1788 // Double the distance if this is a land unit on a different landmass (it's dangerous to go over water!)1789 if(pMusterPlot != NULL && pLoopUnit->getDomainType() == DOMAIN_LAND && pkLoopUnitPlot->getArea() != pMusterPlot->getArea())1790 {1791 iDistance *= 2;1792 }1793 }1794 else1795 {1796 if (pTargetToUse != NULL)1797 iDistance = plotDistance(pkLoopUnitPlot->getX(), pkLoopUnitPlot->getY(), pTargetToUse->getX(), pTargetToUse->getY());1798 else1799 {1800 CvAssertMsg(0, "No muster or target!");1801 iDistance = MAX_INT;1802 }1803 }18041805 kSearchList.push_back(CvOperationSearchUnit(pLoopUnit, iDistance));1806 }1807 }1808 }1809 }1810 }1811 }1812 }18131814 pBestUnit = GetClosestUnit(kSearchList, pMusterPlot, pTargetToUse, NeedToCheckPathToTarget());18151816 // Did we find one?1817 if(pBestUnit != NULL)1818 {1819 pThisArmy->AddUnit(pBestUnit->GetID(), thisOperationSlot.m_iSlotID);1820 return true;1821 }1822 else1823 {1824 if(GC.getLogging() && GC.getAILogging())1825 {1826 strMsg.Format("Could not recruit from secondary units for muster at x=%d y=%d, target of x=%d y=%d", (pMusterPlot)?pMusterPlot->getX():-1, (pMusterPlot)?pMusterPlot->getY():-1, (pTargetToUse)?pTargetToUse->getX():-1, (pTargetToUse)?pTargetToUse->getY():-1);1827 LogOperationSpecialMessage(strMsg);1828 }1829 }18301831 // If not required, let our calling routine know that1832 if(!thisSlotEntry.m_requiredSlot)1833 {1834 *bRequired = false;1835 }1836 }1837 }18381839 return false;1840}