1. We have added the ability to collapse/expand forum categories and widgets on forum home.
    Dismiss Notice
  2. All Civ avatars are brought back and available for selection in the Avatar Gallery! There are 945 avatars total.
    Dismiss Notice
  3. To make the site more secure, we have installed SSL certificates and enabled HTTPS for both the main site and forums.
    Dismiss Notice
  4. Civ6 is released! Order now! (Amazon US | Amazon UK | Amazon CA | Amazon DE | Amazon FR)
    Dismiss Notice
  5. Dismiss Notice
  6. Forum account upgrades are available for ad-free browsing.
    Dismiss Notice

[BtS] FF mod Python help

Discussion in 'Civ4 - Creation & Customization' started by NNCSavage, Aug 7, 2007.

  1. NNCSavage

    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.
     
  2. JeBuS27

    JeBuS27 Heretic

    Joined:
    Sep 21, 2005
    Messages:
    321
    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.
     
  3. JeBuS27

    JeBuS27 Heretic

    Joined:
    Sep 21, 2005
    Messages:
    321
    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.
     
  4. NNCSavage

    NNCSavage Chieftain

    Joined:
    Feb 19, 2005
    Messages:
    24
    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
     
  5. NNCSavage

    NNCSavage Chieftain

    Joined:
    Feb 19, 2005
    Messages:
    24
    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
     
  6. JeBuS27

    JeBuS27 Heretic

    Joined:
    Sep 21, 2005
    Messages:
    321
    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.
     
  7. JeBuS27

    JeBuS27 Heretic

    Joined:
    Sep 21, 2005
    Messages:
    321
    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.
     
  8. NNCSavage

    NNCSavage Chieftain

    Joined:
    Feb 19, 2005
    Messages:
    24
    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).
     
  9. NNCSavage

    NNCSavage Chieftain

    Joined:
    Feb 19, 2005
    Messages:
    24
    Updated for all the buildings I put in and everything works great.
    Time to start working on something else I guess.
     
  10. EmperorFool

    EmperorFool Chieftain

    Joined:
    Mar 2, 2007
    Messages:
    9,633
    Location:
    Mountain View, California
    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.
     
  11. NNCSavage

    NNCSavage Chieftain

    Joined:
    Feb 19, 2005
    Messages:
    24
    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.
     
  12. JeBuS27

    JeBuS27 Heretic

    Joined:
    Sep 21, 2005
    Messages:
    321
    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.
     
  13. NNCSavage

    NNCSavage Chieftain

    Joined:
    Feb 19, 2005
    Messages:
    24
    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
     
  14. JeBuS27

    JeBuS27 Heretic

    Joined:
    Sep 21, 2005
    Messages:
    321
    You got that error because you didn't import CvUtil before trying to use it.
     

Share This Page