jdog5000
Revolutionary
So, trying to get to the bottom of some strange AI voting behavior I perused CvPlayerAI::AI_diploVote today. Here pieces that I'm thinking about updating:
---------------------------------------------
1. Always vote for proposals by Friendly Secretary General
Up at the top of section of voting for proposals (as opposed to electing a leader) is the following:
The bold bit means that if the AI is Friendly towards the secretary general they vote for their proposals no matter what. The rest of the logic of picking how to vote isn't even considered.
It does make sense that a player's relationship with whoever is proposing the legislation would have an effect ... but that blanket condition is ridiculous. The AI would vote to put an embargo on itself if it was proposed by a conniving human they were friends with. They would vote for war against themselves or to give away their own city to. Not sure what is actually possible given constraints on what can be proposed by friends, but you get the idea.
Here's what I'm thinking instead:
- Never defy legislation from friends
- Auto approve trade routes, free trade, open borders, defensive pact, embargo (if not self)
- Up thresholds for voting against civics
That leaves stop war, start war, assigning cities, and nukes. It's possible to easily influence some of these a little bit towards yes, but these seem like more strategic decisions where it may be less appropriate to consider the relationship to the secretary.
---------------------------------------------
2. Stop war "logic"
So far I haven't been able to figure out the reasoning behind the logic the AI uses to vote on stopping wars. Here's the initial bit:
Now the comment says "are we winning wars?" but it isn't really for this player ... iWarsWinning, iWarsLosing, and iChosenWars count how things are going for ePeaceTeam and will be the same for every player in the game.
Let's imagine there's a vote to end the war against the Aztecs. The code counts the wining/losing/chosen feelings of the Aztecs. So, we've got a count of the number of teams who the Aztecs think they're beating, the number the Aztecs are losing to/tied with, and the number of teams the Aztecs chose to go to war with.
One problem I see with this part is the handling of ties, particularly if there's an inactive war where no fighting has occurred and both sides war success is 0. For example, say the Aztecs decided to attack France and that France has two tiny vassal colonies. The Aztecs could be beating France handily but would have two "losses" if their troops have never seen France's weak vassals on the battle field. So, I'm thinking there should be some thresholds so that winning/losing only counts if there's been some real fighting (the thresholds could be dependent on whether Aggressive AI is on).
Now the flow continues on to the actual decision making, I've broken it into pieces so it's easier to work through. If bValid is true the AI will vote to end the war, if false it will vote against and may choose to defy it.
The above block handles the case where the Aztecs are voting to end the war against themselves. The Aztecs will vote to continue the war against themselves if they have chosen to get into more wars than they are losing. Alternatively, the Aztecs will also choose to keep the wars going if they aren't losing more wars than they're winning.
These clauses reads okay at first, however, I think the case of ties where there hasn't been any actual fighting mentioned above would cause this to tilt towards a vote for peace.
This clause means the AI always votes for it's own legislation ... never actually fires as it's preempted by the code from issue 1.
This handles decisions for players who are at war with the Aztecs. The bPropose flag is a special case where the AI is considering whether to put a particular piece of legislation up for a vote. Aside from that, the first clause says the AI will vote for peace if it would be willing consider peace if asked in the diplomacy window by the secretary general. It's decision to vote for peace with the Aztecs (bValid = true) can be overridden if the Aztecs losing more wars than they're winning.
There are problems with using AI_makePeaceTrade here though ... if ePeaceTeam is the human player, AI_makePeaceTrade always returns DENIAL_CONTACT_THEM and so the AI would never vote for peace if they were at war with the human player regardless of how the war is going. Similarly, if the AI is losing badly enough the function returns the same DENIAL_CONTACT_THEM and so the AI won't vote for peace if it's getting beat badly. If the AI is a vassal the function returns DENIAL_VASSAL since as a vassal it doesn't control peace decisions in diplomacy but that doesn't apply here.
I'm not sure quite what to propose here ... I think the AI_makePeaceTrade should only be considered if the AI is on pretty good terms with the secretary. Also, there clearly needs to be a further consideration so the AI won't vote to continue a war which it is losing by more than a little.
This clause handles how third-parties vote. If the third-party has a least okay relations with the Aztecs and the Aztecs are losing, then they vote for peace. If they don't like the Aztecs and the Aztecs are winning, they vote for peace.
It's a little to altruistic, there are several self-interest reasons the AI might want to keep this war going. If they're planning to invade the Aztecs soon, then they probably want the war to continue regardless of who is on top. Similarly, if they are at war with someone who is also at war with the Aztecs then they would want to keep them busy.
This block decides if the AI chooses to defy the resolution. I think there's a pretty clear bug here as the logic only makes sense for the Aztecs and not anyone who's at war with them. It's also possible based on this that a player not at war with the Aztecs would choose to defy the resolution, though that is caught later with a check to CvPlayer::canDefy.
There need to be two cases here, one for the Aztecs and one for those at war with the Aztecs. I'm not sure quite what the logic should be as it is hard to quantify the benefit of maintaining war versus the cost of happiness and lost bonuses. Certainly the AI should only defy if it is really winning and has reason to believe it will keep winning (power comparison).
--------------------------------------------
Thoughts? Ideas? Proposals?
---------------------------------------------
1. Always vote for proposals by Friendly Secretary General
Up at the top of section of voting for proposals (as opposed to electing a leader) is the following:
Code:
if (eSecretaryGeneral == getTeam() ||([B]GET_TEAM(getTeam()).AI_getAttitude(eSecretaryGeneral) == ATTITUDE_FRIENDLY[/B]))
{
return PLAYER_VOTE_YES;
}
The bold bit means that if the AI is Friendly towards the secretary general they vote for their proposals no matter what. The rest of the logic of picking how to vote isn't even considered.
It does make sense that a player's relationship with whoever is proposing the legislation would have an effect ... but that blanket condition is ridiculous. The AI would vote to put an embargo on itself if it was proposed by a conniving human they were friends with. They would vote for war against themselves or to give away their own city to. Not sure what is actually possible given constraints on what can be proposed by friends, but you get the idea.
Here's what I'm thinking instead:
- Never defy legislation from friends
- Auto approve trade routes, free trade, open borders, defensive pact, embargo (if not self)
- Up thresholds for voting against civics
That leaves stop war, start war, assigning cities, and nukes. It's possible to easily influence some of these a little bit towards yes, but these seem like more strategic decisions where it may be less appropriate to consider the relationship to the secretary.
---------------------------------------------
2. Stop war "logic"
So far I haven't been able to figure out the reasoning behind the logic the AI uses to vote on stopping wars. Here's the initial bit:
Code:
int iWarsWinning = 0;
int iWarsLosing = 0;
int iChosenWar = 0;
//Are we winning wars?
for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
{
if (GET_TEAM((TeamTypes)iI).isAlive())
{
[B]if (iI != ePeaceTeam)[/B]
{
if (GET_TEAM((TeamTypes)iI).isAtWar(ePeaceTeam))
{
if (GET_TEAM((TeamTypes)iI).AI_getWarSuccess(ePeaceTeam) < GET_TEAM(ePeaceTeam).AI_getWarSuccess((TeamTypes)iI))
{
++iWarsWinning;
}
else
{
++iWarsLosing;
}
if (GET_TEAM(ePeaceTeam).AI_isChosenWar((TeamTypes)iI))
{
++iChosenWar;
}
}
}
}
}
Now the comment says "are we winning wars?" but it isn't really for this player ... iWarsWinning, iWarsLosing, and iChosenWars count how things are going for ePeaceTeam and will be the same for every player in the game.
Let's imagine there's a vote to end the war against the Aztecs. The code counts the wining/losing/chosen feelings of the Aztecs. So, we've got a count of the number of teams who the Aztecs think they're beating, the number the Aztecs are losing to/tied with, and the number of teams the Aztecs chose to go to war with.
One problem I see with this part is the handling of ties, particularly if there's an inactive war where no fighting has occurred and both sides war success is 0. For example, say the Aztecs decided to attack France and that France has two tiny vassal colonies. The Aztecs could be beating France handily but would have two "losses" if their troops have never seen France's weak vassals on the battle field. So, I'm thinking there should be some thresholds so that winning/losing only counts if there's been some real fighting (the thresholds could be dependent on whether Aggressive AI is on).
Now the flow continues on to the actual decision making, I've broken it into pieces so it's easier to work through. If bValid is true the AI will vote to end the war, if false it will vote against and may choose to defy it.
Code:
if (ePeaceTeam == getTeam())
{
if (iWarsLosing < iChosenWar)
{
bValid = false;
}
else
{
bValid = (iWarsWinning < iWarsLosing);
}
}
The above block handles the case where the Aztecs are voting to end the war against themselves. The Aztecs will vote to continue the war against themselves if they have chosen to get into more wars than they are losing. Alternatively, the Aztecs will also choose to keep the wars going if they aren't losing more wars than they're winning.
These clauses reads okay at first, however, I think the case of ties where there hasn't been any actual fighting mentioned above would cause this to tilt towards a vote for peace.
Code:
else if (eSecretaryGeneral == getTeam() && !bPropose)
{
bValid = true;
}
This clause means the AI always votes for it's own legislation ... never actually fires as it's preempted by the code from issue 1.
Code:
else if (GET_TEAM(ePeaceTeam).isAtWar(getTeam()))
{
bValid = (bPropose || NO_DENIAL == GET_TEAM(getTeam()).AI_makePeaceTrade(ePeaceTeam, eSecretaryGeneral));
if (bValid)
{
bValid = (iWarsWinning > iWarsLosing);
}
}
This handles decisions for players who are at war with the Aztecs. The bPropose flag is a special case where the AI is considering whether to put a particular piece of legislation up for a vote. Aside from that, the first clause says the AI will vote for peace if it would be willing consider peace if asked in the diplomacy window by the secretary general. It's decision to vote for peace with the Aztecs (bValid = true) can be overridden if the Aztecs losing more wars than they're winning.
There are problems with using AI_makePeaceTrade here though ... if ePeaceTeam is the human player, AI_makePeaceTrade always returns DENIAL_CONTACT_THEM and so the AI would never vote for peace if they were at war with the human player regardless of how the war is going. Similarly, if the AI is losing badly enough the function returns the same DENIAL_CONTACT_THEM and so the AI won't vote for peace if it's getting beat badly. If the AI is a vassal the function returns DENIAL_VASSAL since as a vassal it doesn't control peace decisions in diplomacy but that doesn't apply here.
I'm not sure quite what to propose here ... I think the AI_makePeaceTrade should only be considered if the AI is on pretty good terms with the secretary. Also, there clearly needs to be a further consideration so the AI won't vote to continue a war which it is losing by more than a little.
Code:
else
{
if (GET_TEAM(getTeam()).AI_getAttitude(ePeaceTeam) >= ATTITUDE_CAUTIOUS)
{
bValid = (iWarsLosing > iWarsWinning);
}
else
{
bValid = (iWarsWinning > iWarsLosing);
}
}
This clause handles how third-parties vote. If the third-party has a least okay relations with the Aztecs and the Aztecs are losing, then they vote for peace. If they don't like the Aztecs and the Aztecs are winning, they vote for peace.
It's a little to altruistic, there are several self-interest reasons the AI might want to keep this war going. If they're planning to invade the Aztecs soon, then they probably want the war to continue regardless of who is on top. Similarly, if they are at war with someone who is also at war with the Aztecs then they would want to keep them busy.
Code:
if (!bValid && iWarsWinning > 0)
{
if (GC.getGame().getSorenRandNum(2, "AI Erratic Defiance (Force Peace)") == 0)
{
bDefy = true;
}
}
This block decides if the AI chooses to defy the resolution. I think there's a pretty clear bug here as the logic only makes sense for the Aztecs and not anyone who's at war with them. It's also possible based on this that a player not at war with the Aztecs would choose to defy the resolution, though that is caught later with a check to CvPlayer::canDefy.
There need to be two cases here, one for the Aztecs and one for those at war with the Aztecs. I'm not sure quite what the logic should be as it is hard to quantify the benefit of maintaining war versus the cost of happiness and lost bonuses. Certainly the AI should only defy if it is really winning and has reason to believe it will keep winning (power comparison).
--------------------------------------------
Thoughts? Ideas? Proposals?