// Determine how much we are going to tax this player, if we can
void CvDiplomacyAI::DoDetermineTaxRateForVassalOnePlayer(PlayerTypes ePlayer)
{
// Must be able to set taxes for player
if(!GET_TEAM(GetPlayer()->getTeam()).CanSetVassalTax(ePlayer))
return;
TeamTypes eMyTeam = GetPlayer()->getTeam();
CvTeam& kMyTeam = GET_TEAM(eMyTeam);
// Do not allow an AI teammate to do this for a human
if(!GetPlayer()->isHuman() && kMyTeam.isHuman())
return;
// Current tax rate
int iTaxRate = kMyTeam.GetVassalTax(ePlayer);
// Make sure we can actually do that...
bool bWantToLower = iTaxRate > GC.getVASSALAGE_VASSAL_TAX_PERCENT_MINIMUM();
bool bWantToRaise = iTaxRate < GC.getVASSALAGE_VASSAL_TAX_PERCENT_MAXIMUM();
// Because this function will involve lots of iteration over team members, let's store all alive team members in temporary vectors to improve the speed of this function
std::vector<CvPlayerAI*> m_MasterTeam;
std::vector<CvPlayerAI*> m_VassalTeam;
for(int iI=0; iI < MAX_MAJOR_CIVS; iI++)
{
PlayerTypes eLoopPlayer = (PlayerTypes) iI;
if(GET_PLAYER(eLoopPlayer).isAlive())
{
// Master team
if(GET_PLAYER(eLoopPlayer).getTeam() == GetPlayer()->getTeam())
{
m_MasterTeam.push_back(&GET_PLAYER(eLoopPlayer));
}
// Vassal team
else if(GET_PLAYER(eLoopPlayer).getTeam() == GET_PLAYER(ePlayer).getTeam())
{
m_VassalTeam.push_back(&GET_PLAYER(eLoopPlayer));
}
}
}
MajorCivOpinionTypes eTeamOpinion = MAJOR_CIV_OPINION_NEUTRAL;
int iMyCurrentGPT = 0, iMyCurrentGross = 0, iAverageMeanness = 0, iAverageLoyalty = 0, iAverageOpinionScore = 0;
for(std::vector<CvPlayerAI*>::iterator it = m_MasterTeam.begin(); it != m_MasterTeam.end(); it++)
{
iMyCurrentGPT += (*it)->GetTreasury()->CalculateBaseNetGoldTimes100();
iMyCurrentGross += (*it)->GetTreasury()->CalculateBaseNetGoldTimes100();
iAverageMeanness += (*it)->GetDiplomacyAI()->GetMeanness();
iAverageLoyalty += (*it)->GetDiplomacyAI()->GetLoyalty();
iAverageOpinionScore += (int) (*it)->GetDiplomacyAI()->GetMajorCivOpinion(ePlayer);
}
iAverageMeanness /= m_MasterTeam.size();
iAverageLoyalty /= m_MasterTeam.size();
iAverageOpinionScore /= m_MasterTeam.size();
eTeamOpinion = (MajorCivOpinionTypes) iAverageOpinionScore;
int iVassalCurrentGPT = 0, iVassalCurrentGross = 0;
for(std::vector<CvPlayerAI*>::iterator it = m_VassalTeam.begin(); it != m_VassalTeam.end(); it++)
{
iVassalCurrentGPT += (*it)->GetTreasury()->CalculateBaseNetGoldTimes100();
iVassalCurrentGross += (*it)->GetTreasury()->CalculateGrossGoldTimes100();
}
// Hate him? Don't consider lowering!
if(eTeamOpinion == MAJOR_CIV_OPINION_UNFORGIVABLE)
bWantToLower = false;
// Like him? Don't consider raising!
if(eTeamOpinion == MAJOR_CIV_OPINION_ALLY)
bWantToRaise = false;
// We have some choice in the direction taxes can go - pick a direction so we can start deciding
if(bWantToLower && bWantToRaise)
{
// We're in dire straights
if(iMyCurrentGPT <= 0)
{
bWantToLower = false; // don't even consider lowering
// Check to see if taxing the vassal the maximum would get us out of dire straights
if(bWantToRaise)
{
// Wouldn't help us out at all
if((iVassalCurrentGross * GC.getVASSALAGE_VASSAL_TAX_PERCENT_MAXIMUM() / 100 < 100))
{
bWantToRaise = false;
}
// Tax vassal the maximum to get us out of trouble - his feelings be damned
else
{
kMyTeam.DoApplyVassalTax(ePlayer, GC.getVASSALAGE_VASSAL_TAX_PERCENT_MAXIMUM());
return;
}
}
}
// Doing fine - have some choice
else
{
int iScoreForLower = 0;
int iScoreForRaise = 0;
// Starting values based on opinion
switch(eTeamOpinion)
{
case MAJOR_CIV_OPINION_ENEMY:
iScoreForLower = -25;
iScoreForRaise = 25;
case MAJOR_CIV_OPINION_COMPETITOR:
iScoreForLower = -10;
iScoreForRaise = 10;
break;
case MAJOR_CIV_OPINION_NEUTRAL:
iScoreForLower = 0;
iScoreForRaise = 0;
break;
case MAJOR_CIV_OPINION_FAVORABLE:
iScoreForLower = 10;
iScoreForRaise = -10;
break;
case MAJOR_CIV_OPINION_FRIEND:
iScoreForLower = 25;
iScoreForRaise = -25;
break;
default:
CvAssertMsg(false, "Should not have gotten here.");
}
// Still deciding what to be done?
if(bWantToLower && bWantToRaise)
{
// Is our vassal doing better than us monetarily?
if(iVassalCurrentGPT >= iMyCurrentGPT)
{
iScoreForLower *= 75;
iScoreForLower /= 100;
iScoreForRaise *= 125;
iScoreForRaise /= 100;
}
// He is doing worse than 85% of our GPT
else if(iVassalCurrentGPT * 85 <= iMyCurrentGPT * 100)
{
// Have to like the vassal
if(eTeamOpinion > MAJOR_CIV_OPINION_NEUTRAL)
{
// Determine a percentage to lower
int iThreshold = 33;
// He is doing REALLY bad
if(iVassalCurrentGPT * 150 < iMyCurrentGPT * 100)
iThreshold = 75;
int iRand = GC.getGame().getJonRandNum(100, "CvDiplomacyAI: Do we want to give this vassal a nice boost in GPT cus his GPT is less and we like him?");
if(iRand < iThreshold)
{
iScoreForLower *= 150;
iScoreForLower /= 100;
}
}
}
// Raise score for lowering based on loyalty
iScoreForLower *= 100 + (iAverageLoyalty - 5) * 10;
iScoreForLower /= 100;
// Raise score for lowering based on meanness
iScoreForRaise *= 100 + (iAverageMeanness - 5) * 10;
iScoreForRaise /= 100;
bWantToLower = (iScoreForLower > iScoreForRaise);
bWantToRaise = (iScoreForLower < iScoreForRaise);
}
}
}
CvWeightedVector<int, 20, true> aPossibleValues; // in case changed, 100 / 5 is a safe bet for number of possible elements
// New tax value defaults to current tax rate
int iNewTaxValue = iTaxRate;
// Decided we're going to lower - figure out by how much
if(bWantToLower)
{
int iCurrentIndex = 0;
// Possible values are determined by increments of 5 starting from below the current tax line
for(int i = (iTaxRate - 5); i >= GC.getVASSALAGE_VASSAL_TAX_PERCENT_MINIMUM(); i -= 5)
{
int iValue = i;
int iWeight = (iAverageOpinionScore - 3) * iCurrentIndex + 100;
// Determine if we will make at least one GPT profit off of this value, if not, then decentivize
if(iVassalCurrentGross * iValue < 10000)
iWeight /= 4;
aPossibleValues.push_back(iValue, iWeight);
iCurrentIndex++;
}
RandomNumberDelegate fcn;
fcn = MakeDelegate(&GC.getGame(), &CvGame::getJonRandNum);
iNewTaxValue = aPossibleValues.ChooseByWeight(&fcn, "Choose the tax value to assign");
}
// Decided we're going to raise - figure out by how much
else
{
int iCurrentIndex = 0;
// Possible values are determined by increments of 5 starting from above the current tax line
for(int i = (iTaxRate + 5); i <= GC.getVASSALAGE_VASSAL_TAX_PERCENT_MAXIMUM(); i += 5)
{
int iValue = i;
int iWeight = (3 - iAverageOpinionScore) * iCurrentIndex + 100;
// Determine if we will make at least one GPT profit off of this value, if not, then decentivize
if(iVassalCurrentGross * iValue < 10000)
iWeight /= 4;
aPossibleValues.push_back(iValue, iWeight);
iCurrentIndex++;
}
RandomNumberDelegate fcn;
fcn = MakeDelegate(&GC.getGame(), &CvGame::getJonRandNum);
iNewTaxValue = aPossibleValues.ChooseByWeight(&fcn, "Choose the tax value to assign");
}
// Set the tax.
kMyTeam.DoApplyVassalTax(ePlayer, iNewTaxValue);
}