Founding cities only on specific tiles

Code:
   def cannotFoundCity(self,argsList):
	iPlayer, iPlotX, iPlotY = argsList
	pPlot = CyMap().plot(iPlotX, iPlotY)
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SETTLER'):
			return False
		elif pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_EXCAVATOR'):
			if pPlot.getFeatureType() == gc.getInfoTypeForString('FEATURE_RUIN'):		
				return False
		return True

that's how it looks now but i still don't have it working

sorry about the edit thing still getting used to the forum and I'm just throwing up stuff as i think of it.

thanks for helping to try and work this out the Python tutorials have just left my head spinning.
 
The last "return true" should be de-intended one.

Here's how I'd get it to work.

Go into Fury Road/Assets/Python/CvFuryRoadGameUtils.py

Now, in this file, there is no "def cannotFoundCity", because it uses the main BTS one.

So, you have to add one.

Where you add the function is irrelevant, but it must be after the def _init_.

Code:
import CvUtil
import CvGameUtils
import CvGameInterfaceFile
import CvEventInterface
from   CvPythonExtensions import *

class CvFuryRoadGameUtils(CvGameUtils.CvGameUtils):

   ### PUBLIC OVERRIDE FUNCTIONS

   def __init__(self):
      self.parent = CvGameUtils.CvGameUtils
      self.parent.__init__(self)
      self.gc = CyGlobalContext()
      self.lastPlayer = -1 ; self.lastTurn = -1
      self.dOrder = {}
      self.iTruck = -1 ; self.iCapitol = -1
      self.iFall = -1 ; self. iImmune = -1

[COLOR="red"]#Added in "Founding Cities Only On Specific Tiles"
   def cannotFoundCity(self,argsList):
	iPlayer, iPlotX, iPlotY = argsList
	pPlot = CyMap().plot(iPlotX, iPlotY)
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SETTLER'):
			return False
		elif pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_EXCAVATOR'):
			if pPlot.getFeatureType() == gc.getInfoTypeForString('FEATURE_RUIN'):		
				return False
	return True
#End of Additions[/COLOR]

   # Prevent unit from moving into fallout without radimmune
   # Be sure to check XML/PythonCallbackDefines.xml for UNIT_CANNOT_MOVE_INTO
   def unitCannotMoveInto(self,argsList):
      iPlayer, iUnitId, iPlotX, iPlotY = argsList
      pUnit = self.gc.getPlayer(iPlayer).getUnit(iUnitId)
      if self.iFall == -1:
         self.iFall = self.gc.getInfoTypeForString("FEATURE_FALLOUT")
         self.iImmune = self.gc.getInfoTypeForString("PROMOTION_RADIMMUNE")
      if CyMap().plot(iPlotX, iPlotY).getFeatureType() == self.iFall:
         if pUnit.isHasPromotion(self.iImmune): return false
         return true
      return self.parent.unitCannotMoveInto(self,argsList)

Try this- the red code. The indentations as is should be correct. You don't have to add the code where I did, or use the comment style I did, I'm just providing this as an example to explain what I mean by "indent." (note, I just only downloaded the main Fury Road download in the first post of "Welcome to Fury Road" topic in the forum... so some of the other code I've copied may have been changed in a patch, if there is one.)
 
hmmm...

it now crashes on the 'initiailizing' game after you selct all your game options it gets less than a quarter full of the progress bar and then the game freezes?

Code:
    pGroup.clearMissionQueue()
      pGroup.pushMoveToMission(x, y)
      pUnit.finishMoves()
      return True

   def cannotFoundCity(self,argsList):
	iPlayer, iPlotX, iPlotY = argsList
	pPlot = CyMap().plot(iPlotX, iPlotY)
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SETTLER'):
			return False
		elif pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_EXCAVATOR'):
			if pPlot.getFeatureType() == gc.getInfoTypeForString('FEATURE_RUIN'):		
				return False
	return True

I'm pretty sure the code is the same as what you've put up the only difference is that I put it at the end of the file not the beginning, the stuff above it is just the end of the previous entry in the file.
 
The only thing I can think of is that perhaps the order DOES matter... Try putting it between def unitCannotMoveInto and def doHolyCity. That's where it is in normal BTS.
 
I would need to copy the whole list from GameUtils to FuryRoadGameUtils because it doesn't have them in the Fury Road one.

Also in my GameUtil file (the one from beyond the sword assets) it sits between these:

def canBuild(self,argsList):
iX, iY, iBuild, iPlayer = argsList
return -1 # Returning -1 means ignore; 0 means Build cannot be performed; 1 or greater means it can

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

def cannotSelectionListMove(self,argsList):
pPlot = argsList[0]
bAlt = argsList[1]
bShift = argsList[2]
bCtrl = argsList[3]
return False

is that right?
 
It goes like this:

def unitCannotMoveInto in Fury Road

----Some stuff not in Fury Road-----

def cannotFoundCity

----Some stuff not in Fury Road-----

def doHolyCity in Fury Road

Or in the version I just downloaded, that's how it is. Do you understand what I mean?
 
yeah I see what you mean like this:

Code:
# Prevent unit from moving into fallout without radimmune
   # Be sure to check XML/PythonCallbackDefines.xml for UNIT_CANNOT_MOVE_INTO
   def unitCannotMoveInto(self,argsList):
      iPlayer, iUnitId, iPlotX, iPlotY = argsList
      pUnit = self.gc.getPlayer(iPlayer).getUnit(iUnitId)
      if self.iFall == -1:
         self.iFall = self.gc.getInfoTypeForString("FEATURE_FALLOUT")
         self.iImmune = self.gc.getInfoTypeForString("PROMOTION_RADIMMUNE")
      if CyMap().plot(iPlotX, iPlotY).getFeatureType() == self.iFall:
         if pUnit.isHasPromotion(self.iImmune): return false
         return true
      return self.parent.unitCannotMoveInto(self,argsList)
   
   [COLOR="Red"]def cannotFoundCity(self,argsList):
	iPlayer, iPlotX, iPlotY = argsList
	pPlot = CyMap().plot(iPlotX, iPlotY)
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SETTLER'):
			return False
		elif pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_EXCAVATOR'):
			if pPlot.getFeatureType() == gc.getInfoTypeForString('FEATURE_RUIN'):		
				return False
	return True[/COLOR]

   # Prevents holy city founding based on techs
   def doHolyCity(self): return true

I've tried it and it still freezes?
 
What do you mean with "it freezes"? And when does it happen?

And please turn on the python exceptions.
Go to My Documents\My Games\BtS, open the Civilizatio4.ini, search for python and set the value there to 0.

do you mean this:
; Establish connection to Python Debugger
HAPDebugger = 0

it was already set to 0, do you mean to 1?


right i'm done for the night, if you could leave me instructions of anything that might help you, I will try and run it tomorrow. Thanks for all your efforts guys I really appreciate you taking the time to help
 
do you mean this:
; Establish connection to Python Debugger
HAPDebugger = 0

it was already set to 0, do you mean to 1?


right i'm done for the night, if you could leave me instructions of anything that might help you, I will try and run it tomorrow. Thanks for all your efforts guys I really appreciate you taking the time to help

No. In _Civ4Config, which is in Beyond the Sword main folder, search for this:

Code:
; Set to 1 for no python exception popups
HidePythonExceptions = 0

By default it is set to 1. Mine is set to 0. It gives you popup errors whenever a bit of python code is wrong or gives an "exception."
 
I successfully made an excavator unit that can found cities on city ruins (and nowhere else). I attached the mod to this post.

I hope my alterations were easy to follow. To test it out, open the world builder and place an Excavator and some ruins. (currently the Excavator is a UU of a Settler but no civs have it, so you have to place it in the WB).

For some reason, if the cannotFoundCity() function doesn't end in 'return False' the game will hang indefinitely when you try to load a map. This shouldn't matter so much if you always make an elif branch for each unit that has the found city mission. Almost everything else was very similar to the code already posted. (as noted above, ruins are actually an improvement and not a feature, but the same principles apply as in the example I posted earlier).
 

Attachments

I successfully made an excavator unit that can found cities on city ruins (and nowhere else). I attached the mod to this post.

I hope my alterations were easy to follow. To test it out, open the world builder and place an Excavator and some ruins. (currently the Excavator is a UU of a Settler but no civs have it, so you have to place it in the WB).

For some reason, if the cannotFoundCity() function doesn't end in 'return False' the game will hang indefinitely when you try to load a map. This shouldn't matter so much if you always make an elif branch for each unit that has the found city mission. Almost everything else was very similar to the code already posted. (as noted above, ruins are actually an improvement and not a feature, but the same principles apply as in the example I posted earlier).

Ah. Somehow, in the code I posted, the "False" morphed into a "True."

That explains the error, I guess.
 
hi guys thanks for all your work, Legends, the ruins I was referring to are the ruins in the fury road mod and they are in the terrain feature XML, they are the left over of pre-apocalypse cities, not the ruins from a cities that is captured and raised.

So I think i am right in thinking that what was missing was the return false at the end and the return true is further indented from previous code. as well as the 'classnosettler' bit at the top or is that just a note?

how much of this do i copy into the GameInterfaceFile:

import NoSettleGameUtils

GameUtils = NoSettleGameUtils.NoSettleGameUtils()

I just want to make sure I get it right?

hey guys its not hanging at the load screen anymore but the excavator still found anywhere.

here is my code
Code:
def cannotFoundCity(self,argsList):
	iPlayer, iPlotX, iPlotY = argsList
	pPlot = CyMap().plot(iPlotX, iPlotY)
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SETTLER'):
			return False
		elif pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_EXCAVATOR'):
			if pPlot.getFeatureType() == gc.getInfoTypeForString('FEATURE_RUIN'):		
				return False
			return True
	return False

here is Caos Code:
Code:
gc = CyGlobalContext()

[COLOR="Red"]class NoSettleGameUtils(CvGameUtils.CvGameUtils):[/COLOR]
    def cannotFoundCity(self,argsList):
        iPlayer, iPlotX, iPlotY = argsList
        pPlot = gc.getMap().plot(iPlotX, iPlotY)
        for i in range(pPlot.getNumUnits()):
            pUnit = pPlot.getUnit(i)
            if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SETTLER'):
                return False
            elif pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_RUINS_SETTLER'):
		[COLOR="Red"]if pPlot.getImprovementType() == 2: # 2 = IMPROVEMENT_CITY_RUINS[/COLOR]
                    return False
                return True
        return False

I highlighted the bits in red that are different to mine as far as I can tell.

Like I said the ruins are a different type of ruin but you don't have it in brackets and you have the 2's in the middle are these crucial to makke it work and if so what does it mean so I can convert it to fury road.

and the top part of code what would I do with that to work with fury roadwould it be:

class CvFuryRoadGameUtils(CvGameUtils.CvGameUtils):

or

class NoSettleGameUtils(CvFuryRoadGameUtils.CvFuryRoadGameUtils):

or something different
 
CITY_RUINS is the 3rd improvement in the list, so it is numbered 2 (the first one starts at 0, remember). I think this is why there's a 2 there.

I don't know why the indentations are different- Cao, what editing program do you use? I use Notepad++, and if I copy both your code and my code, I get the same indents in both. But when they display in the
Code:
 tags, they seem different...

The reason all that "class" stuff, and the gameInterface tags are there is because Cao did his edits in "Modular Python"- he added a new GameUtils.py file so he didn't have to mess up the old one, with only the noSettler code in it. If you do this, you must make sure GameInterface.py recognizes your new file, otherwise it won't work. I don't [i]think[/i] this is necessary, I think it should work fine in the original file.
 
I thought that the 2's had someting to do with that but wasn't exactly sure how it applied.

I rewrote the code like this:

Code:
   def cannotFoundCity(self,argsList):
	iPlayer, iPlotX, iPlotY = argsList
	pPlot = CyMap().plot(iPlotX, iPlotY)
	for i in range(pPlot.getNumUnits()):
		pUnit = pPlot.getUnit(i)
		if pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_SETTLER'):
			return False
		elif pUnit.getUnitType() == gc.getInfoTypeForString('UNIT_EXCAVATOR'):
			if pPlot.getFeatureType() == 4: # 4 = FEATURE_RUIN		
				return False
			return True
	return False

the ruin was 5th in the list of terrain features so i made it 4, but the unit still founds anywhere?

I switched that python exceptions thing to 0 for the last 2 or 3 tries, but where do i go to find the information because nothing has auto displayed or anything?
 
I strongly suspect it has something to do with Fury Road, so:

In normal BTS, try copying both my code (first) and Cao's code (second) over def cannotFoundCity in CvGameUtils.py, but change the Feature to Improvement and make sure it says IMPROVEMENT_CITY_RUINS, not IMPROVEMENT_RUINS. Then, just copy Cao's original code exactly.

Make sure you back-up the original code for def cannotFoundCity!
 
If you want help debugging your code it really is necessary to have the exceptions displayed so we know what's not working. If you have the HidePythonExceptions = 0 in the ini of your MyGames directory then whenever Python has an error you'll get a popup box (usually multiple).

Off the top of my head the only real difference between my code and yours is that you are using CyMap() and I'm using gc.getMap() but they should both do the same thing. You might want to try switching them anyway just to check.
 
Back
Top Bottom