[SDK] Programming the AI to Perform a Unit Action

Joined
Jul 28, 2006
Messages
4,016
I would like to change the unit AI code (CvUnitAI.cpp) to instruct a civ to move a unit to friendly terrain if that unit has a certain promotion.

Specifically, I have modded Grey Fox's fuel modcomp to give mechanized units a "low fuel" promotion when they run low on fuel (no surprise there), and I have changed the refueling mechanism to take place within friendly borders. So what I now need to do is teach the AI to move its low-fuel units back to the nearest open-borders, vassal, or friendly territory in order for them to be properly refueled. The nearest friendly/open borders city will also do the trick.

Can anyone offer me some advice on how to get started?
 
Is there a reason it has to be in C++? I have also worked on a fuel system, which is released in the mod in my sig. (BTW, we also have a really cool new "tanker truck" unit created by asioasioasio and seZereth.) The mod has a python routine which dispatches tanker trucks to units which are low on fuel. This is kind of the opposite effect from what you described, but the ideas are related. You can see my code in Assets/python/CvFuryRoadGameUtils.py, function AI_unitUpdate.

In your case, triggering on the unit which has low fuel should be easy. But, finding which is the nearest friendly territory may be hard. You would probably want to cache a map of friendly territory, certainly for all units, and possibly cache it from one turn to the next as well.
 
I would have to agree the best bet is to do this in SDK, that way you don't have to worry about any lag no matter how many units are in the game.

As to how to do that, sorry, can't help ya there Gaius Octavius. ;)
 
Many people have said, "oh, don't do that in python, it will be too slow". Of course that is possible. I have some relatively complex python for unit movement and some other mod-specific things. I measured the runtime of one particular game with my python turned on, and then turned off. It was the same initial position, but of course with the python turned off, many of the "interesting" things did not happen.

The extra runtime with all the python turned on was 8%. So, if a turn would have taken 24 sec to run without python, it would take 26 sec with python. I have no way to tell how much faster it would have been with SDK. Even if it was 24 seconds I don't think this is such a big deal.

As with any programming task, if you don't take the effort to make sure the algorithm is efficient, your runtime may be poor. So, investigate how much can be cached from one turn to the next, don't iterate the whole map when iterating units will do, etc.
 
I used to be a big supporter of Python over SDK until I actively got involved with it. I prefer C++ now mainly because it's faster and doesn't ruin multiplayer games. Still, Python has its advantages, but this is one case where it doesn't.

I know it's not that hard to program a basic UnitAI check in the SDK; Dale added in his airbombing components in a fairly straightforward way. It will surely be easier to add a check to see what the present fuel supply of a unit is, and if it's low (or it has the "low fuel" promotion), then send that unit to the nearest friendly city/territory. The hard part, of course, comes in taking into consideration the tactical situation. (I might use the danger check or AI_retreatToCity for this.)

This may not be the best way to run things, but I have preferred it over the supply truck setup for two reasons: 1) it is better for naval units, and 2) it does not require a special unit / mission for the human player to contend with as well. I want everything to be as automated as possible.
 
Well, I am a python programmer, have been for around 6 years now, so you don't need to preach the pros of python to me, but it has its place in Civ4 modding.
 
What does it mean, "python ruins multiplayer games"? I have not tried to support multiplayer in my mod yet, but is there some way in which python is inherently worse than SDK, for multiplayer?
 
Modding certain Python files will make it impossible to play a multiplayer game effectively because whenever they are called you will get OOS errors. Anything using custom script data, for instance, will do this.
 
Where can I read more about problems with using python and multiplayer? I am not using scriptdata, but I have a fair number of random events which occur with python. For example, instead of using the standard animal spawning routine, I have my own which ensures that animals spawn where I want them. I haven't made any special effort to make this work for multiplayer, but I suppose if each player's machine runs the end of turn routine and gets different animal spawns, this would be fatal.
 
Thanks, that tutorial was just what I needed. I read through it. Some classes of errors I had not thought of, such as generating a sync random number while in a local context. I will scan my code closely for this type of problem.

However, back to my original question of "why python would cause OOS errors", I am still confused. It is possible to write code which causes OOS errors in either SDK or python. If you have written code in one language which causes an OOS error, writing the same code in the other language would cause the same OOS error.

The message that I get out of all this is, XML changes and graphics changes are always safe, you cannot screw it up and get OOS errors. Both SDK and python have the *same* risk of OOS errors.

Any disagreement?
 
Slightly more on the topic of "running out of gas", if you do not have a gas truck, and the unit is too far away from friendly territory, it may run out of gas in enemy territory. In your mod, with no fuel trucks, what happens then?
 
Slightly more on the topic of "running out of gas", if you do not have a gas truck, and the unit is too far away from friendly territory, it may run out of gas in enemy territory. In your mod, with no fuel trucks, what happens then?

I took this into account by adding Moctezuma's Influence-Driven War. Thus, when you start to invade an enemy civ, its tiles will flip to you as you fight your way inside. You should never be more than a few tiles away from friendly territory then.
 
So, the only real effect is to slow down advances. Instead of pushing ahead at full speed, you have to back up a few squares every now and then. Is there really no other effect?
 
So, the only real effect is to slow down advances. Instead of pushing ahead at full speed, you have to back up a few squares every now and then. Is there really no other effect?

No... If you blockade enemy islands, they can't be resupplied... If you surround an enemy city, same thing... Also this places upper limits on how many mechanized units you can successfully build and operate, because of the stockpile. Fighters can't run if they don't get supplied, and ships can't fight well. What is the difference between your system and mine in that respect? Nothing, except yours requires more micromanagement. EDIT: Also, you don't have to "back up," as I said. The culture flips as you invade. That really is only an issue for ships that have to return to port.

I didn't come here to debate the validity of this mechanism (though I am open to improvements); I came here to ask for help in getting the AI programmed to use it effectively.
 
I agree my system is designed to require "some" micromanagement because fuel is supposed to be limited and precious in the particular genre of my mod. However, will you enable your players to make choices about *which* units get resupplied if there is a shortage? If all units in friendly territory are eligible for resupply, but there is not enough to resupply all of them, how does the player indicate his priorities?

The working python I indicated earlier in the thread will exactly solve your problem if you apply it backwards. That is, you want to move the low fuel units towards cities, rather than moving fuel trucks towards low fuel units. If you would like some more information on how I hooked my python into the system, please let me know.
 
I might be willing to add a special "air supply" mission for transport planes later, but I can't foresee any large-scale truck operation solely for resupply. For my mod, it would just be too much. However, I shall consider it.

In the meantime, does anyone have a lead on how to implement this? Surely I could use code that tells units to heal in cities or something for a base...
 
In the meantime, does anyone have a lead on how to implement this? Surely I could use code that tells units to heal in cities or something for a base...

You may still be able to get a lead about which SDK functions are involved by tracing the insides of the python callbacks I have used. Or maybe, a working python solution may be more useful than "no leads" on doing it in the SDK.
 
You may still be able to get a lead about which SDK functions are involved by tracing the insides of the python callbacks I have used. Or maybe, a working python solution may be more useful than "no leads" on doing it in the SDK.

A couple new tags in the UnitInfos to determine what resources the unit can carry and how much, then put the AI code in CvPlayer->doUnitsTurn() and CvUnit->doTurn() or similar function.

Once GO gets the important stuff done, it won't be that hard to add units that resupply other units. Probly could do most of that in python, just need the QR Mod first.
 
Okay, I think I have figured out how to do this in an uncomplicated way (ran across something similar recently). You basically just use the pushMoveToMission command to send a unit to a nearby city if it starts to run low on fuel. I would guess this falls under the initial SDK check that runs at the beginning of the turn. However, I don't know if this would affect the whole stack or just the one unit, or whether the AI could override it the next turn. Each possibility has its own advantages and disadvantages.
 
Top Bottom