• 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.

Help creating a unique unit ability

CMatthewT

Chieftain
Joined
Jan 16, 2021
Messages
2
Hi,

I'm creating a mod that adds a new Great Person. I want this unit to be able to "construct a wheat farm," that is, set the resource of the tile they're in to wheat and then place a farm on it. In other words, they will be able to instantaneously create an improved wheat tile anywhere a farm can be built regardless of whether wheat was actually on that tile to begin with.

I understand XML (more or less), and I've successfully created the Great Person and part of the ability.

XML (abridged):

<Builds>
<Row>
<Type>BUILD_WHEAT</Type>
<ImprovementType>IMPROVEMENT_FARM</ImprovementType>
<Description>Construct a Wheat Farm</Description>
<Help>Unit will be consumed.[NEWLINE][NEWLINE]Will transform this tile into an improved source of [ICON_RES_WHEAT] Wheat.</Help>
<Kill>1</Kill>
<EntityEvent>ENTITY_EVENT_MINE</EntityEvent>
<HotKey>KB_W</HotKey>
<OrderPriority>96</OrderPriority>
<IconIndex>21</IconIndex>
<IconAtlas>UNIT_ACTION_ATLAS</IconAtlas>​
</Row>​
</Builds>

So, I currently have a new Great Person that is consumed by building a farm. Of course, my profound lack of Lua savvy limits me here. (I know next to nothing about Lua.) I tried my best to finish this myself, but I really just need a solution here rather than a comprehensive beginner's guide to Lua.

I need to know how to set the tile's resource to wheat when the above build is prompted. (The resource should be set to Wheat BEFORE the farm is placed so that the improvement graphic looks like the normal wheat farm.)

Hopefully, this is a simple thing to figure out. Let me know if anything needs clarifying.

Thanks!
 
You've marked this as solved without giving the solution you used/found - makes it very hard for people who come after you with similar problems to find solutions.

What you want to do - change a tile mid-game - is one of the most complex pieces of Lua going, due to the number of edge cases it has to consider.

While pPlot:SetResourceType(iNewResource, iCount) looks like it should work, it is full of pitfalls.

If the tile is owned by a city, it needs to be unowned first, or any existing resource on that tile will still be used by the city, and the city will not pick up the new resource
However, before unowning the tile, if a citizen is working it, that citizen needs to be reassigned.
If there is an improvement on the tile, it needs to be removed.
However, it that improvement is pillage, it should be repaired first (or effects, like smoke pillars, can continue on the new resource)
There may be a unit (or units) dependent on that improvement - eg a ship in a coastal fort or planes on an airfield, so they will need relocating
There may be a unit in the process of building an improvement on the tile, they need to be stopped (don't forget some combat units can build improvements, so don't just look at workers)
Any existing resource needs to be removed (or the UI Icon Manager can get screwed up)
Now the new resource can be added and any improvement made
If the tile was unowned from a city, it needs to be reowned
The city citizens should all be reassigned depending on the focus of the city

Phew! (And I've probably forgotten a step or two)

The best place to find this code is in IGE
 
You've marked this as solved without giving the solution you used/found - makes it very hard for people who come after you with similar problems to find solutions.

What you want to do - change a tile mid-game - is one of the most complex pieces of Lua going, due to the number of edge cases it has to consider.

While pPlot:SetResourceType(iNewResource, iCount) looks like it should work, it is full of pitfalls.

If the tile is owned by a city, it needs to be unowned first, or any existing resource on that tile will still be used by the city, and the city will not pick up the new resource
However, before unowning the tile, if a citizen is working it, that citizen needs to be reassigned.
If there is an improvement on the tile, it needs to be removed.
However, it that improvement is pillage, it should be repaired first (or effects, like smoke pillars, can continue on the new resource)
There may be a unit (or units) dependent on that improvement - eg a ship in a coastal fort or planes on an airfield, so they will need relocating
There may be a unit in the process of building an improvement on the tile, they need to be stopped (don't forget some combat units can build improvements, so don't just look at workers)
Any existing resource needs to be removed (or the UI Icon Manager can get screwed up)
Now the new resource can be added and any improvement made
If the tile was unowned from a city, it needs to be reowned
The city citizens should all be reassigned depending on the focus of the city

Phew! (And I've probably forgotten a step or two)

The best place to find this code is in IGE
Apologies for not providing the solution. Even knowing very little about Lua, I was able to draw from various sources to come up with at least a partial solution.

I created a new improvement named IMPROVEMENT_WHEAT_FARM which is just a functionless fort graphic buildable by the Great Person in flat plains, grassland, and desert. When this is built, the below code 1) sets the tile's resource to wheat, 2) sets the improvement to farm, and 3) clears any feature that isn't flood plains:

function onImprovementCreated(iHexX, iHexY)
local pPlot = Map.GetPlot(ToGridFromHex(iHexX, iHexY))
if (pPlot:GetImprovementType() == GameInfo.Improvements.IMPROVEMENT_WHEAT_FARM.ID) then
pPlot:SetResourceType(6, 1)
pPlot:SetImprovementType(3)
if pPlot:GetFeatureType() ~= 4 then pPlot:SetFeatureType(-1) end​
end​
end
Events.SerialEventImprovementCreated.Add(onImprovementCreated)

I know this is kind of a clunky noob solution, but it's what worked for me. Of course, I hadn't considered the problems you're mentioning. For now, I'll unmark this as solved and update it with a better solution if/when I get all that stuff worked out.

Thanks!
 
Many SerialEvents don't fire unless the human player can see the "action". You need to ensure by testing (since I cannot remember if does or does not) that Events.SerialEventImprovementCreated fires even when the human cannot see the event.
Code:
pPlot:SetResourceType(6, 1)
Using hardcoded integer values rather than pulling the ID # from GameInfoTypes means that any mod which alters the order in which rows are placed in the Resources XML/SQL database table will cause your code to not place Wheat on the tile, but some other resource.
Code:
pPlot:SetResourceType(GameInfoTypes.RESOURCE_WHEAT, 1)
Same issue applies to "SetImprovementType" and "GetFeatureType".
 
Back
Top Bottom