Updated City Name Manager

Baldyr

"Hit It"
Joined
Dec 5, 2009
Messages
5,530
Location
Sweden
This project is abandoned but will probably be replaced by another some time in the future. Thanks goes out to all that contributed to it however.
Spoiler :
No, this is not about adding entries to the City Name Manager - thats another thread altogether. What I'm proposing to do is cut out some 3000 lines of Python code from the current CityNameManger.py file by replacing that code with "data structures".

This will have several benefits. First and foremost it will also enable non-programmers to easily edit the city name entries. Another benefit is that manually changing the default city name no longer disables the dynamic name changes when the city is acquired by another Civ. This because the new set of code will lookup the actual map tile and not all the known city name aliases. Furthermore, we can have default city names for map tiles that are available for all Civs, even the minor ones who don't have City Name Maps. (This is also helpful for modders and scenario makers.)

Hopefully the code will run faster, also, but I have no proof to support such claims at this point. :p

So, I've made a Python script that will convert all the city name changing code into the new setup. This is an example of the tile designated as the Roman starting location:
Code:
( [COLOR="Sienna"](60, 44)[/COLOR], [COLOR="DarkGreen"]'Roma'[/COLOR], [COLOR="DarkSlateBlue"]{iChina:'Daqin', iArabia:'Rumiya', iFrance:'Rome', iGermany:'Rom', iNetherlands:'Rome'}[/COLOR] )
So once I run my script on the whole map, tile by tile, city name map by city name map, this is what the computer generated entries could look like. Before I go into the specifics of what it contains, I thought I'd show you what lines of code this single line would replace:
Spoiler :
Code:
                        elif (sName == 'Rome' or sName == 'Rom' or sName == 'Rumiya' or sName == 'Roma'):
                                city.setName('Daqin', False)

                        elif (sName == 'Rome' or sName == 'Rom' or sName == 'Roma' or sName == 'Daqin'):
                                city.setName('Rumiya', False)

                        elif (sName == 'Rome' or sName == 'Rom' or sName == 'Rumiya' or sName == 'Daqin'):
                                city.setName('Roma', False)

                        elif (sName == 'Roma' or sName == 'Rom' or sName == 'Rumiya' or sName == 'Daqin'):
                                city.setName('Rome', False)

                        elif (sName == 'Roma' or sName == 'Rome' or sName == 'Rumiya' or sName == 'Daqin'):
                                city.setName('Rom', False)

                        elif (sName == 'Roma' or sName == 'Rom' or sName == 'Rumiya' or sName == 'Daqin'):
                                city.setName('Rome', False)

                        elif (sName == 'Rome' or sName == 'Rom' or sName == 'Rumiya' or sName == 'Daqin'):
                                city.setName('Roma', False)

                        elif (sName == 'Rome' or sName == 'Rom' or sName == 'Rumiya' or sName == 'Daqin'):
                                city.setName('Roma', False)
Now I have to convince you that the above line is more easy to read and edit...

So, the whole line is enclosed in a pair of parenthesis - this makes it a data structure. The first piece of data inside this data structure (known as a "tuple") is this:
Code:
(60, 44)
The first value is the X coordinate for Rome, and the second value is the Y coordinate. The enclosing parenthesis is just what I said before - it makes this data entry a data structure (tuple) in it-self. But we could skip those and just go with two integer values:
Spoiler :
Code:
( [COLOR="Sienna"]60[/COLOR], [COLOR="Sienna"]44[/COLOR], [COLOR="DarkGreen"]'Roma'[/COLOR], [COLOR="DarkSlateBlue"]{iChina:'Daqin', iArabia:'Rumiya', iFrance:'Rome', iGermany:'Rom', iNetherlands:'Rome'}[/COLOR] )
What do you think? Which would be easier in the long run?

Ok, moving on:
Code:
'Roma'
The next piece of data is called a string as it consist of a set of characters - enclosed in a pair of quotations. (Double quotations work just the same.) This would be the default city name for the city located on the tile. So unless some other name is specified for a given Civ, this default name will be used instead.

On to the main attraction:
Code:
{iChina:'Daqin', iArabia:'Rumiya', iFrance:'Rome', iGermany:'Rom', iNetherlands:'Rome'}
This is one single data structure called a "dictionary" as indicated by the curly brackets at each end. This particular dictionary holds 5 entries, each consisting of a pair of values divided by a colon. The first value - the "key" - is a constant variable corresponding to a indexed Civ. The second value in each pair is the city name alias for that Civ, expressed as a string (note the quotations).

Personally I think this new setup is much more clear and also easier to edit. Especially as it involves no actual programming - so you don't have to worry about indentation or logical expressions. The best part is of course that any change or addition you make don't have to be reflected on multiple places in order to work!

Now, what does the community at large think about such a setup? Have I failed to take something into account? (Like what if the city isn't built on the specified map tile?) Is there additional functionality that could be built into an "enhanced" City Name Manager? Could the actual city name entries be formatted in some other fashion?
 
Let me start by saying what a great work you do, Baldyr. Thanks.

Now, concerning the city name manager, there's a question that's bugged me to no end since I began playing RFC:

Why the heck do I found "Murcia" in Australia as the Spanish??? :mad:

I know, because there is no Australia on their settlermap. :lol:

Also, though this is extremely rare, sometimes the AI will send a settler on a galleon, find on arrival that the plot is taken by other civ, and just found the city near it... out of its settlermap.

But can't that change?

Can't the city name manager pick a name for a city found from another civ that does have a name for the plot? Is this doable?
 
This is actually one of the things I believe an update could achieve.

edit: Or, I might have misinterpreted the question. :rolleyes: What exactly did you request?
 
This is actually one of the things I believe an update could achieve.

edit: Or, I might have misinterpreted the question. :rolleyes: What exactly did you request?

Code:
If civ settled plot 
then use name from settler map
else use name from another civ's settler map for plot
how's that?
 
How would your scheme handle tiles that can represent more than one city?

For example if Northern Florida is colonized by a European power, the name when America flips it can vary. It could be Fort Caroline if flipped from the French, Saint Augustine if flipped from the Spanish or Jacksonville.

Another example, Rome uses one set of city names for when it settles southern Italy and a different set when it flips a Greek city.
 
Code:
If civ settled plot 
then use name from settler map
else use name from another civ's settler map for plot
how's that?
Basically, yes. But I would add the information from the settler maps into the data, so it would be the same.
 
How would your scheme handle tiles that can represent more than one city?

For example if Northern Florida is colonized by a European power, the name when America flips it can vary. It could be Fort Caroline if flipped from the French, Saint Augustine if flipped from the Spanish or Jacksonville.

Another example, Rome uses one set of city names for when it settles southern Italy and a different set when it flips a Greek city.
Ok, I didn't realize there was such exceptions to what I perceived as the "rule". :p

The Florida example would have to be considered, yes. Perhaps it could be a entry without any map tile coordinates - then the code would just lookup the city name aliases in the dictionary. Or there could be another value representing the owner of the tile - which means that the Fort Caroline/Saint Augustine tile would have two entries with different prerequisite owners.

The Roman example would be covered by default, as the code would still refer to the Roman city name map for founded cities - but look in the data for any acquired cities (flipped in this case).

This is actually good stuff, so keep the special cases coming. :goodjob: Some of these issues would need to be dealt with manually, so any help from someone who knows the content of the City Name Manager with checking everything before release would be very helpful!

But I count on being able to handle most of the converting with a script. But all sorts of special cases would either have to be built in - or added after the actual conversion. (I noticed some Byzantine city names that depended on which scenario is currently used, among other things.)
 
Baldyr, now I'm totally convinced that your system will work much better for further development!

I'm looking forward to see your first version finished and see it work for the mod.

If you need any assistance, please say so.
 
I guess two features in the original file are missing.

1) Era based city name changes, e.g., Nidaros becomes Trondheim in Renaissance
2) Some “special” acquisition based city name changes, e.g., Chinese city of Sanshan becomes Dal'nij if Russia controls it, and Dal'nij becomes Dalian if China got it back – the name does not go back to Sanshan

Other than that, everything looks totally wonderful.
 
I think it's all a matter of the word: if (or elif in Python).

Baldyr obviously is eager to make this work, so I guess he will think of a solution for this as well.
 
For starters I actually was just gonna replace the current renameCities() section of the City Name Manager, since the other ones - sovietNames() and onTechAcquired() probably work alright with the current code. (I'm not aware of any issues with it, at least. If you can think of one, then lets fix it too.)

But these things could of course also be processed into a more manageable setup later. Like a another data structure for civil/tech/era based city name changes.

Do you think we can get past the special cases where the renaming depends on the previous owner of the city (The Sanshan/Dal'nij/Dalian example) if we have two entries for the tile:
Code:
( (iX, iY), 'Sanshan', [B]iChina[/B], {iRussia:"Dal'nij"} )
( (iX, iY), None, [B]iRussia[/B], {iChina:'Dalian'} )
So the iX and iY values would be the actual coordinates (which I don't currently have, but my script will of course fill those in on its own). The highlighted value(s) is new and indicates city ownership.

The default name for the tile is Sashan - unless Russia founds/acquires the city - then it will be Dal'nij. The next line has no default name (its replaced with a placeholder None value) but the ownership is Russian. If China acquires the city from Russia, then the city will rename Dalian. (It would of course be easy to add a Japanese and Mongol entry as well - this is the whole point of such a setup.)

Its all a matter of logic, but I doubt I will catch all these special cases running a script on the current City Name Manager, so I'll need help checking things once I have done the conversion... :p I'll just post the whole thing here once I'm done, for proofreading.
 
I've been trying to get the conversion script to recognize the special cases (whether they are intentional or not in the current City Name Manager) and I think I finally solved it. If someone can give me actual tile coordinates for tiles with such exceptions (like the Chinese or the Florida examples) I could actually try it!
 
Ok, so I've run the script on the entire City Name Manager (city name maps + renameCities()) and have some interesting results.

This is what my script produced for the tile (17, 37) for instance:
Code:
( (17, 37), 'Tenochtitlán', iMaya, {iMali:'Cidade do México', [COLOR="Red"]iRussia:'Mexico'[/COLOR], iEngland:'Mexico City', iSpain:'Ciudad de México', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} ),
[COLOR="Red"]( (17, 37), '', iRussia, {iRussia:'Mekhiko'} ),[/COLOR]
( (17, 37), 'Ciudad de México', iSpain, {iMali:'Cidade do México', [COLOR="Red"]iRussia:'Mexico'[/COLOR], iEngland:'Mexico City', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} ),
[COLOR="Red"]( (17, 37), '', iRussia, {iRussia:'Mekhiko'} ),[/COLOR]
( (17, 37), 'Mekhiko', iRussia, {iMali:'Cidade do México', [COLOR="Red"]iRussia:'Mexico'[/COLOR], iEngland:'Mexico City', iSpain:'Ciudad de México', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} ),
( (17, 37), 'Tenochtitlán', iInca, {iMali:'Cidade do México', [COLOR="Red"]iRussia:'Mexico'[/COLOR], iEngland:'Mexico City', iSpain:'Ciudad de México', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} ),
[COLOR="Red"]( (17, 37), '', iRussia, {iRussia:'Mekhiko'} ),[/COLOR]
( (17, 37), 'Mexico City', iAztecs, {iMali:'Cidade do México', [COLOR="Red"]iRussia:'Mexico'[/COLOR], iSpain:'Ciudad de México', iFrance:'Mexico', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} ),
[COLOR="Red"]( (17, 37), '', iRussia, {iRussia:'Mekhiko'} ),[/COLOR]
The red lines are the result of obvious errors in the current City Name Manager, as the Russian city name is "Mekhiko" according to the city name map, but according to the renameCities() code it will change to "Mexico" on acquisition. This inconsistency is what caused my script to produce all these nonsensical entries. So this needs to be cleaned up manually. The good thing is, of course, that we were able to spot a bug. :goodjob:

So this is what we could get with a little editing:
Code:
( (17, 37), 'Tenochtitlán', iMaya, {iMali:'Cidade do México', iRussia:'Mekhiko', iEngland:'Mexico City', iSpain:'Ciudad de México', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} )
( (17, 37), 'Ciudad de México', iSpain, {iMali:'Cidade do México', iRussia:'Mekhiko', iEngland:'Mexico City', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} )
( (17, 37), 'Mekhiko', iRussia, {iMali:'Cidade do México', iRussia:'Mekhiko', iEngland:'Mexico City', iSpain:'Ciudad de México', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} )
( (17, 37), 'Tenochtitlán', iInca, {iMali:'Cidade do México', iRussia:'Mekhiko', iEngland:'Mexico City', iSpain:'Ciudad de México', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} )
( (17, 37), 'Mexico City', iAztecs, {iMali:'Cidade do México', iRussia:'Mekhiko', iSpain:'Ciudad de México', iFrance:'Mexico', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} )
But all this data is still redundant - we want to get it down to one single line, if possible (no special cases). The problem would be that I've converted this information from the city name maps - and Mexico City is present on five of them... :p

So we have to pick which one is the default city founder for that tile, and I propose the Mayas:
Code:
( (17, 37), 'Tenochtitlán', iMaya, {iMali:'Cidade do México', iRussia:'Mekhiko', iEngland:'Mexico City', iSpain:'Ciudad de México', iFrance:'Mexico', iAztecs:'Mexico City', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} )
This should do it, right? So we simply delete all but one entry and make sure there are not obvious mistakes translated into the new setup.
 
Another special case: when Incas or Aztecs manage to retake their cities, the city names should not be changed at all. Otherwise, we could see Ciudad de Mexico renamed back into Tenochtitlan.
This is a pretty amazing co-incidence! I noticed that you had posted about Mexico City while I was doing my example above! :eek:

Well, how this would (could) work is that the city will be named whatever it says in the founder's city map. But if there is no entry the city would get the default name, in this case the Mayan name Tenochtitlán. If we want to prevent this from happening we simply have to edit the city name maps so that the tile is covered in more of them.

So if the Mayans retake the city from the Spanish it will rename back into Tenochtitlán - unless we add a special case:
Code:
( (17, 37), '', iSpain, {iMaya:'Ciudad de México'} ),
Or, we could just have the default name of the city be "Mexico City" without any default founder:
Code:
( (17, 37), 'Mexico City', None, {iMali:'Cidade do México', iRussia:'Mekhiko', iSpain:'Ciudad de México', iFrance:'Mexico', iMongolia:'Mexico', iRome:'Mexicopolis', iNetherlands:'Mexico-stad', iGermany:'Mexiko-Stadt', iVikings:'Mexico'} )
Note that there is no need to have any entry for "Mexico City" if this is the default name, so I deleted the Aztec and English entries from the dictionary. And since there are no Mayan or Incan entries the city would rename into the default name on acquisition. (It would still be Tenochtitlán if they actually found it.)

Does this compute with the crew?
 
On the to the next issue: Multiple tiles with the same city name:
Code:
( (11, 46), 'Los Angeles', iSpain, {iJapan:'Rosu', iRussia:'Los-Andzheles'} ),
( (11, 46), 'Los Angeles', iAztecs, {iJapan:'Rosu', iRussia:'Los-Andzheles'} ),
( (11, 47), 'Los Angeles', iSpain, {iJapan:'Rosu', iRussia:'Los-Andzheles'} ),
( (11, 47), 'Los Angeles', iAztecs, {iJapan:'Rosu', iRussia:'Los-Andzheles'} ),
If we start by choosing to keep the Spanish entries and delete the Aztec ones:
Code:
( (11, 46), 'Los Angeles', iSpain, {iJapan:'Rosu', iRussia:'Los-Andzheles'} ),
( (11, 47), 'Los Angeles', iSpain, {iJapan:'Rosu', iRussia:'Los-Andzheles'} ),
This works exactly the same, so its good riddance. But we still don't need a double-entry, so we simply choose to keep the one and delete the other. Lets, for the sake of argument, keep the first one. (Someone would actually have to check the actual map tiles and compare with real-world geography which one is more accurate.)
Code:
( (11, 46), 'Los Angeles', iSpain, {iJapan:'Rosu', iRussia:'Los-Andzheles'} ),
Now, this would seem to make the new City Name Manager less efficient than the original one, because the Los Angeles wouldn't change name to the Japanese or the Russian city name alias if it was founded on the other tile (or any other tile for that matter).

My solution is this: Whenever a city changes hands - and there is no map tile entry for that tile - then the new City Name Manager will look for a map tile entry for any adjacent tile instead. If there is one, then the code will look in the city name alias dictionary for that tile and change the name accordingly.

So if Los Angeles was built on tile (11, 47) then the code would detect the entry for the adjacent tile (11, 46) and the city would change names anyway. Note that this could also work if the city was named something else than "Los Angeles" - but do we want that?
 
Also, I realized that there probably is no need for a default Civ for city tiles, so I adjusted my script accordingly. If its a special case, then the default city name would be replaced by a Civ instead.

Example:
Code:
( (88, 35), [B]'Mumbai'[/B], {iEngland:'Bombay', iJapan:'Munbai', iMali:'Bombaim'} ),
( (88, 35), [I]iEngland[/I], {iJapan:'Bonbei'} ),
The first line is the default name for the tile (bold) and the dictionary holds the English, Japanese and Malinese city name aliases.

The second line constitutes the special case, where the Japanese city name alias will instead be "Bonbei" (and not "Munbai") if the city was acquired from the English (italic).

Does this address the special cases?
 
So, if I understand it correctly, default names would be defined for the plots, and then exceptions for some civs on founding and/or taking the city later.

(?)

The code would be a lot less redundant and the problem I had before, completely solved. The question is to find the best default name for each plot, so less exceptions have to be made.
 
Top Bottom