[BtS] FF mod Python help

NNCSavage

Chieftain
Joined
Feb 19, 2005
Messages
24
Ok, I'm trying to attach the same type of +1 to food/prod/commerce/research that the nutrition and mining facilities have.
I think I found out where the Yields get updated in CvFinalFrontier.py
Code:
	def updatePlotYield(self, pPlot):
		
		pCity = pPlot.getPlotCity()
		
		iOwner = pCity.getOwner()
		
		if (iOwner != -1):
			
			if (pPlot.getFeatureType() == self.iFeatureIDSolarSystem):
				
				pPlayer = gc.getPlayer(iOwner)
				
				pSystem = self.getSystemAt(pPlot.getX(), pPlot.getY())
				
				aiSystemYield = [0,0,0]
				
				# The Forge get's 1 fewer food in all cities
				iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_THE_FORGE')
				if (pPlayer.hasTrait(iTrait)):
					aiSystemYield[0] -= 1
#					if (pCity.isCapital()):
#						aiSystemYield[1] += 2
						
				# Red Syndicate gets +1 food and production for each Trade Route
				iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_SYNDICATE')
				if (pPlayer.hasTrait(iTrait)):
					for iTradeCity in range (pCity.getTradeRoutes()):
						pTradeCity = pCity.getTradeCity(iTradeCity)
#						printd("Trade city object:")
#						printd(pTradeCity)
						if (pTradeCity):
							if (pTradeCity.getName() != ""):
#								printd("entering trade route additions")
								aiSystemYield[0] += 1
								aiSystemYield[1] += 1
				
				# Building mod needs to be done manually
				for iBuildingLoop in range(gc.getNumBuildingInfos()):
					
					# Has buildings
					if (pCity.getNumRealBuilding(iBuildingLoop) > 0):
						
						pBuildingInfo = gc.getBuildingInfo(iBuildingLoop)
						for iYieldLoop in range(3):
							if (pBuildingInfo.getYieldChange(iYieldLoop) > 0):
								aiSystemYield[iYieldLoop] += (pBuildingInfo.getYieldChange(iYieldLoop) * 

pCity.getNumRealBuilding(iBuildingLoop))

I'm still trying to puzzle out some things. I get the Yield = Yield + extrabuildingyield (I think that's how it works) but what is the multiplier doing?
Probably partially due to not understanding some of the functions called.

Just as a test I am trying to add 1 to commerce if the planet has a Research Lab. Since I need to check this at each planet I dumped my code here:
Code:
				for iPlanetLoop in range(pSystem.getNumPlanets()):
					
					pPlanet = pSystem.getPlanetByIndex(iPlanetLoop)
					
					printd("  Planet at Ring ID %d" %(pPlanet.getOrbitRing()))
					
					# added by NNCSavage 08/07/2007
					# Research Lab adds one to commerce yield
					iRlab = CvUtil.findInfoTypeNum(gc.getBuildingInfo, gc.getNumBuildingInfos(), "BUILDING_RESEARCH_LAB")
					if pPlanet.isHasBuilding(iRlab):
						aiSystemYield[2] += 1
					
					# return to normally schedule programming
					for iYieldLoop in range(3):
						iValue = (pPlanet.getTotalYield(iOwner, iYieldLoop) * pPlanet.getPopulation())
						aiSystemYield[iYieldLoop] += iValue
						printd("    Yield %d Value: %d" %(iYieldLoop, iValue))
					
				for iYieldLoop in range(3):
					pCity.setBaseYieldRate(iYieldLoop, aiSystemYield[iYieldLoop])
					printd("  Setting City Base Yield %d to %d" %(iYieldLoop, aiSystemYield[iYieldLoop]))

I'm still at work so I can't test it until I get home
Will what I added work? Is it in the right place? or should I shoot myself in the foot and call it a day? =P

Also I'm almost thinking it might be better to just check current population and add that to research.

Psuedocode:
if planet has research lab
research (before % increases) += current planet pop

Also where do the printd commands send their data?
I've tried every logging command I could track down in game, in INI, log files and searching and must be missing it.
 
While working on editing planet info, I noticed that Yield info for those buildings is actually hardcoded at the end of CvSolarSystem.py

I haven't looked into anything regarding the yields yet, so I can't help you with that, sorry. I hope this helps you though.
 
After taking a bit more of a look, it seems there's more Yield methods in CvSolarSystem.py, so maybe you should check there as well. If you have the will, perhaps try editing the building XML to have the proper YieldChanges, and take out the hardcoded ones.
 
Unfortunately yield changes through <YieldChange> in the XML files just changes the base increase to the system overall, which works for part of replicating the +5, +1 per worker function in Moo2.

I would guess I could edit the core dll and add in reads for per worker changes (that seems easy enough to do with Kael's very nice tutorial) but figuring out how to actually apply the change might be a bit difficult for me.

I'll start digging in the SolarSystem.py file to see if there is anything there.
Thanks for the heads-up
 
Looks like the yield changes for the 4 buildings are hardcoded at the very bottom of the SolarSystem.py file.
And as noted by Jon: This is bad

If anyone adds a building before the Habitation center it will throw the count off.
Easy for me to update though.
Probably should try to code it to look up the building number and then change the rate.
If I can find out where the print messages go (debugger program maybe?) - maybe I can update it
 
The only way I could get any sort of debug messages was to print them to one of the log files using CvUtil.pyPrint(). I don't remember which log it prints to at the moment.
 
Since it was bugging me that the building's info was hardcoded, I decided to make some changes.

In CIV4BuildingInfos.xml I made changes to the Nutrition Facility, Mining Facility, and Maglev Network YieldChanges. Below is the Maglev's changes as an example.
Code:
			<YieldChanges>
				<iYield>0</iYield>
				<iYield>0</iYield>
				<iYield>2</iYield>
			</YieldChanges>

In CvSolarSystem.py I changed the CvPlanet.getExtraYield method to the following.
Code:
	def getExtraYield(self, iOwner, iYieldID):
		
		pPlayer = gc.getPlayer(iOwner)
		
		iExtraYield = 0
		
		iTrait = CvUtil.findInfoTypeNum(gc.getTraitInfo,gc.getNumTraitInfos(),'TRAIT_THE_FORGE')
		iBuildingMiningFacility = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_MINING_FACILITY')
		iBuildingCapitol = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_CAPITOL')
		
		for iBuildingLoop in range(gc.getNumBuildingInfos()):
			if (self.isHasBuilding(iBuildingLoop)):
				#iExtraYield += g_aiBuildingYieldIncrease[iBuildingLoop][iYieldID]
				iExtraYield += gc.getBuildingInfo(iBuildingLoop).getGlobalYieldModifier(iYieldID)
				
				# Production boost for the Forge's Mining Facilities & Capital
				if (iYieldID == 1):
					if (pPlayer.hasTrait(iTrait)):
						if (iBuildingLoop == iBuildingMiningFacility):
							iExtraYield += 1
		
		# Utopia Civic mod to food
		iLaborCivicOption = CvUtil.findInfoTypeNum(gc.getCivicOptionInfo,gc.getNumCivicOptionInfos(),'CIVICOPTION_LABOR')
		iUtopia = CvUtil.findInfoTypeNum(gc.getCivicInfo,gc.getNumCivicInfos(),'CIVIC_UTOPIA')
		
		if (pPlayer.getCivics(iLaborCivicOption) == iUtopia):
			if (iYieldID == 0):		# Food
				iExtraYield += 1
			
		return iExtraYield

The only hard-coded building info left is the Habitation System, because as far as I know, there's no PopCap tag in the building XML. I suppose we could edit the schema and put a new tag in, and add some Python methods to use it, but for now, I'll leave that as is.
 
By adding the iYield to the XML that changes the base yield as well.
the python change would take that same iYield and add the +2 per worker.
So now the Mag-Lev building adds 2 commerce directly to the system total in addition to adding 2 commerice to each population working the planet, right?

If I am correct you could not get the +5 base and +1 per worker that moo2 has by doing that.

Updating the hardcoded to get what I wanted was cake but I'd rather fix the problem.

I think if I do this, it should do what I want, remove the hardcode and be simple to add:
Code:
		# added by NNCSavage 08/08/2007
		iBuildingResearchLab = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_RESEARCH_LAB')
		
		for iBuildingLoop in range(gc.getNumBuildingInfos()):
			if (self.isHasBuilding(iBuildingLoop)):
				iExtraYield += g_aiBuildingYieldIncrease[iBuildingLoop][iYieldID]
				
				# Production boost for the Forge's Mining Facilities & Capital - changed NNCSavage 08/08/2007
				if (iBuildingLoop == iBuildingMiningFacility):
					if (pPlayer.hasTrait(iTrait)):
						if (iYieldID == 1):
							iExtraYield += 1

				# added by NNCSavage 08/08/2007 - Commerce boost for Research Lab
				if (iBuildingLoop == iBuildingResearchLab):
					if(iYieldID == 2):
						iExtraYield += 1

It's also easy enough to copy for each building and will only get called once per loop. I also think I'll update the production boost for the forge to only get called once as well instead of during each pass(even though it doesnt get much further).
 
Updated for all the buildings I put in and everything works great.
Time to start working on something else I guess.
 
I get the Yield = Yield + extrabuildingyield ... but what is the multiplier doing?

I didn't see if anyone addressed this question. The reason for the multiplier is that BtS now allows the same building to be built multiple times in the same city. The epic game doesn't allow it in the interface, so this is probably for mods.
 
Thanks for pointing that out. I "lightbulbed" that after reading Zebra 7's API thread the other day but never updated.

I do have a new question though.

at the bottom of the SolarSystem.py file I added this: to get rid of the hardcoding
Code:
iBuildingADN = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_AIR_DEFENSE_NETWORK')
iBuildingCSY = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_CAPITAL_SHIPYARD')
iBuildingSQF = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_SQUADRON_FACTORY')
iBuildingSTF = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_STAR_FORTRESS')
g_aszBuildingDummyTags[12] = "FEATURE_MODEL_TAG_CAPITAL_SHIPYARD" # 12 (old 7)
g_aszBuildingDummyTags[13] = "FEATURE_MODEL_TAG_SQUADRON_FACTORY" # 13 (old 8)
g_aszBuildingDummyTags[41] = "FEATURE_MODEL_TAG_SQUADRON_DEFENSE_NETWORK" # 41 (old 21)
g_aszBuildingDummyTags[iBuildingSTF] = "FEATURE_MODEL_TAG_STAR_FORTRESS" # 42 (old 22)

As you can see the Star Fortress var is still used because it works.
But if I put the proper iBuilding Var in the other 3, the game pops red globes which I take to mean i screwed something up.
 
Well, one thing to do is to figure out what those lines of code give you in game. Pop open the Python console and see what number it gives you for those 3.
 
I did (shift-~) and got back an error that it didn't know what CvUtil was.

However I went and made changes in the updateDisplay Function that work:
Code:
				# added by NNCSavage 08/09/2007
				iBuildingCSY = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_CAPITAL_SHIPYARD')
				iBuildingSQF = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_SQUADRON_FACTORY')
				iBuildingSDF = CvUtil.findInfoTypeNum(gc.getBuildingInfo,gc.getNumBuildingInfos(),'BUILDING_AIR_DEFENSE_NETWORK')
				for aiBuildingLocation in aiArray:
					iBuildingType = aiBuildingLocation[0]
					iRing = aiBuildingLocation[1]
					szBuildingString = aszBuildingDummyTypes[iRing-1]		# Offset by 1, since Ring index starts at 1 and not 0
					szBuilding = ""
					# added by NNCSavage 08/09/2007
					if (iBuildingType == iBuildingCSY):
						szBuilding = "FEATURE_MODEL_TAG_CAPITAL_SHIPYARD"
					if (iBuildingType == iBuildingSQF):
						szBuilding = "FEATURE_MODEL_TAG_SQUADRON_FACTORY"
					if (iBuildingType == iBuildingSDF):
						szBuilding = "FEATURE_MODEL_TAG_SQUADRON_DEFENSE_NETWORK"
					pPlot.addFeatureDummyModel(szBuildingString, szBuilding)

Found the Star Fortress gets added just below and it probably could have been ignored and when I commented out the hardcode piece for it. everything still worked. /shrug
 
You got that error because you didn't import CvUtil before trying to use it.
 
Top Bottom