Requiring a feature before founding a city

Daryl95

Templar
Joined
Nov 9, 2008
Messages
271
Location
America
I was taking another try at a space mod. I want to require a planet to settle. But I want more than one planet. I'm in CvGameUtils.PY. I have managed to do it for one feature. Forest for now since it won't place planets on the map. I can't make it work for multiple planets. I'd try messing around with dummy nodes in Final Frontier, but that would make a mess that I couldn't clean up. Plus I want to control which planet I place on the map because the final will be a scenario file. So I tried messing with if's and or's and else's. Nothing worked.
Help is appreciated. i.e. I'm python coding ignorant.:)

Original Code:
PHP:
        def cannotFoundCity(self,argsList):
	        iPlayer, iPlotX, iPlotY = argsList
	        return False

New Code For Only 1 Feature:
	def cannotFoundCity(self,argsList):
		iPlayer, iPlotX, iPlotY = argsList
		
		pPlot = CyMap().plot(iPlotX, iPlotY)
		
		if (pPlot):
			
			iFeatureIDPlanet = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_FOREST')
			
			if (pPlot.getFeatureType() != iFeatureIDPlanet):
				return True
			
		return False
 
Did you enable the cannotFoundCity callback? It is disabled by default, so the cannotFoundCity function is never actually run.

If your mod does not include the PythonCallbackDefines.xml already, copy it from BtS (it is directly in Assets\XML). The very first entry in that file is USE_CANNOT_FOUND_CITY_CALLBACK. Set that to 1 instead of 0.

You also have to watch out for the city destroying the feature. By default any feature on the plot is destroyed when you found a city. In the game utils Python there is also a citiesDestroyFeatures function. Note: in Final Frontier Plus I had issues with this. I had to change the default setting in one of the BUG files (BugGameUtils.py) for this callback to False to get it to stop destroying the star system when I merged BUG into FFP. Just having this function return False was not good enough. So if you are using BUG in your mod you should keep this in mind.
 
Did you enable the cannotFoundCity callback? It is disabled by default, so the cannotFoundCity function is never actually run.

If your mod does not include the PythonCallbackDefines.xml already, copy it from BtS (it is directly in Assets\XML). The very first entry in that file is USE_CANNOT_FOUND_CITY_CALLBACK. Set that to 1 instead of 0.

You also have to watch out for the city destroying the feature. By default any feature on the plot is destroyed when you found a city. In the game utils Python there is also a citiesDestroyFeatures function. Note: in Final Frontier Plus I had issues with this. I had to change the default setting in one of the BUG files (BugGameUtils.py) for this callback to False to get it to stop destroying the star system when I merged BUG into FFP. Just having this function return False was not good enough. So if you are using BUG in your mod you should keep this in mind.
Yes I did both of these. When I use the code above though, it only recognizes the first feature and not both.
 
What else did you try?

It's maybe easier to check for every valid feature and let it return False then, and change the last return value simply to True.
You mean by somehow telling it to look at every feature except the ones I want to found the city on and telling it to return false that it'll then only allow the excluded features?
Wouldn't this apply to tiles without features though? There's a lot of empty space out there...
 
Ah. I didn't realize you want to only select FF type star system with multiple planets (I was, and to some extent still am, thinking to myself that in unmodified FF all star systems always have more than one planet, the minimum being 3, so the point was lost on me and I'm still not sure exactly what you want).

Planets are not features in the game engine sense. A star system is a feature. The planets are just decorative graphics attached to the main graphic for the feature as far as the DLL is concerned. You need to check the star system's Python data to determine what planets it has.

A couple of key functions:
pSystem = getSystemAt(iX,iY)
iNumPlanets = pSystem.getNumPlanets().

To inspect the individual planets (once you have pSystem as above):
pPlanet = pSystem.getPlanetByIndex(iI)
where iI can be a number from 0 to iNumPlanets - 1.

This sort of thing is used in a variety of places in the FF Python, so there are plenty of examples in there already.

(And a By The Way type comment: you should probably start with Final Frontier Plus rather than basic Final Frontier. It has all known bugs in FF fixed and a variety of additional things including less stuff hardcoded in the Python - a bunch of that stuff was converted to tags in the XML. The Python is a little more complex in some ways, and just different in other ways, due to the merging in of BUG, but it's mostly the same.)
 
Ah. I didn't realize you want to only select FF type star system with multiple planets (I was, and to some extent still am, thinking to myself that in unmodified FF all star systems always have more than one planet, the minimum being 3, so the point was lost on me and I'm still not sure exactly what you want).

Planets are not features in the game engine sense. A star system is a feature. The planets are just decorative graphics attached to the main graphic for the feature as far as the DLL is concerned. You need to check the star system's Python data to determine what planets it has.

A couple of key functions:
pSystem = getSystemAt(iX,iY)
iNumPlanets = pSystem.getNumPlanets().

To inspect the individual planets (once you have pSystem as above):
pPlanet = pSystem.getPlanetByIndex(iI)
where iI can be a number from 0 to iNumPlanets - 1.

This sort of thing is used in a variety of places in the FF Python, so there are plenty of examples in there already.

(And a By The Way type comment: you should probably start with Final Frontier Plus rather than basic Final Frontier. It has all known bugs in FF fixed and a variety of additional things including less stuff hardcoded in the Python - a bunch of that stuff was converted to tags in the XML. The Python is a little more complex in some ways, and just different in other ways, due to the merging in of BUG, but it's mostly the same.)
I didn't use the FF engine. I transferred over parts of it but the original mod was scratch. Basically this is because I want a game in which planets are the unit for city building and not entire star systems. I created a feature called planet that I use to build a city on. Each civ starts with at least one planet. And can colonize others in the same system or in others. I was afraid if I tried the FF engine it would be too complicated for my skill level so this way I better understand many of the things that were done in the construction of the FF engine by redoing the parts that I want, cities founded on a feature, space fields, units founding on water, getting rid of city buildings, etc. The problem: I can only have 1 planet. If I could overcome this, I am under the belief that I can do everything else.
 
What else did you try?

It's maybe easier to check for every valid feature and let it return False then, and change the last return value simply to True.

Is this what you meant?
Code:
def cannotFoundCity(self,argsList):
              iPlayer, iPlotX, iPlotY = argsList
   
              pPlot = CyMap().plot(iPlotX, iPlotY)
              
              if (pPlot):
                    
                    iFeatureIDFeature01 = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_ICE')
                    
                    if (pPlot.getFeatureType() != iFeatureID Feature01):
                          return False
   
              elif (pPlot):
                    
                    iFeatureIDFeature02 = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_JUNGLE')
                    
                    if (pPlot.getFeatureType() != iFeatureID Feature02):
                          return False
   
              elif (pPlot):
                    
                    iFeatureIDFeature03 = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_OASIS')
                    
                    if (pPlot.getFeatureType() != iFeatureID Feature03):
                          return False
   
              elif (pPlot):
                    
                    iFeatureIDFeature04 = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_FLOOD_PLAINS')
                    
                    if (pPlot.getFeatureType() != iFeatureID Feature04):
                          return False
   
              elif (pPlot):
                    
                    iFeatureIDFeature05 = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_GRAV_FIELD')
                    
                    if (pPlot.getFeatureType() != iFeatureID Feature05):
                          return False
   
              elif (pPlot):
                    
                    iFeatureIDFeature06 = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_SUPERNOVA_AREA')
                    
                    if (pPlot.getFeatureType() != iFeatureID Feature06):
                          return False
   
              elif (pPlot):
                    
                    iFeatureIDFeature07 = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_FALLOUT')
                    
                    if (pPlot.getFeatureType() != iFeatureID Feature07):
                          return False
                    
              return True
I tried this but I didn't have a HUD when I started a game.
 
Yes, that's in general what I mean.
But all the lines:
PHP:
elif (pPlot):

are not necessary and would prevent the stuff from working. Remove them, should then be okay.


As explanation:
PHP:
if (pPlot):
    [....]
elif (pPlot):

The first if checks if a plot is valid. But the elif clause will ONLY be checked if the if clause is not valid. Since both clauses the same, either only the if clause will be checked, or nothing at all.
 
Yes, that's in general what I mean.
But all the lines:
PHP:
elif (pPlot):
are not necessary and would prevent the stuff from working. Remove them, should then be okay.


As explanation:
PHP:
if (pPlot):
    [....]
elif (pPlot):
The first if checks if a plot is valid. But the elif clause will ONLY be checked if the if clause is not valid. Since both clauses the same, either only the if clause will be checked, or nothing at all.
I messed around with it and found an unwanted space in the code. It's always something stupid. The HUD came back, but it lets me found anywhere now. Even on the features that returned false. I tried it the switchway again. It said I was defeated.
 
What your code is doing:
If the plot is valid check to see if it has FEATURE_ICE. If it does not have feature ice it returns False.

Returning False lets the city be founded. Therefore your code lets a city be founded anywhere except on the ice feature (which is Nebula, if you are using the regular FF features - which would then be impassable anyway).

What you should do is make a list of all the features that allow the city to be built. If the plot has a feature and it is in the list then return False. Otherwise return True.

For example:
Code:
def cannotFoundCity(self,argsList):
              iPlayer, iPlotX, iPlotY = argsList
   
              pPlot = CyMap().plot(iPlotX, iPlotY)
              
              if (pPlot):
                    lFeatures = [gc.getInfoTypeForString("FEATURE_ICE"),
                                 gc.getInfoTypeForString("FEATURE_JUNGLE"),
                                 gc.getInfoTypeForString("FEATURE_OASIS"),
                                 gc.getInfoTypeForString("FEATURE_FLOOD_PLAINS"),
                                 gc.getInfoTypeForString("FEATURE_GRAV_FIELD"),
                                 gc.getInfoTypeForString("FEATURE_SUPERNOVA_AREA"),
                                 gc.getInfoTypeForString("FEATURE_FALLOUT")]
                    
                    if (pPlot.getFeatureType() in lFeatures):
                          return False
 
                    
              return True
Or something like that, give or take the correct indentation levels.
 
What your code is doing:
If the plot is valid check to see if it has FEATURE_ICE. If it does not have feature ice it returns False.

Returning False lets the city be founded. Therefore your code lets a city be founded anywhere except on the ice feature (which is Nebula, if you are using the regular FF features - which would then be impassable anyway).

What you should do is make a list of all the features that allow the city to be built. If the plot has a feature and it is in the list then return False. Otherwise return True.

For example:
Code:
def cannotFoundCity(self,argsList):
              iPlayer, iPlotX, iPlotY = argsList
   
              pPlot = CyMap().plot(iPlotX, iPlotY)
              
              if (pPlot):
                    lFeatures = [gc.getInfoTypeForString("FEATURE_ICE"),
                                 gc.getInfoTypeForString("FEATURE_JUNGLE"),
                                 gc.getInfoTypeForString("FEATURE_OASIS"),
                                 gc.getInfoTypeForString("FEATURE_FLOOD_PLAINS"),
                                 gc.getInfoTypeForString("FEATURE_GRAV_FIELD"),
                                 gc.getInfoTypeForString("FEATURE_SUPERNOVA_AREA"),
                                 gc.getInfoTypeForString("FEATURE_FALLOUT")]
                    
                    if (pPlot.getFeatureType() in lFeatures):
                          return False
 
                    
              return True
Or something like that, give or take the correct indentation levels.

I think it worked! :)
 
Top Bottom