I'd like to address Alberts2, Koshling, AIAndy, anyone who is knowledgeable about the unit AI portions of the code for a bit. I think we need a deeper discussion on some of these issues as I often feel like I'm guessing about certain things and it would be good to share our understandings and strategize together to find better ways to improve things. Suffice it to say I REALLY don't want to do anything that's going to cause unanticipated results.
To start the discussion, we're still having some difficulty with city attack stack formation. This is just one of many issues I'd like to discuss but we need to start somewhere right?
By the way, Alberts2, our discussion and the results of your implementation of the new Hunter companion AI produced what I believe is an outstanding improvement for the AI. (Putting the needs for a hunting party in proper perspective to some other potential concerns is still one of a great many priority issues the AI still has but if the AI isn't being harassed I think it's currently very appropriate - and effective.) So that's a real inspiration for us knocking heads further. Well done man!
Anyhow, this particular section in the code is troubling to me. I made an adjustment here a while back and I'll explain it and why I did but let me first post the code and then I'll bring up the discussion points.
This segment is found in
void CvCityAI::AI_chooseProduction()
and falls into the routine that determines current build priorities for the city.
Code:
if( iStartAttackStackRand > 0 )
{
int iAttackCityCount = kPlayer.AI_totalAreaUnitAIs(pArea, UNITAI_ATTACK_CITY);
int iAttackCount = iAttackCityCount + kPlayer.AI_totalAreaUnitAIs(pArea, UNITAI_ATTACK);
if( (iAttackCount) == 0 )
{
if( !bFinancialTrouble )
{
if (AI_chooseUnit("build attack force", UNITAI_ATTACK, iStartAttackStackRand))
{
return;
}
}
}
else
{
if( (iAttackCount > 1) && (iAttackCityCount == 0) )
{
if (AI_chooseUnit("start city attack stack", UNITAI_ATTACK_CITY))
{
return;
}
}
else if (iAttackCityCount < (3 + iBuildUnitProb / 10))
{
if (AI_chooseUnit("add to city attack stack", UNITAI_ATTACK_CITY))
{
return;
}
}
else if (iAttackCount-iAttackCityCount < (3 + iBuildUnitProb / 10))
{
if (AI_chooseUnit("add to attack stack", UNITAI_ATTACK))
{
return;
}
}
}
}
Ok, lets start with some questions.
1) If I'm understanding this right, any call to build a unit with AI_chooseUnit is translated through the brokerage and may end up being a call to another city to build the unit, not necessarily this one. Am I correct?
2) City attack stacks will also themselves make calls to the brokerage (tendering) system to ask to be filled to its optimal stack size and content. Correct?
3) If a city attack ai unit is trained (without necessarily being called by a city attack stack request of the brokerage system but rather from a call here) and there is then subsequently a call for a city attack ai unit BY the brokerage, this unit will be found first and answer the call before another unit is ordered for training? Is that right? I'm a little confused on this point. If that's correct then:
4) The newly trained city AI unit that was ordered by a city (and not an existing stack) would come out and immediately start calling for other units to form its own stack with right?
Assuming 3 and 4 are correct:
5) What then happens when a unit that is already calling for other units to be trained and join it in forming a new city attack stack is itself called to join another stack by the brokerage finding a suitable match for another stack's call? Does this potentially start a domino effect that will call far more than expected amount of city attack units to be trained?
6) Would it then stand to reason that our method of counting city attack and attack UNITS rather than STACKS is completely flawed here? This really means that as a stack begins to form, it keeps any further stacks from being able to form right? Or even worse, it only considers the nation to have a stack formed if the count of those AI's is currently geographically local to the city? It just seems very flawed to be taking a count of units rather than a count of centralized units that comprise the leaders of each stack. Even counting groups wouldn't quite be the same.
7) If all of the above is true and there IS the suspected 'issue', should we add a new AI specifically to lead city (and other types of) attack stacks that is only called for by the city (in this function) and then is tasked to ask of the brokerage mechanism for the appropriate balance of additional units it seeks for its army? (then if killed later another unit in the stack is selected to become the stack leader and its AI is changed accordingly) Or would it be better to use some other sort of solution? I've insinuated MY proposal.
The change I made was quite a while ago as it looked like the AI was only ever building one siege unit because it would only potentially build one when it was called through this routine. I later found the issue was located elsewhere in that the city attack stacks were, once started, asking the brokerage for only attack AIs and weren't asking for CITY attack AIs.
But that's the root of another issue. If siege units become the leader of a city attack stack, many can't attack all targets properly and will ignore targets, potentially even cities themselves, that they could and should be attacking. I've really come to the conclusion that for this and the benefit of better crafting promotion selections for siege, that siege units would be easier managed if split up into new AI types for each of their specific roles, then become a part of what is called for by a stack leader.
I also wonder how effective the Shadow command is. Is it already established that we can tell the AI to build separate mini-stacks that have their own behavior commands but generally march right along with another stack of an AI type? Is it easily established that a stack of an AI type isn't to feel ready to do certain things (like deploy) unless stacks of another AI type are fully prepared to accompany them?
I'm getting ahead of myself. Let's talk more about the questions above and see where this goes.