CvPlot* CvArmyAI::DetectNearbyEnemy(PlayerTypes eEnemy, bool bNaval) { UnitHandle pUnit = GetFirstUnit(); while(pUnit) { for(int iDirectionLoop = 0; iDirectionLoop < NUM_DIRECTION_TYPES; ++iDirectionLoop) { CvPlot* pAdjacentPlot = plotDirection(pUnit->getX(), pUnit->getY(), ((DirectionTypes)iDirectionLoop)); if(pAdjacentPlot != NULL && pAdjacentPlot->isWater()==bNaval && pAdjacentPlot->getOwner() == eEnemy) { UnitHandle pOtherUnit = pAdjacentPlot->getBestDefender(eEnemy); if(pOtherUnit) { if(GC.getLogging() && GC.getAILogging()) { CvString strMsg; strMsg.Format("Ran into enemy unit during attack (x=%d y=%d). Need to declare war to continue!", pAdjacentPlot->getX(), pAdjacentPlot->getY()); GET_PLAYER(m_eOwner).getAIOperation(m_iOperationID)->LogOperationSpecialMessage(strMsg); } return pAdjacentPlot; } } } pUnit = GetNextUnit(); } return NULL; }
/// Find first unit who is sitting in this domain UnitHandle CvArmyAI::GetFirstUnitInDomain(DomainTypes eDomain) { UnitHandle pUnit, pCurrentUnit; pCurrentUnit = GetFirstUnit(); while(pCurrentUnit) { if(pCurrentUnit->plot()->isWater() && eDomain == DOMAIN_SEA || !pCurrentUnit->plot()->isWater() && eDomain == DOMAIN_LAND) { return pCurrentUnit; } pCurrentUnit = GetNextUnit(); } return pUnit; }
/// Everyone in the water now? bool CvArmyAI::AreAllInWater() { UnitHandle pUnit; pUnit = GetFirstUnit(); while(pUnit) { if(!pUnit->plot()->isWater()) { return false; } pUnit = GetNextUnit(); } return true; }
/// Return distance from this plot of unit in army farthest away int CvArmyAI::GetFurthestUnitDistance(CvPlot* pPlot) { int iLargestDistance = 0; CvUnit* pUnit = GetFirstUnit(); while(pUnit) { int iNewDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY()); if(iNewDistance > iLargestDistance) { iLargestDistance = iNewDistance; } pUnit = GetNextUnit(pUnit); } return iLargestDistance; }
// Gather up all units for this team int GroundTaskingManagerClass::CollectGroundAssets (int to_collect) { Unit u,pu; int count=0,objListBuilt=0; // Create the unit lists VuListIterator myit(AllParentList); u = GetFirstUnit(&myit); while (u) { if (u->GetTeam() == owner && u->GetDomain() == DOMAIN_LAND && !u->Scripted()) { // We've got at least one unit to assign - build our objective lists if (!objListBuilt) { Setup(); BuildObjectiveLists(to_collect); objListBuilt = 1; } u->RallyUnit(MIN_TASK_GROUND); u->UpdateParentStatistics(); // We want to order support battalions individually. if (!u->Real() && FindUnitSupportRole(u)) { pu = u; u = pu->GetFirstUnitElement(); while (u) { AddToLists(u, to_collect); count++; u = pu->GetNextUnitElement(); } } else { AddToLists(u, to_collect); count++; } } u = GetNextUnit(&myit); } return count; }
void GroundTaskingManagerClass::RequestEngineer (Objective o, int division) { Unit u; o->SetNeedRepair(1); VuListIterator myit(AllParentList); u = GetFirstUnit(&myit); while (u) { if (u->GetTeam() == owner && u->GetDomain() == DOMAIN_LAND && u->GetUnitNormalRole() == GRO_ENGINEER && u->GetUnitDivision() == division && u->GetUnitOrders() != GORD_REPAIR) { u->SetUnitOrders(GORD_REPAIR,o->Id()); return; } u = GetNextUnit(&myit); } // Find the best _free_ engineer to send to this location }
/// Can all units in this army move on ocean? bool CvArmyAI::IsAllOceanGoing() { CvUnit* pUnit = GetFirstUnit(); while(pUnit) { if(pUnit->getDomainType() != DOMAIN_SEA && !pUnit->IsHasEmbarkAbility()) { return false; } // If can move over ocean, not a coastal vessel if(pUnit->isTerrainImpassable(TERRAIN_OCEAN)) { return false; } pUnit = GetNextUnit(pUnit); } return true; }
/// Find average speed of units in army int CvArmyAI::GetMovementRate() { int iMovementAverage = 2; // A reasonable default int iNumUnits = 0; int iTotalMovementAllowance = 0; UnitHandle pUnit; pUnit = GetFirstUnit(); while(pUnit) { iNumUnits++; iTotalMovementAllowance += pUnit->baseMoves(); pUnit = GetNextUnit(); } if(iNumUnits > 0) { iMovementAverage = (iTotalMovementAllowance + (iNumUnits / 2)) / iNumUnits; } return iMovementAverage; }
/// Get center of mass of units in army (account for world wrap!) CvPlot* CvArmyAI::GetCenterOfMass(float* pfVarX, float* pfVarY) { int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; UnitHandle pUnit = GetFirstUnit(); if (!pUnit) return NULL; int iTotalX2 = 0; int iTotalY2 = 0; int iWorldWidth = GC.getMap().getGridWidth(); int iWorldHeight = GC.getMap().getGridHeight(); //the first unit is our reference ... int iRefX = pUnit->getX(); int iRefY = pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); while(pUnit) { int iDX = pUnit->getX() - iRefX; int iDY = pUnit->getY() - iRefY; if (GC.getMap().isWrapX()) { if( iDX > +(iWorldWidth / 2)) iDX -= iWorldWidth; if( iDX < -(iWorldWidth / 2)) iDX += iWorldWidth; } if (GC.getMap().isWrapY()) { if( iDY > +(iWorldHeight / 2)) iDY -= iWorldHeight; if( iDY < -(iWorldHeight / 2)) iDY += iWorldHeight; } iTotalX += iDX; iTotalY += iDY; iTotalX2 += iDX*iDX; iTotalY2 += iDY*iDY; iNumUnits++; pUnit = GetNextUnit(); } if (iNumUnits==0) return NULL; //this is for debugging float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits); float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits); //finally, compute average (with rounding) int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX; int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY; if (fVarX > 64 || fVarY > 64) { CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY); OutputDebugString( msg.c_str() ); } //this handles wrapped coordinates CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY); if (!pCOM) return NULL; if (pfVarX) *pfVarX = fVarX; if (pfVarY) *pfVarY = fVarY; //don't return it directly but use the plot of the closest unit pUnit = GetFirstUnit(); std::vector<SPlotWithScore> vPlots; while (pUnit) { if (pUnit->plot()->getDomain()==GetDomainType()) { int iDistToCOM = plotDistance(*pUnit->plot(),*pCOM); int iDistToTarget = plotDistance(pUnit->getX(),pUnit->getY(),GetGoalX(),GetGoalY()); vPlots.push_back( SPlotWithScore(pUnit->plot(),iDistToCOM*100+iDistToTarget) ); } pUnit = GetNextUnit(); } if (vPlots.empty()) return NULL; //this sorts ascending! std::sort(vPlots.begin(),vPlots.end()); return vPlots.front().pPlot; }
/// Get center of mass of units in army (account for world wrap!) CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired) { CvPlot* pRtnValue = NULL; int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; UnitHandle pUnit; int iReferenceUnitX = -1; int iWorldWidth = GC.getMap().getGridWidth(); pUnit = GetFirstUnit(); if(pUnit) { iReferenceUnitX = pUnit->getX(); } while(pUnit) { int iUnitX = pUnit->getX(); bool bWorldWrapAdjust = false; int iDiff = iUnitX - iReferenceUnitX; if(abs(iDiff) > (iWorldWidth / 2)) { bWorldWrapAdjust = true; } if(bWorldWrapAdjust) { iTotalX += iUnitX + iWorldWidth; } else { iTotalX += iUnitX; } iTotalY += pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); } if(iNumUnits > 0) { int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits; if(iAverageX >= iWorldWidth) { iAverageX = iAverageX - iWorldWidth; } int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits; pRtnValue = GC.getMap().plot(iAverageX, iAverageY); } // Domain check if (eDomainRequired != NO_DOMAIN && pRtnValue) { if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA) { // Find an adjacent plot that works for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } // Try two plots out if really having problems for (int iDX = -2; iDX <= 2; iDX++) { for (int iDY = -2; iDY <= 2; iDY++) { CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2); if (pLoopPlot) { if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } } } // Give up - just use location of first unit pUnit = GetFirstUnit(); pRtnValue = pUnit->plot(); } } return pRtnValue; }
/// Get center of mass of units in army (account for world wrap!) CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired) { CvPlot* pRtnValue = NULL; int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; UnitHandle pUnit; int iReferenceUnitX = -1; int iWorldWidth = GC.getMap().getGridWidth(); pUnit = GetFirstUnit(); if(pUnit) { iReferenceUnitX = pUnit->getX(); } while(pUnit) { int iUnitX = pUnit->getX(); bool bWorldWrapAdjust = false; int iDiff = iUnitX - iReferenceUnitX; if(abs(iDiff) > (iWorldWidth / 2)) { bWorldWrapAdjust = true; } if(bWorldWrapAdjust) { iTotalX += iUnitX + iWorldWidth; } else { iTotalX += iUnitX; } iTotalY += pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); } if(iNumUnits > 0) { int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits; if(iAverageX >= iWorldWidth) { iAverageX = iAverageX - iWorldWidth; } int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits; pRtnValue = GC.getMap().plot(iAverageX, iAverageY); } // Domain check if (eDomainRequired != NO_DOMAIN && pRtnValue) { if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA) { // Find an adjacent plot that works for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } // Try two plots out if really having problems #ifdef AUI_HEXSPACE_DX_LOOPS int iMaxDX, iDX; CvPlot* pLoopPlot; for (int iDY = -2; iDY <= 2; iDY++) { iMaxDX = 2 - MAX(0, iDY); for (iDX = -2 - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!) { // No need for range check because loops are set up properly pLoopPlot = plotXY(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY); if (pLoopPlot) { if (hexDistance(iDX, iDY) == 2) #else for (int iDX = -2; iDX <= 2; iDX++) { for (int iDY = -2; iDY <= 2; iDY++) { CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2); if (pLoopPlot) { #ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE if (hexDistance(iDX, iDY) == 2) #else if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2) #endif #endif { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } } } // Give up - just use location of first unit pUnit = GetFirstUnit(); pRtnValue = pUnit->plot(); } } return pRtnValue; } /// Return distance from this plot of unit in army farthest away int CvArmyAI::GetFurthestUnitDistance(CvPlot* pPlot) { int iLargestDistance = 0; UnitHandle pUnit; int iNewDistance; pUnit = GetFirstUnit(); while(pUnit) { iNewDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY()); if(iNewDistance > iLargestDistance) { iLargestDistance = iNewDistance; } pUnit = GetNextUnit(); } return iLargestDistance; } // FORMATION ACCESSORS /// Retrieve index of the formation used by this army int CvArmyAI::GetFormationIndex() const { return m_iFormationIndex; } /// Set index of the formation used by this army void CvArmyAI::SetFormationIndex(int iFormationIndex) { CvArmyFormationSlot slot; if(m_iFormationIndex != iFormationIndex) { m_iFormationIndex = iFormationIndex; CvMultiUnitFormationInfo* thisFormation = GC.getMultiUnitFormationInfo(m_iFormationIndex); if(thisFormation) { int iNumSlots = thisFormation->getNumFormationSlotEntries(); // Build all the formation entries m_FormationEntries.clear(); for(int iI = 0; iI < iNumSlots; iI++) { slot.SetUnitID(ARMY_NO_UNIT); slot.SetTurnAtCheckpoint(ARMYSLOT_UNKNOWN_TURN_AT_CHECKPOINT); m_FormationEntries.push_back(slot); } } } } /// How many slots are there in this formation if filled int CvArmyAI::GetNumFormationEntries() const { return m_FormationEntries.size(); } /// How many slots do we currently have filled? int CvArmyAI::GetNumSlotsFilled() const { int iRtnValue = 0; for(unsigned int iI = 0; iI < m_FormationEntries.size(); iI++) { if(m_FormationEntries[iI].m_iUnitID != ARMY_NO_UNIT) { iRtnValue++; } } return iRtnValue; }
// Supplies units - must be called by Campaign Master int SupplyUnits (Team who, CampaignTime deltaTime) { Objective o,s; Unit unit; int supply,fuel,replacements,gots,gotf,type; int sneeded=0,fneeded=0,rneeded=0; float sratio,fratio,rratio; GridIndex x,y; MissionRequestClass mis; // A.S. begin additional variables 2001-12-09 // A.S. We now distinguish between aircrafts and ground vehicles int rneeded_a=0, rneeded_v=0, repl_a=0, repl_v=0; float rratio_a, rratio_v, a_v_nratio, repl; // A.S. float sqnbonus, lambda; // A.S. int repl_a_s = 0, repl_v_s = 0, repl_s = 0, repl_sa = 0, prob = 0; // A.S. debug variables // end added section if (!TeamInfo[who] || !(TeamInfo[who]->flags & TEAM_ACTIVE)) return 0; sratio = fratio = rratio = 0.0F; // A.S. begin, 2001-12-09. rratio_a = rratio_v = a_v_nratio = repl = lambda = 0.0F; // A.S. sqnbonus = RelSquadBonus; // A.S. gives Sqn relative (!) more repl. than Bde. // end added section // zero supply values { VuListIterator objit(AllObjList); o = GetFirstObjective(&objit); while (o){ if (o->GetTeam() == who) o->static_data.local_data = 0; o = GetNextObjective(&objit); } } // Calculate needs { VuListIterator myit(AllUnitList); unit = GetFirstUnit(&myit); while (unit) { if (unit->GetTeam() == who && (unit->IsBattalion() || unit->IsSquadron())) { sneeded += unit->GetUnitSupplyNeed(FALSE); fneeded += unit->GetUnitFuelNeed(FALSE); rneeded += unit->GetFullstrengthVehicles() - unit->GetTotalVehicles(); // A.S. begin if (unit->IsSquadron() && NoTypeBonusRepl) // A.S. extra calculation for squadrons { rneeded_a += unit->GetFullstrengthVehicles() - unit->GetTotalVehicles(); } // end added section } unit = GetNextUnit(&myit); } } // A.S. begin, 2001-12-09. if (NoTypeBonusRepl) { rneeded_v = rneeded - rneeded_a; //A.S. calculation for groud vehicles if (rneeded > 0) a_v_nratio = ( (float)rneeded_a ) / rneeded; else a_v_nratio = 1; repl = (float)TeamInfo[who]->GetReplacementsAvail(); // aggregate replacements available lambda = a_v_nratio * sqnbonus; if (lambda > 1) lambda = 1; } // end added section // Calculate the maximum ratio of supply we can give out if (sneeded > 0) sratio = (float)TeamInfo[who]->GetSupplyAvail() / sneeded; if (sratio > MAX_SUPPLY_RATIO) sratio = MAX_SUPPLY_RATIO; if (fneeded > 0) fratio = (float)TeamInfo[who]->GetFuelAvail() / fneeded; if (fratio > MAX_SUPPLY_RATIO) fratio = MAX_SUPPLY_RATIO; if (rneeded > 0) rratio = (float)TeamInfo[who]->GetReplacementsAvail() / rneeded; if (!NoTypeBonusRepl) // A.S. added if-condiion 2001-12-09 { if (rratio > 0.25F) rratio = 0.25F; } // A.S. begin, 2001-12-09 if (NoTypeBonusRepl) { if (rratio > MAX_SUPPLY_RATIO) { rratio = MAX_SUPPLY_RATIO; } if (rneeded_a > 0) rratio_a = repl / rneeded_a; else rratio_a = MAX_SUPPLY_RATIO; if (rneeded_v > 0) rratio_v = repl / rneeded_v; else rratio_v = MAX_SUPPLY_RATIO; if (rratio_a > MAX_SUPPLY_RATIO) rratio_a = MAX_SUPPLY_RATIO; if (rratio_v > MAX_SUPPLY_RATIO) rratio_v = MAX_SUPPLY_RATIO; if (repl == 0) { // to handle situations like 0/0 ! rratio_a = 0; rratio_v = 0; } } // end added section // Supply units { VuListIterator myit(AllUnitList); unit = GetFirstUnit(&myit); while (unit) { // We only supply/repair Battalions and Squadrons if ( unit->GetTeam() == who && (unit->IsBattalion() || unit->IsSquadron()) && TheCampaign.CurrentTime - unit->GetLastResupplyTime() > unit->GetUnitSupplyTime() ){ float typeBonus = 1.0F; if (unit->GetUnitCurrentRole() == GRO_ATTACK) typeBonus = 6.0F; if (unit->IsSquadron()) { ((SquadronClass*)unit)->ReinforcePilots(2); typeBonus = 2.0F; } // Add some randomness typeBonus += ((rand()%50)-25.0F)/100.0F; if (typeBonus < 0.0F) typeBonus = 0.0F; supply = FloatToInt32(unit->GetUnitSupplyNeed(FALSE) * sratio * typeBonus); fuel = FloatToInt32(unit->GetUnitFuelNeed(FALSE) * fratio * typeBonus); // A.S. 2001-12-09. No Type Bonus for replacements. This helps fixing the bug that units can get more replacements than available. if (NoTypeBonusRepl) typeBonus = 1.0F; // end added section replacements = FloatToInt32((unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * rratio * typeBonus); // A.S. begin, 2001-12-09 repl_s += replacements; // debug if (NoTypeBonusRepl) // New code for distinguishing between aircrafts and ground vehicles { if (unit->IsSquadron()) // this algorithm guarantees that no team can get more repl than available { prob = rand() % 100; repl_a = FloatToInt32((unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (lambda) * rratio_a); if ( TeamInfo[who]->GetReplacementsAvail() >= 1 && prob < 51 && ( ((float)unit->GetTotalVehicles())/unit->GetFullstrengthVehicles() <= 0.8F)) // rounding up with probability 0.5 repl_a = FloatToInt32( (float) ceil( (unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (lambda) * rratio_a) ); if (repl_a > 0) { TeamInfo[who]->SetReplacementsAvail( TeamInfo[who]->GetReplacementsAvail() - repl_a ); unit->ChangeVehicles( min(repl_a, TeamInfo[who]->GetReplacementsAvail()) ); repl_a_s += min(repl_a, TeamInfo[who]->GetReplacementsAvail()); // debug } } else { prob = rand() % 100; repl_v = FloatToInt32((unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (1 - lambda) * rratio_v); if ( TeamInfo[who]->GetReplacementsAvail() > 12 && prob < 51 && ( ((float)unit->GetTotalVehicles())/unit->GetFullstrengthVehicles() <= 0.85F)) // rounding up repl_v = FloatToInt32( (float) ceil( (unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (1 - lambda) * rratio_v) ); if (repl_v > 0) { TeamInfo[who]->SetReplacementsAvail(TeamInfo[who]->GetReplacementsAvail() - repl_v); unit->ChangeVehicles( min(repl_v, TeamInfo[who]->GetReplacementsAvail()) ); repl_v_s += min(repl_v, TeamInfo[who]->GetReplacementsAvail()); // debug } } // prob = rand() % 100; } else { if (replacements) // ++++++ old code begin ++++++ { TeamInfo[who]->SetReplacementsAvail(TeamInfo[who]->GetReplacementsAvail() - replacements); if (unit->IsSquadron()) { repl_sa += replacements; // A.S. debug TeamInfo[who]->SetReplacementsAvail(TeamInfo[who]->GetReplacementsAvail() - replacements); unit->SetLastResupply(replacements); } unit->ChangeVehicles(replacements); } } // end added section (important: this section replaces(!) the section marked with ++++++ old code ++++++ !) if (fuel || supply) { unit->GetLocation(&x,&y); o = FindNearestFriendlyObjective(who, &x, &y, 0); if (o) { s = FindNearestSupplySource(o); if (s) { TeamInfo[who]->SetSupplyAvail(TeamInfo[who]->GetSupplyAvail() - supply); TeamInfo[who]->SetFuelAvail(TeamInfo[who]->GetFuelAvail() - fuel); gots = supply; gotf = fuel; if (SendSupply(s,o,&gots,&gotf)) SupplyUnit(unit,supply,gots,fuel,gotf); } } } unit->SetLastResupplyTime(TheCampaign.CurrentTime); } unit = GetNextUnit(&myit); } } // A.S. debug begin //if (NoTypeBonusRepl) { // if (who == 2 || who==6) { // FILE *deb; // deb = fopen("c:\\temp\\deb1.txt", "a"); // fprintf(deb, "Team %2d ReplaAvail = %3d A_Needed = %3d V_Needed %4d Aircraft = %2d Vehicle = %3d TIME = %d\n", who, (int)repl, rneeded_a, rneeded_v, repl_a_s, repl_v_s, TheCampaign.CurrentTime ); // fclose(deb); // } //} //else { // if (who == 2 || who==6) { // A.S. debug // FILE *deb; // deb = fopen("c:\\temp\\deb1.txt", "a"); // fprintf(deb, "Team %2d ReplaAvail = %3d Needed = %3d | Repl_a = %2d repl_v = %3d | TIME = %d\n", who, TeamInfo[who]->GetReplacementsAvail(), rneeded, repl_sa, (repl_s-repl_sa) , TheCampaign.CurrentTime % CampaignHours ); // fclose(deb); // } //} // A.S. debug end // Reset loss values, set supply values, and request missions { VuListIterator objit(AllObjList); o = GetFirstObjective(&objit); while (o){ if (o->GetTeam() == who){ supply = LOBYTE(o->static_data.local_data); fuel = HIBYTE(o->static_data.local_data); if (supply > 5 || fuel > 5){ o->SendObjMessage(o->Id(),FalconObjectiveMessage::objSetSupply,(short)(supply),(short)(fuel),0); type = o->GetType(); if (type == TYPE_ROAD || type == TYPE_INTERSECT) { // Request an interdiction mission mis.requesterID = o->Id(); o->GetLocation(&mis.tx,&mis.ty); mis.vs = o->GetTeam(); mis.who = GetEnemyTeam(mis.vs); mis.tot = Camp_GetCurrentTime() + (30+rand()%480)*CampaignMinutes; mis.tot_type = TYPE_NE; mis.targetID = FalconNullId; mis.mission = AMIS_INT; mis.roe_check = ROE_AIR_ATTACK; mis.context = enemySupplyInterdictionZone; mis.RequestMission(); } // RV - Biker - Do something special for bridges //if (type == TYPE_BRIDGE || type == TYPE_DEPOT || type == TYPE_PORT) if (type == TYPE_DEPOT || type == TYPE_PORT) { // Request an interdiction strike mission mis.requesterID = o->Id(); o->GetLocation(&mis.tx,&mis.ty); mis.vs = o->GetTeam(); mis.who = GetEnemyTeam(mis.vs); mis.tot = Camp_GetCurrentTime() + (30+rand()%480)*CampaignMinutes; mis.tot_type = TYPE_NE; mis.targetID = o->Id(); mis.mission = AMIS_INTSTRIKE; mis.roe_check = ROE_AIR_ATTACK; if (type == TYPE_DEPOT) mis.context = enemySupplyInterdictionDepot; if (type == TYPE_PORT) mis.context = enemySupplyInterdictionPort; mis.RequestMission(); } if (type == TYPE_BRIDGE) { // Check distance to FLOT GridIndex ox = 0, oy = 0; o->GetLocation(&ox, &oy); float dist = DistanceToFront(ox,oy); if (dist >= 50.0f) { mis.requesterID = o->Id(); mis.tx = ox; mis.ty = oy; mis.vs = o->GetTeam(); mis.who = GetEnemyTeam(mis.vs); mis.tot = Camp_GetCurrentTime() + (30+rand()%480)*CampaignMinutes; mis.tot_type = TYPE_NE; mis.targetID = o->Id(); mis.mission = AMIS_INTSTRIKE; mis.roe_check = ROE_AIR_ATTACK; mis.context = enemySupplyInterdictionBridge; mis.RequestMission(); } } } } o = GetNextObjective(&objit); } } return 1; }
/// Get center of mass of units in army (account for world wrap!) CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired) { int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; #if defined(MOD_BALANCE_CORE) UnitHandle pUnit = GetFirstUnit(); if (!pUnit) return NULL; int iTotalX2 = 0; int iTotalY2 = 0; int iWorldWidth = GC.getMap().getGridWidth(); int iWorldHeight = GC.getMap().getGridHeight(); //the first unit is our reference ... int iRefX = pUnit->getX(); int iRefY = pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); while(pUnit) { int iDX = pUnit->getX() - iRefX; int iDY = pUnit->getY() - iRefY; if (GC.getMap().isWrapX()) { if( iDX > +(iWorldWidth / 2)) iDX -= iWorldWidth; if( iDX < -(iWorldWidth / 2)) iDX += iWorldWidth; } if (GC.getMap().isWrapY()) { if( iDY > +(iWorldHeight / 2)) iDY -= iWorldHeight; if( iDY < -(iWorldHeight / 2)) iDY += iWorldHeight; } iTotalX += iDX; iTotalY += iDY; iTotalX2 += iDX*iDX; iTotalY2 += iDY*iDY; iNumUnits++; pUnit = GetNextUnit(); } if (iNumUnits==0) return NULL; //this is for debugging float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits); float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits); //finally, compute average (with rounding) int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX; int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY; if (fVarX > 64 || fVarY > 64) { CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY); OutputDebugString( msg.c_str() ); } //this handles wrapped coordinates CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY); if (!pCOM) return NULL; //don't return it directly but use the plot of the closest unit pUnit = GetFirstUnit(); std::vector<SPlotWithScore> vPlots; while (pUnit) { if (eDomainRequired == NO_DOMAIN || pUnit->plot()->getDomain()==eDomainRequired) vPlots.push_back( SPlotWithScore(pUnit->plot(),plotDistance(*pUnit->plot(),*pCOM)) ); pUnit = GetNextUnit(); } if (vPlots.empty()) return NULL; //this sorts ascending! std::sort(vPlots.begin(),vPlots.end()); return vPlots.front().pPlot; #else CvPlot* pRtnValue = NULL; UnitHandle pUnit; int iReferenceUnitX = -1; int iWorldWidth = GC.getMap().getGridWidth(); pUnit = GetFirstUnit(); if(pUnit) { iReferenceUnitX = pUnit->getX(); } while(pUnit) { int iUnitX = pUnit->getX(); bool bWorldWrapAdjust = false; int iDiff = iUnitX - iReferenceUnitX; if(abs(iDiff) > (iWorldWidth / 2)) { bWorldWrapAdjust = true; } if(bWorldWrapAdjust) { iTotalX += iUnitX + iWorldWidth; } else { iTotalX += iUnitX; } iTotalY += pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); } if(iNumUnits > 0) { int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits; if(iAverageX >= iWorldWidth) { iAverageX = iAverageX - iWorldWidth; } int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits; pRtnValue = GC.getMap().plot(iAverageX, iAverageY); } // Domain check if (eDomainRequired != NO_DOMAIN && pRtnValue) { if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA) { // Find an adjacent plot that works for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } // Try two plots out if really having problems for (int iDX = -2; iDX <= 2; iDX++) { for (int iDY = -2; iDY <= 2; iDY++) { CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2); if (pLoopPlot) { if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } } } // Give up - just use location of first unit pUnit = GetFirstUnit(); pRtnValue = pUnit->plot(); } } return pRtnValue; #endif }