bool CvSelectionGroupAI::isHeadUnit(CvUnit* pUnit) { if (getHeadUnit()==pUnit) { return true; } return false; }
bool CvSelectionGroupAI::AI_isDeclareWar(const CvPlot* pPlot) { FAssert(getHeadUnit() != NULL); if (isHuman()) { return false; } else { bool bLimitedWar = false; if (pPlot != NULL) { TeamTypes ePlotTeam = pPlot->getTeam(); if (ePlotTeam != NO_TEAM) { WarPlanTypes eWarplan = GET_TEAM(getTeam()).AI_getWarPlan(ePlotTeam); if (eWarplan == WARPLAN_LIMITED) { bLimitedWar = true; } } } CvUnit* pHeadUnit = getHeadUnit(); if (pHeadUnit != NULL) { switch (pHeadUnit->AI_getUnitAIType()) { case UNITAI_UNKNOWN: case UNITAI_ANIMAL: case UNITAI_SETTLE: case UNITAI_WORKER: break; case UNITAI_ATTACK_CITY: case UNITAI_ATTACK_CITY_LEMMING: return true; break; case UNITAI_ATTACK: case UNITAI_COLLATERAL: case UNITAI_PILLAGE: if (bLimitedWar) { return true; } break; case UNITAI_PARADROP: case UNITAI_RESERVE: case UNITAI_COUNTER: case UNITAI_CITY_DEFENSE: case UNITAI_CITY_COUNTER: case UNITAI_CITY_SPECIAL: case UNITAI_EXPLORE: case UNITAI_MISSIONARY: case UNITAI_PROPHET: case UNITAI_ARTIST: case UNITAI_SCIENTIST: case UNITAI_GENERAL: case UNITAI_MERCHANT: case UNITAI_ENGINEER: case UNITAI_SPY: case UNITAI_ICBM: case UNITAI_WORKER_SEA: break; case UNITAI_ATTACK_SEA: case UNITAI_RESERVE_SEA: case UNITAI_ESCORT_SEA: if (bLimitedWar) { return true; } break; case UNITAI_EXPLORE_SEA: break; case UNITAI_ASSAULT_SEA: if (hasCargo()) { return true; } break; case UNITAI_SETTLER_SEA: case UNITAI_MISSIONARY_SEA: case UNITAI_SPY_SEA: case UNITAI_CARRIER_SEA: case UNITAI_MISSILE_CARRIER_SEA: case UNITAI_PIRATE_SEA: case UNITAI_ATTACK_AIR: case UNITAI_DEFENSE_AIR: case UNITAI_CARRIER_AIR: case UNITAI_MISSILE_AIR: break; default: FAssert(false); break; } } } return false; }
// Returns true if the group has become busy... bool CvSelectionGroupAI::AI_update() { CLLNode<IDInfo>* pEntityNode; CvUnit* pLoopUnit; bool bDead; bool bFollow; PROFILE("CvSelectionGroupAI::AI_update"); FAssert(getOwnerINLINE() != NO_PLAYER); if (!AI_isControlled()) { return false; } if (getNumUnits() == 0) { return false; } if (isForceUpdate()) { clearMissionQueue(); // XXX ??? setActivityType(ACTIVITY_AWAKE); setForceUpdate(false); // if we are in the middle of attacking with a stack, cancel it AI_cancelGroupAttack(); } FAssert(!(GET_PLAYER(getOwnerINLINE()).isAutoMoves())); int iTempHack = 0; // XXX bDead = false; bool bFailedAlreadyFighting = false; while ((m_bGroupAttack && !bFailedAlreadyFighting) || readyToMove()) { iTempHack++; if (iTempHack > 100) { FAssert(false); CvUnit* pHeadUnit = getHeadUnit(); if (NULL != pHeadUnit) { if (GC.getLogging()) { TCHAR szOut[1024]; CvWString szTempString; getUnitAIString(szTempString, pHeadUnit->AI_getUnitAIType()); sprintf(szOut, "Unit stuck in loop: %S(%S)[%d, %d] (%S)\n", pHeadUnit->getName().GetCString(), GET_PLAYER(pHeadUnit->getOwnerINLINE()).getName(), pHeadUnit->getX_INLINE(), pHeadUnit->getY_INLINE(), szTempString.GetCString()); gDLL->messageControlLog(szOut); } pHeadUnit->finishMoves(); } break; } // if we want to force the group to attack, force another attack if (m_bGroupAttack) { m_bGroupAttack = false; groupAttack(m_iGroupAttackX, m_iGroupAttackY, MOVE_DIRECT_ATTACK, bFailedAlreadyFighting); } // else pick AI action else { CvUnit* pHeadUnit = getHeadUnit(); if (pHeadUnit == NULL || pHeadUnit->isDelayedDeath()) { break; } resetPath(); if (pHeadUnit->AI_update()) { // AI_update returns true when we should abort the loop and wait until next slice break; } } if (doDelayedDeath()) { bDead = true; break; } // if no longer group attacking, and force separate is true, then bail, decide what to do after group is split up // (UnitAI of head unit may have changed) if (!m_bGroupAttack && AI_isForceSeparate()) { AI_separate(); // pointers could become invalid... return true; } } if (!bDead) { if (!isHuman()) { bFollow = false; // if we not group attacking, then check for follow action if (!m_bGroupAttack) { pEntityNode = headUnitNode(); while ((pEntityNode != NULL) && readyToMove(true)) { pLoopUnit = ::getUnit(pEntityNode->m_data); pEntityNode = nextUnitNode(pEntityNode); if (pLoopUnit->canMove()) { resetPath(); if (pLoopUnit->AI_follow()) { bFollow = true; break; } } } } if (doDelayedDeath()) { bDead = true; } if (!bDead) { if (!bFollow && readyToMove(true)) { pushMission(MISSION_SKIP); } } } } if (bDead) { return true; } return (isBusy() || isCargoBusy()); }
// Returns true if the group has become busy... bool CvSelectionGroupAI::AI_update() { CLLNode<IDInfo>* pEntityNode; CvUnit* pLoopUnit; bool bDead; bool bFollow; PROFILE("CvSelectionGroupAI::AI_update"); FAssert(getOwnerINLINE() != NO_PLAYER); if (!AI_isControlled()) { return false; } if (getNumUnits() == 0) { return false; } // K-Mod / BBAI if (getActivityType() == ACTIVITY_SLEEP && !isHuman() && !getHeadUnit()->isCargo()) { setForceUpdate(true); } // end if (isForceUpdate()) { doForceUpdate(); // K-Mod (based on old code) } //FAssert(!(GET_PLAYER(getOwnerINLINE()).isAutoMoves())); // (no longer true in K-Mod) int iTempHack = 0; // XXX bDead = false; bool bFailedAlreadyFighting = false; //while ((m_bGroupAttack && !bFailedAlreadyFighting) || readyToMove()) while ((AI_isGroupAttack() && !isBusy()) || readyToMove()) // K-Mod { iTempHack++; if (iTempHack > 100) { FAssertMsg(false, "unit stuck in a loop"); CvUnit* pHeadUnit = getHeadUnit(); if (NULL != pHeadUnit) { if (GC.getLogging()) { TCHAR szOut[1024]; CvWString szTempString; getUnitAIString(szTempString, pHeadUnit->AI_getUnitAIType()); sprintf(szOut, "Unit stuck in loop: %S(%S)[%d, %d] (%S)\n", pHeadUnit->getName().GetCString(), GET_PLAYER(pHeadUnit->getOwnerINLINE()).getName(), pHeadUnit->getX_INLINE(), pHeadUnit->getY_INLINE(), szTempString.GetCString()); gDLL->messageControlLog(szOut); } pHeadUnit->finishMoves(); } break; } // if we want to force the group to attack, force another attack if (AI_isGroupAttack()) { AI_cancelGroupAttack(); groupAttack(m_iGroupAttackX, m_iGroupAttackY, MOVE_DIRECT_ATTACK, bFailedAlreadyFighting); } // else pick AI action else { CvUnit* pHeadUnit = getHeadUnit(); //if (pHeadUnit == NULL || pHeadUnit->isDelayedDeath()) if (pHeadUnit == NULL || pHeadUnit->doDelayedDeath()) // K-Mod { break; } //resetPath(); if (pHeadUnit->AI_update()) { // AI_update returns true when we should abort the loop and wait until next slice FAssert(!pHeadUnit->isDelayedDeath()); break; } } if (doDelayedDeath()) { bDead = true; break; } // if no longer group attacking, and force separate is true, then bail, decide what to do after group is split up // (UnitAI of head unit may have changed) if (!AI_isGroupAttack() && AI_isForceSeparate()) { AI_separate(); // pointers could become invalid... //return true; return false; // K-Mod } } if (!bDead) { if (!isHuman()) { bFollow = false; // if we not group attacking, then check for follow action if (!AI_isGroupAttack()) { pEntityNode = headUnitNode(); // K-Mod note: I've rearranged a few things below, and added 'bFirst'. bool bFirst = true; while ((pEntityNode != NULL) && readyToMove(true)) { pLoopUnit = ::getUnit(pEntityNode->m_data); pEntityNode = nextUnitNode(pEntityNode); if (bFirst) resetPath(); if (pLoopUnit->canMove()) { if (pLoopUnit->AI_follow(bFirst)) { bFollow = true; bFirst = true; // let the next unit start fresh. } else bFirst = false; } } // K-Mod end } if (doDelayedDeath()) { bDead = true; } if (!bDead) { if (!bFollow && readyToMove(true)) { pushMission(MISSION_SKIP); } } /************************************************************************************************/ /* BETTER_BTS_AI_MOD 04/28/10 jdog5000 */ /* */ /* Unit AI */ /************************************************************************************************/ // AI should never put units to sleep, how does this ever happen? //FAssert( getHeadUnit()->isCargo() || getActivityType() != ACTIVITY_SLEEP ); /************************************************************************************************/ /* BETTER_BTS_AI_MOD END */ /************************************************************************************************/ } } if (bDead) { //return true; return false; // K-Mod } return (isBusy() || isCargoBusy()); }
bool CvSelectionGroupAI::AI_tradeRoutes() { PROFILE_FUNC(); const IDInfo kEurope(getOwnerINLINE(), CvTradeRoute::EUROPE_CITY_ID); CvCity* pPlotCity = plot()->getPlotCity(); CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE()); std::set<int>::iterator it; std::map<IDInfo, int> cityValues; std::vector<CvTradeRoute*> routes; std::vector<int> routeValues; std::vector<bool> yieldsDelivered(NUM_YIELD_TYPES, false); std::vector<bool> yieldsToUnload(NUM_YIELD_TYPES, false); std::vector<int> yieldsOnBoard(NUM_YIELD_TYPES, false); if (!isHuman() || (getAutomateType() == AUTOMATE_TRANSPORT_FULL)) { std::vector<CvTradeRoute*> aiRoutes; kOwner.getTradeRoutes(aiRoutes); for (uint i = 0; i < aiRoutes.size(); ++i) { CvTradeRoute* pRoute = aiRoutes[i]; // transport feeder - start - Nightinggale CvCity* pDestinationCity = ::getCity(pRoute->getDestinationCity()); if (pDestinationCity != NULL && pDestinationCity->isAutoImportStopped(pRoute->getYield())) { // ignore trade routes where destination is using feeder service and is full continue; } // transport feeder - end - Nightinggale // traderoute fix - start - Nightinggale if (isHuman() && pRoute->getDestinationCity().eOwner != getOwnerINLINE()) { // humans can't transport to allied cities with fully automated transports continue; } // traderoute fix - end - Nightinggale CvCity* pSourceCity = ::getCity(pRoute->getSourceCity()); CvArea* pSourceWaterArea = pSourceCity->waterArea(); if ((pSourceCity != NULL) && ((getDomainType() != DOMAIN_SEA) || (pSourceWaterArea != NULL))) { int iSourceArea = (getDomainType() == DOMAIN_SEA) ? pSourceWaterArea->getID() : pSourceCity->getArea(); if (getDomainType() == DOMAIN_SEA ? plot()->isAdjacentToArea(iSourceArea) : (iSourceArea == getArea())) { if ((getDomainType() == DOMAIN_SEA) || (pRoute->getDestinationCity() != kEurope)) { routes.push_back(pRoute); routeValues.push_back(0); yieldsDelivered[pRoute->getYield()] = true; if (pPlotCity != NULL && ::getCity(pRoute->getDestinationCity()) == pPlotCity) { yieldsToUnload[pRoute->getYield()] = true; } cityValues[pRoute->getSourceCity()] = 0; cityValues[pRoute->getDestinationCity()] = 0; } } } } } else { for (it = m_aTradeRoutes.begin(); it != m_aTradeRoutes.end(); ++it) { CvTradeRoute* pRoute = kOwner.getTradeRoute(*it); CvCity* pSourceCity = ::getCity(pRoute->getSourceCity()); if (pSourceCity != NULL) { CvArea* pSourceWaterArea = pSourceCity->waterArea(); if (getDomainType() != DOMAIN_SEA || pSourceWaterArea != NULL) { int iSourceArea = (getDomainType() == DOMAIN_SEA) ? pSourceWaterArea->getID() : pSourceCity->getArea(); if (getDomainType() == DOMAIN_SEA ? plot()->isAdjacentToArea(iSourceArea) : (iSourceArea == getArea())) { if ((getDomainType() == DOMAIN_SEA) || (pRoute->getDestinationCity() != kEurope)) { routes.push_back(pRoute); routeValues.push_back(0); yieldsDelivered[pRoute->getYield()] = true; if (pPlotCity != NULL && ::getCity(pRoute->getDestinationCity()) == pPlotCity) { yieldsToUnload[pRoute->getYield()] = true; } cityValues[pRoute->getSourceCity()] = 0; cityValues[pRoute->getDestinationCity()] = 0; } } else { FAssertMsg(false, "Unexpected : Unit can't run trade route it's assigned to"); } } } } } if ((pPlotCity != NULL) && hasCargo()) { std::vector<CvUnit*> units; //Unload everything which we should unload here, or can't unload anywhere... CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode(); while (pUnitNode != NULL) { CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data); pUnitNode = plot()->nextUnitNode(pUnitNode); if (pLoopUnit != NULL) { YieldTypes eYield = pLoopUnit->getYield(); CvUnit* pTransport = pLoopUnit->getTransportUnit(); if ((eYield != NO_YIELD) && pTransport != NULL && (yieldsToUnload[eYield] || !(yieldsDelivered[eYield]))) { if (pTransport->getGroup() == this && pLoopUnit->canUnload()) { units.push_back(pLoopUnit); } } } } for (uint i = 0; i < units.size(); ++i) { units[i]->unload(); } } short aiYieldsLoaded[NUM_YIELD_TYPES]; AI_getYieldsLoaded(aiYieldsLoaded); bool bNoCargo = true; for (int i = 0; i < NUM_YIELD_TYPES; ++i) { if (aiYieldsLoaded[i] > 0) { bNoCargo = false; break; } } if (!bNoCargo) { //We need to iterate over every destination city and see if we can unload. for (uint i = 0; i < routes.size(); ++i) { CvCity* pDestinationCity = ::getCity(routes[i]->getDestinationCity()); if ((pDestinationCity == NULL) || (pDestinationCity != pPlotCity)) { int iRouteValue = kOwner.AI_transferYieldValue(routes[i]->getDestinationCity(), routes[i]->getYield(), aiYieldsLoaded[routes[i]->getYield()]); if (iRouteValue > 0) { cityValues[routes[i]->getDestinationCity()] += iRouteValue; routeValues[i] += iRouteValue; } } } } //We need to iterate over every source city, and see if there's anything which needs moving to the respective destination city. //We apply some bias to the city we are presently at, but not too much - sometimes empty runs need to be made... //Basically this looks at the entire NEXT trade run (source-city to dest-city), with some bias given towards //starting it from pPlotCity as sourceCity. //If we are carrying cargo, only count cities where we can unload. for (uint i = 0; i < routes.size(); ++i) { CvCity* pSourceCity = ::getCity(routes[i]->getSourceCity()); if ((pSourceCity != NULL) && (bNoCargo || (cityValues[routes[i]->getSourceCity()] > 0))) { CvCity* pDestinationCity = ::getCity(routes[i]->getDestinationCity()); YieldTypes eYield = routes[i]->getYield(); // transport feeder - start - Nightinggale //int iAmount = pSourceCity->getYieldStored(eYield) - pSourceCity->getMaintainLevel(eYield); int iAmount = pSourceCity->getYieldStored(eYield) - pSourceCity->getAutoMaintainThreshold(eYield); // transport feeder - end - Nightinggale if (iAmount > 0) { int iExportValue = kOwner.AI_transferYieldValue(routes[i]->getSourceCity(), routes[i]->getYield(), -iAmount); int iImportValue = kOwner.AI_transferYieldValue(routes[i]->getDestinationCity(), routes[i]->getYield(), iAmount); int iRouteValue = (iExportValue + iImportValue + 2 * std::min(iExportValue, iImportValue)) / 4; if (pSourceCity == pPlotCity) { cityValues[routes[i]->getDestinationCity()] += 2 * iRouteValue; } else { cityValues[routes[i]->getSourceCity()] += iRouteValue; } routeValues[i] = iRouteValue; } } } IDInfo kBestDestination(NO_PLAYER, -1); int iBestDestinationValue = 0; for (std::map<IDInfo, int>::iterator it = cityValues.begin(); it != cityValues.end(); ++it) { int iValue = it->second; if (iValue > 0) { CvCity* pCity = ::getCity(it->first); if (pCity != NULL) { FAssert(!atPlot(pCity->plot())); if (generatePath(plot(), pCity->plot(), MOVE_NO_ENEMY_TERRITORY, true)) { iValue /= 1 + kOwner.AI_plotTargetMissionAIs(pCity->plot(), MISSIONAI_TRANSPORT, this, 0); } else { iValue = 0; } } if (iValue > iBestDestinationValue) { iBestDestinationValue = iValue; kBestDestination = it->first; } } } if ((pPlotCity != NULL) && (kBestDestination.eOwner != NO_PLAYER)) { //We need to keep looping and recalculating //For example a city might have "101" of an item, we want to move the first 100 but not the 1. //But it could also have 200, in which case we might want 2 loads of 100... //But it could also have 200 of two resources, and we'd want to move 100 of each... ///TKs MEd int iTestCount = 0; while (!isFull()) { iTestCount++; if (iTestCount == 1000) { FAssert(iTestCount == 0); int iID = pPlotCity->getID(); int iIDplayer = GET_PLAYER(kBestDestination.eOwner).getID(); // break; } if (iTestCount == 1001) { break; } ///TKe int iBestRoute = -1; int iBestRouteValue = 0; //Now, for any trade routes which this group is assigned to, try to pick up cargo here. for (uint i = 0; i < routes.size(); ++i) { CvCity* pSourceCity = ::getCity(routes[i]->getSourceCity()); if ((pSourceCity != NULL) && (routes[i]->getDestinationCity() == kBestDestination)) { CvCity* pDestinationCity = ::getCity(routes[i]->getDestinationCity()); YieldTypes eYield = routes[i]->getYield(); if ((pPlotCity == pSourceCity)) { // transport feeder - start - Nightinggale //int iAmount = pSourceCity->getYieldStored(eYield) - pSourceCity->getMaintainLevel(eYield); int iAmount = pSourceCity->getYieldStored(eYield) - pSourceCity->getAutoMaintainThreshold(eYield); // transport feeder - end - Nightinggale if (iAmount > 0) { int iExportValue = kOwner.AI_transferYieldValue(routes[i]->getSourceCity(), routes[i]->getYield(), -iAmount); int iImportValue = kOwner.AI_transferYieldValue(routes[i]->getDestinationCity(), routes[i]->getYield(), iAmount); int iRouteValue = (iExportValue + iImportValue + 2 * std::min(iExportValue, iImportValue)) / 4; if (iRouteValue > iBestRouteValue) { iBestRouteValue = iRouteValue; iBestRoute = i; } } } } } if (iBestRouteValue > 0) { CLLNode<IDInfo>* pUnitNode = headUnitNode(); while (pUnitNode != NULL) { CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data); pUnitNode = nextUnitNode(pUnitNode); if (pLoopUnit != NULL) { if (pLoopUnit->canLoadYield(plot(), routes[iBestRoute]->getYield(), false)) { pLoopUnit->loadYield(routes[iBestRoute]->getYield(), false); break; } } } } else { break; } } //XXX fill hold. } if ((kBestDestination.eOwner == NO_PLAYER) && hasCargo()) { // Transport group is full and can't find any destination CvCity* pCity = kOwner.AI_findBestPort(); if (pCity != NULL && !atPlot(pCity->plot())) { kBestDestination = pCity->getIDInfo(); } } //As a final step, we could consider loading yields which would be useful as parts of delivery runs... if (kBestDestination != kEurope) { CvCity* pBestDestinationCity = ::getCity(kBestDestination); if (pBestDestinationCity != NULL) { FAssert(!atPlot(pBestDestinationCity->plot())); pushMission(MISSION_MOVE_TO, pBestDestinationCity->getX_INLINE(), pBestDestinationCity->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_TRANSPORT, pBestDestinationCity->plot()); if (atPlot(pBestDestinationCity->plot())) { //Unload any goods if required (we can always pick them back up if this is an i+e city). std::vector<CvUnit*> units; CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode(); CvUnit* pLoopUnit; while (pUnitNode != NULL) { pLoopUnit = ::getUnit(pUnitNode->m_data); pUnitNode = plot()->nextUnitNode(pUnitNode); YieldTypes eYield = pLoopUnit->getYield(); if ((eYield != NO_YIELD) && pLoopUnit->isCargo()) { if (pLoopUnit->getTransportUnit()->getGroup() == this && pLoopUnit->canUnload()) { units.push_back(pLoopUnit); } } } for (uint i = 0; i < units.size(); ++i) { units[i]->unload(); } } return true; } } else { if (isHuman()) { getHeadUnit()->AI_setUnitAIState(UNITAI_STATE_SAIL); } } return false; }
bool CvSelectionGroupAI::AI_isDeclareWar(const CvPlot* pPlot) { FAssert(getHeadUnit() != NULL); if (isHuman()) { return false; } else { bool bLimitedWar = false; if (pPlot != NULL) { TeamTypes ePlotTeam = pPlot->getTeam(); if (ePlotTeam != NO_TEAM) { WarPlanTypes eWarplan = GET_TEAM(getTeam()).AI_getWarPlan(ePlotTeam); if (eWarplan == WARPLAN_LIMITED) { bLimitedWar = true; } } } CvUnit* pHeadUnit = getHeadUnit(); if (pHeadUnit != NULL) { switch (pHeadUnit->AI_getUnitAIType()) { case UNITAI_UNKNOWN: case UNITAI_COLONIST: case UNITAI_SETTLER: case UNITAI_WORKER: case UNITAI_MISSIONARY: case UNITAI_SCOUT: case UNITAI_WAGON: case UNITAI_TREASURE: case UNITAI_YIELD: case UNITAI_GENERAL: ///TKs Med Animal case UNITAI_ANIMAL: case UNITAI_HUNTSMAN: case UNITAI_MARAUDER: case UNITAI_TRADER: ///TKe return false; break; case UNITAI_DEFENSIVE: case UNITAI_OFFENSIVE: case UNITAI_COUNTER: return true; break; case UNITAI_TRANSPORT_SEA: return false; break; case UNITAI_ASSAULT_SEA: case UNITAI_COMBAT_SEA: case UNITAI_PIRATE_SEA: return true; break; default: FAssert(false); break; } } } return false; }
int CvSelectionGroupAI::AI_getGroupflag() const { return getHeadUnit()->AI_getGroupflag(); }
bool CvSelectionGroupAI::AI_isDeclareWar(const CvPlot* pPlot) { FAssert(getHeadUnit() != NULL); if (isHuman()) { return false; } else { bool bLimitedWar = false; if (pPlot != NULL) { TeamTypes ePlotTeam = pPlot->getTeam(); if (ePlotTeam != NO_TEAM) { WarPlanTypes eWarplan = GET_TEAM(getTeam()).AI_getWarPlan(ePlotTeam); if (eWarplan == WARPLAN_LIMITED) { bLimitedWar = true; } } } CvUnit* pHeadUnit = getHeadUnit(); if (pHeadUnit != NULL) { switch (pHeadUnit->AI_getUnitAIType()) { case UNITAI_UNKNOWN: case UNITAI_ANIMAL: // R&R, ray, Wild Animals case UNITAI_ANIMAL_SEA: // R&R, ray, Wild Animals case UNITAI_FLEEING: // R&R, ray, Fleeing Units case UNITAI_COLONIST: case UNITAI_SETTLER: case UNITAI_WORKER: case UNITAI_MISSIONARY: case UNITAI_SCOUT: case UNITAI_WAGON: case UNITAI_TREASURE: case UNITAI_YIELD: case UNITAI_GENERAL: return false; break; case UNITAI_DEFENSIVE: case UNITAI_OFFENSIVE: case UNITAI_COUNTER: return true; break; //TAC Whaling, ray case UNITAI_WORKER_SEA: //End TAC Whaling, ray case UNITAI_TRANSPORT_SEA: return false; break; case UNITAI_ASSAULT_SEA: case UNITAI_COMBAT_SEA: case UNITAI_PIRATE_SEA: case UNITAI_ESCORT_SEA: // TAC - AI Escort Sea - koma13 return true; break; default: FAssert(false); break; } } } return false; }