Skip to content

Commit

Permalink
Merge pull request #8351 from LoneGazebo/oleole
Browse files Browse the repository at this point in the history
Oleole
  • Loading branch information
RecursiveVision authored Oct 25, 2021
2 parents 7acd6bd + 9f25da9 commit 2aaec5a
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 101 deletions.
111 changes: 42 additions & 69 deletions CvGameCoreDLL_Expansion2/CvTacticalAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3819,37 +3819,10 @@ void CvTacticalAI::ExecuteMovesToSafestPlot(CvUnit* pUnit)
TacticalAIHelpers::PerformRangedOpportunityAttack(pUnit,true);

//so easy
CvPlot* pBestPlot = TacticalAIHelpers::FindSafestPlotInReach(pUnit,true,true,true);

if (pBestPlot != NULL)
{
//check if somebody else can take our place
CvUnit* pSwapUnit = pUnit->GetPotentialUnitToSwapWith(*pBestPlot);
if (pSwapUnit)
{
//melee units are there to soak damage ...
int iDangerLimit = pSwapUnit->GetCurrHitPoints();
if (pSwapUnit->IsCanAttackRanged())
iDangerLimit += pSwapUnit->GetCurrHitPoints() / 2;

if (pSwapUnit->GetDanger(pUnit->plot()) < iDangerLimit)
{
pSwapUnit->SetActivityType(ACTIVITY_AWAKE);
pUnit->PushMission(CvTypes::getMISSION_SWAP_UNITS(), pBestPlot->getX(), pBestPlot->getY());
UnitProcessed(pUnit->GetID());
return;
}
else
{
//cannot swap, get a new plot
pBestPlot = TacticalAIHelpers::FindSafestPlotInReach(pUnit,true,false,true);
}
}
}

CvPlot* pBestPlot = TacticalAIHelpers::FindSafestPlotInReach(pUnit, true, true);
if (pBestPlot != NULL)
{
//check if we can bump somebody else
//check if we need to bump somebody else
CvUnit* pBumpUnit = pUnit->GetPotentialUnitToPushOut(*pBestPlot);
if (pBumpUnit)
{
Expand All @@ -3858,16 +3831,8 @@ void CvTacticalAI::ExecuteMovesToSafestPlot(CvUnit* pUnit)
UnitProcessed(pUnit->GetID());
return;
}
else
{
//cannot bump, get a new plot
pBestPlot = TacticalAIHelpers::FindSafestPlotInReach(pUnit, true, false, false);
}
}
}

if (pBestPlot != NULL)
{
//pillage before retreat, if we have movement points to spare
if (pUnit->getMoves()>GC.getMOVE_DENOMINATOR() && pBestPlot->isAdjacent(pUnit->plot()) && pUnit->shouldPillage(pUnit->plot()))
pUnit->PushMission(CvTypes::getMISSION_PILLAGE());
Expand Down Expand Up @@ -4038,13 +4003,9 @@ void CvTacticalAI::ExecuteHeals(bool bFirstPass)
{
if (pBetterPlot != pUnit->plot())
{
CvUnit* pSwapUnit = pUnit->GetPotentialUnitToSwapWith(*pBetterPlot);
int iDangerLimit = pSwapUnit ? (pSwapUnit->IsCanAttackRanged() ? pSwapUnit->GetCurrHitPoints() : (3 * pSwapUnit->GetCurrHitPoints()) / 2) : 0;
if (pSwapUnit && pSwapUnit->GetDanger(pUnit->plot()) < iDangerLimit)
{
pSwapUnit->SetActivityType(ACTIVITY_AWAKE);
pUnit->PushMission(CvTypes::getMISSION_SWAP_UNITS(), pBetterPlot->getX(), pBetterPlot->getY());
}
CvUnit* pPushUnit = pUnit->GetPotentialUnitToPushOut(*pBetterPlot);
if (pPushUnit)
pUnit->PushBlockingUnitOutOfPlot(*pBetterPlot);
else //plot should be free
ExecuteMoveToPlot(pUnit, pBetterPlot);
}
Expand Down Expand Up @@ -6075,7 +6036,7 @@ bool TacticalAIHelpers::PerformRangedOpportunityAttack(CvUnit* pUnit, bool bAllo
}
}

CvPlot* TacticalAIHelpers::FindSafestPlotInReach(const CvUnit* pUnit, bool bAllowEmbark, bool bConsiderSwap, bool bConsiderPush)
CvPlot* TacticalAIHelpers::FindSafestPlotInReach(const CvUnit* pUnit, bool bAllowEmbark, bool bConsiderPush)
{
vector<OptionWithScore<CvPlot*>> aCityList;
vector<OptionWithScore<CvPlot*>> aZeroDangerList;
Expand All @@ -6085,26 +6046,25 @@ CvPlot* TacticalAIHelpers::FindSafestPlotInReach(const CvUnit* pUnit, bool bAllo
//for current plot
int iCurrentHealRate = pUnit->healRate(pUnit->plot());

ReachablePlots eligiblePlots = pUnit->GetAllPlotsInReachThisTurn(); //embarkation allowed for now, we sort it out below
//embarkation allowed for now, we sort it out below
ReachablePlots eligiblePlots = pUnit->GetAllPlotsInReachThisTurn();
for (ReachablePlots::iterator it=eligiblePlots.begin(); it!=eligiblePlots.end(); ++it)
{
CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(it->iPlotIndex);

// don't attack though
if (pPlot->getNumVisibleEnemyDefenders(pUnit) > 0)
if (pPlot->getNumVisibleEnemyDefenders(pUnit) > 0 || pPlot->isEnemyCity(*pUnit))
continue;

// allow capturing civilians!
int iFlags = CvUnit::MOVEFLAG_DESTINATION;
// allow capturing civilians!
if (pPlot->isVisibleEnemyUnit(pUnit))
iFlags |= CvUnit::MOVEFLAG_ATTACK;

if (!pUnit->canMoveInto(*pPlot, iFlags))
//if we cannot move in because one of our own units is blocking us
if (!pUnit->canMoveInto(*pPlot, iFlags) && pUnit->canMoveInto(*pPlot,iFlags | CvUnit::MOVEFLAG_IGNORE_STACKING))
{
bool bCanSwap = bConsiderSwap && pUnit->CanSwapWithUnitHere(*pPlot);
bool bCanPush = bConsiderPush && pUnit->CanPushOutUnitHere(*pPlot);

if (!bCanPush && !bCanSwap)
if (!bConsiderPush || !pUnit->CanPushOutUnitHere(*pPlot))
continue;
}

Expand Down Expand Up @@ -6312,13 +6272,9 @@ CvPlot* TacticalAIHelpers::FindClosestSafePlotForHealing(CvUnit* pUnit)
}

//can we stay there?
if (!pUnit->canMoveInto(*pPlot, CvUnit::MOVEFLAG_DESTINATION))
if (!pUnit->canMoveInto(*pPlot, CvUnit::MOVEFLAG_DESTINATION) && pUnit->canMoveInto(*pPlot, CvUnit::MOVEFLAG_DESTINATION | CvUnit::MOVEFLAG_IGNORE_STACKING))
{
//can we swap?
CvUnit* pSwapUnit = pUnit->GetPotentialUnitToSwapWith(*pPlot);
//melee units are there to soak damage ...
int iDangerLimit = pSwapUnit ? (pSwapUnit->IsCanAttackRanged() ? pSwapUnit->GetCurrHitPoints() : (3 * pSwapUnit->GetCurrHitPoints()) / 2) : 0;
if (!pSwapUnit || !pSwapUnit->isNativeDomain(pUnit->plot()) || pSwapUnit->GetDanger(pUnit->plot()) > iDangerLimit)
if (!pUnit->CanPushOutUnitHere(*pPlot))
continue;
}

Expand Down Expand Up @@ -7325,7 +7281,7 @@ STacticalAssignment ScorePlotForCombatUnitOffensiveMove(const SUnitStats& unit,
const CvUnit* pUnit = unit.pUnit;

//can we put a combat unit here?
if (testPlot.isBlockedByNonSimCombatUnit())
if (testPlot.isBlockedByNonSimUnit( pUnit->isNativeDomain(pTestPlot) ))
return result;

//cannot deal with enemies here, only friendly/empty plots
Expand Down Expand Up @@ -7422,7 +7378,7 @@ STacticalAssignment ScorePlotForCombatUnitDefensiveMove(const SUnitStats& unit,
const CvUnit* pUnit = unit.pUnit;

//can we put a combat unit here?
if (testPlot.isBlockedByNonSimCombatUnit())
if (testPlot.isBlockedByNonSimUnit( pUnit->isNativeDomain(pTestPlot) ))
return result;

//cannot deal with enemies here, only friendly/empty plots
Expand Down Expand Up @@ -7570,7 +7526,7 @@ STacticalAssignment ScorePlotForNonFightingUnitMove(const SUnitStats& unit, cons
else if (unit.eStrategy == MS_EMBARKED)
{
//can we put a combat unit here?
if (testPlot.isBlockedByNonSimCombatUnit())
if (testPlot.isBlockedByNonSimUnit( pUnit->isNativeDomain(pTestPlot) ))
return result;

if (evalMode!=EM_INTERMEDIATE)
Expand Down Expand Up @@ -7715,6 +7671,7 @@ CvTacticalPlot::CvTacticalPlot(const CvPlot* plot, PlayerTypes ePlayer, const se
bHasAirCover = pPlot->HasAirCover(ePlayer);
bIsVisibleToEnemy = pPlot->isVisibleToEnemy(ePlayer);
bBlockedByNonSimCombatUnit = false;
bBlockedByNonSimEmbarkedUnit = false;

//updated if necessary
bEdgeOfTheKnownWorldUnknown = true;
Expand All @@ -7723,7 +7680,7 @@ CvTacticalPlot::CvTacticalPlot(const CvPlot* plot, PlayerTypes ePlayer, const se
bAdjacentToEnemyCitadel = false;

//set only once
bFriendlyCombatUnitEndTurn = false;
bFriendlyDefenderEndTurn = false;

iDamageDealt = 0;

Expand Down Expand Up @@ -7780,16 +7737,32 @@ CvTacticalPlot::CvTacticalPlot(const CvPlot* plot, PlayerTypes ePlayer, const se
{
//check if we can use the plot for combat units
if (pPlotUnit->IsCanDefend())
bBlockedByNonSimCombatUnit = true;
{
if (pPlotUnit->isEmbarked())
bBlockedByNonSimEmbarkedUnit = true;
else
bBlockedByNonSimCombatUnit = true;
}
}
//owned units not included in sim
else if (allOurUnits.find(pPlotUnit) == allOurUnits.end())
{
if (pPlotUnit->IsCanDefend() && !pPlotUnit->isEmbarked())
if (pPlotUnit->IsCanDefend())
{
bBlockedByNonSimCombatUnit = true;
if (pPlotUnit->isEmbarked())
bBlockedByNonSimEmbarkedUnit = true;
else
bBlockedByNonSimCombatUnit = true;

if (pPlotUnit->TurnProcessed())
bFriendlyCombatUnitEndTurn = true;
bFriendlyDefenderEndTurn = true;

//rules for cities are complex so just don't try it
if (pPlot->isCity())
{
bBlockedByNonSimCombatUnit = true;
bBlockedByNonSimEmbarkedUnit = true;
}
}
}
}
Expand Down Expand Up @@ -7863,10 +7836,10 @@ bool CvTacticalPlot::hasSupportBonus(int iIgnoreUnitPlot) const
void CvTacticalPlot::setCombatUnitEndTurn(CvTacticalPosition& currentPosition, eTactPlotDomain unitDomain)
{
//don't do this twice
if (!pPlot || bFriendlyCombatUnitEndTurn)
if (!pPlot || bFriendlyDefenderEndTurn)
return;

bFriendlyCombatUnitEndTurn = true;
bFriendlyDefenderEndTurn = true;

CvPlot** aNeighbors = GC.getMap().getNeighborsUnchecked(pPlot);
for (int i = 0; i < 6; i++)
Expand Down
11 changes: 6 additions & 5 deletions CvGameCoreDLL_Expansion2/CvTacticalAI.h
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ class CvTacticalPlot
void setNextToEnemyCitadel(bool bValue) { bAdjacentToEnemyCitadel = bValue; }
bool hasAirCover() const { return bHasAirCover; }
bool isVisibleToEnemy() const { return bIsVisibleToEnemy; }
bool isBlockedByNonSimCombatUnit() const { return bBlockedByNonSimCombatUnit; }
bool isBlockedByNonSimUnit(bool bCombat) const { return bCombat ? bBlockedByNonSimCombatUnit : bBlockedByNonSimEmbarkedUnit; }

bool hasFriendlyCombatUnit() const;
bool hasFriendlyEmbarkedUnit() const;
Expand All @@ -732,7 +732,7 @@ class CvTacticalPlot
void setEnemyDistance(eTactPlotDomain eDomain, int iDistance);
bool checkEdgePlotsForSurprises(const CvTacticalPosition& currentPosition, vector<int>& landEnemies, vector<int>& seaEnemies);
bool isValid() const { return pPlot != NULL; }
bool isCombatEndTurn() const { return bFriendlyCombatUnitEndTurn; }
bool isCombatEndTurn() const { return bFriendlyDefenderEndTurn; }
void changeNeighboringUnitCount(CvTacticalPosition& currentPosition, const STacticalAssignment& assignment, int iChange) const;
void setCombatUnitEndTurn(CvTacticalPosition& currentPosition, eTactPlotDomain unitDomain);

Expand All @@ -746,11 +746,13 @@ class CvTacticalPlot
unsigned char aiFriendlyCombatUnitsAdjacent[3]; //for flanking. set initially and updated every time a unit moves
unsigned char aiFriendlyCombatUnitsAdjacentEndTurn[3]; //ranged units need cover. updated every time a unit finishes
unsigned char nSupportUnitsAdjacent; //for general bonus (not differentiated by domain)
unsigned char iDamageDealt; //damage dealt to this plot in previous simulated attacks

//set once and not changed afterwards
bool bIsVisibleToEnemy:1;
bool bHasAirCover:1;
bool bBlockedByNonSimCombatUnit:1;
bool bBlockedByNonSimEmbarkedUnit:1;

//this is updated if the civilian is captured
bool bEnemyCivilianPresent:1;
Expand All @@ -760,9 +762,8 @@ class CvTacticalPlot
//updated if an enemy is killed, after pillage or after adding a newly visible plot
bool bEdgeOfTheKnownWorld:1; //neighboring plot is not part of sim and invisible
bool bAdjacentToEnemyCitadel:1;
bool bFriendlyCombatUnitEndTurn:1;

unsigned char iDamageDealt; //damage dealt to this plot in previous simulated attacks
bool bFriendlyDefenderEndTurn:1;
};

struct SAttackStats
Expand Down Expand Up @@ -956,7 +957,7 @@ namespace TacticalAIHelpers
bool PerformRangedOpportunityAttack(CvUnit* pUnit, bool bAllowMovement = false);
bool PerformOpportunityAttack(CvUnit* pUnit, bool bAllowMovement = false);
bool IsAttackNetPositive(CvUnit* pUnit, const CvPlot* pTarget);
CvPlot* FindSafestPlotInReach(const CvUnit* pUnit, bool bAllowEmbark, bool bConsiderSwap = false, bool bConsiderPush = false);
CvPlot* FindSafestPlotInReach(const CvUnit* pUnit, bool bAllowEmbark, bool bConsiderPush = false);
CvPlot* FindClosestSafePlotForHealing(CvUnit* pUnit);
bool IsGoodPlotForStaging(CvPlayer* pPlayer, CvPlot* pCandidate, DomainTypes eDomain);

Expand Down
Loading

0 comments on commit 2aaec5a

Please sign in to comment.