Finding next to nothing to help me learn how to mod this game

Adam Hall

Chieftain
Joined
Aug 9, 2017
Messages
20
I have modded at least two other games, not a CIV one before though. Generally I can pick it up by reading various posts, doco, example mod source, etc... For this game, I have found next to nothing. The best source I have seen is the "LUA Objects" spreadsheet. And that barely helps at all. It doesn't give function parameters or their return values for example. And the "Fire Tuner". Forget it.

Let me start basic and see if anyone can help me. How can I execute some code when a city has started producing something? I know LUA very well. In other game modding, these event handlers are called "hooks". What hook can I use to do this? Where are any of the hooks documented???

Any help in anything beyond simple stuff like adding XML entries to create your own "whatever" would be very helpful.

Thanks
 
Firaxis hasn't released anything looking like a documentation this time, and I'm afraid that's not going to change.

So our only hope for a documentation is to have the DLL source code released soon so we can find out the functions parameters ourselves, until then modding is a game of guess. Terrible waste of time, yes.

Now coming from civ5, some of the function are similar, so it helps a bit.

For your question maybe Events.CityProductionChanged or Events.CityProductionUpdated

the first two parameters are playerID and cityID, unsure of the order of the rest, but one is ProductionTypes (as in ProductionTypes.BUILDING) and another the objectID (like the Building or Unit ID)
 
OK, I did see: Events.CityProductionChanged. But I still don't get how to use it. Is it to change the production? Will it return what is being produced? And of course how can the game call my code to do anything?

If this is all we get for doco on this stuff, shame on Firaxis for even claiming to call this game moddable. I am sorry but only being able to make a new CIV with a fancy name and maybe my name as the leader, is not moddable in my book.
 
Functions added to Hook events in Civ6 generally do not return data, they are passed data via the arguments Firaxis has programmed the event to pass along to any function subscribed as a listener to a given game event.

In the case of Events.CityProductionChanged we write a listener (or "hooked" event) that executes based on the data passed whenever the event fires. Note that it fires when a player changes the item they are producing in a city:
Code:
function OnCityProductionChanged(iPlayer, iCityID, ItemTypeReference, ItemID, UnknownInteger)
	--the event is for when the Item in the qeue is changed to something else, not for when more 'cogs' are added to the Item's progress
	--ItemTypeReference = 0 : -> UNIT
	--ItemTypeReference = 1 : -> BUILDING
	--ItemTypeReference = 2 : -> DISTRICT
	--ItemTypeReference = 3 : -> PROJECT
	--ItemID = -1 when ItemID was purchased
	--UnknownInteger = 0 except when item is purchased, in which case it appears to be equal to (CityID - 1)
	print("City Production Item changed for Player " .. iPlayer .. " in city with ID# of " .. iCityID .. ": ItemTypeReference was " .. ItemTypeReference .. " and ItemID was " .. ItemID)
end
Events.CityProductionChanged.Add(OnCityProductionChanged)
  • All this would do is make a print statement in the game's lua.log.
  • Since the game engine is not looking for a return data from any function hooked to Events.CityProductionChanged even if you add
    Code:
    return iPlayer
    before the end of the quoted function this would not have any effect on anything because the game engine is not looking for anything to be sent back.

This is another example of the same hook event from a mod where I am using it to determine if another function should be fired
Code:
function OnCityProductionChanged(iPlayer, iCityID, ItemTypeReference, ItemID, UnknownInteger)
	--OnCityProductionChanged(iPlayer, iCityID, ItemTypeReference, ItemID, UnknownInteger)
	--ItemTypeReference = 0 : -> UNIT
	--ItemTypeReference = 1 : -> BUILDING
	--ItemTypeReference = 2 : -> DISTRICT
	--ItemID = -1 when ItemID was purchased
	--UnknownInteger = 0 except when item is purchased, in which case it appears to be equal to (CityID - 1)
	local pCity = Players[iPlayer]:GetCities():FindID(iCityID)
	PrintToLog("[OnCityProductionChanged] fired for the city of " .. Locale.Lookup(pCity:GetName()) .. " with values of iPlayer = " .. iPlayer .. ", iCityID = " .. iCityID .. ", ItemTypeReference = " .. ItemTypeReference .. ", ItemID = " .. ItemID .. ", UnknownInteger = " .. UnknownInteger)
	if ItemTypeReference == 0 then
		PrintToLog("[OnCityProductionChanged] dummy building placements are being re-evaluated for the city of " .. Locale.Lookup(pCity:GetName()))
		SetCityUnitProductionModifiers(pCity)
	end
end
Again, nothing is returned from the original function OnCityProductionChanged I created. The function merely uses the data passed to it from the game engine.
 
@LeeS, thanks! That is exactly what I was looking for as a start. At the need I see you call this:
SetCityUnitProductionModifiers(pCity)

I don't see that function in the LUA objects spreadsheet which is my only source. My true goal is to be able to modify what a city decides to build. Is that somehow related to changing what a city builds?
 
SetCityUnitProductionModifiers(pCity) is a function I created within my lua file to do stuff to the specified city whose lua object is temporarily being used in variable pCity

I did not post the code of the function I wrote and called SetCityUnitProductionModifiers(pCity) because it is long and involved.
 
SetCityUnitProductionModifiers(pCity) is a function I created within my lua file to do stuff to the specified city whose lua object is temporarily being used in variable pCity

I did not post the code of the function I wrote and called SetCityUnitProductionModifiers(pCity) because it is long and involved.

Oh ok. I guess my question is, can we alter what a city builds?
 
we can remove an item from their "qeue" but we have no way I know of to set the item the city is building.

Here's an example file from one of my mods:
Code:
local bDebugPrint = false
	-- this controls debug printing

function PrintToLog(sMessage)
	if bDebugPrint then
		print(sMessage)
	end
end
function OnCityProductionChanged(iPlayer, CityID, ItemTypeReference, ItemID, UnknownInteger)
	local pCity = Players[iPlayer]:GetCities():FindID(CityID)
	PrintToLog("[OnCityProductionChanged] fired for the city of " .. Locale.Lookup(pCity:GetName()) .. " with values of iPlayer = " .. iPlayer .. ", CityID = " .. CityID .. ", ItemTypeReference = " .. ItemTypeReference .. ", ItemID = " .. ItemID .. ", UnknownInteger = " .. UnknownInteger)
	if ItemTypeReference == 1 then
		if ItemID >= 0 then
			local tBuildingData = GameInfo.Buildings[ItemID]
			if pCity:GetBuildQueue():CurrentlyBuilding() == tBuildingData.BuildingType then
				if (tBuildingData.IsDummy == true) then
					PrintToLog("[OnCityProductionChanged] !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
					PrintToLog("[OnCityProductionChanged] an attempt was made to construct a dummy building in the city of " .. Locale.Lookup(pCity:GetName()) .. ": " .. tBuildingData.BuildingType)
					PrintToLog("[OnCityProductionChanged] the attempt was intercepted and disallowed")
					PrintToLog("[OnCityProductionChanged] !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
					pCity:GetBuildQueue():RemoveBuilding(ItemID)
				end
			end
		end
	end
end
function OnLoadScreenClose()
	Events.CityProductionChanged.Add(OnCityProductionChanged)
end
Events.LoadScreenClose.Add(OnLoadScreenClose)

print("KeepAIFromBuildingDummies.lua loaded to end of file successfully")
Altho I can probably get rid of this lua code in my mod entirely since I am using an alternative method of locking all players from attempting to construct any building where column IsDummy is set to boolean true

If you are confused by where this column IsDummy came from, I add it to the game as part of the mod.

---------------------------------------------------

Also, you can do a RemoveBuilding and a RemoveDistrict but so far as I know there is no RemoveUnit or RemoveProject available to City:GetBuildQueue()

---------------------------------------------------

This bit of the code
Code:
function OnLoadScreenClose()
	Events.CityProductionChanged.Add(OnCityProductionChanged)
end
Events.LoadScreenClose.Add(OnLoadScreenClose)
creates a function that fires upon the human player clicking the "globe" symbol when the game is ready to start play of the game either upon a new game set-up or reload of a saved game. This function delays the OnCityProductionChanged function from being added as a listener to Events.CityProductionChanged and thereby keeps the code from firing at all as part of the game starting/reloading process. Otherwise as the game loaded a save the function would fire for each and every city already placed on the map, and depending on what I coded OnCityProductionChanged to do might have undesired effects on the conditions of the game after a save reloads. Stuff like projects suddenly magically completed or whatever, depending on what the code within my function might be. So as a general rule I delay hooking up my functions to the game events until "LoadScreenClose".
 
Last edited:
@LeeS. Ok, thanks for replying. I guess I am not surprised we can't control what is built. It goes along the lines of why the AI is still awful for this game. They don't give us the ability to modify basic behaviors like this. So modders can't fix an AI that Firaxis hasn't been able to get right in 9 months.
 
You absolutely can change what the AI builds by changing their preferences. There are many preferences defined through XML that you can edit using XML/SQL. It also seems that the AI does recognize when you attach MODIFIERS to things. MODIFIERS are Civ6's way of handling most of the moddable gameplay. Lua seems to be mostly used for UI.
 
You absolutely can change what the AI builds by changing their preferences. There are many preferences defined through XML that you can edit using XML/SQL. It also seems that the AI does recognize when you attach MODIFIERS to things. MODIFIERS are Civ6's way of handling most of the moddable gameplay. Lua seems to be mostly used for UI.

I have looked extensively at the XML. I also have done some simple test mods updating XML and doing SQL. But I have yet to see something that could help me in this regard.

Let's say I want the AI to build more naval units than it currently does. Where would I even look? For example, I did update GlobalParameters.AI_ISLAND_COAST_PERCENTAGE via SQL in a mod. It did not affect the AI in any way that I could tell.
 
You absolutely can change what the AI builds by changing their preferences. There are many preferences defined through XML that you can edit using XML/SQL. It also seems that the AI does recognize when you attach MODIFIERS to things. MODIFIERS are Civ6's way of handling most of the moddable gameplay. Lua seems to be mostly used for UI.
we were talking about lua code to directly set what a given city is producing at a given point rather than the AI preferences as to what to try to build.
 
I have looked extensively at the XML. I also have done some simple test mods updating XML and doing SQL. But I have yet to see something that could help me in this regard.

Let's say I want the AI to build more naval units than it currently does. Where would I even look? For example, I did update GlobalParameters.AI_ISLAND_COAST_PERCENTAGE via SQL in a mod. It did not affect the AI in any way that I could tell.
AiLists, AIFavoredItems, AiListTypes are where you would probably want to start in driving what an AI will tend to want to build but this is not the same as directly determining what a city is building. A good place to start examining how these three tables work would be Leaders.xml
 
we were talking about lua code to directly set what a given city is producing at a given point rather than the AI preferences as to what to try to build.
CityManager.RequestOperation is not working for the AI ?

I know that I've not found a way to use the equivalent (UnitManager.RequestOperation) for units (the move order seems to be given by the AI before I can give mine after the movements points are restored), but I assumed that I wouldn't have the same issue for the city build queue (but I've not tested it yet)
 
CityManager.RequestOperation is not working for the AI ?
You don't show it as valid in GameplayScript.

I don't tend to work in UI side unless I have to to get a specific effect, like hiding dummy buildings from the ProductionPanel.

UI is just mind-numbing AssignStartingPlots.
 
I have looked extensively at the XML. I also have done some simple test mods updating XML and doing SQL. But I have yet to see something that could help me in this regard.

Let's say I want the AI to build more naval units than it currently does. Where would I even look? For example, I did update GlobalParameters.AI_ISLAND_COAST_PERCENTAGE via SQL in a mod. It did not affect the AI in any way that I could tell.

That sounds like it affects how likely they are to settle coastally, but idk.

If you want them to build more naval units, I believe you have a few choices. You can buff naval units in a way that is obviously connected to something the AI can "rate" (such as their combat strength), you can add specific units to the list of Favored Items, you can change the pseudoyield (how much value the AI assumes something has) of the naval units, you can give the AI a boost to producing naval units (so when they do decide to make them, they make more. I'm not sure if the AI actually recognizes it has this bonus...it seems to, from my testing), and I think you might be able to change how much they value each pseudoyield (but idk where to do that).

we were talking about lua code to directly set what a given city is producing at a given point rather than the AI preferences as to what to try to build.

Right, I was just trying to give a general overview of what kind of effects can be done where, since OP was claiming nothing was moddable at all.

AiLists, AIFavoredItems, AiListTypes are where you would probably want to start in driving what an AI will tend to want to build but this is not the same as directly determining what a city is building. A good place to start examining how these three tables work would be Leaders.xml

^^^

Alternatively, download one of the other AI mods and see what they do (AI+, Artificially Intelligent)
 
AiLists, AIFavoredItems, AiListTypes are where you would probably want to start in driving what an AI will tend to want to build but this is not the same as directly determining what a city is building. A good place to start examining how these three tables work would be Leaders.xml

Finally tried some of these out. I update 2 rows with SQL. Whatever I did worked! The AI started making way more naval units. Too many actually but that's ok. I set it real high to see if I would notice.

So here is what I changed. I still do not know what exactly what each change does:

update PseudoYields
set DefaultValue = 99.0
where PseudoYieldType = 'PSEUDOYIELD_UNIT_NAVAL_COMBAT';
-- XML had 1.0
-- What is strange is the database itself ended up getting a value of 297!

update AiFavoredItems
set Value = 500
where ListType = 'NavalUnitPreferences'
and Item = 'PSEUDOYIELD_UNIT_NAVAL_COMBAT';
-- XML had 150

Any ideas what these mean exactly? Thanks.
 
A pseudoyield gives the AI a rough estimate of the "value" of something. Since most of the game is about gaining/converting/spending yields, they decided to call this a "pseudo" yield. So while the AI may have a tough time figuring out how much value they are getting out of a military unit, you can give it a pseudoyield so it has a guess.

The preferences I believe are multiplied by the pseudoyield in some fashion to produce an actual decision. This way not all the AIs play identically all the time, since you can set preferences differently for each. So Victoria may have a high preference for Naval Combat units, for example.

Basically, the pseudoyield is the objective value of an item, and a preference is a particular AIs judgement of that category of item.

Someone who knows more, please feel free to correct me.
 
Back
Top Bottom