Change localization strings during game?

Serp

King
Joined
Apr 1, 2015
Messages
661
Is it possible to change localization language strings during the game, eg. with lua?

I'm currently improving this mod https://forums.civfanatics.com/threads/civ-iv-traits-in-civ-v.530701/

This mod assigns 2 more character traits to every civilization, hardcoded in sql.
I added instead lua code that is distributing the traits randomly at the start of the game (via dummy policies and whowards bugfix).
The mod also hardcoded in sql a change in Leadernames, so that the Leadernames will show Icons next to them to indicate the new traits. But how do I add those icons to the leadernames now, after the game started and traits where randomly distributed?

Btw, is there any way to hook into a function? Eg. into the player:getName() or the Locale.ConvertTextKey ? This could be one solution, to add the icons to whatever getName returns, but I guess its not possible.

So maybe change databank entries directly, is this possible?

The last solution I can imagine is to change UI lua code files. But no clue which one I should choose, depending on installed mods like EUI or others, changes will be reverted or diploscreen is removed.
 
Btw, is there any way to hook into a function?
Only by modding the DLL and adding a GameEvent to ask if any mod wants to change the value - this would be horrendously slow

So maybe change databank entries directly, is this possible?
Also not possible, on start-up the database is cached in C++ class objects. Any changes to the database do not update the C++ cache, so are ignored. You could mod the DLL and add Lua API methods to update specific entries in the cache, but this almost certainly wouldn't be multi-player compatible
 
Updating textkeys has been done successfully in other mods.
For instance, in earlier versions UniqueDiplomacyUtils it was used to achieve unique diplomacy lines depending on which civilization the AI was 'talking to'.
(In v3, it seems to alter Diplomacy_Responses directly; the following method was left for compatibility and should not be used anymore in that mod).

It includes the following code:
Code:
-- (technically, you could use these to alter Game Text entries not related to
-- diplomacy. I won't stop you if you want to repurpose the code for that!)

-- This function replaces a specific diplomacy line with another from the
-- current locale.
-- Please remember that you will lose the line you're replacing, so bear that
-- in mind if you need it later.
function ChangeDiplomacyGameText(targetText, newText)
    if (targetText and newText) then
        local locale = "Language_" ..Locale.GetCurrentLanguage().Type;     
        local newTextTest;
        for _ in DB.Query("SELECT Text FROM " ..locale .." WHERE Tag='" .. newText .. "'") do newTextTest = _.Text end
        if newTextTest then
            -- gsub escapes the apostrophes so that we don't get an error
            for _ in DB.Query("UPDATE " .. locale .. " SET Text = '" .. string.gsub(newTextTest, "'", "''") .."' WHERE Tag='" ..targetText .."'") do end
            Locale.SetCurrentLanguage( Locale.GetCurrentLanguage().Type );
            --print(targetText .. " changed to " .. newText .. " in " .. locale .. "!");
        end
    end
end

The main trick here is using:
Code:
Locale.SetCurrentLanguage( Locale.GetCurrentLanguage().Type );
which actually makes the game use the updated textkeys.

---
The same question appeared in this thread as well:
https://forums.civfanatics.com/threads/lua-to-change-database-text-at-game-start.609098/
which referenced this post:
https://forums.civfanatics.com/thre...ough-sql-still-possible.535966/#post-13511608

Note that the post by JFD mentions that this resets upon game reload, meaning that the changes will need to be re-applied every time this happens.

---
I am unsure which effects (if any) changing textkeys would have on multiplayer.

NB: As is mentioned in the linked threads, this can be very slow if you update a lot of things!
 
Aaaah, yes, I already used and inspected Leugis Barbarian Immersion mod and that mod is changing the barbarian names with lua! and it has the same code you mentioned, how could I forget about it :D Thank you Troller0001 :)

assuming you have indeed change the strings everytime the game loads, what event should I use for it? Events.SequenceGameInitComplete or Events.LoadScreenClose?

edit:
I will use SequenceGameInitComplete, since then it already chages during the loading screen, which might be better regarding waiting for the changes (althouh I only change a handful of strings).

edit2:
It worked quite well :) But:
For whatever reason, leadernames that are pulled via "pPlayer:GetName()" are not affected (by changing eg. "TXT_KEY_LEADER_ALEXANDER" string). Does anyone know how GetName() works? Or which TXT_KEY it is using? Fortunately GetName() is not that often used in the game, but if someone knows more about it, that would make it perfect :)
 
Last edited:
I've seen people use both of them, but couldn't really find a difference with a quick search. (I've also used them in several of my mods without a clear reason why I chose one over the other, so there's that :confused:)

Looking at the source code itself, it seems like LoadScreenClose fires when the player actually clicks the "start game" (or "load game") button (see: LoadScreen.lua)
SequenceGameInitComplete calls a method that creates this "start game" (or "load game") button, and modifies some icons on the load screen (IIRC it adds the tooltips, but I wasn't that bothered to dig deeper in the game's source code).

Note: In multiplayer games, SequenceGameInitComplete directly calls LoadScreenClose (in LoadScreen.lua), meaning that LoadScreenClose fires directly after SequenceGameInitComplete in multiplayer games.
 
I was ujnder the impression that SequenceGameInitComplete only fires when a new game is created and not when a saved game is reloaded.

But I generally use LoadScreenClose if I need to delay until the user is fully in the game. Though this can cause perceptible lag to the user between the mouse-click and actually getting in-game when a long or complex script is executed.

Looking at some of my Civ5 code I'm pretty sure "Player:GetName()" returns the already-localized name of the Leader. "City:GetName()" also works the same way as I recall. You get "Augustus" or "Rome" instead of TXT_KEY_LEADER_AUGUSTUS or TXT_KEY_CITY_NAME_ROME. I don't find anywhere I'm localizing anything for a TXT_KEY result for those methods and I do know my code prints "Augustus" for example instead of a TXT_KEY value.

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

My suspicion is there might be pregame and ingame issues going on here with not reflecting changes made to the TXT_KEY value. I've never been 100% convinced that everything we see in the exposed databases are equal to everything that is actually used by the game.

Civ6 displays this really hard -- stuff added by the expansions cannot generally be affected by any attempt to do an UPDATE on any of the expansion-introduced TXT_KEYS because modding apparently can only affect the "debug" version of the localization and Firaxis have never followed through to make the expansions also add their stuff to the "debug" version of the localization database.

For Civ5 I might also be full of stuff on this point and it is just an issue with the way Views work as opposed to actual Tables, with the result that certain things are essentially cached in Civ5 when a game is first started and unless you delete the cache you won't see certain things getting altered by anything in a mod.
 
Last edited:
ehm... is there any reason why to use those game events at all?
Is there any downside if I simply execute the code, that I want to be executed at game start, directly in lua, without any function? Will all players already be placed at that time and will this also work in multiplayer (desync)?
I just added dummy policies this way and it seems to work.
Maybe related to this: My lua files needed "InGameUIAddin" to work, I guess this is because of "SequenceGameInitComplete" ? So if I dont use this, I also dont need InGameUIAddin, which might be good?
 
You want InGameUIAddin regardless of the hooks events you apply your code to, and even if not hooking your code into any events.

Your code will execute after map generation and player placements on the map as a general rule so far as my experience has shown. So you can for example look through all cities of all players to see if any have completed WonderX as the game loads and then have your code assign a listener (or not) to an appropriate hook event depending on whether or not the wonder has been completed by any player. You could also look through all units of all players as the game loads and record the positions of all these units into an lua table. I still tend to do these things in functions assigned to LoadScreenClose, myself, but you can in fact execute a lot of "set-up" code as the game loads without needing to assign anything to any hook events. The difference though is that your code in such cases will only ever execute once per game session as the game loads.
 
Last edited:
Top Bottom