Naval AI Breakdown

Thunderbrd

C2C War Dog
Joined
Jan 2, 2010
Messages
29,801
Location
Las Vegas
I'm currently working on trying to gain a full understanding of the Naval AI structure of C2C as a whole.

This is a project along the path of the Naval Rework Project. I'm at first here just trying to get a full picture of what AIs to set our naval units to. I know there's a few new 'roles' being thrown in as well so I'm also looking to see if a new AI setting or two is necessary and how to set them up properly if needbe. In particular, the Corvettes, Cutters, Merchant Ships and Troop Transport units may require some new AIs and/or adjustments to existing AIs.

Along the way I think there may also be other edits we might wish to make to the Naval AI structures. We have some strategic matters that aren't currently being addressed... Surround and Destroy, ZoCs etc...

There are a number of issues I want to investigate here. This was really sparked off because I don't really the way the XML is supposed to work. We have, for example, the Torpedo Boat with the following XML settings:
Steam Industrial DefaultUnitAI UnitAIs NotUnitAIs
x62-x65 centers on x64
Torpedo Boat UNITAI_RESERVE_SEA UNITAI_PIRATE_SEA UNITAI_ESCORT_SEA
UNITAI_SPY_SEA UNITAI_RESERVE_SEA
UNITAI_ASSAULT_SEA UNITAI_ATTACK_SEA
UNITAI_EXPLORE_SEA

I asked Koshling about this and he expressed that it's probably a bug that the primary AI of UNITAI_RESERVE_SEA is also a NotAI setting as well... but also said a lot of these XML settings were somewhat mysterious to him as well. He said, in fact:
Koshling said:
This is no an area I ever well understood I'm afraid. I think having a unit AI and a not-unit AI of the same value is a bug really, and in that case the not will essentially be ignored - I cannot see why you'd WANT this situation at least.

UnitAIs have two functions:

1) A unitAI type determines which AI is applied to stacks lead by that unit (note - only the stack leader has any impact on how a stack behaves)
2) When choosing the unit to lead a stack it is done based on the unitAIs involved. For this reason you have to b slightly careful about what you allow to stack together, as the 'losing' unitAI will be totally subservient to the winning one (thus settlers command their stacks, so if you lt one get into a military attack stack it will lose all will to perform attack functions).

When a city chooses a unit to build (or put out a tender for), it is (usually) specified by requesting a unit of a particular AI type (i.e. - AI types map to 'purposes')

Changing a unit's AI type is one of those here-be-dragons areas

So I felt I should really begin to investigate the full picture of the Naval AI here.


Although I want to make sure that I understand the 3 differing AI tags, their usage, and how they affect the unit's choices, I figured I'd start by attempting to breakdown exactly what a given AI setting is told to do.

To help some of you who are less code based understand, Groups are commanded by one AI setting at a time, the AI setting of its lead unit. When a Group's turn comes up and it doesn't have an assigned activity it's in the process of fulfilling already (if it does it'll continue to perform that activity) then it will run through a series of checks based on its unit AI setting.

So I figured I'd start with the first naval AI on the list, which for the list I'm going off of here is UNITAI_RESERVE_SEA. I'm simply evaluating the code and trying to put its process into as plain English as possible.

I'll be posting these one at a time and I'm inviting those who can read the code to point out where I may be wrong or may be overlooking details. I'm not breaking down all the functions that are called within the functions of evaluation in their entirety - just trying to summarize what lies down those roads as best as possible without a complete breakdown of every step of processing there. Some of those function calls are scanned rather than read in their entirety so I may well be a little wrong about some presumptions here and that's one of the motivators to post these breakdowns here.

The other motivation is to highlight problems, overlooked points at which to enact other strategies, and offer the entire community the opportunity to review the AI processes and add commentary and feedback since this affects all our games. An advanced player can review these breakdowns to spot potential weaknesses in the AI's approach to naval decisionmaking and if big weaknesses are found, it's appreciated if it's pointed out.

But in particular, this is a huge invitation to the other coders among us to input their thoughts on edits that should be made and their insights as to why the structure has been designed as it is.

I'll try to keep these 'English translations' as updated as possible as changes are made.

The next steps, after fully evaluating the AI processes for each AI will be to gain a full understanding for how units are chosen to be built, how they gain their initial AI settings, and then how to best assign (or create and then assign) AIs to our naval units.

So I'll make my next post here the English breakdown for the UNITAI_RESERVE_SEA setting.
 
UNITAI_RESERVE_SEA
The pure code:
Code:
void CvUnitAI::AI_reserveSeaMove()
{
	PROFILE_FUNC();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						06/14/09	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4  || iOurDefense == 0)  //prioritize getting outta there
		{
			if (AI_anyAttack(2, 60))
			{
				return;
			}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
			//if (AI_protect(40))
			if (AI_protect(40, 3))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			{
				return;
			}

			if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 4))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (AI_guardBonus(30))
	{
		return;
	}

	if (AI_heal(30, 1))
	{
		return;
	}

	if (AI_anyAttack(1, 55))
	{
		return;
	}
	
	if (AI_seaBombardRange(6))
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	//if (AI_protect(40))
	if (AI_protect(40, 5))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/03/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
	if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true))
	{
		return;
	}

	if (AI_group(UNITAI_RESERVE_SEA, 1))
	{
		return;
	}
	
	if (bombardRate() > 0)
	{
		if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true))
		{
			return;
		}
	}
*/
	// Shadow any nearby settler sea transport out at sea
	if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 5))
	{
		return;
	}
	
	if (AI_group(UNITAI_RESERVE_SEA, 1, -1, -1, false, false, false, 8))
	{
		return;
	}
	
	if (getGroup()->hasBombardCapability())
	{
		if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true, false, 8))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/	

	if (AI_heal(50, 3))
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	if (AI_protect(40))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_anyAttack(3, 45))
	{
		return;
	}

	if (AI_heal())
	{
		return;
	}

	if (!isNeverInvisible())
	{
		if (AI_anyAttack(5, 35))
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/03/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                      */
/************************************************************************************************/
	// Shadow settler transport with cargo 
	if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true, false, 10))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_travelToUpgradeCity())
	{
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}
English Translation:

AI Reserve Sea:

  • If our current Plot is a city(or fort but doesn't matter if its ours or not):
    • iOurDefense = the total strength of all our units on this plot
    • iEnemyOffense = total strength of all enemy units within 2 plots

    • if we're damaged at all(interesting it's only asking the stack leader here and not the rest of the stack right?):
      • iOurDefense is doubled. (Make the unit much more reluctant to attack so that it may take a break to heal if its not absolutely necessary)

    • if iEnemyOffense is greater than iOurDefense divided by 4 (We'll attack or move on if it's really showing that it's important to weaken the enemy with this unit that cannot defend the city anyhow or the city is in danger of being taken) OR iOurDefense is equal to zero (If the city is defenseless you pretty much have nothing to lose anyhow - get out of there!):
      • if AI_anyAttack (AI_anyAttack(2, 60))(if the unit may attack an enemy(in a variety of ways - return to break down further)) at a range of 2 with an odds of 60 or better
        • Then do so and we're done.

      • Otherwise (AI_protect(40, 3)) if a unit we can see is threatening to raze a plot within 3 turns from our current location that we have at least a 40% odds against, go to that plot. (seems a little late if it's going to take 3 rounds to get there doesn't it?) This uses AI_protect which could use some more evaluation to make absolutely sure this is what it means.
        • Then do so and we're done.

      • Otherwise (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 4)) Go and shadow (estalbish yourself as an escort) a nearby (within 4 rnds away) unit set to a sea settler AI that has no greater than 2 other units already shadowing whether it has cargo or not but it must be outside the city.
        • If we can then do so and we're done.

      • Otherwise (AI_retreatToCity()) Escape to nearby somewhat safe city with checks to make sure its fairly safe to get there as well.
        • If we can do so then do it and we're done. There's some funny stuff here though, like possibly just skipping the turn (when perhaps it's not wise for them to do so as this has been called to get the ship out of there!)

      • Otherwise (AI_safety()) Get to a 'safe' plot.
        • If we can do so then do it and we're done.(Apparently at this point either it's assumed that the ship will have made use of itself in its tenuous position in the city that may be about to be captured or it can't so it stays put - however, it may just apply to anything else further down the line here as well so this might be interesting for those. Also, I wonder if they ever hit this particular check here since the previous one seems to account in some way for most situations to include passing its action at some points.)

  • Otherwise (AI_guardBonus(30)) Go sit on and protect our naval resources, particularly if they have a lot of value - if they don't care enough based on this value threshold which is difficult to enumerate simplistically, they won't bother.
    • If we can do so go to it, assign that as our mission, and we're done.

  • Otherwise (AI_heal(30, 1)) I think this basically means heal if you've been damaged at least 30% or move to a better location (within 1 turn move I think) to heal at least if the location sucks to do so, then do so. It looks like there's some calls to just heal if in a good spot to do so regardless of the amount of damage. Note: most of the time a 'better location' is defined as a city.
    • If we can heal under noted parameters do so.

  • Otherwise (AI_anyAttack(1, 55)) Attack any enemy within a space away that has a 55% chance of success or better (this can also instead lead to ranged assaults and such.)
    • If we can do so, attack and we're good.

  • Otherwise (AI_seaBombardRange(6)) If there's an enemy city within 6 spaces away, go bombard (reduce it's defenses) (and it looks like plundering may be included as well as Ranged Assault and even blockading) it if we can. Also, if we're at the best plot from which to bombard the city we'll skip if we can't do any of the above.
    • Looks like it's only if such a city isn't within 6 spaces away that we'll proceed at all past this point...

  • Otherwise (AI_protect(40, 5)) noted above but not terribly well mapped out I think. Range of 5 moves this time.
    • If we can do this we're done.

  • Otherwise (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 5)) Slightly longer (5 over 4) range over the above.
    • If we can do this we're done.

  • Otherwise (AI_group(UNITAI_RESERVE_SEA, 1, -1, -1, false, false, false, 8)) Join up to one other Reserve AI within 8 rounds away and follow them. (I think... this is very complex)
    • If we can do this we're done. I suspect I may need to do a full breakdown on this function as it may have the NotAI in use there.

  • Otherwise (getGroup()->hasBombardCapability()) if this group may bombard then
    • If (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true, false, 8)) Accompany a Sea Assault stack that doesn't already have 2 or more shadows as long as the assault force has loaded units. Doesn't have to be out of a city but must be within 8 turns away of movement.
      • If we can, do this to back up a city assault with the ability to bombard.

  • Otherwise (AI_heal(50, 3)) If damaged by 50% or more then heal but get to a safe place to do so within 3 moves away first.
    • If we can do this we're done.

  • Otherwise (AI_protect(40)) looks like no limit to movement to go to protect as long as we have a 50% odds against the incoming threat.
    • If we can do this we're done.

  • Otherwise (AI_anyAttack(3, 45)) If there's an enemy within 3 spaces and we have at least a 45% chance of victory, attack it.
    • If we can do this we're done.

  • Otherwise (AI_heal()) Heal immediately if needbe - I think this means go to the best place to do so first.
    • If we can do this we're done.

  • Otherwise if (!isNeverInvisible()) if the unit has any form of invisibility then:
    • If (AI_anyAttack(5, 35)) If there's an enemy within 5 spaces and we have at least a 35% chance of victory, attack it.
      • If we can do this we're done.

  • Otherwise if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true, false, 10)) Shadow any sea settler with cargo within 10 rounds away
    • If we can do this we're done.

  • Otherwise (AI_travelToUpgradeCity()) If we can upgrade and need to get to a city to do it then get there and upgrade - Note: some units can upgrade outside of a city so I'm not sure why they don't check this possibility first.
    • If we can do this we're done.

  • Otherwise (AI_patrol()) Amble around - if we find a goody get it. We won't go past this point if there's anywhere we can move to basically. I don't think this is really about exploring as much as just moving about where we've explored.
    • If we can do this we're done.

  • Otherwise (AI_retreatToCity()) get to the nearest city
    • If we can do this we're done.

  • Otherwise (AI_safety()) get somewhere as safe as possible.
    • If we can do this we're done.

  • Otherwise, Skip move.


In summary, UNITAI_RESERVE_SEA is a setting for supporting combat ships in general, both for accompanying invasions and settlers and responding to threats offshore. In many cases they will maintain their AI setting, simply shadowing other efforts which then takes them where the action is forming around those efforts. During war, if they miss joining these efforts (and there are limits to how many will be able to join each), and if the enemy shores are too distant, they'll generally be hanging around friendly shores to protect.

Some simple tweaking of this would be very useful for a Coast Guard AI setting I think. Cutters are intended to have no other use than to protect your shores and Corvettes, while useful to accompany other efforts to offer a strong and cheap support for other units in enemy coastal waters, may desire a slightly differing setting as well though for now would be probably mostly appropriately set to this Reserve setting.

Currently, the ships (from steam powered and more advanced) that have this as their primary setting are:
Torpedo Boat
Ironclad
Nautilus
Pre-Dreadnought
Qship
Steel Cruiser
Destroyer
Coast Guard Cutter
Dreadnought
Submarine
Cruiser
Attack Destroyer
Escort Frigate
Heavy Cruiser
Attack Submarine
Littoral Combat Ship
Nuclear Submarine
Stealth Submarine
AEGIS Cruiser
Stealth Destroyer
Unmanned Destroyer
Unmanned Submarine
Shockwave Cruiser
Shockwave Submarine

(Note many of these are not recognized because I'm using the new names they should have after the naval review is applied rather than the ones they may currently have.)

And the following have the Reserve AI setting as one of it's 'multiple tag AI settings':
Iron Frigate
Ironclad
Nautilus
Pre-Dreadnought
Qship
Steel Cruiser
Destroyer
Battlecruiser
Coast Guard Cutter
Dreadnought
Submarine
Battleship
Cruiser
Attack Destroyer
Escort Frigate
Heavy Cruiser
Heavy Battleship
Attack Submarine
Nuclear Submarine
Missile Cruiser
Littoral Combat Ship
Stealth Destroyer
AEGIS Cruiser
Stealth Submarine
Unmanned Submarine
Unmanned Destroyer
Shockwave Destroyer
Shockwave Cruiser
Shockwave Battleship
Shockwave Submarine

KEY:
Is listed as both its single AI setting AND in its list of AIs.
HAS in its multiple list of AIs BUT is NOT its single AI setting
DOES NOT HAVE in its multiple list of AIs (Actually... looks like all that have the setting as it's single AI setting also have it as one of it's many AIs list.)
Listed in both single AI setting and NotAI list

Is Listed as a NOTAI:
Uboat
Somali Pirate
Unmanned Pirate Skiff


So it looks like Cruisers, Destroyers and Subs should be set with this as the primary and as part of it's 'list of AIs'. For those it appears most of the AI path of decision-making does make sense here. Until further work is done, I'm thinking Corvettes would probably fit fine with most of these choices. Not so sure that Cutters (Coast Guard) ships would be best under this though some minor editing on a new AI definition could produce a very good structure for them. I'm also thinking that to help define Destroyer, Cruiser, and Sub definitions a little better and to support larger naval fleet volumes by the AI when needed, some cloning and tweaking of these could be useful.

Then again, this multi-list AI thing... I'm thinking that the main AI doesn't really matter any more? That when units are built, it picks from the best among those that CAN be that AI then assigns that AI to the new unit based on the intention under which it was built? Problem there is that there's a lot of 'sub-role' considerations to be made there. What kind of complex programming will I see to get the AI to build a variety of differing units rather than ALL one type for a particular AI role I wonder? Ugh...

Anyhow, the first post expressed what sort of commentary this thread seeks. Any thoughts by anyone so far?
 
The hardcoded attack success probabilities are a huge problem with that don't you think?

The replaceability of the two units has to figure surely. If your unit was just captured (ie. 0XP), and their unit is 9th level, then even 25% success odds for your attack would be well worth it. If the situation is reversed, you'd want more like 99% odds before you'd risk it. XP is the main consideration here, although heroes being totally irreplaceable are another type the AI - or anyone else - should not risk lightly.
 
The hardcoded attack success probabilities are a huge problem with that don't you think?

The replaceability of the two units has to figure surely. If your unit was just captured (ie. 0XP), and their unit is 9th level, then even 25% success odds for your attack would be well worth it. If the situation is reversed, you'd want more like 99% odds before you'd risk it. XP is the main consideration here, although heroes being totally irreplaceable are another type the AI - or anyone else - should not risk lightly.

I may be explaining that function call in an oversimplified manner... the function is pretty involved and could take a significant amount of analysis to break it down as well. Would be interesting to do because I was thinking the odds tolerance was pretty low and quite risky but then again if you've got backup that can also come in to finish the job it may not be inappropriate... so that's a factor that may not be under enough consideration as well.

In general I agree that the uniqueness and real value of the potential enemy, including if it's a rare opportunity to attack a normally stronger more valuable weakened and vulnerable unit should all be taken into consideration, as well as the overall value of protecting this particular unit or group. And once the attack is made, it doesn't appear to be giving any consideration for the potential position of vulnerability that the unit may be left in after making the attack.

I also see little to no planning to cross defend the Reserve AI stacks so that it may be as strong against any and all attackers as it can be. Thus it makes the ships easy to pick off by throwing the best types to take that unit down up against them. This really would be a very major problem after the units planned are implemented.

Also I'm thinking if those Reserve AIs that are shadowing other unit stacks should be told to surround enemies to offer support or simply increased odds for themselves when attacking.

There also appears to be a gap in supporting Carrier and Missile groups here.
 
UNITAI_ATTACK_SEA

The code:
Spoiler :
Code:
void CvUnitAI::AI_attackSeaMove()
{
	PROFILE_FUNC();
	MEMORY_TRACK();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						06/14/09	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		PROFILE("CvUnitAI::AI_attackSeaMove.City");

		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4  || iOurDefense == 0) //prioritize getting outta there
		{
			if (AI_anyAttack(2, 50))
			{
				return;
			}

			if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, false, true, 2))
			{
				return;
			}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
			//if (AI_protect(35))
			if (AI_protect(35, 3))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (AI_heal(30, 1))
	{
		return;
	}
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                            Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - sea bombard AI formally DCM 1.7 AI_RbombardCity()
	// Dale - RB: Field Bombard START
	//if (AI_RbombardCity())
	//{
	//	return;
	//}
	//if (AI_RbombardNaval())
	//{
	//	return;
	//}
	// Dale - RB: Field Bombard END

	// Dale - ARB: Archer Bombard START
	if (AI_Abombard())
	{
		return;
	}
	// Dale - ARB: Archer Bombard END
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                Glider1    */
/************************************************************************************************/

	{
		PROFILE("CvUnitAI::AI_attackSeaMove.BasicAttacks");

		if (AI_anyAttack(1, 35))
		{
			return;
		}

		if (AI_seaBombardRange(1))
		{
			return;
		}
		
		if (AI_anyAttack(2, 40))
		{
			return;
		}
		
		if (AI_goody(2))
		{
			return;
		}
		
		if (AI_seaBombardRange(6))
		{
			return;
		}
		
		if (AI_heal(50, 3))
		{
			return;
		}

		if (AI_heal())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/10/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	// BBAI TODO: Turn this into a function, have docked escort ships do it to

	//Fuyu: search for more attackers, and when enough are found, always try to break through
	CvCity* pCity = plot()->getPlotCity();

	if( pCity != NULL )
	{
		if( pCity->isBlockaded() )
		{
			PROFILE("CvUnitAI::AI_attackSeaMove.Blockaded");

			int iBlockadeRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE");
			// City under blockade
			// Attacker has low odds since anyAttack checks above passed, try to break if sufficient numbers

			int iAttackers = plot()->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
			int iBlockaders = GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), (iBlockadeRange + 1));
			//bool bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);

			if (true)
			{
				int iMaxRange = iBlockadeRange - 1;
				if( gUnitLog
				Level > 2 ) logBBAI("      Not enough attack fleet found in %S, searching for more in a %d-tile radius", pCity->getName().GetCString(), iMaxRange);

				for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
				{
					for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
					{
						CvPlot* pLoopPlot = plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), iDX, iDY);
							
						if (pLoopPlot != NULL && pLoopPlot->isWater())
						{
							if (pLoopPlot->getBlockadedCount(getTeam()) > 0)
							{
								iAttackers += pLoopPlot->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
							}
						}
					}
				}
			}
			//bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);

			//if (bBreakBlockade)
			if (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders)
			{
				if( gUnitLogLevel > 2 ) logBBAI("      Found %d attackers and %d blockaders, proceeding to break blockade", iAttackers, iBlockaders);
				if(true) /* (iAttackers > GC.getGameINLINE().getSorenRandNum(2*iBlockaders + 1, "AI - Break blockade")) */
				{
					// BBAI TODO: Make odds scale by # of blockaders vs number of attackers
					if (baseMoves() >= iBlockadeRange)
					{
						if (AI_anyAttack(1, 15))
						{
							return;
						}
					}
					else
					{
						//Fuyu: Even slow ships should attack
						//Assuming that every ship can reach a blockade with 2 moves
						if (AI_anyAttack(2, 15))
						{
							return;
						}
					}
					
					//If no mission was pushed yet and we have a lot of ships, try again with even lower odds
					if(iAttackers > 2*iBlockaders)
					{
						if (AI_anyAttack(1, 10))
						{
							return;
						}
					}
				}
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	
	if (AI_group(UNITAI_CARRIER_SEA, /*iMaxGroup*/ 4, 1, -1, true, false, false, /*iMaxPath*/ 5))
	{
		return;
	}
	
	if (AI_group(UNITAI_ATTACK_SEA, /*iMaxGroup*/ 1, -1, -1, true, false, false, /*iMaxPath*/ 3))
	{
		return;
	}
	
	if (!plot()->isOwned() || !isEnemy(plot()->getTeam()))
	{
		PROFILE("CvUnitAI::AI_attackSeaMove.Neutral");

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/11/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
		if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34))
		{
			return;
		}
		
		if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51))
		{
			return;
		}

		if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, -1, false, false, false))
		{
			return;
		}
	}
	
	if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false))
	{
		return;
	}
*/
		if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, true, false, 4))
		{
			return;
		}
		
		if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51, true, false, 5))
		{
			return;
		}

		// Group with large flotillas first
		if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, 3, false, false, false, 3, false, true, false))
		{
			return;
		}

		if (AI_group(UNITAI_ASSAULT_SEA, -1, 2, -1, false, false, false, 5, false, true, false))
		{
			return;
		}
	}
	
	if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false, 10))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	
	if (plot()->isOwned() && (isEnemy(plot()->getTeam())))
	{
		if (AI_blockade())
		{
			return;
		}
	}
	if (AI_pillageRange(4))
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	//if (AI_protect(35))
	if (AI_protect(35, 3))
	{
		return;
	}

	if (AI_protect(35, 8))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		return;
	}

		//TBEVAL
	if (AI_travelToUpgradeCity())
	{
		return;
	}

	if (AI_seaAreaAttack())
	{
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

Code:
AI_attackSeaMove()

If our current Plot is a city(or fort but doesn't matter if its ours or not):
	iOurDefense = the total strength of all our units on this plot
	iEnemyOffense = total strength of all enemy units within 2 plots
	
	if we're damaged at all(interesting it's only asking the stack leader here and not the rest of the stack right?):
		iOurDefense is doubled. (Make the unit much more reluctant to attack so that it may take a break to heal if its not absolutely necessary)
	
	if iEnemyOffense is greater than iOurDefense divided by 4 (We'll attack or move on if it's really showing that it's important to weaken the enemy with this unit that cannot defend the city anyhow or the city is in danger of being taken) OR  iOurDefense is equal to zero (If the city is defenseless you pretty much have nothing to lose anyhow - get out of there!):
		if (AI_anyAttack(2, 50))(if the unit may attack an enemy(in a variety of ways - return to break down further)) at a range of 2 with an odds of 60 or better
			Then do so and we're done.
			
		if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, false, true, 2)) Go and shadow (estalbish yourself as an escort) a nearby (within 2 rnds away) unit set to an attack by sea AI that has no greater than 4 other units already shadowing whether it has cargo or not but it must be outside the city.
			If we can then do so and we're done.
			
		if (AI_protect(35, 3)) If a unit we can see is threatening to raze a plot within 3 turns from our current location that we have at least a 35% odds against, go to that plot.  (seems a little late if it's going to take 3 rounds to get there doesn't it?)  This uses AI_protect which could use some more evaluation to make absolutely sure this is what it means.
			If we can do so then do it and we're done.
			
		if (AI_retreatToCity()) Escape to nearby somewhat safe city with checks to make sure its fairly safe to get there as well.
			If we can do so then do it and we're done.  There's some funny stuff here though, like possibly just skipping the turn (when perhaps it's not wise for them to do so as this has been called to get the ship out of there!)
			
		if (AI_safety()) Get to a 'safe' plot.
			If we can do so then do it and we're done.
	
if (AI_heal(30, 1)) Heal if you've been damaged at least 30% or move to a better location (within 1 turn move I think) to heal at least if the location sucks to do so, then do so.
	If we can do so then do it and we're done.
		
if (AI_Abombard()) If we can archer bombard with this unit and we're within range to do so against a valid target, do it.  (Does not seem to consider its plot for damaging terrain here...)  Archer Bombard should probably be officially obsoleted soon which would mean the removal of this line.
	If we can do so then do it and we're done.
		
if (AI_anyAttack(1, 35)) If there's a valid target for attack within a round away, go attack it if the odds are better than 35%.  There's alternative means to attack called by this method including Ranged Assault.
	If we can do so then do it and we're done.
		
if (AI_seaBombardRange(1)) If an enemy city is within 1 round's movement away and any form of bombardment, Ranged Assault, or Blockade would be effective against it, go there and blast away.
	If we can do so then do it and we're done.
		
if (AI_anyAttack(2, 40)) If there's a valid target for attack within 2 rounds away, go attack it if the odds are better than 40%.  There's alternative means to attack called by this method including Ranged Assault.
	If we can do so then do it and we're done.
	
if (AI_goody(2)) Basically if there's a goody within 2 rounds away go get it.
	If we can do so then do it and we're done.
	
if (AI_seaBombardRange(6)) If an enemy city is within 6 rounds movement away and any form of bombardment, Ranged Assault, or Blockade would be effective against it, go there and blast away.
	If we can do so then do it and we're done.
	
if (AI_heal(50, 3)) Heal if you're in a city and damaged at all, or if you've been damaged at least 50% - move first to a safe place to do so as long as getting there doesn't take more than 3 rounds.)
	If we can do so then do it and we're done.
	
if (AI_heal()) Do nothing but heal basically.
	If we can do so then do it and we're done.
	
Define the city that's on this plot as pCity.

If pCity isn't NULL (thus if it IS a city at all that we're in) then:
	if (pCity->isBlockaded()) If the city we're in has a blockade placed upon it by any unit then:
		iBlockadeRange is defined as a Global Variable: SHIP_BLOCKADE_RANGE (which is defined in GlobalDefines.xml as 3)
		iAttackers is defined as the number of our units with UNITAI_ATTACK_SEA that exist on this plot
		iBlockaders is defined as the number of enemy ships that can currently blockade this city (using iBlockadeRange+1 to define this range).
		
		iMaxRange is defined as iBlockadeRange -1
		(log statement is patently ignorable)
		
		Then we loop through all plots within iMaxRange, making sure plot is Valid and is a Water plot
			If the plot is blockaded against us then
				The count of our UNITAI_ATTACK_SEA units in each of those plots is added to iAttackers
		
		if iAttackers is greater than the number of blockaders plus 2 (iBlockaders + 2) OR iAttackers is greater than or equal to 2 times the number of blockaders (2 * iBlockaders) then: (Here we're making sure we're strong enough to pull this off really - given all the other attack it checks this one seems a bit over-engineered though there is a bit of a reason for that - it's going to be willing to lemming units if needbe - not that a 45% chance seen elsewhere isn't already somewhat of a lemming imho)
			if we can normally move as far as iBlockade Range
				if (AI_anyAttack(1, 15)) If we can reach an enemy ship within 1 round and have at least 15% odds, go do whatever we can to kill it, primarily meaning attack it.
				If we could do so we're done.
		Otherwise
			if (AI_anyAttack(2, 15)) Then after checking if we can reach a closer target, we'll look another round's movement out and attack those further out ships as long as our odds are at least 15%.
			If we could do so we're done.
			
		if iAttackers is greater than twice the number of blockaders then (if we've really got overwhelming numbers on our side)
			if (AI_anyAttack(1, 10)) If we can reach an enemy within 1 round and our odds are at least 10%, attack!
			If we could do so we're done.

if we can group ourselves with a Carrier group and there's no more than 4 Attack AI already in that group and the group is no farther than 5 rounds away, go join them and follow their commands.
	if we do this we're done.
	
if we can group ourselves with an Attack AI unit (no more than 1 in that group) and it's no further than 3 rounds away, go join it and follow that units commands.
	if we do this we're done.
	
if the plot we're on is not owned or it is not that of an enemy then
	if one of our Sea Assault groups with no more than 4 shadow groups is within 4 rounds away and does have loaded units whether in a city or not, go shadow that group to support it.
		if we do this we're done.
		
	if on of our Carrier groups with no more than 5 other shadowing groups is within 5 rounds away and does have loaded units whether in a city or not, go shadow that group to support it.
		if we do this we're done.
		
	if we can group ourselves with a Sea Assault group that doesn't have more than 4 Attack AI units in it already as long as it has loaded units and is within 3 rounds away then go there and group and follow the commands of that stack leader
		if we do this we're done.
		
	if we can group ourselves with a Sea Assault group that doesn't have more than 2 Attack AI units in it already as long as it has loaded units and is within 5 rounds away then go there and group and follow the commands of that stack leader
		if we do this we're done.
		
if we can group ourselves with a Carrier group that doesn't have more than 1 Attack AI within 10 rounds away then do it
	if we do this we're done.
	
if the plot we're on is an enemy plot then
	if we can blockade and its worthwhile to do so (the blockade function is rather complex) then lets go blockade
		if we do this we're done
	
if we can pillage an enemy (or in neutral waters) plot within 4 rounds away, go do that
	if we do this we're done
	
if (AI_protect(35, 3)) If a unit we can see is threatening to raze a plot within 3 turns from our current location that we have at least a 35% odds against, go to that plot.  (seems a little late if it's going to take 3 rounds to get there doesn't it?)  This uses AI_protect which could use some more evaluation to make absolutely sure this is what it means.
	If we can do so then do it and we're done.
	
if (AI_protect(35, 8)) If a unit we can see is threatening to raze a plot within 8 turns from our current location that we have at least a 35% odds against, go to that plot.  (seems a little late if it's going to take 3 rounds to get there doesn't it?)  This uses AI_protect which could use some more evaluation to make absolutely sure this is what it means.
	If we can do so then do it and we're done. Checking the closer needs first.

if (AI_travelToUpgradeCity()) If we need to upgrade do it and if that means getting to the nearest city that makes it possible to do so then do that
	If we can do so then do it and we're done.

if (AI_seaAreaAttack())  From what I can tell, scanning through this fairly complex function, it basically means - go anywhere the water touches here where there is trouble brewing
	If we can do so then do it and we're done.
	
if (AI_patrol()) Meander about
	If we can do so then do it and we're done.
	
if (AI_retreatToCity()) If all the above hasn't worked out, get to a city
	If we can do so then do it and we're done.
	
if (AI_safety()) If all of the above hasn't worked out, find the best defensible position
	If we can do so then do it and we're done.
	
if all that hasn't worked, just skip turn.


In summary, The Naval Attack AI starts off much the same as the Reserve AI but shows a great deal more focus on reckless hostility, then on joining in with other groups to bolster those efforts. The odds given here suggest a presumption that there is assumed to be collateral to be offered by these units though it may work well for Subs as well with their ability to weaken and hinder so that might be an interesting way to go for now.
There's obviously some major tweaking needed for C2C. This is all painfully insufficient. Too many ships would be operating on their own and leaving themselves terribly vulnerable as a result. There's simply too much taking place before grouping kicks in so only nations that have a very developed navy would have proper groups forming. Even small group sets can be far more effective at the kinds of independent operations these AI's have called for and cross protecting the stacks is very important, particularly for this and reserve AI type units.
The missions this type will do would be well supported by some Reserve units joining them simply to accompany to offer backup and protection. Small tweaks could achieve this pretty easily I think.

But as for THIS AI, it's primarily used for punching and going after whatever threats exist. It definitely is programmed to throw its weight around.
 
The hardcoded attack success probabilities are a huge problem with that don't you think?

The replaceability of the two units has to figure surely. If your unit was just captured (ie. 0XP), and their unit is 9th level, then even 25% success odds for your attack would be well worth it. If the situation is reversed, you'd want more like 99% odds before you'd risk it. XP is the main consideration here, although heroes being totally irreplaceable are another type the AI - or anyone else - should not risk lightly.

Base Civ IV does indeed have that issue, but I rewrote he odds evaluation a year or two ago to normalize it relative to unit value. Basically each unit has a value (more or less its base strength, adjusted upward by promotions) and the 'odds' in all the calls are re-interpretted as 'percent chance to destroy more enemy value than we would lose'. Thus if a capital ship with strength 40 has a 50% chance of wining against a lesser support ship (say strength 20) it would actually require the parameter set much lower than 50 for it to make the attack (because it has a 50% chance of destroying a 20 value enemy and a 50% chance of losing a 40 value uni of its own by doing so).

The effect of this change is to make the AI consider the actual expected loss/gain more accurately. It applies to all AI combat (land, sea, or air)
 
Base Civ IV does indeed have that issue, but I rewrote he odds evaluation a year or two ago to normalize it relative to unit value. Basically each unit has a value (more or less its base strength, adjusted upward by promotions) and the 'odds' in all the calls are re-interpretted as 'percent chance to destroy more enemy value than we would lose'. Thus if a capital ship with strength 40 has a 50% chance of wining against a lesser support ship (say strength 20) it would actually require the parameter set much lower than 50 for it to make the attack (because it has a 50% chance of destroying a 20 value enemy and a 50% chance of losing a 40 value uni of its own by doing so).

The effect of this change is to make the AI consider the actual expected loss/gain more accurately. It applies to all AI combat (land, sea, or air)

Thanks for that, good to know and great work as always Koshling. However, I hope you will point us in the direction of that code, so that it can be reviewed along with the rest of AI (okay only naval is being reviewed at the moment, but like the randomly-typing monkeys, it is only a matter of time before we get to the rest of it...:lol:). With all respect, I feel confident that it would benefit from a review, even by C noobs like me.

Specifically, I see this further issue which affects any such evaluation.

How much less risk does being (say) twice as 'valuable' equate to?
a. Does it vary with playstyle (ie. 'cautious' v. 'audacious', peaceful v. warmonger, etc.)?
b. Is it different while at war than when one is an HN or barb?
c. It clearly does vary with replaceability. If a newly built unit will have 20XP (and won't take ages to build), then those first four promotions (as well as any from buildings/traits etc. of course) are of relatively little value. Field XP is far less replaceable, ergo more valuable.
d. i. If one side is strategically much stronger than the other, it will probably value its units less. For example, if I have 3-to-1 strategic "value" advantage, I may not mind losing half of my strength in wiping out the enemy, even though half my strength is significantly more ("valuable" - in theory anyway) than their strength in total.
d. ii. Tactically this impacts as well. If I have backup units that will ensure that my first attacker's sacrifice will not have been in vain, then I may be able to discount the first attacker's value. Conversely (as TB has raised), if my attacking unit has very little chance of survival even if successful, then the 'value' of its (kamikaze) success is reduced considerably.

Perhaps you've already considered all this and more. But it can't hurt for us to have a little stickybeak can it?;)
 
Thanks for that, good to know and great work as always Koshling. However, I hope you will point us in the direction of that code, so that it can be reviewed along with the rest of AI (okay only naval is being reviewed at the moment, but like the randomly-typing monkeys, it is only a matter of time before we get to the rest of it...:lol:). With all respect, I feel confident that it would benefit from a review, even by C noobs like me.
I had thought Koshling had said something about all this earlier and since I didn't go into a full evaluation of the attack function I wasn't sure if it generically applied to that function - looks like it does so that is indeed good (good job Koshling!)

Perhaps eventually a review in this style could be appropriate for some of these side functions yes. But they do take some time to write up and I pretty much saw what I needed to see here to move on with the project that got me started on this so until I come back with a focus on actually IMPROVING and possibly fleshing out more naval AI settings (which I do think we could very much benefit from) then I'll be leaving this sit for a bit now.

@Koshling: Nice to see you back on the forums man! Quick question here - how confident are we that the Shadow function is working properly? We know the Shadow mission command doesn't work for player units and it seems pretty important to the design here that it works for the AI.

I've also noticed that it would be very helpful that units that are shadowing remember that they are so that when they get side tracked by a 'sub-mission' objective they quickly take themselves back to the stack they were shadowing to begin with. I'm not sure if they do at the moment since I haven't evaluated that too much.

Also... I noticed you did not include brokerage methods for naval units. I figure that was an eventual plan... I'm thinking they could benefit greatly from that.


a. Does it vary with playstyle (ie. 'cautious' v. 'audacious', peaceful v. warmonger, etc.)?
Without evaluating myself I can't answer these questions but I wanted to comment on the intentions of them.

This one... really is a 2 part question. Established current war strategies should influence attack willingness (and I think it does) and I would really like to see Leader Flavors also influence the odds tolerances - that would be a very nice touch, yes.

b. Is it different while at war than when one is an HN or barb?
Again, established war strategies should play a role but I don't know if they do. I don't THINK HN or Barb makes a difference (though I do think that units that CAN be invisible to any other units but currently aren't should certainly have a higher cause to be attacked ruthlessly when they can be seen.)

c. It clearly does vary with replaceability. If a newly built unit will have 20XP (and won't take ages to build), then those first four promotions (as well as any from buildings/traits etc. of course) are of relatively little value. Field XP is far less replaceable, ergo more valuable.
Since we'll have Admirals fairly soon I'm hoping that attached leading units can also add a very significant amount of value to the 'irreplaceability' factor.

d. i. If one side is strategically much stronger than the other, it will probably value its units less. For example, if I have 3-to-1 strategic "value" advantage, I may not mind losing half of my strength in wiping out the enemy, even though half my strength is significantly more ("valuable" - in theory anyway) than their strength in total.
True but I don't think this should be generically considered. If I have a huge navy and very little land attack units then my land attack units shouldn't think they're more than sufficient a force just because my navy (which doesn't mean much in this current land war for example) should be tallied in to that perception of strength. A few strength 'categories' should be established for this I think.


d. ii. Tactically this impacts as well. If I have backup units that will ensure that my first attacker's sacrifice will not have been in vain, then I may be able to discount the first attacker's value. Conversely (as TB has raised), if my attacking unit has very little chance of survival even if successful, then the 'value' of its (kamikaze) success is reduced considerably.
It's interesting - if you look at the Sea Attack AI, you'll notice that for the purpose of evaluating whether or not to try to break a blockade on your city the AI does actually consider this kind of thing to some extent. So perhaps an adaptation of this sort of programming into its own simple function call could play a role.

One thing you have to be careful with though is that with AI its very difficult to debug things. You could end up with a horribly behaving AI and having a very hard time trying to figure out why if you make it TOO complex. Simple is generally good for this. Also, AI can greatly hinder turn times - the more intelligent the more delay usually. So one must consider streamlining the code as carefully as possible in its design. An overengineered AI code will quickly slow down turn times a lot. The Assault AI (which is something I really should work myself through though I'd say it's probably about 10x the complexity of the 2 above) is one example of a heavily engineered AI that takes a long time to process as a result (and could be a place that really needs a clear audit for speed and accuracy of intent!)

Perhaps you've already considered all this and more. But it can't hurt for us to have a little stickybeak can it?;)

I quite like this process of discussing the AI routines in open forum. It's too bad it takes me so long to work these up. At some point, once more of the basic gameplay modifications I've planned are completed, I'd love for us to have these discussions in serious depth just like these in regards to the whole AI. We really could make the AI very lethal. I'm really in awe of some of the amazing things Koshling has done and there's a lot to be learned by following his examples - really advanced work! I do think, having reviewed the code for as long as I have, that the original firaxis programmers did a suitable job on AI but they did not consider a constantly adjusting mod like this when they made it. Koshling's advancements have helped some portions of the code keep in mind flexible environments and that's truly a gift he's given us there.
 
Nothing I said was meant to imply more work for you my friend...;) My suggestions were for me and others like me, who might spot glaring problems, or gradually learn enough C++ to make a contribution. (I have an IT degree and background, and am even halfway competent in VB!:))

True but I don't think this should be generically considered. If I have a huge navy and very little land attack units then my land attack units shouldn't think they're more than sufficient a force just because my navy (which doesn't mean much in this current land war for example) should be tallied in to that perception of strength. A few strength 'categories' should be established for this I think.

Yes that's why I said "strategic" rather than "grand strategic";). Certainly naval forces are almost totally irrelevant to a land war (except of course for city bombarding - not sure whether ranged assault can really make a difference). So are forces on another landmass or at the other end of this one.
 
I am not aware of AI shadowing being broken, but you I think they re-evaluate it every turn once they reach the same tile as the unit being shadowed, so they can 'get distracted' and decide to do something else fairly easily. Might need a check on whether they were previously shadowing at the start of the relevant routine, and if thy were evaluate explicily if they are still needed in that role before checking other priorities.
 
Nothing I said was meant to imply more work for you my friend...;) My suggestions were for me and others like me, who might spot glaring problems, or gradually learn enough C++ to make a contribution. (I have an IT degree and background, and am even halfway competent in VB!:))
And here I have no degree or programming background prior to learning to mod (to Koshling's great dismay at times methinks ;) )

If you were to join us in helping us improve the AI I'd think it'd be greatly appreciated assistance. I think it would be particularly cool if we all worked on the AI through breakdowns and discussions like these so that we can all have input while someone takes the reigns on the programming side. I've got so much to do to try to simply catch up to projects I've begun that this really feels like a side project for me to work on the AI extensively though it really should be a programmer or two's core workload to get it to where it really would be a tough AI. So your help would be invaluable!



Yes that's why I said "strategic" rather than "grand strategic";). Certainly naval forces are almost totally irrelevant to a land war (except of course for city bombarding - not sure whether ranged assault can really make a difference). So are forces on another landmass or at the other end of this one.
I was mostly trying to point out that such grouped power calculations haven't been defined yet and would be very useful to define for a few various purposes like the one you mentioned. Including, I think, helping to direct when to build more units.

I've often thought that the AI should be a lot less haphazard and a lot more goal based. For example, define theaters of war and define how many units of each role need to be prepared at all times to address that theater of war and track what we have and what we need there already - then command units according to balancing these needs and targets within those theaters.

Very different approach entirely. Somewhat along the lines of what Koshling was saying a long time ago regarding the need for a better overall central command structure.

I am not aware of AI shadowing being broken, but you I think they re-evaluate it every turn once they reach the same tile as the unit being shadowed, so they can 'get distracted' and decide to do something else fairly easily. Might need a check on whether they were previously shadowing at the start of the relevant routine, and if thy were evaluate explicily if they are still needed in that role before checking other priorities.
Yes, that would help I think. Something to bring them back around after a sub-mission is accomplished - with checks to make sure other missions aren't necessary to address first - but then remembering their original role rather than being left to draw back together IF they're still in a close enough vicinity after all other work is done etc...

Currently the biggest fault in the naval AI is that AI navies split up and scatter a great deal making them very vulnerable. These sub-stacks should be prepared to defend themselves against the host of targeted approaches that may be used against specific ships before going all over the place. I tend to find them one boat here one boat there and very susceptible to being hit by the type of vessel that counters them (or to surround and destroy).
 
The other problem with the naval AI is that they don't know that they are being damaged each turn by land units so sit and try to heal while they slowly get destroyed.:D
 
The other problem with the naval AI is that they don't know that they are being damaged each turn by land units so sit and try to heal while they slowly get destroyed.:D

Are they able to see those land units?
If not it could explain it.
 
Are they able to see those land units?
If not it could explain it.

I don't think archer bombard and similar are taken into account when making valuations of whether a tile is safe to heal on - I think it only looks at enemy units in terms of their ability to direct attack it (applies to land and sea, it's just that in the land case a unit that can bombard it can also attack it [unless its trying to heal on a coastal tile where a ship is bombarding it I guess])
 
I don't think archer bombard and similar are taken into account when making valuations of whether a tile is safe to heal on - I think it only looks at enemy units in terms of their ability to direct attack it (applies to land and sea, it's just that in the land case a unit that can bombard it can also attack it [unless its trying to heal on a coastal tile where a ship is bombarding it I guess])

You are right adding the marked code in CvUnitAI::exposedToDanger should fix it.

Code:
					while ( getThreateningUnit(pAdjacentPlot, pUnit, pPlot, iIndex, bConsiderOnlyWorstThreat) )
					{
						FAssert(pUnit != NULL);

						if ( !isInvisible( pUnit->getTeam(), false ) )
						{
							if(threateningUnit->canArcherBombardAt(threateningUnit->plot(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) || threateningUnit->canBombardAtRanged(threateningUnit->plot(), pPlot->getX_INLINE(), pPlot->getY_INLINE()))
								return true;

							int iOdds = pUnit->AI_attackOddsAtPlot(pPlot,(CvUnitAI*)pOurDefender);

							//	AI_attackOddsAtPlot returns a value capped artificially below at 1, but for the ensuing calculation
							//	that causes nasty rounding errors so we just treat 1 as if it were certainty of failure
							if ( iOdds == 1 )
							{
								iOdds = 0;
							}
 
if(threateningUnit->canArcherBombard(pPlot) || threateningUnit->canBombard(pPlot))
Incorrect. Slightly.

Should be:

if(threateningUnit->canArcherBombard(pPlot) || threateningUnit->canRBombard(pPlot))

And does this take into account ranges greater than 1 I wonder?
 
Incorrect. Slightly.

Should be:

if(threateningUnit->canArcherBombard(pPlot) || threateningUnit->canRBombard(pPlot))

And does this take into account ranges greater than 1 I wonder?

Ok but there is no threateningUnit->canRBombard(pPlot)) it only has a bool parameter.

This should do it
Code:
					if(threateningUnit->canArcherBombardAt(threateningUnit->plot(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) || threateningUnit->canBombardAtRanged(threateningUnit->plot(), pPlot->getX_INLINE(), pPlot->getY_INLINE()))
						return true;
 
Top Bottom