game hangs when units are made immobile?

davidlallen

Deity
Joined
Apr 28, 2008
Messages
4,743
Location
California
I have an interesting problem with a promotion to make units run out of gas. It seems the standard game engine will hang, if a stack of units is in motion and suddenly one has a *negative* number of move points. This may not seem like a problem, but I cannot think of any easy workaround.

Here is how you can see the problem.

1. Take a completely vanilla game, no mods or extensions.
2. Copy units/civ4promotioninfos.xml to customassets, and modify one of the promotions (maybe "Guerilla I"). Change the one line:
<iMovesChange>-4</iMovesChange>
Let's call this the Promotion of Immobility, it's a catchy name. In my mod, it represents "Out Of Gasoline".
3. Start the game. Any map, etc.
4. In World Builder, give yourself two units in the same plot.
5. In the game, double click the two units to make a stack, and give them a move order to a distant destination.
6. Advance one turn so the two units are "in motion"
7. In WB, select one of the units and give it your Promotion of Immobility
8. In the game, mouse over *do not click* the stack. You can see that the unit has negative movement points available.
8. Click on your stack. The game freezes.

Now, if you had a unit with a movement of exactly one, and you gave it an iMovesChange of -1, then the unit would have zero movement points. In this case the behavior is still probably wrong, but at least it doesn't hang. The game computes the number of turns to reach the destination the same as before, but the stack doesn't move. If the destination was 5 turns away, it stays at 5 turns forever.

What I wanted to do, is have one Promotion of Immobility that could be attached to any unit. I am using -4 because a gunship has movement of 4, so when I attach the promotion to any unit it will have movement of zero or less and be immobile. Depending on which other promotions the unit may have, its movement could normally be 1,2,3,4. I really don't want to have four immobility promotions and then have to pick out the right one. There is some chance that I may accidentally choose too low a value and the unit could still move slowly, or I may accidentally choose too high a value and run into the hanging problem.

Can anybody suggest a "safer" way to achieve immobility?
 
I can think about 2 solutions :

_ add an attribute to the unit isImmobile with a function setImmobile(bool). And add in the canMove function if(isImmobile) return false; .I think this is the safest way.

_ set an immobile timer of 999 when you add the promotion(without reducing the movement), and remove the timer when you remove the promotion.

I have tried to do such a thing when i wanted to have immobile guardians. I've stopped since i encounter a lot of problems. The solution are just 2 ideas and i don't know if they are safe.
And you can end up with some infinite loops when a unit in a stack can't move(don't know if this has been fix with 3.17). For an example the group need to split to enter a boat, the group split but stay in place because an unit can't move. On the next update the group merge and so on.I've seen 2 or 3 case like that with an immobile unit.

Tcho !
 
There is a simple way to get around it, create copies of all gas unit, but append _IMBL to the unit name. Make the iCost -1 and iMoves 0. So they can't be built, and can't move. Now just change the gas truck function from giving the "out of gas" promo to changing the unit to the _IMBL one (get stats on the old unit, create _IMBL unit, add promos, experience to it).
 
There is a simple way to get around it, create copies of all gas unit, but append _IMBL to the unit name. Make the iCost -1 and iMoves 0. So they can't be built, and can't move. Now just change the gas truck function from giving the "out of gas" promo to changing the unit to the _IMBL one (get stats on the old unit, create _IMBL unit, add promos, experience to it).

That is a good suggestion. I found another way, which is working but it is hard for me to tell how much it slows the game down. When I immobilize the unit, I give it a promotion. Then in unitCannotMove, I check for this promotion and return true. The check is very fast, but I imagine it is called very often as the unit tries to move all different places.
 
Two other comments on the proposed "_IMBL" approach.

* I have about ten such units which could be immobile. Creating the unitinfos entries is trivial with copy/paste. But, each such unit also shows up in the civilopedia. This is "noise". Is there a way to prevent these special-effect-only units from showing up there? (This would be helpful for something else also, it would be possible to add "surprise" units that are not spoiled by their civilopedia entries)

* I must be missing something about how to get the experience copied correctly. See my post in this nearby thread. Have you done this before, could you point me to the code?
 
You could edit the CvPediaUnit.py and tell it to skip the units you don't want shown when it does the loop over all the unit infos.
 
Update: Sto has given the solution to my problem with experience points. There is a python function "convert" which does exactly what I need: "pNew.convert(pOld); pOld.kill()" is all that I need.

Also, regarding runtime, the cannotMoveInto approach *doubles* the runtime of the mod!! Since I am not directly telling the AI the unit can't move, I guess it spends a huge amount of time trying to move each unit everywhere, until it gives up. A 350 turn autoplay with everything "on" takes 105 minutes. The same start position, with everything except cannotMoveInto commented out, takes 104 minutes. With cannotMoveInto also commented out, it takes 52 minutes.

I will try Primordial Stew's suggestion of making _IMBL copies, along with Jeckel's suggestion about skipping them in the pedia.
 
Update: skipping the units in the pedia is possible, but not so simple.

1. Make sure that each immobile unit has its own unitclass. If UNIT_TANK_IMBL has UNITCLASS_TANK, then the pedia for tank will display "Replaced by Immobile Tank".

2. There is a function placeUnits in CvPediaMain.py which builds the five column list of units in the main square panel on the left, when you select "Units" in the single column right side panel. Modify this to skip the immobile units. I did it by deleting them from the list.

3. There is a function placeLinks in CvPediaUnit.py which builds the list of units in the single column right side panel, when you click on units in the left panel. Modify this to skip the immobile units. You cannot delete them from the list, you must skip them, because the loop is over indices from 0 to getNumUnitInfos. If you make the list shorter it gets out of sync.

4. I haven't done this last part yet. But, as a result of #1, we have introduced a bunch of new unitclasses. These now show up in the unitcombat list. When you select "Unit Categories" in the top menu, you get a list of unitcombats, when you click on a unitcombat such as "Melee Units" you get a table showing the name, cost, strength of each unit with that unitcombat. The code to build this table will also need to be modified to skip the immobile units.

This code should be available in the next rev of Fury Road, version 0.7 or later, in case you want a working example.
 
Back
Top Bottom