/// Are we devious enough to declare war on our friend?
bool CvDiplomacyAI::IsWillingToAttackFriend(PlayerTypes ePlayer, bool bDirect, bool bImpulse)
{
// If this is called for a human, always return no
if (GetPlayer()->isHuman())
return false;
// No backstabbing if we're not competitive.
if (!IsCompetingForVictory())
return false;
// Never backstab if they resurrected us or vice versa
if (WasResurrectedBy(ePlayer))
return false;
if (GET_PLAYER(ePlayer).GetDiplomacyAI()->WasResurrectedBy(GetID()))
return false;
// Too scared of them?
if (GetMajorCivApproach(ePlayer) == MAJOR_CIV_APPROACH_AFRAID)
return false;
// Like them too much?
if (GetMajorCivOpinion(ePlayer) == MAJOR_CIV_OPINION_ALLY)
return false;
if (GetDoFType(ePlayer) == DOF_TYPE_BATTLE_BROTHERS)
return false;
bool bEndgameAggressive = IsEndgameAggressiveTo(ePlayer);
bool bUntrustworthy = IsUntrustworthy(ePlayer);
if (!bImpulse && !bEndgameAggressive && !bUntrustworthy)
{
// Liberating our cities?
if (IsPlayerLiberatedCapital(ePlayer) && bDirect)
return false;
if (IsCityRecentlyLiberatedBy(ePlayer) && GetPlayer()->getCitiesLost() > 0)
return false;
// Don't declare war if we agreed to start a coop war with them, that's dumb.
if (GetGlobalCoopWarWithState(ePlayer) >= COOP_WAR_STATE_PREPARING)
return false;
// Don't declare war if we promised not to attack!
if (bDirect)
{
if (IsPlayerMoveTroopsRequestAccepted(ePlayer))
return false;
if (GET_PLAYER(ePlayer).GetDiplomacyAI()->IsPlayerMadeMilitaryPromise(GetID()))
return false;
}
}
// What kind of backstabbing is this?
// Backstab timer?
bool bBackstabTimer = (GET_PLAYER(ePlayer).GetDiplomacyAI()->IsDoFBroken(GetID()) && GET_PLAYER(ePlayer).GetDiplomacyAI()->GetTurnsSinceDoFBroken(GetID()) < /*10*/ GC.getDOF_BROKEN_BACKSTAB_TIMER());
if (bBackstabTimer && bDirect)
{
// Only do this if there are no consequences
for (int iPlayerLoop = 0; iPlayerLoop < MAX_MAJOR_CIVS; iPlayerLoop++)
{
PlayerTypes eLoopPlayer = (PlayerTypes) iPlayerLoop;
if (IsPlayerValid(eLoopPlayer))
{
if (WouldBeUpsetIfAttackedFriend(eLoopPlayer, ePlayer) && !WasEverBackstabbedBy(eLoopPlayer) && !GET_PLAYER(eLoopPlayer).GetDiplomacyAI()->WasEverBackstabbedBy(GetID()) && !GET_PLAYER(eLoopPlayer).GetDiplomacyAI()->IsUntrustworthy(GetID()))
{
if (IsFriendOrAlly(eLoopPlayer))
{
return false;
}
else if (IsStrategicTradePartner(eLoopPlayer))
{
return false;
}
else if (!IsEasyTarget(eLoopPlayer))
{
return false;
}
else if (!IsBackstabber() && GetMajorCivOpinion(eLoopPlayer) >= MAJOR_CIV_OPINION_FAVORABLE)
{
return false;
}
}
}
}
}
// Declaration of Friendship or Defensive Pact?
else if (IsDoFAccepted(ePlayer) || (IsHasDefensivePact(ePlayer) && !IsWantsToEndDefensivePactWithPlayer(ePlayer)))
{
// Don't directly backstab if approach is FRIENDLY (unless they provoked us)
if (bDirect && !bImpulse && GetMajorCivApproach(ePlayer) == MAJOR_CIV_APPROACH_FRIENDLY)
return false;
// We must be stronger than them
bool bEasyTarget = IsEasyTarget(ePlayer);
if (bEasyTarget)
{
if (GetPlayerMilitaryStrengthComparedToUs(ePlayer) > STRENGTH_POWERFUL)
return false;
if (GetPlayerEconomicStrengthComparedToUs(ePlayer) > STRENGTH_POWERFUL)
return false;
}
else
{
if (GetPlayerMilitaryStrengthComparedToUs(ePlayer) > STRENGTH_AVERAGE)
return false;
if (GetPlayerEconomicStrengthComparedToUs(ePlayer) > STRENGTH_AVERAGE)
return false;
}
// Don't backstab if we're loyal
if (!IsBackstabber() && !bEndgameAggressive && GetLoyalty() > 6)
return false;
// We need a good reason to even consider backstabbing a friend...
bool bGoodReason = IsBackstabber(); // if we've already backstabbed one friend, more willing to backstab others
bGoodReason |= bEndgameAggressive;
bGoodReason |= bUntrustworthy;
bGoodReason |= IsCloseToDominationVictory() && GET_PLAYER(ePlayer).GetCapitalConqueror() == NO_PLAYER;
bGoodReason |= GET_PLAYER(ePlayer).GetDiplomacyAI()->GetWeDeclaredWarOnFriendCount() > 0; // they also backstabbed people
bGoodReason |= GetBiggestCompetitor() == ePlayer;
bGoodReason |= GetWarmongerThreat(ePlayer) >= THREAT_SEVERE;
if (!bDirect)
{
bGoodReason |= IsGoingForWorldConquest() && GET_PLAYER(ePlayer).GetCapitalConqueror() == NO_PLAYER;
bGoodReason |= IsMajorCompetitor(ePlayer);
}
if (!bGoodReason)
return false;
// Further checks are only necessary for Declarations of Friendship...breaking a DP doesn't earn a global backstabbing penalty
if (IsDoFAccepted(ePlayer))
{
// Okay, so we have a good reason. Are there any consequences from doing this that we're unwilling to face?
if (bDirect)
{
for (int iPlayerLoop = 0; iPlayerLoop < MAX_MAJOR_CIVS; iPlayerLoop++)
{
PlayerTypes eLoopPlayer = (PlayerTypes) iPlayerLoop;
if (IsPlayerValid(eLoopPlayer))
{
if (WouldBeUpsetIfAttackedFriend(eLoopPlayer, ePlayer) && !WasEverBackstabbedBy(eLoopPlayer) && !GET_PLAYER(eLoopPlayer).GetDiplomacyAI()->WasEverBackstabbedBy(GetID()) && !GET_PLAYER(eLoopPlayer).GetDiplomacyAI()->IsUntrustworthy(GetID()))
{
if (IsFriendOrAlly(eLoopPlayer))
{
return false;
}
else if (IsStrategicTradePartner(eLoopPlayer))
{
return false;
}
else if (!(IsEasyTarget(eLoopPlayer) || GetPlayer()->GetMilitaryAI()->HavePreferredAttackTarget(eLoopPlayer)) && GetPlayer()->GetProximityToPlayer(eLoopPlayer) >= PLAYER_PROXIMITY_CLOSE)
{
return false;
}
else if (!IsBackstabber() && GetMajorCivOpinion(eLoopPlayer) >= MAJOR_CIV_OPINION_FRIEND)
{
return false;
}
}
}
}
}
// Indirect backstab via Defensive Pact - much lower bar. Aim here is to prevent AIs from getting caught up in DP gridlock.
else
{
// Ignore vassals!
if (!GET_PLAYER(ePlayer).IsVassalOfSomeone())
{
// Don't do it if we're very loyal
if (!IsBackstabber() && !bEndgameAggressive && GetLoyalty() > 8)
return false;
// Don't do it if we'd lose a valuable trade partner
if (IsStrategicTradePartner(ePlayer))
return false;
// Impulse wars against people we like are a bad idea.
if (bImpulse && GetMajorCivOpinion(ePlayer) >= MAJOR_CIV_OPINION_FRIEND)
return false;
// Impulse wars against neighbors that aren't easy targets are a bad idea.
if (bImpulse && GET_PLAYER(ePlayer).GetProximityToPlayer(GetID()) >= PLAYER_PROXIMITY_CLOSE && !IsEasyTarget(ePlayer))
return false;
}
}
}
}
// If we've gone through all the hoops then we're okay with it.
return true;
}
/// This will do for now...may write more sophisticated logic later
bool CvDiplomacyAI::WouldBeUpsetIfAttackedFriend(PlayerTypes ePlayer, PlayerTypes eBackstabPlayer) const
{
if (GET_PLAYER(ePlayer).GetDiplomacyAI()->WasEverBackstabbedBy(eBackstabPlayer))
return false;
if (GET_PLAYER(eBackstabPlayer).GetDiplomacyAI()->WasEverBackstabbedBy(ePlayer))
return false;
return true;
}
/// Is this player a friend or ally in any way? Quick heuristic check that only checks for good things.
bool CvDiplomacyAI::IsFriendOrAlly(PlayerTypes ePlayer) const
{
if (IsTeammate(ePlayer))
return true;
if (!GET_PLAYER(ePlayer).isAlive())
return false;
if (IsDoFAccepted(ePlayer))
return true;
if (IsHasDefensivePact(ePlayer))
return true;
if (GetMajorCivOpinion(ePlayer) == MAJOR_CIV_OPINION_ALLY)
return true;
if (GetDoFType(ePlayer) >= DOF_TYPE_ALLIES)
return true;
if (WasResurrectedBy(ePlayer))
return true;
if (GET_PLAYER(ePlayer).GetDiplomacyAI()->WasResurrectedBy(GetID()))
return true;
return false;
}