Buffed AI for BNW

Thanks for pushing the extreme ends of this mod Joncnunn. If the player is pushing out high culture/tourism on relatively low core yields, that would bypass the adaptive buff. That combined with the AI's poor strategic play. Also playing on tiny islands probably doesn't engage the combat AI as much, which means bypassing the combat buffs the AI gets in this mod? (Is that true? I haven't played on these types of maps)

EDIT:
Could I ask a question? Should I turn off the adaptive buff for city states?

I think it was a mistake not to because it actually hurts the conquest civs and hurts their ability to expand. The reason is that currently city states get more yield to build a lot more troops because of the leak they get, making conquest of them that much harder. It also means a lot more unit spam and difficulty to get civilians into the city states because of the traffic jam.

So I think I should boost only the major civs, so that the conquest civs that capture a CS (which will be easier to do) will likely also get an adaptive buff, which would make their presence more of a challenge for players to deal with.

It indeed happened that the AI didn't declare war on me at all the whole game. America was the only other civ that got an ideology and they wisely picked Freedom with me already being at Influential influence level over them.
The English & Celt AIs though declared a lot of wars on each other and the Celts were in last place. England conquered the northern most Celt city in one of those wars.

Yes, it would be a good idea to not have leaks to city states, it makes Venice & Austria too powerful and harms the Mongolian AI.

I would have been able to shave 5 to 10 turns off my victory time if the Celts hadn't been in the game to found a religion first and taken Monasteries.

Also if the Coal had been closer that would have helped by a few turns (it finally got into my borders [5 hexes away from nearest city] a few turns before the game ended and my worker was still mining it. (I had a few thousand gold ready to cash buy 4 factories, RA's weren't worth it and I already had spies for the key city states)
 
Suggest you play this mod. In this mod AI missionary and prophet spam is reduced and so people don't need radical tactics to keep foreign religion out. In the base game it is ridiculous (but it has to be). That is one of the reasons I built this mod.
Do they still do that? I don't play with any mods that affect AI behaviour in this regard (as far as I'm aware at least) but it seems that since either BnW or the fall patch, the AI has started agressively converting my cities if I have founded a religion. They still spam missionaries and prophets and they will convert city states following my religion (good move) as well as any city not having a religion (also good move), but I all but never experience them converting my own cities once I have myself adopted a religion. I have frequently AI Great Prophets marching right through my lands and then pass on to other areas even without buying Inquisitors. I though actually Firaxis had rebalanced this, because I feel in this particular regard, the AI is pretty good as it is.
 
Just started my Spain game on V 17.

Spain may be one of the better civs to play with this mod since if Spain gets a science/gold/hammer based natural wonder it will be fed directly into the AI while if not, it won't. (In the base game playing Spain suffers from if you want the AI to be competitive you need to play on one difficulty level higher than normal if you get a natural wonder early but at your normal level if you don't)

In this start I had an all faith (+ happiness) natural wonder. (No food from it.) There were four possible pantheons to go with (Dance of the Aurora, Goddess of the Hunt, One With Nature, Religious Idols), I went with Dance of the Aurora. (All but one Silver was on Tundra, and there were a lot more Tundra tiles that would be worked without forest than 8)

This does present me in the situation of effectively having started with 2 cities, but both started pretty bad. (Combo of a badly placed city state on the map and my other mod increasing minimum allowed distance by one.)
 
Hi Kaspergm
In this mod religion unit spam is reduced. The religion AI behaviour is either smart AI or default. That is all there is to religion in this mod. In practice, the AI still builds enough religion units.

Hope that answers the question.
 
Hi Joncnunn
Yet another thing I didn't forsee with adaptive buffs, the effect on Spain. Also, if you increase the city spacing in this mod, it could make the mod easier because the AI won't be able to settle new cities as easily which means it won't get the adaptive buff as much. Increasing by one is probably not much effect though.

Update on progress for next version (for my own motivation):
  • There is a bug in this mod for immortal or higher players. I thought the AI work rate increased with decreasing numbers but it does not. It is set to 50% but should be higher not lower. So in next release will delete the AI work rate which will put it back to default. That will mean immortal AI workers will be 75% and diety 100% work rate
  • AI is guarding its workers
  • Minor civs guard their workers
  • Workers don't go wandering like drunks around map.
  • AI doesn't retreat workers because they are guarded and therefore it is more productive.
  • AI doesn't have to build as many workers because they are guarded and more productive
  • AI is more carefully about escorting settlers
  • Still need to ensure that settlers are always guarded (at the moment I still have a bit of work to do on that).
  • Minor civs don't get adaptive buff

QUESTION:
In next release I'm thinking of making civs with a high victory competitiveness less likely to sign RA's with player. What does anyone think?
 
Hi Joncnunn
Yet another thing I didn't forsee with adaptive buffs, the effect on Spain. Also, if you increase the city spacing in this mod, it could make the mod easier because the AI won't be able to settle new cities as easily which means it won't get the adaptive buff as much. Increasing by one is probably not much effect though.

QUESTION:
In next release I'm thinking of making civs with a high victory competitiveness less likely to sign RA's with player. What does anyone think?

I've been doing the increase city spacing by one for quite a while (before BNW came out), it actually makes the AI smarter about where to found city locations compared to standard.

I do wish though there was a way to make the increased city spacing not apply to from the city states though. (And the BE idea of having Outposts [the equivalent of city states in BE] only start with the city tile itself is also good)
(In the mean time though those playing on "plus" maps are less likely to run into that particular one with it having relocated most of the city states to small islands off the coast of the bigger landmasses)

On high victory competitiveness, that would depend directly on what victory condition that particular AI is after. For AIs seeking science victory, it's clear they should continue to sign RAs. AIs seeking cultural or diplomatic victory though would be situation dependent.
 
EDIT: Ok, so how about this?

What about a RA buff instead?
1 - RA's provide more yield to AI than the player at agreement end. (but AI doesn't know this)
2 - AI's that sign RA's with each other get more yield at agreement end. (but AI doesn't know that)
 
EDIT: Ok, so how about this?

What about a RA buff instead?
1 - RA's provide more yield to AI than the player at agreement end. (but AI doesn't know this)
2 - AI's that sign RA's with each other get more yield at agreement end. (but AI doesn't know that)

#2 would be much more effective. AI already loves to sign RAs when it can (when both AIs are in the same era)

The problem with #1 is that the human would never sign an RA with whichever AI they believe to be closest to them again if it was implemented. (The human wouldn't sign one with the worst place either due to getting so few beakers out of it even in base game, so the human would try to get RAs with [who they believe are] the 2nd or 3rd best AIs to still get a decent return but without risking who they believe the closest AI to them narrowing the gap.)
 
Thanks Joncnunn, I'll give thought to #2

Meanwhile, huge milestone today (just needs final testing). Finally found the section of the code that I need to ensure that settlers are always guarded.

So in V18, workers will make improvements quicker and the AI won't need as many workers because they are guarded. This will mean it will be able to afford an extra military unit and be able to build a military quicker. Also, since the AI will not loose settlers nearly as much, it will mean that the AI will settle more effectively and possibly get the adaptive buff as well. Lastly, the loopholes are closed for players to steal workers off city states and major civs. They can do it on easier levels still, and if the player explorers really well, they can still find the occasional worker that barbs captured because the AI wasn't able to allocate enough guard units to protect all its workers.

If I also add something to boost the late game, I'll be pretty happy with this mod!
 
Here is the proposed code to implement #2 on research agreements. If someone could check it for logic that would be great. It gives me more time to check other parts of the code and test.

Spoiler :

Code:
Code is from [B]void CvGameDeals DoEndTradedItem(CvTradedItem* pItem, PlayerTypes eToPlayer, bool bCancelled)[/B]
.
.
.
.
	PlayerTypes eFromPlayer = pItem->m_eFromPlayer;
.
.
.

	// Research Agreement
	else if(pItem->m_eItemType == TRADE_ITEM_RESEARCH_AGREEMENT)
	{
		GET_TEAM(eFromTeam).SetHasResearchAgreement(eToTeam, false);

		if(!GET_TEAM(eFromTeam).isAtWar(eToTeam) && !bCancelled)
		{
			// Beaker boost = ((sum of both players' beakers over term of RA) / 2) / 3) * (median tech percentage rate)
			CvTeam& kTeam = GET_TEAM(toPlayer.getTeam());
			int iToPlayerBeakers = toPlayer.GetResearchAgreementCounter(eFromPlayer);
			int iFromPlayerBeakers = fromPlayer.GetResearchAgreementCounter(eToPlayer);
			int iBeakersBonus = min(iToPlayerBeakers, iFromPlayerBeakers) / GC.getRESEARCH_AGREEMENT_BOOST_DIVISOR(); //one (third) of minimum contribution
			iBeakersBonus = (iBeakersBonus * toPlayer.GetMedianTechPercentage()) / 100;

[B]			// Glider1 - BuffedAI
			// Boost beaker bonus between completed AI-AI research agreements
			if (!toPlayer.isHuman() && !fromPlayer.isHuman())
			{
				iBeakersBonus *= GC.getRESEARCH_AGREEMENT_AI_BUFF();
				iBeakersBonus /= 100;
			}
			// end[/B]

			TechTypes eCurrentTech = toPlayer.GetPlayerTechs()->GetCurrentResearch();
			if(eCurrentTech == NO_TECH)
			{
				toPlayer.changeOverflowResearch(iBeakersBonus);
			}
			else
			{
				kTeam.GetTeamTechs()->ChangeResearchProgress(eCurrentTech, iBeakersBonus, eToPlayer);
			}

			pNotifications = toPlayer.GetNotifications();
			if(pNotifications)
			{
				strBuffer = GetLocalizedText("TXT_KEY_NTFN_RA_FREE_TECH", fromPlayer.getNameKey());
				strSummary = GetLocalizedText("TXT_KEY_NTFN_RA_FREE_TECH_S", fromPlayer.getNameKey());
				pNotifications->Add(NOTIFICATION_DEAL_EXPIRED_RESEARCH_AGREEMENT, strBuffer, strSummary, -1, -1, -1);
			}
		}



EDIT:

If the code is ok, what value for GC.getRESEARCH_AGREEMENT_AI_BUFF() should I use?

Thanks!
 
If the code is ok, what value for GC.getRESEARCH_AGREEMENT_AI_BUFF() should I use?

Normally instead of nested if statements it would be written as !toPlayer.isHuman() && !fromPlayer.isHuman()

Looks to me like it's only keeping track of past X turns reserach in context of active RAs,
And it also looks like the same bonus has to be given to both.

So define
HumanScience as the humans beakers produced most recently.
FromScience as the from AIs beakers produced most recently.
ToScience as the to AIs beakers produced most recently.

Then the bonus Multiplier to apply would be Max(1 , Min (HumanScience/FromScience, HumanScience/ToScience))

Then then iBeakers could just be multiplied by the bonus Multiplier.

So the AIs get the smaller of the two advantages from beakers, but the bonus will turn itself off if either is producing more science than the human.

(What's written assumes that a double is being returned by the formulas for beakers instead of integers. If integers are being returned, then casting to double needs done to avoid it doing integer division and at the end the result truncated back to an int.)
 
Thanks. I'll be honest, you have lost me. I thought we were only interested in AI-AI research agreement deals because of the negatives you mentioned on #1.

To reiterate, proposal is:
#2 - AI's that sign RA's with each other get more yield at agreement end. (but AI doesn't know that)

I think the code runs from the perspective of each player so that both players get the calculation and the notification that way.

EDIT:
I updated the code above to show you the entire slab that covers the end of deal. I have to be careful because testing this idea for bugs is a pain.

Spoiler :

Code:
Code is from [B]void CvGameDeals DoEndTradedItem(CvTradedItem* pItem, PlayerTypes eToPlayer, bool bCancelled)[/B]
.
.
.
.
	PlayerTypes eFromPlayer = pItem->m_eFromPlayer;
.
.
.

	// Research Agreement
	else if(pItem->m_eItemType == TRADE_ITEM_RESEARCH_AGREEMENT)
	{
		GET_TEAM(eFromTeam).SetHasResearchAgreement(eToTeam, false);

		if(!GET_TEAM(eFromTeam).isAtWar(eToTeam) && !bCancelled)
		{
			// Beaker boost = ((sum of both players' beakers over term of RA) / 2) / 3) * (median tech percentage rate)
			CvTeam& kTeam = GET_TEAM(toPlayer.getTeam());
			int iToPlayerBeakers = toPlayer.GetResearchAgreementCounter(eFromPlayer);
			int iFromPlayerBeakers = fromPlayer.GetResearchAgreementCounter(eToPlayer);
			int iBeakersBonus = min(iToPlayerBeakers, iFromPlayerBeakers) / GC.getRESEARCH_AGREEMENT_BOOST_DIVISOR(); //one (third) of minimum contribution
			iBeakersBonus = (iBeakersBonus * toPlayer.GetMedianTechPercentage()) / 100;

[B]			// Glider1 - BuffedAI
			// Boost beaker bonus between completed AI-AI research agreements
			if (!toPlayer.isHuman() && !fromPlayer.isHuman())
			{
				iBeakersBonus *= GC.getRESEARCH_AGREEMENT_AI_BUFF(); // say 200/100 ratio of 2.
				iBeakersBonus /= 100;
			}
			// end[/B]

			TechTypes eCurrentTech = toPlayer.GetPlayerTechs()->GetCurrentResearch();
			if(eCurrentTech == NO_TECH)
			{
				toPlayer.changeOverflowResearch(iBeakersBonus);
			}
			else
			{
				kTeam.GetTeamTechs()->ChangeResearchProgress(eCurrentTech, iBeakersBonus, eToPlayer);
			}

			pNotifications = toPlayer.GetNotifications();
			if(pNotifications)
			{
				strBuffer = GetLocalizedText("TXT_KEY_NTFN_RA_FREE_TECH", fromPlayer.getNameKey());
				strSummary = GetLocalizedText("TXT_KEY_NTFN_RA_FREE_TECH_S", fromPlayer.getNameKey());
				pNotifications->Add(NOTIFICATION_DEAL_EXPIRED_RESEARCH_AGREEMENT, strBuffer, strSummary, -1, -1, -1);
			}
		}
 
Thanks. I'll be honest, you have lost me. I thought we were only interested in AI-AI research agreement deals because of the negatives you mentioned on #1.

To reiterate, proposal is:
#2 - AI's that sign RA's with each other get more yield at agreement end. (but AI doesn't know that)

That's true, my ideal is that instead of a flat bonus to AI when both civs are AIs, that the bonus be dynamic.
The min ( Human / AI_FROM, Human / AI_TO) portion would calculate the ratios of the human current beaker production with both of the AIs involved in the trade deal and use the smaller bonus.

The max (1, ...) then ensures that if the AI actually is producing more beakers than a human the AI doesn't get a penalty and just turns off the dynamic bonus.

All three of these field would need to be fetched (the human isn't part of the trade deal and the variables already defined for each AI involved in the RA was for multiple turns)

Example: AI 1 & AI 2 RA completes

During the most recent turn the Human produced 300 beakers, AI 1 produced 200 beakers, AI 2 produced 150 beakers.

Max (1.0, Min ( 300.0 / 200.0), (300.0 / 150.0) ->
Max (1.0, Min (1.5, 2.0)) ->
Max (1.0, 1.5) ->
1.5

Both AIs involved in the RA would get 1.5 times as many beakers as normal

Let's say the base formula would normally have given them both 800 beakers, so in this case they would instead get 1200 beakers. (A nice 400 extra beakers to help catch up)
 
Thanks. Good idea!

Could you check this code then?

Spoiler :
Code:
			// Glider1 - BuffedAI
			// Adaptively boost beaker bonus between completed AI to AI research agreements only
			if (!toPlayer.isHuman() && !fromPlayer.isHuman())
			{
				CvPlayer& pPlayer = GET_PLAYER(GC.getGame().getActivePlayer());
				float activePlayerYield = (float) pPlayer.GetScienceTimes100();
				float toPlayerYield = (float) std::max(1, toPlayer.GetScienceTimes100());
				float fromPlayerYield = (float) std::max(1, fromPlayer.GetScienceTimes100());

				float toPlayerBuff = activePlayerYield / toPlayerYield;
				float fromPlayerBuff = activePlayerYield / fromPlayerYield;
				float researchBuff = fromPlayerBuff;

				// Note: std::min causes a compiler error with floats for some reason
				if (toPlayerBuff < fromPlayerBuff)
					researchBuff = toPlayerBuff;

				if (researchBuff < 1.0)
					researchBuff = 1.0;

				iBeakersBonus = (int)((float)iBeakersBonus * researchBuff);
			}
			// end

EDIT:
If you are happy with the code, I could upload the beta for V18 in case you or anyone wants to try it (just let me know), which includes all the AI updates and this change as well. I will be spending the weekend (if not longer) doing final testing on V18 before officially releasing it.
 
Thanks. Good idea!

Could you check this code then?

Spoiler :
Code:
			// Glider1 - BuffedAI
			// Adaptively boost beaker bonus between completed AI to AI research agreements only
			if (!toPlayer.isHuman() && !fromPlayer.isHuman())
			{
				CvPlayer& pPlayer = GET_PLAYER(GC.getGame().getActivePlayer());
				float activePlayerYield = (float) pPlayer.GetScienceTimes100();
				float toPlayerYield = (float) std::max(1, toPlayer.GetScienceTimes100());
				float fromPlayerYield = (float) std::max(1, fromPlayer.GetScienceTimes100());

				float toPlayerBuff = activePlayerYield / toPlayerYield;
				float fromPlayerBuff = activePlayerYield / fromPlayerYield;
				float researchBuff = fromPlayerBuff;

				// Note: std::min causes a compiler error with floats for some reason
				if (toPlayerBuff < fromPlayerBuff)
					researchBuff = toPlayerBuff;

				if (researchBuff < 1.0)
					researchBuff = 1.0;

				iBeakersBonus = (int)((float)iBeakersBonus * researchBuff);
			}
			// end

EDIT:
If you are happy with the code, I could upload the beta for V18 in case you or anyone wants to try it (just let me know), which includes all the AI updates and this change as well. I will be spending the weekend (if not longer) doing final testing on V18 before officially releasing it.

That looks good, in fact yours is a bit safer since you've avoided division by zero if one of the AI civs some how manages to produce 0 science beakers.

My current game as Spain with V17 may take the full weekend (perhaps slightly longer) to finish. (I'm one turn from entering the Industrial era)
 
I am interested in trying out your V18 beta for the weekend.

Also could you explain how and when the science buff is activated? I tried looking through your code but my basic C++ knowledge from university has failed me lolz
 
Thanks thelemon, v18beta attached. If you look at the code for V18, search for Glider1. You will find a function in CvPlayer::getBuffedYield.

There are now three ways that the AI can get a science buff:
1) Adaptive buff: It can get production, gold, science leaked to it on a per city basis every turn according to the formula:
iBuffedYield = (iTotalPlayerYield / iTotalPlayerPopulation) * iAICityPopulation.

Take a look at the forums for a deeper explanation. I've posted a lot about it already. It depends on whether the AI is falling behind the players yield.

2) Adaptive buff: In V18, AI's that sign research agreements with each other (not with the player) should get an increased bounty at the end of the agreement if they are lagging the player in science. (see the code in CvDealClasses in V18).

3) Passive buff: per-era modifiers similar to base game.

V18 so far:
  • You should notice that the AI is protecting its workers much better including city states during the opening game phase.
  • The AI is protecting its settlers better during the opening game phase, but there is still work to do.
  • The version is stable, but have not played it through in detail in the late game.
  • The AI should be more productive in the opening game phase because it won't loose workers as much and won't retreat them as much because they are guarded. The AI also doesn't need to build as many workers either.
  • The logic bug in V17 is gone that city states were also getting the adaptive buff, making it hard for conquerors to capture them. Now they don't get it any more and Monte is devouring them nicely.
  • If you play on immortal or higher, workers will finish improvements quicker.

TODO_list:
  • Fix the bug in the base game where the AI doesn't check for enemy units before landing its settlers from water.
  • Fix the bug in the base game where the AI can pull off a unit that is guarding a settler, just because it has decided to start a barbarian operation. (Scrub this bug because can't reproduce and the base code looks to check for it.)
  • Improve the code in the base game that decides when it is acceptable for settlers to venture out without being guarded (could be as simple as teaching settlers to avoid enemies yet still keeping their destination in mind
  • Teach AI more rules about when to stop guarding civilians.
 
Also could you explain how and when the science buff is activated? I tried looking through your code but my basic C++ knowledge from university has failed me lolz

It's mostly that Firaxis is doing something unusual for modern software running on modern machines. The methods _Times100 actually return 100 * the represented value and are either integers or longs. Think of it as using an int or long for money amounts but having the amounts representing pennies.
(Avoiding doubles was much more popular twenty years ago before it became standard for all machines to have a math coprocessor. Money isn't involved so there's no need to worry about binary doubles not being exact.)
 
Just a bit of info on V18 beta. With the new code, I haven't yet built and tested the code that tells the AI when to specifically stop guarding workers. At the moment it will guard them until it reaches four cities when it relaxes the guarding. I have to teach the AI when it should stop guarding a worker and release that unit to fight on the frontline. It should be pretty easy, because it depends on threat level and war state and that is easy to find out.

EDIT:
I really need V18 save games for the situation when an AI settler disembarks onto land right in the fire of an enemy or barbarian. That should be easy to fix if I have a save game of it. Please upload if you ever take sight of the situation. If all goes well I should in the near future be able to upload the next V18 beta with the new code, that will be save game compatible with previous V18.
 
Just to say i've been loving this mod. The improvement's are great and I've had fun trying new openings and strategies. I have also been playing with time victory only for a while because the AI does seem to be better at doing that. I saw you mentioned earlier that you had a score victory mod that better balances the scoring and gave points for completing the science victories and others. Is this still in beta?
 
Back
Top Bottom