[MOD] Improved Creative Trait (and good for learning python)

naf4ever

Dread Lord
Joined
Feb 8, 2003
Messages
405
Location
Southeast Washington State
This mod here which I originally created for use with my Ultimate Strategy mod makes the Creative trait better and more unique. Basically for any cities size 5 and under it functions exactly like the creative trait now does giving +2 culture/city. With cities 6 and larger though it removes this bonus and instead replaces it with a free Artist! (note: because the culture bonus for cities size 5 and under is done through python you dont actually see the additional +2 culture rate/turn listed on your city screen. But if you glance at your total culture for that city you will see it is indeed rising by an additional +2 every turn like it should.)

This code was originally a piece to give free specialists to certain civics written by Aussie_Lurker. Also thanks goes out to The_Lopez for assistance.

On another note ive found learning python to be quite a task but this piece of code has been extremely useful in helping me undestand many functions. So for those of you also trying to learn it like me, here is a detailed rundown of the lines of code and what they do. You'll find each line is very useful and can easily be incorporated into other programs you're trying to make:

Code:
class FreeSpec:

	def onBeginPlayerTurn(self, argsList):
		'Called at the beginning of a players turn'
		
		iGameTurn, iPlayer = argsList
		player = gc.getActivePlayer()

The class definitions, nothing special here.

Code:
if (player.hasTrait(gc.getInfoTypeForString("TRAIT_CREATIVE"))):
This line tells it to check and see if the current active player has the creative trait and if it does then go to the next line. You can change the creative part to any other trait if you want. In addition you can change this line back to the original in Aussie_Lurker's mod: (player.isCivic(gc.getInfoTypeForString("CIVIC_SLAVERY"))): which then makes the whole free specialist dependent on the civics instead of traits, in this case slavery!

Code:
for i in range(player.getNumCities()):
This line was very helpful to learn. Its a way to tell the mod to focus on all active cities of that player and then perform the following actions which are on lines below it. Great if you want to do something that affects every city of that player.

Code:
if (player.getCity(i).getPopulation() >= 6):
This tells it to check if the population is 6 or greater then if so it goes to the next line. You can of course change the pop requirement to anything else. I actually have it set to 8 in my mod. You can also replace .getPopulation() >=6): with another command in case you want it to be based on something else like if the city has a particular building or currently has unhappy people.

Code:
player.getCity(i).setFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
Assuming the line above this one is true this tells it to add the free specialist and how many, in this case one. Again very easy to change the values or specialist type if you want.

Code:
else:
        player.getCity(i).changeCulture(iPlayer, 2, True)
In case the "If" statement above for the population requirement was false this line gets implemented instead. This is where it gives the cities +2 culture. The "True" part tells the additional culture to function normally and affect city borders and territory appropriately (I think).

Hope this has been useful. I was able to learn a lot by studying these lines of code. Ive tested this mod pretty good but if you find any errors please let me know.

-Naf
 

Attachments

MrUnderhill said:
Err, correct me if I'm wrong, but wouldn't that screw up any other free Artist bonuses the city already has, like Caste System or Statue of Liberty? Wouldn't it be better to use the current count +1?

Nope. Try the mod out...

It works fine with all those things. I did this city in worldbuilder real quick, here is a screenshot. This town has the free artist from my mod (on the bottom where super specialists usually show) and another free artist from the statue of liberty (highlighted). Caste System doesnt affect it at all because that only unlocks the limit for specialists, it doesnt give you any. Ive also had my free artist from the creative trait and super specialist artists from Great Artists co-existing with no problems.

freespec.jpg
 
If you were feeling adventerous you could probably go into the city screen interface python and edit it so that the culture showed up correctly.
 
I agree, its a pretty easy fix too... and a good exercise for you naf.
 
TheLopez said:
I agree, its a pretty easy fix too... and a good exercise for you naf.

I'm impressed, Naf! You've really taken up this learning python and run with it. Another modder is born! :cheers:
 
TheLopez said:
I agree, its a pretty easy fix too... and a good exercise for you naf.

I see. Ive never done any interface alterations before.... Where do you start for something like this? Do i need to alter something like CvMainInterface.py or am i just adding on to the mod code in my existing files?
 
You would need to change the CvMainInterface.py file. The method name is updateCityScreen, you would need to make the changes near line 2435 in an unaltered CvMainInterface.py file.
 
TheLopez said:
You would need to change the CvMainInterface.py file. The method name is updateCityScreen, you would need to make the changes near line 2435 in an unaltered CvMainInterface.py file.

Either Im making this too hard on myself or this isnt as easy as it seems. Here's what i got so far. The line you mentioned was different in my base CvMainInterface.py file, it refers to the text for units. But around line 2235 I saw this:

Code:
iFirst = float(pHeadSelectedCity.getCulture(pHeadSelectedCity.getOwner())) / float(pHeadSelectedCity.getCultureThreshold())
				screen.setBarPercentage( "CultureBar", InfoBarTypes.INFOBAR_STORED, iFirst )
				if ( iFirst == 1 ):
					screen.setBarPercentage( "CultureBar", InfoBarTypes.INFOBAR_RATE, ( float(pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)) / float(pHeadSelectedCity.getCultureThreshold()) ) )
				else:
					screen.setBarPercentage( "CultureBar", InfoBarTypes.INFOBAR_RATE, ( ( float(pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)) / float(pHeadSelectedCity.getCultureThreshold()) ) ) / ( 1 - iFirst ) )
				screen.show( "CultureBar" )

Though after seeing all the "percentage" remarks and the way the formula is devised it became clear this is simply referring to the way the culture bar is displayed not the actual rate. And since the culture from my mod gets added fine here this doesnt appear to be the problem.

Earlier though on line 2207 I saw this:
Code:
if ( pHeadSelectedCity.getCultureLevel != CultureLevelTypes.NO_CULTURELEVEL ):
					szBuffer = localText.getText("INTERFACE_CITY_COMMERCE_RATE", (gc.getCommerceInfo(CommerceTypes.COMMERCE_CULTURE).getChar(), gc.getCultureLevelInfo(pHeadSelectedCity.getCultureLevel()).getTextKey(), pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)))
					screen.setLabel( "CultureText", "Background", szBuffer, CvUtil.FONT_CENTER_JUSTIFY, 125, yResolution - 184, -1.3, FontTypes.GAME_FONT, WidgetTypes.WIDGET_GENERAL, -1, -1 )
					screen.setHitTest( "CultureText", HitTestTypes.HITTEST_NOHIT )
					screen.show( "CultureText" )

This is what i was looking for. This seems to affect the display rate for the commerce. But I noticed from seeing the INTERFACE_CITY_COMMERCE_RATE in the localText.getText("INTERFACE_CITY_COMMERCE_RATE", (gc.getCommerceInfo(CommerceTypes.COMMERCE_CULTURE).getChar() line that the values for the display rate isnt done here, but called from a text file. So i dug up this in Civ4GameTextInfos.xml:
Code:
<TEXT>
		<Tag>INTERFACE_CITY_COMMERCE_RATE</Tag>
		<English>%F1: %s2 (%D3/Turn)</English>
		<French>%F1 : %s2 (%D3/tour)</French>
		<German>%F1: %s2 (%D3/Runde)</German>
		<Italian>%F1: %s2 (%D3/turno)</Italian>
		<Spanish>%F1: %s2 (%D3/turno)</Spanish>
		<Russian>%F1: %s2 (%D3/Turn)</Russian>
		<Japanese>%F1: %s2 (%D3/Turn)</Japanese>
		<Chinese>%F1: %s2 (%D3/Turn)</Chinese>
	</TEXT>

Bingo! Since the city interface displays the culture rate as "Culture: Fledgling (2/Turn)" this is exactly the formula im looking for. Only problem now is how in the heck do i affect the %D3 variable since that number is in essence the culture rate that gets displayed. Anyone know where they are getting this number from?

Or perhaps my original method for adding the 2 culture/turn to the city isnt the appropriate way to do such a thing since it obviously isnt being noticed by whatever function calculates %D3 .

Any insight?
 
Wow, thanks for your detailed explanation! :goodjob: That it is a very nice way of giving python-noobs like me some first insights in what is going on.
I hope other modders will do the same - at least every now and then.

CellKu
 
naf4ever said:
Or perhaps my original method for adding the 2 culture/turn to the city isnt the appropriate way to do such a thing since it obviously isnt being noticed by whatever function calculates %D3 .

Any insight?

You will need to build the % string by hand. I had to do this for the gold/turn string in the mercenaries mod. Though I don't know where you can get the culture/turn info, TGA any ideas?
 
Is there a way to do math in XML? Any easy fix would be to create a new text tag in Civ4GameTextInfos.xml that will be called just for Creative civilizations in this case and I would make the %D3 simply (%D3 +2) . lol ...

Or do you know how to call multiple text files in a single variable spot? If I could call the %D3 all by itself, then add 2 in the python file and then call the others. For example something like this:
Code:
localText.getText("INTERFACE_CITY_COMMERCE_%F1" : "INTERFACE_CITY_COMMERCE_%s1" "(" ""(INTERFACE_CITY_COMMERCE_%D3 +2)" "/Turn)" ,,,,,,,,,,,,,,

Where INTERFACE_CITY_COMMERCE_%F1 and the others simply refer to new text entries that refer to only the variable. Is this possible? I tried to call multiple text tags but it just takes them literally and clumps them all together and shows on my city display screen one long jumbled word.

EDIT: On another note this display issue really isnt that big. The mod works fine as is and trying to figure this out is taking time away from working on other mods :) I'll probably revisit this issue later in the future though...
 
naf4ever said:
Earlier though on line 2207 I saw this:
Code:
if ( pHeadSelectedCity.getCultureLevel != CultureLevelTypes.NO_CULTURELEVEL ):
	szBuffer = localText.getText("INTERFACE_CITY_COMMERCE_RATE", (gc.getCommerceInfo(CommerceTypes.COMMERCE_CULTURE).getChar(), gc.getCultureLevelInfo(pHeadSelectedCity.getCultureLevel()).getTextKey(), pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)))
I think this is the line you want to change to change the numerical value displayed.

Code:
gc.getCommerceInfo(CommerceTypes.COMMERCE_CULTURE).getChar()
gets the culture symbol (ties in with %F1)

Code:
gc.getCultureLevelInfo(pHeadSelectedCity.getCultureLevel()).getTextKey()
gets the text key entry for the selected cities cultural status (the %s2), and

Code:
pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)
gets the current culture being produced a turn (ties in with %D3).

Basically you will need a bit of logic before this line to calculate how much culture the city should be getting, and replace this last section with that.

Something like:

Code:
if ( pHeadSelectedCity.getCultureLevel != CultureLevelTypes.NO_CULTURELEVEL ):

[B]	if <blah blah blah>:
		cultureAdd = <blah>
	else:
		cultureAdd = 0[/B]

	szBuffer = localText.getText("INTERFACE_CITY_COMMERCE_RATE", (gc.getCommerceInfo(CommerceTypes.COMMERCE_CULTURE).getChar(), gc.getCultureLevelInfo(pHeadSelectedCity.getCultureLevel()).getTextKey(), pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE) [B]+ cultureAdd[/B]))

You would have to do something similar in the other section of code you quoted to get the light pink to show up correctly.

Code:
[B]if <blah blah blah>:
	cultureAdd = <blah>
else:
	cultureAdd = 0[/B]

if ( iFirst == 1 ):
	screen.setBarPercentage( "CultureBar", InfoBarTypes.INFOBAR_RATE, ( float(pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)[B] + cultureAdd[/B]) / float(pHeadSelectedCity.getCultureThreshold()) ) )
else:
	screen.setBarPercentage( "CultureBar", InfoBarTypes.INFOBAR_RATE, ( ( float(pHeadSelectedCity.getCommerceRate(CommerceTypes.COMMERCE_CULTURE)[B] + cultureAdd[/B]) / float(pHeadSelectedCity.getCultureThreshold()) ) ) / ( 1 - iFirst ) )

I think.
 
Back
Top Bottom