void CvPlayerAI::AI_doTurnPre() { CvAssertMsg(getPersonalityType() != NO_LEADER, "getPersonalityType() is not expected to be equal with NO_LEADER"); CvAssertMsg(getLeaderType() != NO_LEADER, "getLeaderType() is not expected to be equal with NO_LEADER"); CvAssertMsg(getCivilizationType() != NO_CIVILIZATION, "getCivilizationType() is not expected to be equal with NO_CIVILIZATION"); if(isHuman()) { return; } AI_updateFoundValues(); AI_doResearch(); AI_considerAnnex(); GetPlayerPolicies()->DoPolicyAI(); if(isBarbarian()) { return; } if(isMinorCiv()) { return; } }
void CvPlayerAI::AI_doTurnPost() { if(isHuman()) { return; } if(isBarbarian()) { return; } if(isMinorCiv()) { return; } for(int i = 0; i < GC.getNumVictoryInfos(); ++i) { AI_launch((VictoryTypes)i); } ProcessGreatPeople(); GetEspionageAI()->DoTurn(); }
void CvPlayerAI::AI_doTurnPost() { AI_PERF_FORMAT("AI-perf.csv", ("CvPlayerAI::AI_doTurnPost, Turn %03d, %s", GC.getGame().getElapsedGameTurns(), getCivilizationShortDescription()) ); if(isHuman()) { return; } if(isBarbarian()) { return; } if(isMinorCiv()) { return; } for(int i = 0; i < GC.getNumVictoryInfos(); ++i) { AI_launch((VictoryTypes)i); } ProcessGreatPeople(); GetEspionageAI()->DoTurn(); GetTradeAI()->DoTurn(); }
quint8 cPlayer::notoriety( P_CHAR pChar ) // Gets the notoriety toward another char { // 0x01 Blue, 0x02 Green, 0x03 Grey, 0x05 Orange, 0x06 Red, 0x07 Yellow quint8 result; if ( isInvulnerable() ) { return 7; } if ( isIncognito() ) { return 1; // Always Innocent } if ( isPolymorphed() && !isHuman() ) { return 3; // Polymorph Defaults to Grey Name } // Guilds override kills if ( guild_ && pChar != this ) { P_PLAYER player = dynamic_cast<P_PLAYER>( pChar ); if ( player && player->guild_ ) { // Same Guild => Green if ( player->guild_ == guild_ || guild_->isAllied(player->guild_) ) { return 0x02; } else if ( guild_->isAtWar(player->guild_) ) { return 0x05; } } } if ( pChar->kills() > Config::instance()->maxkills() ) { result = 0x06; // 6 = Red -> Murderer } else if ( account_ ) { if ( isCriminal() ) result = 0x03; else if ( karma_ < -2000 ) result = 0x06; else if ( karma_ < 0 ) result = 0x03; else result = 0x01; } else { // Everything else result = 0x03; } return result; }
void CvCityAI::AI_doTurn() { AI_PERF_FORMAT("City-AI-perf.csv", ("CvCityAI::AI_doTurn, Turn %03d, %s, %s", GC.getGame().getElapsedGameTurns(), GetPlayer()->getCivilizationShortDescription(), getName().c_str()) ); VALIDATE_OBJECT if(!isHuman()) { AI_stealPlots(); } }
void CvPlayerAI::AI_doResearch() { CvAssertMsg(!isHuman(), "isHuman did not return false as expected"); if(GetPlayerTechs()->GetCurrentResearch() == NO_TECH) { AI_chooseResearch(); //AI_forceUpdateStrategies(); //to account for current research. } }
void CvPlayerAI::AI_doTurnUnitsPost() { CvUnit* pLoopUnit; int iLoop; if(!isHuman()) { for(pLoopUnit = firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = nextUnit(&iLoop)) { pLoopUnit->AI_promote(); } } }
void CvPlayerAI::AI_doTurnUnitsPre() { GetTacticalAI()->InitializeQueuedAttacks(); if(isHuman()) { return; } if(isBarbarian()) { return; } }
void CvPlayerAI::AI_doTurnPre() { AI_PERF_FORMAT("AI-perf.csv", ("CvPlayerAI::AI_doTurnPre, Turn %03d, %s", GC.getGame().getElapsedGameTurns(), getCivilizationShortDescription()) ); CvAssertMsg(getPersonalityType() != NO_LEADER, "getPersonalityType() is not expected to be equal with NO_LEADER"); CvAssertMsg(getLeaderType() != NO_LEADER, "getLeaderType() is not expected to be equal with NO_LEADER"); CvAssertMsg(getCivilizationType() != NO_CIVILIZATION, "getCivilizationType() is not expected to be equal with NO_CIVILIZATION"); if(isHuman()) { return; } AI_updateFoundValues(); AI_doResearch(); AI_considerAnnex(); }
bool CvPlayerAI::AI_captureUnit(UnitTypes, CvPlot* pPlot) { CvCity* pNearestCity; CvAssert(!isHuman()); // Barbs always capture if (isBarbarian()) return true; // we own it if (pPlot->getTeam() == getTeam()) return true; // no man's land - may as well if (pPlot->getTeam() == NO_TEAM) return true; // friendly, sure (okay, this is pretty much just means open borders) if (pPlot->IsFriendlyTerritory(GetID())) return true; // not friendly, but "near" us pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY(), NO_PLAYER, getTeam()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 7) return true; } // very near someone we aren't friends with (and far from our nearest city) pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 4) return false; } // I'd rather we grab it and run than destroy it return true; }
bool CvPlayerAI::AI_captureUnit(UnitTypes, CvPlot* pPlot) { CvCity* pNearestCity; CvAssert(!isHuman()); // Barbs always capture if (isBarbarian()) return true; if (pPlot->getTeam() == getTeam()) return true; pNearestCity = GC.getMap().findCity(pPlot->getX(), pPlot->getY(), NO_PLAYER, getTeam()); if (pNearestCity != NULL) { if (plotDistance(pPlot->getX(), pPlot->getY(), pNearestCity->getX(), pNearestCity->getY()) <= 4) return true; } return false; }
void CvPlayerAI::AI_doTurnPost() { AI_PERF_FORMAT("AI-perf.csv", ("CvPlayerAI::AI_doTurnPost, Turn %03d, %s", GC.getGame().getElapsedGameTurns(), getCivilizationShortDescription()) ); if(isHuman()) { return; } // EventEngine - v0.1, Snarko // DO NOT pass pEvent to AI_chooseEventOption. The event is deleted when an option has been chosen. int iLoop = 0; for(CvEvent* pEvent = firstEvent(&iLoop, false); pEvent != NULL; pEvent = nextEvent(&iLoop, false)) { AI_chooseEventOption(pEvent->GetID()); } // END EventEngine if(isBarbarian()) { return; } if(isMinorCiv()) { return; } for(int i = 0; i < GC.getNumVictoryInfos(); ++i) { AI_launch((VictoryTypes)i); } ProcessGreatPeople(); GetEspionageAI()->DoTurn(); GetTradeAI()->DoTurn(); }
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; }
// 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; }
// --------------------------------------------------------------------------- void CvPlayerAI::AI_unitUpdate() { GC.getPathFinder().ForceReset(); GC.getIgnoreUnitsPathFinder().ForceReset(); GC.getRouteFinder().ForceReset(); GC.GetWaterRouteFinder().ForceReset(); // Set individual pathers as MP cache safe. A global for all pathers might be simpler, // but this will allow selective control in case one type of pather is causing out-of-syncs. bool bCommonPathFinderMPCaching = GC.getPathFinder().SetMPCacheSafe(true); bool bIgnoreUnitsPathFinderMPCaching = GC.getIgnoreUnitsPathFinder().SetMPCacheSafe(true); bool bTacticalPathFinderMPCaching = GC.GetTacticalAnalysisMapFinder().SetMPCacheSafe(true); bool bInfluencePathFinderMPCaching = GC.getInfluenceFinder().SetMPCacheSafe(true); bool bRoutePathFinderMPCaching = GC.getRouteFinder().SetMPCacheSafe(true); bool bWaterRoutePathFinderMPCaching = GC.GetWaterRouteFinder().SetMPCacheSafe(true); ICvEngineScriptSystem1* pkScriptSystem = gDLL->GetScriptSystem(); if(pkScriptSystem) { CvLuaArgsHandle args; args->Push(GetID()); bool bResult; LuaSupport::CallHook(pkScriptSystem, "PlayerPreAIUnitUpdate", args.get(), bResult); } //GC.getGame().GetTacticalAnalysisMap()->RefreshDataForNextPlayer(this); // this was a !hasBusyUnit around the entire rest of the function, so I tried to make it a bit flatter. if(hasBusyUnitOrCity()) { return; } if(isHuman()) { CvUnit::dispatchingNetMessage(true); // The homeland AI goes first. GetHomelandAI()->FindAutomatedUnits(); GetHomelandAI()->Update(); CvUnit::dispatchingNetMessage(false); } else { // Update tactical AI GetTacticalAI()->CommandeerUnits(); // Now let the tactical AI run. Putting it after the operations update allows units who have // just been handed off to the tactical AI to get a move in the same turn they switch between // AI subsystems GetTacticalAI()->Update(); // Skip homeland AI processing if a barbarian if(m_eID != BARBARIAN_PLAYER) { // Now its the homeland AI's turn. GetHomelandAI()->RecruitUnits(); GetHomelandAI()->Update(); } } GC.getPathFinder().SetMPCacheSafe(bCommonPathFinderMPCaching); GC.getIgnoreUnitsPathFinder().SetMPCacheSafe(bIgnoreUnitsPathFinderMPCaching); GC.GetTacticalAnalysisMapFinder().SetMPCacheSafe(bTacticalPathFinderMPCaching); GC.getInfluenceFinder().SetMPCacheSafe(bInfluencePathFinderMPCaching); GC.getRouteFinder().SetMPCacheSafe(bRoutePathFinderMPCaching); GC.GetWaterRouteFinder().SetMPCacheSafe(bWaterRoutePathFinderMPCaching); }
bool BaseAI::startTurn() { int count = 0; count = getWallCount(); walls.clear(); walls.resize(count); for(int i = 0; i < count; i++) { walls[i] = Wall(getWalls()+i); } count = getCrateCount(); crates.clear(); crates.resize(count); for(int i = 0; i < count; i++) { crates[i] = Crate(getCrates()+i); } count = getWeaponCount(); weapons.clear(); weapons.resize(count); for(int i = 0; i < count; i++) { weapons[i] = Weapon(getWeapons()+i); } count = getHumanCount(); humans.clear(); humans.resize(count); for(int i = 0; i < count; i++) { humans[i] = Human(getHumans()+i); } count = getZombieCount(); zombies.clear(); zombies.resize(count); for(int i = 0; i < count; i++) { zombies[i] = Zombie(getZombies()+i); } count = getAirstrikeCount(); airstrikes.clear(); airstrikes.resize(count); for(int i = 0; i < count; i++) { airstrikes[i] = Airstrike(getAirstrikes()+i); } count = getSpawnzoneCount(); spawnzones.clear(); spawnzones.resize(count); for(int i = 0; i < count; i++) { spawnzones[i] = Spawnzone(getSpawnzones()+i); } if(turnNum() == 1) { init(); if(!isHuman()) { return true; } } if(isHuman()) { return runHuman(); } else { return runZombie(); } }
UINT8 cNPC::notoriety( P_CHAR pChar ) // Gets the notoriety toward another char { if (isIncognito()) { return 0x03; } /* Hard to tell because the ai-types are now string based 0 = invalid/across server line 1 = innocent (blue) 2 = guilded/ally (green) 3 = attackable but not criminal (gray) 4 = criminal (gray) 5 = enemy (orange) 6 = murderer (red) 7 = invulnerable (yellow) //7 = unknown use (translucent (like 0x4000 hue)) */ UINT8 result; if (isInvulnerable()) { return 7; } // Check for Guild status + Highlight // UINT8 guildStatus = GuildCompare( this, pChar ); // if( npcaitype() == 0x02 ) // return 0x06; // 6 = Red -> Monster if( ai_ && ai_->notorietyOverride() ) return ai_->notorietyOverride(); if( !pChar ) return 3; if( pChar->kills() > SrvParams->maxkills() ) result = 0x06; // 6 = Red -> Murderer // else if( guildStatus == 1 ) // result = 0x02; // 2 = Green -> Same Guild // else if( guildStatus == 2 ) // result = 0x05; // 5 = Orange -> Enemy Guild else { // Monsters are always bad // if( npcaitype_ == 4 ) // return 0x01; if( isHuman() ) { if( karma_ >= 0 ) result = 0x01; else result = 0x06; } // Everything else else { return 3; } } return result; }
// 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()); }
bool CvSelectionGroupAI::AI_isControlled() { return (!isHuman() || isAutomated()); }
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; }
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; }