Modder's Guide to Final Frontier Plus

The variable "iImprovement" doesn't appear anywhere in the regular Final Frontier Plus version of CvFinalFrontierEvents.py, but it is in the B5 version (I happen to have v1.4 installed) in the onImprovementBuilt function. That function is 2 functions after the onModNetMessage function there (with onUnitBuilt in between).

My guess: Your indentation is off such that the line that says "def onImprovementBuilt(self, argsList):" (and the rest of the function, too) appears to the Python to be inside the onModNetMessage function. The line that says "def onModNetMessage(self, argsList):" is indented with one tab so the line that says "def onImprovementBuilt(self, argsList):" is indented more than that (and either you don't have the no longer needed onUnitBuildImprovement function or it is also indented too far) if my guess is right. There could also be problems with the onImprovementBuilt which ought to have a line that says "iImprovement, iX, iY = argsList". But this is all just a guess that is based on very little actual information.

Anyhow, in order to diagnose this better we need to see what is on line 395 of your new CvFinalFrontierEvents.py. We also need several lines before that line for context - 15 or so might be good enough.
 
Below is line 363 to line 456 from CvFinalFrontierEvents.py, from what you said in your last post it would seem the problem is down to the Jump Point creation code that is peculiar to the B5 mod.
Code:
# Working on a building?
			if (pCity.isProductionBuilding()):
				
				iBuilding = pCity.getProductionBuilding()
				
				pOldPlanet.setBuildingProduction(iBuilding, pCity.getProduction())
				
#				szText = "Old Planet: %s %d: %s" %(pCity.getName(), pOldPlanet.getOrbitRing(), CvSolarSystem.aszPlanetTypeNames[pOldPlanet.getPlanetType()])
#				printd(szText)
#				printd("Assigning %d to production of building %d" %(pCity.getProduction(), iBuilding))
				
				# Planet doesn't already have this building
				if (not pPlanet.isHasBuilding(iBuilding)):
					pCity.setProduction(pPlanet.getBuildingProduction(iBuilding))
				# Planet does have this building, pop the queue
				else:
					pCity.popOrder(0, false, true)
				
				CyInterface().setDirty(InterfaceDirtyBits.CityScreen_DIRTY_BIT, True)
			
			pSystem.setBuildingPlanetRing(iPlanetRing)
			
			CyInterface().setDirty(InterfaceDirtyBits.CitizenButtons_DIRTY_BIT, True)
			CyInterface().setDirty(InterfaceDirtyBits.SelectionButtons_DIRTY_BIT, True)
			
#############################################################################################
#		Starbase Stuff
#############################################################################################

		#------------------------------ JumpPoint STARTS
		iImprovementJumpPointID = CvUtil.findInfoTypeNum(gc.getImprovementInfo,gc.getNumImprovementInfos(),'IMPROVEMENT_JUMP_POINT')
		#JumpPoint Finished
		if (iImprovement == iImprovementJumpPointID):
			pPlot = CyMap().plot(iX, iY)
			#pPlot.setImprovementType(-1)
			
			# Look for the jumping Ship on this plot
			for iUnitLoop in range(pPlot.getNumUnits()):
				pUnit = pPlot.getUnit(iUnitLoop)
#				pUnit.setName("Da unit")
#				pUnit.setMoves(0)	#Resets the movement points for every other ship (so they can jump)
				
#				if (pUnit.getScriptData() == "BuildingJumpPoint"):	#THIS CODE IS USELESS SINCE THE SCRIPT IS NEVER SET
					#self.doMakeStarbase(pUnit.getOwner(), iX, iY)
					#self.aiKillTimerData = [3, pUnit.getOwner(), pUnit.getID()]
#					szTitle = self.szGameDate = CyGameTextMgr().getTimeStr(CyGame().getGameTurn(), false)
#					popup = PyPopup.PyPopup(-1)
#					popup.setHeaderString(szTitle)
#					popup.setBodyString('pUnit!')
#					popup.launch(true, PopupStates.POPUPSTATE_QUEUED)
					
			self.jumpPointCulture(pUnit.getOwner(), iX, iY)
		#------------------------------ JumpPoint ENDS

	def jumpPointCulture(self, iPlayer, iX, iY):
		
		#Create culture at the jump point location, so that ships can jump from there
		#Based on the updateStarbaseCulture(...)
		iActiveX = iX#iXLoop
		iActiveY = iY#iYLoop
			
		if (iActiveX < 0):
			iActiveX = CyMap().getGridWidth() + iActiveX
		if (iActiveY < 0):
			iActiveY = CyMap().getGridHeight() + iActiveY
			
		pLoopPlot = CyMap().plot(iActiveX, iActiveY)	#GETS THE PLOT IN THIS COORDINATE

		# Don't override culture that's already here
		if (pLoopPlot.getOwner() == -1):				#DOES THE PLOT BELONG TO SOMEONE?
			pLoopPlot.setOwner(iPlayer)					#SET THE PLOT'S CULTURE
		#jumpPointCulture() END
		
	def updateStarbaseCulture(self, iPlayer, iX, iY):
		
		# Create culture around unit
		for iXLoop in range(iX-2, iX+3):
			for iYLoop in range(iY-2, iY+3):
				iActiveX = iXLoop
				iActiveY = iYLoop
				if CyMap().isWrapX():
					if (iActiveX < 0):
						iActiveX = CyMap().getGridWidth() + iActiveX
				if CyMap().isWrapY():
					if (iActiveY < 0):
						iActiveY = CyMap().getGridHeight() + iActiveY
				pLoopPlot = CyMap().plot(iActiveX, iActiveY)
#				printd("Setting Player %d as the owner of %d, %d" %(iPlayer, iXLoop, iYLoop))
				# Don't override culture that's already here
				if not pLoopPlot.isNone():
					if (pLoopPlot.getOwner() == -1):
						pLoopPlot.setOwnerNoUnitCheck(iPlayer)
		
	def updateAllStarbases(self):
Hope this is enough to help find a solution.
 
Yes, you are missing the beginning of the onImprovementBuilt function. It should look something like this:
Code:
#############################################################################################
#		Starbase Stuff
#############################################################################################

	def onImprovementBuilt(self, argsList):
		'Improvement Built'
		iImprovement, iX, iY = argsList

		
		#------------------------------ JumpPoint STARTS
		iImprovementJumpPointID = CvUtil.findInfoTypeNum(gc.getImprovementInfo,gc.getNumImprovementInfos(),'IMPROVEMENT_JUMP_POINT')
		#JumpPoint Finished
That should be enough context for you to see where it goes.
 
I'm having a problem updating the older Star Trek scenarios. I get a python exception in CvAI saying that none type has not attribute getPopulationLimit. Removing these two lines in onGameStart fixes the problem:
Code:
				if(not pPlayer.isHuman()):
                                        AI.doCityAIUpdate(pPlayer.getCity(0))
I've modified the startup code to account for the old worldbuilder version, but I don't think I've done it well enough. Since this function isn't called anywhere else at the start of the game, this "fix" could introduce AI problems.
 
It would be good to figure out why that isn't working there, since it probably indicates that something somewhere is wrong, but I think removing it should have minimal effect on the AI (probably none at all).

The same doCityAIUpdate should be called at the beginning of each player's turn (it is called at the end of updateHumanCityTurn, which is called by doBeginTurnAI, which is called by onBeginPlayerTurn which is called for each player at the start of their turn) for each of their systems that has population that isn't assigned to a planet but could be.

Because of that, removing the initial call for it would probably have no effect on the AI. Probably. The only effect that I can think of is that on the first turn the human player would tend to be #1 in GNP, production, and food output as shown in the demographics simply because the human goes first and therefore would be the only one that has any population producing any of that stuff until the AIs each run a turn - which is a completely trivial effect.
 
My only guess is that solar systems haven't fully loaded yet, which is odd, since it's after the loading code. I noticed that the line of code only exists after the worldbuilder changes were made; the scenarios I'm updating use the old worldbuilder (ie, the one that came with Final Frontier) so the loading code is different.
 
Hi All
Is there a limit to the number of <TechTypes> PrereqTechs that can be added in the Civ4UnitInfos?
Example of section i am referring.
Code:
			<PrereqTech>TECH_B5_MILITARY_ELITE</PrereqTech>
			<TechTypes>
				<PrereqTech>TECH_B5_LASER_WEAPONS</PrereqTech>
				<PrereqTech>TECH_B5_PLASMA_WEAPONS</PrereqTech>
				<PrereqTech>TECH_B5_MASS_DRIVERS</PrereqTech>
			</TechTypes>
There are also some that have 4 additional PrereqTechs. The reason i ask is that i am now getting a failure to load after adding them.
 
I think the max is controlled by a global define. In BtS's GlobalDefines.xml there is a NUM_UNIT_AND_TECH_PREREQS value that is set to 3.

I assume you are using the FF-style GlobalDefinesAlt.xml isntead of a GlobalDefines.xml, so try adding it to the GlobalDefinesAlt.xml:
Code:
	<Define>
		<DefineName>NUM_UNIT_AND_TECH_PREREQS</DefineName>
		<iDefineIntVal>[B]4[/B]</iDefineIntVal>
	</Define>
Or whatever value you need instead of 3.
 
What's on line 156?

Whenever you see a Python exception, you should always look in the Python file specified and post the code around that line. Otherwise, I have no idea what you're doing wrong, because the B5 CvFinalFrontierEvents.py and FF+ CvFinalFrontierPlus.py files are not identical.
 
Not sure about the crash, but I have a through about the Python error message.

That is the same line 156 as in regular FF+. This is in the loop that swaps out the starting unit for a civ's unique version for that unit class, if it has one.

So my first thought is that iCivUnitType is -1 rather than a valid unit type. Does the civ in question actually get a unit of the starting unit class? In regular FF+ that would be a planetary defense ship. If the civ gets NONE as its unit type for the starting unit's unit class (as defined for it in CIV4CivilizationInfos.xml) then this would be the problem as the code never checks to see if the unit it is trying to create is valid. If this is the problem then the fix would be to check iCivUnitType to see if it is valid before trying to create the unit.

You can see what the unit type is by activating the printd() statements - in CvSolarSystem.py, line 16 in regular FF+ version, set g_bPrintDebugText to be True. This will print a line to the PythonDbg.log file every time it tries to swap a unit for a unique version (via line 154 in CvFinalFrontierEvents.py).
 
Hi
I looked through CIV4CivilizationInfos.xml for iCivUnitType but didn't find this tag. Also looked in a lot of other files and couldn't find it. However there was the <FreeUnitClasses/> which was blank for all Civs. I've now amended this so that all civ's get the free starting unit specified in the FinalFrontier.Py and FinalFrontierFlat.Py.

I'll give this a go and see how it pans out.

Edit. Still does exactly the same thing, crashes when starting unit deleted.
 
Just to make sure B5 hasn't changed any of this code, can you post all the code around that line? It should be comment-delineated (that is, each section is started by a comment explaining what it does), but it might not all be, so just grab any lines that look relevant.

Hi
I looked through CIV4CivilizationInfos.xml for iCivUnitType but didn't find this tag. Also looked in a lot of other files and couldn't find it. However there was the <FreeUnitClasses/> which was blank for all Civs. I've now amended this so that all civ's get the free starting unit specified in the FinalFrontier.Py and FinalFrontierFlat.Py.

I'll give this a go and see how it pans out.

Edit. Still does exactly the same thing, crashes when starting unit deleted.

<FreeUnitClasses/> is blank in Final Frontier too, because Jon Shafer hardcoded the free units in the mapscript (so they would start on the player's first city). So you can keep it blank.

I should really change it to use <FreeUnitClasses>...
 
It wouldn't be an iCivUnitType tag in the XML, that's just the variable name I used int he Python.

In CIV4CivilizationInfos.xml the relevant part would be the Units sections. That is where the civ's UUs for the various unit classes are defined, and where it can be blocked from making units of some unit classes. FOr example, in FF+ the Avowers have UU version of the 3 generations of scout ships, which is done via this part of the XML:
Code:
			<Units>
				<Unit>
					<UnitClassType>UNITCLASS_SCOUT_I</UnitClassType>
					<UnitType>UNIT_RECON_I</UnitType>
				</Unit>
				<Unit>
					<UnitClassType>UNITCLASS_SCOUT_II</UnitClassType>
					<UnitType>UNIT_RECON_II</UnitType>
				</Unit>
				<Unit>
					<UnitClassType>UNITCLASS_SCOUT_III</UnitClassType>
					<UnitType>UNIT_RECON_III</UnitType>
				</Unit>
			</Units>
and the Pirates are blocked from building a bunch of units, including Colony Ships, so their Units section starts like so:
Code:
			<Units>
				<Unit>
					<UnitClassType>UNITCLASS_COLONY_SHIP</UnitClassType>
					<UnitType>NONE</UnitType>
				</Unit>

If a playable civ has "<UnitType>NONE</UnitType>" for the unit class of the unit that is given to the players for free at the start of the game, then that will result in iCivUnitType being set to -1 (for NO_UNIT). You can't create a NO_UNIT unit, thus the error popup.

At least, that is my current theory as to why you get the popup.

I still have have no real theory as to why it crashes if you delete the unit. The only thing that has come to mind is perhaps a bug in code associated with the onUnitKilled, or maybe onUnitLost, event.
 
This is the code before and after line 156 as you can see, the B5 mod hasn't changed much, if anything.
Code:
		# Check the player for unique units, swapping out the starting ship(s) for the player's UU if appropriate
				pCivilization = gc.getCivilizationInfo(pPlayer.getCivilizationType())
				pyPlayer = PyPlayer(iPlayerLoop)
				apUnitList = pyPlayer.getUnitList()
				for pUnitLoop in apUnitList :
					iUnitType = pUnitLoop.getUnitType() # this unit's unit type
					iUnitClass = pUnitLoop.getUnitClassType() # this unit's unit class
					iCivUnitType = pCivilization.getCivilizationUnits(iUnitClass) # this civ's unit type of this class
					if (iUnitType != iCivUnitType ):
						# existing unit's type does not match this civ's unit for the unit's class
						printd("Found unit to swap: id = %d, from type = %d to type = %d" %(pUnitLoop.getID(), iUnitType, iCivUnitType))
						# add new unit
						pNewUnit = pPlayer.initUnit(iCivUnitType, pCity.getX(), pCity.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION)
						# remove old unit
						pUnitLoop.kill(false, -1)
		
				# Set up Player stuff: Star Systems & Gold		
				self.doBeginTurnAI(iPlayerLoop, false)
 
Back
Top Bottom