AIs and the Art of War

Code:
if (AI_group(UNITAI_SETTLE, 3, -1, -1, false, false, false, 1, true))
The 3 in the second parameter is the indication of the maximum number of units in the group that it will allow the unit to join with (including itself.) So by changing it to 3 it allows the settler group to take two additional defensive units from city defense AI.

I still don't see why this should be a issue because settlers use the ContractBroker to get units as escort. I don't see that line of code anywhere in this piece of code:confused:.

The issues i noticed are that sometimes they start moving without any escort and the escort might be to weak. The answers must be in CvUnitAI::AI_settleMove.
 
True the contract broker can handle that. This would allow some idle or already existing defenders to jump in before the contract is fulfilled and perhaps speed up the process for the AI which would then leave the contracted unit to fill in for the units that left with the settler (presuming it at least tries to get those units to the plot it was contracted to immediately go to before realizing that the contract is no longer needing fulfilled. I'm not sure if it would do that or not.)

You're right though that CvUnitAI::AI_settleMove would ultimately have the control that determines when they believe themselves ready to depart. So that function warrants some closer examination to determine where this is taking place.
 
NVM, I found this line and thought it had something to do with it and it doesn't... this is just for settler units that are on the way already.
Code:
if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pMissionPlot, MISSIONAI_GUARD_CITY) > 0)

I'm still looking for why a settler would charge off without any aid. It looks like it can do it if the game option Aggressive AI is in use.
Code:
if (!GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_PEACE) &&
			!GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) &&
			(!getGroup()->canDefend() || getGroup()->getStrength() < 2*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE)))

Everything I've pieced together about this portion of the settler ai process suggests that this line determines when the contracts are called to have city defenders come to assist. I'm wondering about how necessary the canDefend call is.

But all in all, this really should enable the settler to have what they need before departing. The more I study the code the more it looks right to get units generated and sent to the settler before it goes on its merry way.

However... Eureka! I think I've found the problem:
Code:
				if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )
				{
					//	For now advertise the work as being here since we'll be holding position
					//	while we wait for a defender.  It would be more optimal to 'meet' the defender
					//	on the way or at the target plot, but this might leave us exposed on the way so
					//	the calculations involved are somewhat harder and not attempted for now
					if( gUnitLogLevel >= 3 )
					{
						logBBAI("    Settler for player %d (%S) at (%d,%d) requesting defensive escort\n",
								getOwner(),
								GET_PLAYER(getOwner()).getCivilizationDescription(0),
								plot()->getX_INLINE(),
								plot()->getY_INLINE());
					}

					GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(HIGH_PRIORITY_ESCORT_PRIORITY, DEFENSIVE_UNITCAPABILITIES, plot()->getX_INLINE(), plot()->getY_INLINE(), this, UNITAI_CITY_DEFENSE, 2*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE));

					m_contractsLastEstablishedTurn = GC.getGameINLINE().getGameTurn();
					m_contractualState = CONTRACTUAL_STATE_AWAITING_ANSWER;

					return;
				}
return without setting the unit to skip may be the problem here. returning it continues to process and finding that it's found no solution it may well try to update turn again. By doing so it runs through here once more and this time it catches 'if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )' and misses the return, moving on to going ahead and setting off to settle later in the code.

To correct this I'm thinking all we need to do is add getGroup()->pushMission(MISSION_SKIP); just before the return command. Mind... this is a theory and its possible I'm still overlooking something intended to catch the unit here such as setting the contractual state perhaps being established as being cause to skip later when it hits the unit update but without going that far into analysis this seems to be a solution (and may be better for processing either way.)



Another issue here is that we really need to figure out how to get a pack(singular and ungrouped) of city defenders to shadow along with attack forces so that when cities are captured they can immediately do their defensive thing. I've got some concepts on how to get this done but getting them built for this purpose and working with the contract broker is still a little mysterious here, something I need to sort out better.
 
However... Eureka! I think I've found the problem:
Code:
				if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )
				{
					//	For now advertise the work as being here since we'll be holding position
					//	while we wait for a defender.  It would be more optimal to 'meet' the defender
					//	on the way or at the target plot, but this might leave us exposed on the way so
					//	the calculations involved are somewhat harder and not attempted for now
					if( gUnitLogLevel >= 3 )
					{
						logBBAI("    Settler for player %d (%S) at (%d,%d) requesting defensive escort\n",
								getOwner(),
								GET_PLAYER(getOwner()).getCivilizationDescription(0),
								plot()->getX_INLINE(),
								plot()->getY_INLINE());
					}

					GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(HIGH_PRIORITY_ESCORT_PRIORITY, DEFENSIVE_UNITCAPABILITIES, plot()->getX_INLINE(), plot()->getY_INLINE(), this, UNITAI_CITY_DEFENSE, 2*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE));

					m_contractsLastEstablishedTurn = GC.getGameINLINE().getGameTurn();
					m_contractualState = CONTRACTUAL_STATE_AWAITING_ANSWER;

					return;
				}
return without setting the unit to skip may be the problem here. returning it continues to process and finding that it's found no solution it may well try to update turn again. By doing so it runs through here once more and this time it catches 'if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )' and misses the return, moving on to going ahead and setting off to settle later in the code.

To correct this I'm thinking all we need to do is add getGroup()->pushMission(MISSION_SKIP); just before the return command. Mind... this is a theory and its possible I'm still overlooking something intended to catch the unit here such as setting the contractual state perhaps being established as being cause to skip later when it hits the unit update but without going that far into analysis this seems to be a solution (and may be better for processing either way.)

No that part is correct there is no need to Skip there, even in case it updates again in the same turn and reaches 'if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )'. This is correct because the settler already called out for units in that turn and waits for them'CONTRACTUAL_STATE_AWAITING_ANSWER' so there is no need to advertiseWork again.

The only code to move out is this
Code:
				else
				{
					CvPlot* pMissionPlot = getGroup()->AI_getMissionAIPlot();
					if (pMissionPlot == pCitySitePlot && getGroup()->AI_getMissionAIType() == MISSIONAI_FOUND)
					{
						// safety check. (cf. conditions in AI_found)
						[B][COLOR="Red"]if (getGroup()->canDefend() && getGroup()->getStrength() > 4*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE))[/COLOR][/B]
						{
							if( gUnitLogLevel >= 2 )
							{
								logBBAI("    Settler continuing mission to %d, %d", pCitySitePlot->getX_INLINE(), pCitySitePlot->getY_INLINE());
							}
							CvPlot* pEndTurnPlot = getPathEndTurnPlot();
							getGroup()->pushMission(MISSION_MOVE_TO, pEndTurnPlot->getX(), pEndTurnPlot->getY(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pCitySitePlot);
							return;
						}
					}
				}

I changed the marked line because the old code
Code:
if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pMissionPlot, MISSIONAI_GUARD_CITY) > 0)
always let them leave with only one escort.


In a test game for whatever reason i saw one settler with only one unit as escort. This should not be possible unless that unit is four times stronger as the best available UNITAI_CITY_DEFENSE unit. Maybe the reason was that this settler founded a city in a area without any danger:confused:. Or maybe the other units had been killed before.

But it is a improvement to the current svn so i might put my changes to CvUnitAI::AI_settleMove in the svn after another test.

Edit:
Code:
			// Afforess: removed, unneeded, causes settlers to get stuck in cities.
			//if (AI_retreatToCity())
			//{
			//	return;
			//}
There was a reason for this AI_retreatToCity() call. Afforess commented it out because he thought it made them stuck in cities but he missed that they where just waiting for their escort.
 
I wondered about that last call.

Ok, but if it should be waiting in CONTRACTUAL_STATE_AWAITING_ANSWER, then what keeps it from hitting:
Code:
		if (iAreaBestFoundValue > 0)
		{
			if (AI_found())
			{
				return;
			}
		}
or is the command to wait if the contractual state is to do so given in AI_found()? (I haven't looked that far.)

I wondered about that line you adjusted in red - I don't think its a bad change but doesn't:

if (pMissionPlot == pCitySitePlot && getGroup()->AI_getMissionAIType() == MISSIONAI_FOUND)

only allow a settler that's already determined where it's heading to plant a city to reach that line in red you edited?
 
I was wondering about the AI transporting settlers to other continents. Is that still possible if a settler has 3 units as escort.
 
I was wondering about the AI transporting settlers to other continents. Is that still possible if a settler has 3 units as escort.

Good question. Something to research. Setting the number to 3 I believe includes the settler himself in those above examples but again I should look more closely before making that claim with surety.

Another few questions I would have for you: If you set them to want 4*the strength of the strongest defender before departing then should we not also increase the maxgroup on the willingness to join the group for the city defender AIs? This would mean 4 defenders right?

What if the BEST defender (strengthwise) isn't chosen to group with them? Then ONLY the brokerage method can get a 5th escort out to them and only the brokerage fulfillment, which is not terribly high on the city defense AI's agenda (perhaps that should be set higher but there could be cause not to do that too) can command the defender to join the group - this could leave the settler waiting for much longer than it should have to.

It appears to me that it may be best to just use a group count of 2 defenders and not worry overly much about the strength - we would just need to make sure that the units for city defense are kept to military ones in the unit xmls.


EDIT: Also... taking a look at AI_found it appears that the line you changed above:
Code:
if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_GUARD_CITY) > 0)
also appears there as a second control check before sending the unit on its initial mission assignment to go found the city at a particular chosen site. Should at least be changed in the same manner such as you did here:
Code:
if (getGroup()->canDefend() && getGroup()->getStrength() > 4*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE))
And of course I'm suggesting instead of 4*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE) we use "getGroup()->countNumUnitAIType(UNITAI_CITY_DEFENSE) >= 2" for reasons noted above (if we want more than 2 then I suggest the next 1 or 2 be City Counter units as well.)
 
Ok, so I'm making some adjustments here that you'll probably need to review with a compare on the Unit AI file but it's easier than showing them all here - there's quite a few.

I looked over the naval AI and it operates on different principles. I don't THINK there will be a problem there but I can't be sure. There's a check here:
Code:
bool CvUnitAI::AI_allowGroup(const CvUnit* pUnit, UnitAITypes eUnitAI) const
{
	CvSelectionGroup* pGroup = pUnit->getGroup();
	CvPlot* pPlot = pUnit->plot();

	if (pUnit == this)
	{
		return false;
	}

	if (!pUnit->isGroupHead())
	{
		return false;
	}

	//	Don't join a unit that was itself wondering what to do this turn
	if ( (static_cast<const CvUnitAI*>(pUnit))->m_contractsLastEstablishedTurn == GC.getGameINLINE().getGameTurn() &&
		 (m_contractualState == CONTRACTUAL_STATE_AWAITING_WORK || m_contractualState == CONTRACTUAL_STATE_NO_WORK_FOUND))
	{
		return false;
	}

	if (pGroup == getGroup())
	{
		return false;
	}

	if (pUnit->isCargo())
	{
		return false;
	}

	if (pUnit->AI_getUnitAIType() != eUnitAI)
	{
		return false;
	}

	switch (pGroup->AI_getMissionAIType())
	{
	case MISSIONAI_GUARD_CITY:
		// do not join groups that are guarding cities
		// intentional fallthrough
	case MISSIONAI_LOAD_SETTLER:
	case MISSIONAI_LOAD_ASSAULT:
	case MISSIONAI_LOAD_SPECIAL:
		// do not join groups that are loading into transports (we might not fit and get stuck in loop forever)
		return false;
		break;
	default:
		break;
	}
That keeps units from merging with a unit planning to load onto a transport. This MAY be blocking things from moving past the brokerage check since it may be that this Allow Group check could be stopping units from joining with the settler - however I don't think so because I don't think the settler has determined yet that it's going to load. At the time it does it just goes ahead and does so with the whole group if it can. Might stuff it up on the other side of the waves if it can't get all the units onto the settle group and it isn't dropped off directly at the founding site. Getting into super-complex land here.

There's also a reason that this was disallowed here at some point and we may be breaching that with the way the settler AI is setup currently. I don't know - it's a tough puzzle to sort out.
 
How is the best defender choosen (easy explaination please :mischief:)?
Because in the very early game, basically all you have to be afraid of are animals and here and there a neaderthal.

Usually my city protection stack for a settler are an Axeman and a Hunter, while the hunter will go back to my next Tribe once the city is founded. Once you reached Sed. Lifestlye and can begin to found multiple cities at a time, Archers can deal with animals pretty good. Also, on a more crowded map you need bigger stacks now. But they don't have to stay in your cities too long, since city defenses are very OP during this period (walls n stuff). So you can have a bigger, mobile stack and a very small stay-in-the-new-city stack.

This may help speeding up city founding in the early game, but I assume it would be... "interesting" to code :sad:
 
How is the best defender choosen (easy explaination please :mischief:)?
Because in the very early game, basically all you have to be afraid of are animals and here and there a neaderthal.
By strength of available potential defenders mostly.

You're right about the rest except without getting into the details of how to build the settler stack in and outside of war and dependent on the era and so on, generically it's important for the settler to have a very strong chance of survival in any situation. Won't take tooo long for them to make sure of this with a little more strength sent along with the settler. I do this as a player already. And having the majority of what you'd use to defend the city once you get there is also very handy because it cuts down on singular units in travel to bolster the defenses being subject to being picked off by strike teams.
 
The barbarian player must use a different mechanism for new cities as they don't seem to send out settlers. Cities just appear. The problem is that they then request units from other barbarian cities giving me plenty of time to capture the undefended city and sometimes get myself a captive. This becomes the main way I get settlers at one point as it happens so often that I have a constant stream of them heading back to my capital for outfitting as settlers.
 
It's possible they may use some differing routines. At this point, all cities, even barb ones, should be better protected as city defense ai units shouldn't leave the city at the request of other units unless the minimum protections are still in place (unless there's something about the brokerage mechanism I'm missing here.)
 
Ok, so I'm making some adjustments here that you'll probably need to review with a compare on the Unit AI file but it's easier than showing them all here - there's quite a few.

There is no need to rush things here! That code hasn't been changed in years and nobody really cared about it since then. So a few more days or weeks don't matter and i think putting untested changes into the svn is not the right way. Those AI changes must be tested in a few new games to really see their impact.
 
I needed to share the changes - they seemed to be working fine with the one potential concern being some holdup in the system. I would've used a branch commit but I can't seem to wrap my head around how exactly to do that.

Looking into this further, it appears that there are some disagreements in the city's choose production code with these adjustments so I'm attempting some solutions there. It's also, apparently, a bad idea to have City Counter use the mincitydefense command... That's ONLY for city defender AIs.

I may have this working better now - continuing testing.
 
Yeah... not yet. I seem to be finding some trouble with the contract broker not finding a valid defensive unit - city defense. I'm not sure how that can happen here. I'm wondering though, since I'm stepping out - if a unit doesn't have the AI set as their primary AI and only in the list of unit AIs it can be, does it qualify to be selected for building in

UnitTypes CvCityAI::AI_bestUnitAI(UnitAITypes eUnitAI, int& iBestValue, bool bAsync, bool bNoRand, CvUnitSelectionCriteria* criteria)

?

AND there's a slowdown I see.

So I'm just tinkering around here trying desperately to figure out how commands are designed to work and why I'm tripping them up. By all means if you correct things I just need to know how and why. The goal is not just to correct this portion of the code... it's to earn some understanding that gives me more control so I can develop other factors and AIs such as for the healers. So if you see something I'm not understanding, by all means please explain!
 
Yeah... not yet. I seem to be finding some trouble with the contract broker not finding a valid defensive unit - city defense. I'm not sure how that can happen here. I'm wondering though, since I'm stepping out - if a unit doesn't have the AI set as their primary AI and only in the list of unit AIs it can be, does it qualify to be selected for building in

UnitTypes CvCityAI::AI_bestUnitAI(UnitAITypes eUnitAI, int& iBestValue, bool bAsync, bool bNoRand, CvUnitSelectionCriteria* criteria)

?

AND there's a slowdown I see.

So I'm just tinkering around here trying desperately to figure out how commands are designed to work and why I'm tripping them up. By all means if you correct things I just need to know how and why. The goal is not just to correct this portion of the code... it's to earn some understanding that gives me more control so I can develop other factors and AIs such as for the healers. So if you see something I'm not understanding, by all means please explain!

Things are going very slow here but i'am still looking into it and i'am not finding answers. For some reason since i updated my svn two days ago there is something wrong with the settlers:confused: before it just worked no matter what i changed:crazyeye::confused::(. The AI takes much to long to expand we had this problem before and something in your recent changes brought it back.
 
Ok, I've reverted some things, kept a few other adjustments, and mostly went to use your method of counting the best defender strength. Seems to work better.

The problem is a little confusing but from what I can tell, it might be possible that in the early eras some AIs aren't finding any specific city defender AI types. (Which is very strange imo but I haven't thoroughly checked the XML to see if this is likely to be possible.) There's other ways it can fill in the details with your method so it may be best to use the call you've utilized there (for now at least.)

The changes I kept mostly amounted to getting the AI to consider it important to have more city defenders and having a stronger minimum amount of them remaining stationary within the city so they can make the most of fortification bonuses.

Yeah, not the most intuitive systems to work with here are they?

Anyhow, I'm doing some further testing to confirm that the problems with my latest adjustments have been repaired. So in a bit here I'll recommit to help those who are playing with the SVN version.

I'm not sure what was causing the slowdown but an attempt to debug a non-issue I didn't realize was a non-issue MAY have had something to do with that.

One thing I wonder though... I was wondering if it was a bad thing to have two potential brokerage calls like I had in the settle AI... maybe that was causing some serious trouble? I dunno...


EDIT: Testing is showing that they are still only taking one unit with them with the 2*strength of best city defender.

This tells me that they MAY not have a city defender in the evaluation because 2*0 would = 0 and perhaps only the canDefend() check is working at all.
 
Is it possible that the expansion of the AI is more crippled by costs then settler and unit production?
Especially in the early game, maintenance grows pretty fast. But then is it possible to build enough :gold: buildings quickly enough to overcompensate that, so founding new cities so they can start developing earlier is the best way here, even if this means <100% :science: or building wealth.

Similar issue with :mad: from city limitations. Does the AI overexpand over their current civis limit?
 
Is it possible that the expansion of the AI is more crippled by costs then settler and unit production?
Especially in the early game, maintenance grows pretty fast. But then is it possible to build enough :gold: buildings quickly enough to overcompensate that, so founding new cities so they can start developing earlier is the best way here, even if this means <100% :science: or building wealth.

Similar issue with :mad: from city limitations. Does the AI overexpand over their current civis limit?

Possible at some points in the game yes. There's numerous places where there are check points considered, including those you mention. At the point I'm looking right now it's getting cleared up but not necessarily in the best manner.
 
Back
Top Bottom