all terrain settlers?

davidlallen

Deity
Joined
Apr 28, 2008
Messages
4,743
Location
California
It's the Dune Wars team, back with another request to twist BBAI into doing things it did not expect. As you may recall in Dune Wars we have an archipelago type map, and a number of units which are DOMAIN_SEA and have bCanMoveAllTerrain. This allows the transport units to be built in landlocked cities and carry settlers to other islands to settle. This is working fine, although we have made a number of minor tweaks for loading and unloading all terrain transports. Maniac wrote the original all terrain transport code.

But, one of the civs (the desert natives, Fremen) has basic units which can move on all terrain, including the settler, warrior, scout and worker. The Fremen civ does not have transports; it does not need them, since its basic units can move on all terrain.

This seems to confuse the AI. The Fremen civ usually never expands past its initial island at all, or if it does, it is because its warriors conquer a barbarian city on another island. I have reproduced this problem in vanilla: the AI does not use all terrain settlers. I have created a vanilla mod, attached, which shows the problem. It is a customized unitinfos file only. I did the experiment in three stages:

1. Use the mod directory but a normal unmodified unitinfos file. Create a high water archipelago game and save it on turn 0. Autoplay 255 turns and see the results. As you expect the civs expand out to other islands. The civs had expanded to 2-3 islands each, probably 6-8 cities total.

2. Modify all the DOMAIN_SEA units to DOMAIN_LAND and modify their UNITAI's to some legal value for DOMAIN_LAND. The point is to remove all sea units without invalidating the save game. Load the save game and autoplay 255 turns. Each civ expands on its island but does not go any further. This is also as we expect.

3. Use the attached unitinfos file, which has bCanMoveAllTerrain set for settler, warrior, worker and scout. Load the save game, play 55 turns as the human player and ensure that the human player can create colonies on other islands. The units all cross ocean as needed and it is easy to set up a colony on another island. Then autoplay another 200 turns. In this case the AI never expands, just like run #2, although it could. The AI scouts walk on water fine, but no AI settler ever sets off across water.

This exactly matches what we see happening for the Fremen civ in Dune Wars. The human player can expand (rapidly, in fact) but the AI doesn't know what to do with it.

My question is, can you help me understand how I can locally modify BBAI to use all terrain settlers? The Fremen people thank you in advance.
 
This is from memory of reading the code, not reading the code.

But the civ 'find a new location to settle' code looks in the local area; which is defined as the continent; when it tries to pull off a direct route to a settlement.

I guess a better way to approach it would be to look for the best settlement value in every area and the best locally.

Settlers should check to see if they can reach the best location globally (which involves both a 'can I move there directly' and a 'is there a transport to carry me' path), and the best location locally (with maybe a bias towards the closer one, if both are possible?)

Downside: checking to see if a Settler can reach a location not in the same area is a really expensive operation if it doesn't work. A* doesn't give up until it searches every location that can be reached from either the start or the end node (depending on how it is written), and the built-in A* implementation doesn't do a 'can we reach the destination in fewer than X turns' style operation.

...

But, if you want an idea of where to look, start looking in the settler AI decision code, and the code that sets the settler AI type (I think there is a different AI for settler and settler sea?) when it is built.
 
Just a question: the AI Fremen settlers never enter water or they enter water and come back? If it is the second they might be forgetting to where they were going because of the change of domain and recalculate what they want to do , like it happened ( happens? not very up to date in there ) in Planetfall with attacking SoD ...
 
Just a question: the AI Fremen settlers never enter water or they enter water and come back? If it is the second they might be forgetting to where they were going because of the change of domain and recalculate what they want to do , like it happened ( happens? not very up to date in there ) in Planetfall with attacking SoD ...

In the standalone mod example I attached, settlers are never even built. I assume the AI is considering to build a settler and send it to a nearby island. But it overlooks that the settler can walk there, instead tries and fails to find a transport unit it could build, and gives up on the whole affair. The same thing happens in DW.

So, I would like a way for the AI to use the bCanMoveAllTerrain flag when deciding to build and send a settler.
 
Getting settlers to new city sites is a three tiered process for the AI:

1) Picking city sites

I imagine this is working fine for this civ, but it'd be good to double check. Do the Fremen have city sites picked out on other "islands"?

2) Building a settler

Build decisions all come from CvCityAI::AI_chooseProduction. If you search in CvCityAI for AI_chooseUnit(UNITAI_SETTLE) you will find the two places where the AI will build a settler. In both of these there is a check against the best found value of a city site in the area, but in one spot it also checks other areas:

Code:
if ((iAreaBestFoundValue > iMinFoundValue) || (iWaterAreaBestFoundValue > iMinFoundValue))

Digging a little deeper you'll find that iWaterAreaBestFoundValue is of course set up for the standard game, so only cities which have a waterArea() (ie, they're on the coast) will think about building settlers for colonizing. For your mod this isn't the right approach, as I understand it every civ has access at least to all-terrain transports. So, you want every city to think that it has direct access to the "ocean" area. The right way to do this I think is to change CvCity::waterArea so that it returns CvMap::findBiggestArea(true) once the civ can build all terrain units.

(Side note: This may explain why the AI is sometimes so bad at colonizing ... only coastal cities will build settlers for colonizing, so if the AI has only one or two port cities it will be really slow. Thanks for drawing my attention here!)

3) Moving the settler to the plot

In CvUnitAI::AI_settleMove, you probably just need to remove the area check from this line:

Code:
if (pCitySitePlot->getArea() == getArea() && generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true))

Path generation will take care of the area check for non-all-terrain units, then the settler will consider all city sites it can reach as if they were local.

Let me know how it goes!
 
Thanks for the suggestions. I have started to carry out these experiments but I got a little stuck. First, I downloaded the standard BBAI 0.81 release and copied my unitinfos into the directory, and ran the same experiment as before. I verified that the ctrl-z debug view of the map had colored circles on distant islands, indicating that the AI was finding valid colony sites. I autoplayed 255 turns and found the same result, no settlers built or launched.

Then I used the BBAI sources and built my own cvgamecoredll.dll. I have done this successfully for several minor mods of my own, and I do it for Dune Wars; so I have the basic steps down. I copied a full set of the unmodified BTS sources into a new build area, then unzipped the BBAI source zip onto it. This replaces the changed files. Then I took my Makefile from Dune Wars and compiled with that. The DW makefile lists a couple of extra source files so I just deleted the offending references in the Makefile. After a couple of tries I had a cvgamecoredll.dll.

However, when I use this and run the experiment, there aren't any colored circles. I have not made any changes to the sources yet, just recompiled.

Is there something special I should be doing in the build, to get the debug circles to show up? Using the distributed dll, I did not have to take any special steps, they were just there.

Once I verify that the same colored circles appear, then I will "trust" that I have built correctly, and I will continue to the next step. That will be to modify the sources as you suggest and see if the settlers are built and travel like the human player can do.

EDIT: I got the colored circles with my dll. I think I forgot that you have to autoplay some turns *after* ctrl-z, the circles are only drawn when the AI runs and ctrl-z is on. Sadly I will not be able to work on the suggestions again until Tuesday or so.
 
3) Moving the settler to the plot

In CvUnitAI::AI_settleMove, you probably just need to remove the area check from this line:

Code:
if (pCitySitePlot->getArea() == getArea() && generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true))

I did a quick experiment. I removed the getArea check from this line, ran 100 turns, and then used WB to add a settler and a couple of all-terrain warriors to each AI city. Then I autoplayed another 100 turns. The settlers were still sitting there, ignoring the nice colored circles on other islands they could clearly reach.

So, there must be at least one more check preventing them. It wasn't clear to me how the AI decides which units should be in a group with the settler. Is it possible that it picks the units in the city with the highest attack strength and puts them into the same group? Then the pathfinding would have some attack units which cannot move on water, along with the settler, and no movement would happen.

In that case, I would like guidance about how to make sure the settler is only grouped with other units that also have all terrain movement.
 
Before that, examine how the settlers are grouped. Are the settlers in a group with an escort? What is the unit AIs of the units in the group with the settler?
 
Unit grouping with settlers is complex ... the head unit of each group is an island, they make decisions on their own. So, the short answer is that whichever unit near the settler which moves first and doesn't have any higher priorities will groups with the settler. The different UNITAIs examine different things before looking for settlers to group with, and not all will group.

I just checked and there's a second area check which would block all-terrain settler's looking at other areas in CvUnitAI::AI_found. I'd suggest changing it to:

Code:
if (pCitySitePlot->getArea() == getArea() [B]|| canMoveAllTerrain()[/B])

Now, having a mixture of allterrain and non-allterrain land units in your mod is going to make life interesting. It should work okay, but there are a few things you'll need to take care of and add.

First, have you seen AI all-terrain land units moving to other islands? Maybe you've addressed this already, but I think you need to fix CvGameCoreUtils::pathDestValid. There's a check for AI controlled land units which verifies that areas are the same (with one small exception) before allowing path planning to the destination tile. I suggest:

Code:
if (pToPlot->getArea() != iGroupAreaID && [B]!(getGroup()->canMoveAllTerrain())[/B])

Where the CvSelectionGroup::canMoveAllTerrain function was added in BBAI. The pathValid function should be fine as it uses CvUnit::canMove which is setup properly for allterrain units.

Second, you'll need to keep non-allterrain units from grouping with allterrain ones. The right way to do this I think is to mimic the bIgnoreFaster option in CvUnitAI::AI_group, that way non-allterrain will never join with allterrain, but allterrain can choose to join with non-allterrain if desired. If you create an option like bIgnoreAllTerrainIfNot, add it to the end of the list and in CvUnitAI.h give it a default of true. You should also do a similar thing in CvUnitAI::AI_groupMergeRange.

Third, you'll need to decide what are the circumstances you want all terrain units to consider traveling to other islands. There are quite a few area checks in the CvUnitAI::AI_xxxxMove functions, and leaving them in keeps the AI doing what it's been tested doing and makes turn times faster. However, beyond settling there will be other things you want them to move allterrain for. I imagine you'll want to make sure their attack city stacks check all areas when moving out on offensives. What else? Having workers do it is dangerous as they might get picked off and don't have escorts, but they will avoid any enemy units that they can see. Spies and missionaries?
 
Thanks for the advice. I am still not able to get the settlers moving. I have deleted the two tests for area == getArea as you suggested. I have also made sure that all the early game units have bCanMoveAllTerrain: settler, warrior, scout, archer, swordsman, axeman, chariot. This eliminates any need to change how the AI creates or moves stacks for now.

I take a high sea level, archipelago map and autoplay 100 turns. Each civ seems to build one settler but never moves it. I can also add settlers and autoplay more, and the settlers never move. When I click on the settler which has appeared in my city during the autoplay, I can see what else is grouped with it; it is grouped with an archer and a warrior, both of which have bCanMoveAllTerrain. So the stack can move to other islands. I do see scouts, and occasionally other units, moving onto the water and other islands. After the autoplay finishes I can pick up my own settler group and move it to another island and start a colony fine.

I have attached my modified cvunitai.cpp (search "davidlallen" in two places to see my changes) and also the unitinfos.xml file with the bCanMoveAllTerrain's set.

Is there something else I can try, to get these settlers moving?
 

Attachments

If you have had a chance to investigate, please let me know. I can try to follow up any leads if you can suggest experiments.
 
Did you also do the change for CvGameCoreUtils:: pathDestValid above?

There's a check for AI controlled land units which verifies that areas are the same (with one small exception) before allowing path planning to the destination tile. I suggest:

Code:
if (pToPlot->getArea() != iGroupAreaID && [B]!(getGroup()->canMoveAllTerrain())[/B])

That did it for me ... the issues now is that workers are putting roads over the ocean, which is interesting.
 
It is working for me now! I guess I misinterpreted your suggestion above; since I was seeing scouts and other units moving to other continents, I assumed I did not need to modify pathDestValid. The exact line in pathDestValid is:

if ((pToPlot->getArea() != iGroupAreaID) && !(pSelectionGroup->canMoveAllTerrain()))

I agree it is weird to see workers building roads on ocean; workers can build roads anywhere they can walk, and there is no way to disable that on certain terrains. Fortunately, in the target application of Dune Wars, there are no roads anyway.

Now that you have helped me get something basically working, I will go back and see if I can get the Fremen settlers moving. Thanks a million.
 
Back
Top Bottom