• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

LUA - Forcing Units to Move, i.e. getting pushmission to work correctly....

sman1975

Emperor
Joined
Aug 27, 2016
Messages
1,376
Location
Dallas, TX
Hello,

I'm working on a scenario and I need to write a very "hands on" function to control an AI team to get them to place their units at certain parts of the map as the scenario progresses.

The code in use is something like this:
Code:
for pUnit in player:Units() do                                                                        -- Cycle through all player's units
        pUnit:PopMission()                                                                                -- Clear previous mission (sometimes....)
        pUnit:PushMission(MissionTypes.MISSION_MOVE_TO, targetX, targetY, 8, 0, 1)                        -- Move to target X & Y    - Flage = 8 (ignore danger)
end

Where targets X & Y represent the objective - and these values change during the course of the scenario.

About half the time, it works beautifully, and the units move like the AI has some, uh, I....

The other half of the time, about half of the units behave well, and the other half go on some kind of odd scavenger hunt on the other/wrong side of the map. :mad:

I've read a lot about "operations" the AI uses to template things it would like to do; then it "assigns" units to those templates, then moves them accordingly.

From my observations, on the "bad" games, the AI uses 2 templates, one of which follows my pushmissions, the other template is based on something it felt was important to do....

Question - is there any LUA method, etc., that can be used to directly "kill" these templates at game start, or somehow remove units from them?

Or somehow make the pushmission more persuasive 100% of the time.

Thanks!

sman
 
PushMission(MissionTypes.MISSION_MOVE_TO.......) will also become invalid if any interfering unit occupies the target, and the game will cancel the mission.
And from feedback I've gotten from other mod-makers, will CTD when issued if there is any interfering issue with the target tile being a valid target, can CTD if there are uits in the way in-between, and etc.
What you are seeing with the units wanting to wander half-way round the world just sounds like the usual bizarre unit-pathings when there is a bottleneck, clutter, or interferene in a specific part of the map.
 
@LeeS - that's a pretty good explanation, as usual... :)

So - is the solution to manage my own route path for each unit?

I was thinking about something I learned in college (back on punch cards.... kidding. sorta) - the routine was fairly simple. The algorithm basically involves calculating an intermediate "temp" destination, derived at by mathematically reducing the deltas in both X and Y coordinates by an approximate amount.

For example, start location = 10, 10 and destination = 20, 20
1. Assuming a move speed of two, the first iteration would subtract 1 from each coordinate, so the new temporary destination would be 11, 11.
2. I suppose, this is where in Civ V I would insert the 'JumpToNearestValidPlot' call? Or test the plot to make sure it's empty then allow the pushmission...
3. Then repeat until deltas == 0.

Will play around with it. I'm not looking for Swiss-clock precision, just basically a function that executes every 5 turns or so, and tries to get a scrum going in more or less the right direction.

Then again, I seem to remember WHoward had some form of "legal" path function, which I'm sure would be more elegant and useful

Thanks again!
 
  1. This might serve as a working logic-structure to start with.
  2. As set-up every Ai major player would have their combat units start heading toward the target plot.
  3. I arbitrarily picked a target plot XY of 50,50 at the top of the code.
  4. You would need to work out methods so that only units of Civilization_X, for example, would be affected, and then not all the combat units of the proper domain, as this logic starting code is written
  5. but it should at least give you some direction on one way that ought to work.
I had to stick the lua file in a zip in order for the forum to accept it. Dunno why.
 

Attachments

@LeeS - Wow. Just wow. I am simply gobsmacked by your solution! Très elegant. Your code makes my little attempts seem very simplistic by comparison. I'll embed this today and let you know how it's working.

Cannot thank you enough. Wow.

Just wow.
 
I had difficulty getting the code to work acceptably. It does indeed drive the units in the way I was intending, but as it uses all movement points, they would often end up next to enemy units in the area but not attack. This gave the enemy first shot at them, and in Civ V that usually is a good advantage. It actually looked like normal AI movement very much in this area. After 20+ test runs, the "casualty rates" of the offensive using the old algorithm would usually take the objective with <50% strength left. The new approach would most often not take the objective and end the scenario with average of 7%.

I know the code provided was only meant to be a shell, but it looked beyond my capability to code all the exceptions required to account for the presence of enemy and how to respond proactively and not be target practice every time.

I looked around some more and saw a thread that looked quite interesting: https://forums.civfanatics.com/thre...addtemporarydominancezone-actually-do.479891/

I tweaked this quite a bit to fit into my scenario, and here's what I ended up with:

Calling function - executes every 5 turns (since AI_TACTICAL_MAP_TEMP_ZONE_TURNS is set to 4):
Code:
moveAIUnits(playerID, iTargetX, iTargetY)

Function code:
Code:
function moveAIUnits(playerID, iTargetX, iTargetY)                                                        -- Pushes a scrum of combat units towards objectives; fires every 4 turns
    local gameTurn = Game.GetGameTurn()
    local pPlayer = Players[playerID]

    for pUnit in pPlayer:Units() do                                                                        -- Cycle through all player's units
        if gameTurn == 1 then                                                                            -- On 1st turn, push units to assembly (safe) areas to organize for later objectives
            pUnit:PopMission()                                                                            -- Clear previous mission (sometimes....)
            pUnit:PushMission(MissionTypes.MISSION_MOVE_TO, iTargetX, iTargetY, 8, 0, 1)                -- Move to target X & Y    - Flage = 8 (ignore danger)
        elseif (pUnit:GetDomainType() == GameInfoTypes.DOMAIN_LAND) then                                -- Only process land units
            pUnit:SetDeployFromOperationTurn(gameTurn + 1)                                                -- Add unit to next turn's operation
        end
    end
    if gameTurn > 1 then                                                                                -- After assembling, create operation targeting iTargetX, iTargetY
        pPlayer:AddTemporaryDominanceZone (iTargetX, iTargetY)
    end
end

The end results are pretty much what I was looking for. The AI now creates a scrum moving towards the objective located at iTargetX, iTargetY - in more or less good order, and does account for nearby threats and engages as they should. The gameTurn 1 trap is how I set up the offensive by first moving units to a safe assembly area, then the next time the function fires on turn 5, the units start moving directly to the first objective. So for what simple task I was trying to do, this code works more or less OK.

Two issues:
- I changed the AI Define "AI_STRATEGY_MILITARY_RESERVE_PERCENTAGE" - lowering it from 35 to 5 - to free up more units - helped eliminate a problem where the offensive was constantly losing troops as AI shifted them back to the capital for home defense every few turns.

- The other issue is a bit of a pain. It seems there is about a 10 second increase turn length time after the first AddTemporaryDominanceZone command fires. I'm not sure exactly what that is, but I suspect it has something to do with route deconfliction - if 80 units are trying to navigate to the same plot, it must take the AI some time to figure out legal routes for all of them.

It still looks quite good while executing, but doesn't come without a cost.

Anyways, thanks again for the advice and assistance. It really does help improve my understanding of what's going on and how to get stuff working.
 
Last edited:
Ugh.... It was working yesterday, I swear..... :crazyeye:

The code in the previous post isn't fully baked yet. The land units still work quite well, but the great generals and workers I had moving with the army for some reason decide to move in exactly 180 degrees opposite direction...

I've even tried modifying the code where the generals and workers get the PUSHMISSION command, while the normal combat units get the SETDEPLOY command. Changes nothing - soldiers go where they're ordered, the generals go off to the Officers Club... Double Ugh...

Appreciate it if anyone has a theory why "special" land units don't obey a simple push mission - or failing that - how to completely delete AI operations....

Thanks.
 
civilian units will refuse to go through combat units owned by another player, or to pass through other civilian units. Regardless of whether the two players are at war.

I believe the auto-pathing takes this into account even when the unit's owner cannot see the interfering units/tiles.
 
@LeeS - that makes sense. But in my own peculiar case - I have 3 workers on the map with about 20 other combat units, and 5 Great Generals. Of course on Turn 0, the units move almost randomly. Nothing is directed until the first PUSHMISSION statement executes on Turn 1, since GameEvents.PlayerDoTurn doesn't seem to work for Turn 0.

However, even after that first PUSHMISSION executes, the workers continue to move in the opposite direction - even after 3-4 PUSHMISSION statements later - they seem heckbent on going the opposite way - as if they're assigned to a different operation (they huddle together and move as a pack).

After so much time troubleshooting an issue that has a rather trivial impact on the game, I'm about decided to remove them initially, then spawn them in a logical place on the map on turn 3 and move on to better problems.

Thanks again.
 
Back
Top Bottom