[MOD] Mana Flares and Unique Events Add-On

I like the imperial roads idea. But why do you have it as an event? Why not have it as a tech, available after construction? After you have researched it, 1-3 stone resources are placed (dependent on the number of cities you control) on the map within your borders. When you have connected the stone, the worker spell "Build Imperial Roads" appears in cities other than the capital, as per your rules.

...

I wanted to add the improvements + roads as event so I can set it to e.g. 20% for each game so it's not in every game and more unique.

Any chance this will get updated for RiFE 1.20?

I will add a version as soon as possible.


Spoiler GIR03ImperialRoads (Part 1 / 4) :

Spoiler AStarTools.py by 12monkeys :

Code:
## Civilization 4 (c) 2005 Firaxis Games
##
## name     : AStarTool.py
## author   : 12monkeys
## date     : 10.03.2006
## version  : 1.1
##


from CvPythonExtensions import *
import sys
import CvConfigParser
# import SdToolKit as sd

gc = CyGlobalContext()

		
#####################################################################
# Class : AStar
#####################################################################
# class provides functions to create a path from plot A to plot B for 
# a given unit. 
# Main function to be used from outsiede are : 
# 	generatePath()	: creates a path and prepares the reults
# 	getPath()		: retrurns the path if one has been found
#	generateArea()	: creates an area a unit can move to
#	getArea()		: returns the area if one has been created
# see the methods for further definitions
#####################################################################				
class AStar:
	
	def __init__(self):
		self.pOpenList 				= AStarList()
		self.pCloseList 			= AStarList()
		self.pTargetPlot 			= None
		self.pFromPlot 				= None
		self.pUnit 					= None
		self.fHeuristicMvmtFactor 	= 0.0 				# possible smallest cost value a move from plot to plot will take
		self.fHeuristicTieBreak		= float(1.0/1000.0) 	# assuming the paths are shorter than 400 steps
		self.bResultValid			= false
		self.iLoopCount				= 0
		self.eDomain 				= 0
		self.bIgnoreMovesLeft		= false
		self.MODE_AREA				= 'A'
		self.MODE_PATH				= 'P'
			
	# moves a plot from open list to close list
	def moveToClose(self, pPlot):
		pParent = self.pOpenList.getParent(pPlot)
		iGCost = self.pOpenList.getGCosts(pPlot)
		fHCost = self.pOpenList.getHCosts(pPlot)
		self.pCloseList.set(pPlot, pParent, iGCost, fHCost)
		self.pOpenList.delete(pPlot)
		
	# returns the minimum x-distance, considering the x-axis over-/underflow
	def getRealXDist(self, x1, x2):
		d1 = abs(x1-x2)
		d2 = abs(min(x1, x2)+CyMap().getGridWidth()-max(x1, x2))
		return min(d1, d2)
		
	# returns the minimum y-distance, considering the y-axis over-/underflow
	def getRealYDist(self, y1, y2):
		d1 = abs(y1-y2)
		d2 = abs(min(y1, y2)+CyMap().getGridHeight()-max(y1, y2))
		return min(d1, d2)
	
	# calculates the heuristic 
	def calcHeuristic(self, pPlot):
		if self.nMode == self.MODE_PATH:
			# using "diagonal distance" method
			H = self.fHeuristicMvmtFactor * max(self.getRealXDist(pPlot.getX(), self.pTargetPlot.getX()), self.getRealYDist(pPlot.getY(), self.pTargetPlot.getY()))
			# methods to calculate the tie-break value usding the vector cross-product (dot-product)
			dx1 = pPlot.getX() - self.pTargetPlot.getX()
			dy1 = pPlot.getY() - self.pTargetPlot.getY()
			dx2 = self.pFromPlot.getX() - pPlot.getX()
			dy2 = self.pFromPlot.getY() - pPlot.getY()
			cross = float(abs(dx1*dy2 - dx2*dy1))
			H += float(cross*0.001)
		elif self.nMode == self.MODE_AREA:
			# no heuristic if we want to find an area. THis ensures that the complete area is examined
			H = 0.0
		return H

	# calculates a factor for the heuristic for the heuristic
	def calculateHeuristicFactors(self):
		pUnitTypeInfo = gc.getUnitInfo(self.pUnit.getUnitType())
		self.eDomain = pUnitTypeInfo.getDomainType()
		if (self.eDomain == DomainTypes.DOMAIN_SEA):
			# all sea plots have movements costs of 60/plot
			self.fHeuristicMvmtFactor 	= 60.0
		else:
			# min possible movement costs of 12/plot
			self.fHeuristicMvmtFactor 	= 12.0 
			
	# checks in case of sea plots, if there is a landbridge between the two plots
	def fnCheckLandBridge(self, pPlot, x, y):
		pTestPlot = CyMap().plot(pPlot.getX()+x, pPlot.getY()+y)
		if not (pPlot.isCity() or pTestPlot.isCity()):
			pTestPlot = CyMap().plot(pPlot.getX()+x, pPlot.getY())
			if (pTestPlot.isCoastalLand()):
				pTestPlot = CyMap().plot(pPlot.getX(), pPlot.getY()+y)
				if (pTestPlot.isCoastalLand()):
					return true
		return false
			
	# returns an adjacent plots reletaive to the coordinates of pPlot.
	# takes consideration of x and/or y overlows or underflows
	def getNewPlot(self, pPlot, dx, dy):
		x = pPlot.getX()+dx
		y = pPlot.getY()+dy
		# check x underflow
		if x < 0:
			x += CyMap().getGridWidth()
		# check x overflow
		elif x >= CyMap().getGridWidth():
			x -= CyMap().getGridWidth()
		# check y underflow
		if y < 0:
			y += CyMap().getGridHeight()
		# check y overflow
		elif y >= CyMap().getGridHeight():
			y -= CyMap().getGridHeight()
		return CyMap().plot(x, y)
		
	# core function of the A* algorithm
	# calculates the adjacents and puts them on the open list together wth the moving costs.
	# in case of area check, the heuristic is zero.
	def addAdjacents(self, pPlot):
		# loops for adjacent plots
		for dx in range(-1, 2):
			for dy in range(-1, 2):
				# ignore center plot
				if not (dx == 0 and dy == 0):
					# create a plot objects
					pNewPlot = self.getNewPlot(pPlot, dx, dy)
					# check in case sof a sea unit, if there is a land bridge to cross
					if (dx != 0) and (dy != 0) and (self.eDomain == DomainTypes.DOMAIN_SEA):
						bCont = not self.fnCheckLandBridge(pPlot, dx, dy)
					else: 
						bCont = true
					if bCont:
						# check if the plot is passable
						if self.pUnit.canMoveOrAttackInto(pNewPlot, true):
							# check if the plot is already on the close list
							if not self.pCloseList.exists(pNewPlot):
								# calculate movement cost from root plot to new plot
								if self.pCloseList.exists(pPlot):
									iParentGCosts = self.pCloseList.getGCosts(pPlot)
								else:
									iParentGCosts = self.pOpenList.getGCosts(pPlot)
								iGCosts = pPlot.movementCost(self.pUnit, pNewPlot)+iParentGCosts
								if (self.bIgnoreMovesLeft) or (iGCosts <= self.iMovesLeft):
									# calculate heuristics cost new plot to targetplot
									fHCosts = self.calcHeuristic(pNewPlot)
									# calculate total costs new plot to targetplot
									fFCosts = float(iGCosts) + fHCosts
									# checks if the plot is on the open list already
									if self.pOpenList.exists(pNewPlot):
										# check if the already stored costs are less than the actual ones
										if iGCosts <= self.pOpenList.getGCosts(pNewPlot):
											self.pOpenList.set(pNewPlot, pPlot, iGCosts, fHCosts)
									else:
										# add it to the open list
										self.pOpenList.set(pNewPlot, pPlot, iGCosts, fHCosts)
						else:
							if self.nMode == self.MODE_AREA:
								self.pCloseList.set(pNewPlot, pPlot, -1, 0)
		return 
	
	# 
	# returns the path data which has been generate by "generatePath()" method.
	# It only returns a result when there is a valid result stored. If there is 
	# no valid result, the function returns an empty list
	# Attention : The first element of the returned list, is the last plot of the path!!!
	# The Method should only be called, if the "generatePath()" method has been called before.
	#
	# Parameters:
	# 	none
	# Returns: 
	# 	list in the format [(xn,yn), .... , (x2,y2), (x1,y1), (x0,y0)]
	# 	where 
	#		(xn,yn) : is the to-plot tuple and 
	#		(x0,y0) : is the from-plot tuple. x and y are ints.
	# 
	def getPath(self):
		lPath = []
		if self.bResultValid:
			pWorkPlot 	= self.pTargetPlot
			pParentPlot	= self.pTargetPlot
			while true:
				# adding target plot to the path
				lPath.append(self.pCloseList.getXY(pWorkPlot))
				# looking for the parent of the 
				pParentPlot = self.pCloseList.getParent(pWorkPlot)
				# make parent the work plot
				pWorkPlot = pParentPlot
				# check if we reached from plot
				if (pWorkPlot.getX() == self.pFromPlot.getX()) and (pWorkPlot.getY() == self.pFromPlot.getY()):
					break
		return lPath			
			
	#
	# tries to find a path from plot A to B and returns the overall movement costs for 
	# the unit. If no path could be found -1 is returned.
	# To get the path itself, the method getPath() must be called afterwards.
	# 
	# Parameters:
	# 	pUnit			: CyUnit 
	# 	pFromPlot 		: CyPlot
	# 	pToPlot 		: CyPlot
	# 	bIgnoreMovesLeft: bool
	# Returns:
	#	int 		(the costs to get from pFromPlot to pToPlot. -1 if no path could be found)
	#
	# The parameter "bIgnoreMovesLeft" can be used to reduce execution time. If the parameter is true, 
	# the algorithm stops a single path examiation if the remaining moves of a unit are not enough 
	# to reach the target plot. This significantly speeds up the algorithm in case you want to look for the 
	# the movable area. 
	# The parameter should be set to false in case you want to find a path from plot A to B without 
	# cost restrictions.
	# 
	def generatePath(self, pUnit, pFromPlot, pToPlot, bIgnoreMovesLeft):
	
		# clear the actual results
		self.bResultValid = false
		self.pOpenList.clear()
		self.pCloseList.clear()
		self.nMode = self.MODE_PATH
		
		# setting some variables
		self.pTargetPlot 		= pToPlot
		self.pFromPlot 			= pFromPlot
		self.pUnit 				= pUnit
		pNewPlot 				= pFromPlot
		pCurrentPlot			= pFromPlot
		bBreak 					= false
		self.iLoopCount			= 0
		self.iMovesLeft			= pUnit.movesLeft()
		self.bIgnoreMovesLeft	= bIgnoreMovesLeft

		# perfrom some checks ...
		if ((pFromPlot.getX() == pToPlot.getX()) and (pFromPlot.getY() == pToPlot.getY())):
			# From and To plot are equal -> break
			return -1
		if not (self.pUnit.canMoveOrAttackInto(pToPlot, true)):
			# To plot not passable -> break
			return -1		
		
		# calculates some values for the heuristic
		self.calculateHeuristicFactors()
		
		# put start plot on the open list
		self.pOpenList.set(pCurrentPlot, pCurrentPlot, 0, self.calcHeuristic(pNewPlot))	

		# repeat until target plot is reached
		while (true):
			self.addAdjacents(pCurrentPlot)
			self.moveToClose(pCurrentPlot)	
			if (self.pCloseList.exists(self.pTargetPlot)):
				# path found
				break
			if (self.pOpenList.len() == 0):
				# no path found
				bBreak = true
				break
			# find the plot with the lowest costs on the open list
			pCurrentPlot = self.pOpenList.findMinFCost()
			self.iLoopCount	+= 1

		# return the G-Costs of the Target Plot
		if bBreak:
			# no path found
			iReturn = -1
			self.bResultValid = false
		else:
			iReturn = int(self.pCloseList.getGCosts(pCurrentPlot))
			self.bResultValid = true
			
		return iReturn

	#
	# returns the area which has been found by "generateArea()". If no valid result is stored, an
	# empty list is retured.
	# The method should only be called, if the "generateArea()" method has been called before.
	# 
	# Parameters:
	# 	none
	# Returns:
	# 	list on the format [((x0,y0),c0), ((x1,y1),c1), ... , ((xn,yn),cn)]
	# 	where :
	#		(x,y) : is a tuple of ints describing the plots coordinates 
	#		c : the movements costs to get to the plot. -1 if the plot is impassable 
	# 
	def getArea(self):
		lArea = []
		if self.bResultValid:
			for i in range(self.pCloseList.len()):
				if i == 0:
					lAPlot = self.pCloseList.getFirst()
				else:
					lAPlot = self.pCloseList.getNext()
				iCosts = self.pCloseList.getGCosts(CyMap().plot(lAPlot[0], lAPlot[1]))
				lArea.append((lAPlot, iCosts))
		return lArea		

	#
	# creates an area a unit can move to within its remaining movement points. 
	# the function always returns 1, because even an empty list is a result.
	# to get the area itself, after the generateArea function, the method getArea() must be called
	#
	# Paramters : 
	#	pUnit		: CyUnit 
	#	pFromPlot 	: CyPlot
	# Returns : 
	#	int 		(constant 1)
	#
	def generateArea(self, pUnit, pFromPlot):
		
		# clear the actual results
		self.bResultValid = false
		self.pOpenList.clear()
		self.pCloseList.clear()
		self.nMode = self.MODE_AREA
		
		# setting some variables
		self.pTargetPlot 		= None
		self.pFromPlot 			= pFromPlot
		self.pUnit 				= pUnit
		pNewPlot 				= pFromPlot
		pCurrentPlot			= pFromPlot
		bBreak 					= false
		self.iLoopCount			= 0
		self.iMovesLeft			= pUnit.movesLeft()
		self.bIgnoreMovesLeft	= false

		
		# calculates some values for the heuristic
		self.calculateHeuristicFactors()
		
		# put start plot on the open list
		self.pOpenList.set(pCurrentPlot, pCurrentPlot, 0, self.calcHeuristic(pNewPlot))	

		# repeat until target plot is reached
		while (true):
			self.addAdjacents(pCurrentPlot)
			self.moveToClose(pCurrentPlot)	
			if (self.pOpenList.len() == 0):
				# list is empty -> all plots are examined
				break
			# find the plot with the lowest costs on the open list
			pCurrentPlot = self.pOpenList.findMinFCost()
			self.iLoopCount	+= 1

		# return the G-Costs of the Target Plot
		iReturn = 1
		self.bResultValid = true
		
		return iReturn
		
		
#####################################################################
# Class : AStarMoveArea
#####################################################################
# class provides functions to create a list of plots a unit can move 
# within its left moves. It also provides some functions to display
# and clear the this area.
# Main function to be used from outsiede are : 
# 	highlightMoveArea()		: calculates and highlights the area the can move to and computes the plot colors
#	dehighlightMoveArea()	: clears the display of that area
# see the methods for further definitions
# 
# the colors of the signle plots can be set in the __init__ section of the class
# COLOR_CLEAR can be used for no highlighting at all
#####################################################################		
class AStarMoveArea:

	def __init__(self):
		self.dPlotList 					= {}
		self.AS 						= AStar()
		self.pUnit 						= 0
		self.pFromPlot 					= 0
		self.PLE_HIGHLIGHT_PLOTS	 	= PlotLandscapeLayers.PLOT_LANDSCAPE_LAYER_REVEALED_PLOTS 
		self.lArea 						= []
		self.iActivePlayerTeam			= 0
		self.iActivePlayer				= 0
		
		# color values
		self.COL_NO						= "COLOR_CLEAR"

		config = CvConfigParser.CvConfigParser("AStarTools.ini")		
		if (config != None):
			self.COL_IMPASSABLE 			= config.get( "AStarTools", "Color Impassable Terrain", 			"COLOR_CLEAR" )
			self.COL_PASSABLE 				= config.get( "AStarTools", "Color Passable Terrain", 			 	"COLOR_WHITE" )
			self.COL_TERRITORY_NEUTRAL 		= config.get( "AStarTools", "Color Passable Neutral Territory",	 	"COLOR_PLAYER_DARK_YELLOW" )
			self.COL_TERRITORY_ENEMY 		= config.get( "AStarTools", "Color Passable Enemy Territory", 	 	"COLOR_PLAYER_DARK_RED" )
			self.COL_TERRITORY_BARBARIAN 	= config.get( "AStarTools", "Color Passable Barbarian Territory", 	"COLOR_PLAYER_DARK_CYAN" )
			self.COL_UNIT_NEUTRAL 			= config.get( "AStarTools", "Color Neutral Unit", 				 	"COLOR_YELLOW" )
			self.COL_UNIT_ENEMY 			= config.get( "AStarTools", "Color Enemy Unit", 					"COLOR_RED" )
			self.COL_UNIT_BARBARIAN 		= config.get( "AStarTools", "Color Barbarian Unit", 				"COLOR_CYAN" )			
		
	# converts a CyPlot into a tuple (x,y)
	def getPlotXY(self, pPlot):
		return (pPlot.getX(), pPlot.getY())
		
	# checks if there are any units on the plot and returns the corresponding color
	def checkUnit(self, pPlot):
		iNumUnits = pPlot.getNumUnits()
		bEnemy = false
		bNeutral = false
		bBarbarian = false
		for i in range(iNumUnits):
			pUnit = pPlot.getUnit(i)
			iTeam = pUnit.getTeam()
			if ((pUnit.getInvisibleType() == InvisibleTypes.NO_INVISIBLE) or \
				(pUnit.getInvisibleType() == self.pUnit.getSeeInvisibleType())) and \
				(not pUnit.isCounterSpy()):
				if (iTeam != self.iActivePlayerTeam):
					if (gc.getTeam(iTeam).isBarbarian()):
						bBarbarian = true
					elif (gc.getTeam(iTeam).isAtWar(self.iActivePlayerTeam)):
						bEnemy = true
					else:
						bNeutral = true
		if bEnemy:
			return self.COL_UNIT_ENEMY
		elif bBarbarian:
			return self.COL_UNIT_BARBARIAN
		elif bNeutral:
			return self.COL_UNIT_NEUTRAL
		return self.COL_PASSABLE

	# checks if there forwign territory on the plot and returns the corresponding color
	def checkTerritory(self, pPlot):
		iPlayer = pPlot.getRevealedOwner(self.iActivePlayerTeam, false)
		pPlayer = gc.getPlayer(iPlayer)
		iTeam = pPlot.getRevealedTeam(self.iActivePlayerTeam, false)
		pTeam = gc.getTeam(iTeam)
		if pPlot.isRevealedGoody(iTeam):
			if (pPlot.getImprovementType() == 3):#ImprovementTypes.IMPROVEMENT_GOODY_HUT):
				return self.COL_TERRITORY_BARBARIAN
		elif (iPlayer == PlayerTypes.NO_PLAYER) or (iPlayer == self.iActivePlayer):
			return self.COL_PASSABLE
		elif pTeam.isAtWar(self.iActivePlayerTeam):
			return self.COL_TERRITORY_ENEMY
		else:
			return self.COL_TERRITORY_NEUTRAL			
	
	# checks if there are revelaed plots adjacent to the given plot
	def checkAdjacentRevealed(self, pPlot):
		for dx in range(-1, 2):
			for dy in range(-1, 2):
				if not (dx == 0 and dy == 0):
					if CyMap().plot(pPlot.getX()+dx, pPlot.getY()+dy).isRevealed(self.iActivePlayerTeam, false):
						return true
		return false
	
	# handles the color for a plot
	def setPlotColor(self, x, y, iCosts):
		pPlot = CyMap().plot(x, y)
		tPlot = (x, y)
		self.dPlotList[tPlot] = self.COL_NO
		# check impassable
		if iCosts == -1:
			if (pPlot.isWater() and (self.eDomain == DomainTypes.DOMAIN_SEA)) or ((not pPlot.isWater()) and (self.eDomain == DomainTypes.DOMAIN_LAND)):
				self.dPlotList[tPlot] = self.COL_IMPASSABLE
		# check if plot is reachable
		elif iCosts <= self.iMovesLeft:
			# check if the plot is reavealed
			if pPlot.isRevealed(self.iActivePlayerTeam, false):
				# check if a unit at that plot
				if pPlot.isUnit() and pPlot.isVisible(self.iActivePlayerTeam, false):
					self.dPlotList[tPlot] = self.checkUnit(pPlot)
				# check if the plot is foreign territory
				elif pPlot.isVisible(self.iActivePlayerTeam, false):
					self.dPlotList[tPlot] = self.checkTerritory(pPlot)
				# nothing special with that plot
				else:
					self.dPlotList[tPlot] = self.COL_PASSABLE
			else:
				if self.checkAdjacentRevealed(pPlot):
					self.dPlotList[tPlot] = self.COL_PASSABLE
				else:
					self.dPlotList[tPlot] = self.COL_NO		
	
	#
	# highlights the area a unit can move to with its remaining movement points
	#
	# Parameters:
	# 	pUnit : CyUnit
	# Returns:
	# 	int		(constant 1)
	# 
	def highlightMoveArea(self, pUnit):
		# init some variables
		self.pUnit 				= pUnit
		self.pFromPlot 			= pUnit.plot()
		self.dPlotList 			= {}
		self.iMovesLeft 		= self.pUnit.movesLeft()
		pUnitTypeInfo 			= gc.getUnitInfo(self.pUnit.getUnitType())
		self.eDomain 			= pUnitTypeInfo.getDomainType()
		self.iActivePlayer 		= CyGame().getActivePlayer()
		pActivePlayer 			= gc.getPlayer(self.iActivePlayer)
		self.iActivePlayerTeam 	= pActivePlayer.getTeam()
		
		# add from plot to OK list
		self.dPlotList[self.getPlotXY(self.pFromPlot)] = 0

		# creates the infromation of the moveable area
		self.AS.generateArea(self.pUnit, self.pFromPlot)
		self.lArea = self.AS.getArea()
		
		# analyze data and set plot colors
		for i in range(len(self.lArea)):
			tItem = self.lArea[i]
			self.setPlotColor(tItem[0][0], tItem[0][1], tItem[1])
				
		# highlight the area
		self.highlightMoves()
		return 1
	
	# displays the area on the screen
	def highlightMoves(self):
		for plot, color in self.dPlotList.items(): 
			if color != self.COL_NO:
				CyEngine().addColoredPlotAlt(plot[0], plot[1], PlotStyles.PLOT_STYLE_TARGET, self.PLE_HIGHLIGHT_PLOTS, color, .5)

	#
	# clears the disaply of the area 
	#
	# Parameters:
	# 	none
	# Returns:
	# 	int		(constant 1)
	# 
	def dehighlightMoveArea(self):
		CyEngine().clearColoredPlots(self.PLE_HIGHLIGHT_PLOTS)
		return 1
	

	
#####################################################################
# Class : AStarPlot
#####################################################################
# class which is used to handle a specific plot format
# the plot data is stored as tuple in the format (x, y)
# class provides several function to handle this format 
# Only for internal use. 
#####################################################################		
class AStarPlot:
	
	def __init__(self):
		self.lPlot = (-1, -1)
		self.IDX_X = 0
		self.IDX_Y = 1
		
	# clears plot data
	def clear(self):
		self.lPlot = (-1, -1)
		
	# x, y : ints
	def setXY(self, x, y):
		self.lPlot = (x, y)
		
	# pPlot: CyPlot
	def setXYplot(self, pPlot):
		self.lPlot = (pPlot.getX(), pPlot.getY())
		
	# return x: int
	def getX(self):
		return self.lPlot[self.IDX_X]

	# return y: int
	def getY(self):
		return self.lPlot[self.IDX_Y]

	# x, y : ints
	# return (x,y)
	def getXY(self):
		return (self.getX(), self.getY())
		
	# pCompPlot: AStarPlot()
	# returns true if plot coords are equal
	def compare(self, pCompPlot):
		if (self.getX() == pCompPlot.getX()) and (self.getY() == pCompPlot.getY()):
			return true
		else:
			return false

			
#####################################################################
# Class : AStarList
#####################################################################
# class wto handle the open and close list for the AStar algorithm
# for internal use only
#####################################################################		
class AStarList:
	
	def __init__(self):
		self.dList = {}
		self.IDX_PARENT = 0
		self.IDX_GCOSTS = 1
		self.IDX_HCOSTS = 2
		self.IDX_FCOSTS = 3
		self.IDX_X = 0
		self.IDX_Y = 1
		self.maxCost = 9999999.9

	# clears the list
	def clear(self):
		self.dList = {}

	# creates a AStarPlot 
	# x, y: int
	# return: AStarPlot
	def makeAPlotXY(self, x, y):
		pAPlot = AStarPlot()
		pAPlot.setXY(x, y)
		return pAPlot
		
	# creates a AStarPlot 
	# pPlot = CyPlot
	# return: AStarPlot
	def makeAPlot(self, pPlot):
		return self.makeAPlotXY(pPlot.getX(), pPlot.getY())
		
	# sets all plot data
	# pAParent: AStarPlot, others are floats
	# return: ((x,y), int, float, float)
	def setPlotData(self, pAParent, iGCosts, fHCosts, fFCosts):
		return (pAParent, iGCosts, fHCosts, fFCosts)

	# returns all plot data
	# pAPlot: AStarPlot
	# return: ((x,y), float, float, float)
	def getPlotData(self, pAPlot):
		return self.dList[pAPlot.getXY()]

		
	# adds the complete plot to the list
	# pThisPlot, pParentPlot : CyPlot
	# iGCosts, fHCosts : int, float
	# if plot already exists, it will be overwritten
	def set(self, pThisPlot, pParentPlot, iGCosts, fHCosts):
		pAThisPlot = self.makeAPlot(pThisPlot)
		pAParentPlot = self.makeAPlot(pParentPlot)
		self.dList[pAThisPlot.getXY()] = self.setPlotData(pAParentPlot, iGCosts, fHCosts, float(iGCosts)+float(fHCosts))
			
	# pPlot : CyPlot
	# deletes the plot from the list
	def delete(self, pPlot):
		pAPlot = self.makeAPlot(pPlot)
		if self.dList.has_key(pAPlot.getXY()):
			del self.dList[pAPlot.getXY()]
			return true
		else:
			return false
			
	# pPlot : CyPlot
	# returns the g-costs as float
	def getGCosts(self, pPlot):
		pAPlot = self.makeAPlot(pPlot)
		return float(self.dList[pAPlot.getXY()][self.IDX_GCOSTS])

	# pPlot : CyPlot
	# returns the h-costs as float
	def getHCosts(self, pPlot):
		pAPlot = self.makeAPlot(pPlot)
		return float(self.dList[pAPlot.getXY()][self.IDX_HCOSTS])

	# pPlot : CyPlot
	# returns the f-costs as float
	def getFCosts(self, pPlot):
		pAPlot = self.makeAPlot(pPlot)
		return float(self.dList[pAPlot.getXY()][self.IDX_FCOSTS])

	# pPlot : CyPlot
	# returns the parent plot of the passed plot as CyPlot
	def getParent(self, pPlot):
		pAPlot = self.makeAPlot(pPlot)
		pAPlotData = self.getPlotData(pAPlot)
		x = pAPlotData[self.IDX_PARENT].getX()
		y = pAPlotData[self.IDX_PARENT].getY()
		return CyMap().plot(x, y)
		
	# returns the coords of a plot	(x,y)
	# pPlot: CyPlot
	def getXY(self, pPlot):
		pAPlot = self.makeAPlot(pPlot)
		return pAPlot.getXY()
		
	# pPlot : CyPlot
	# returns true if the plot exists in the list
	def exists(self, pPlot):
		pAPlot = self.makeAPlot(pPlot)
		if self.dList.has_key(pAPlot.getXY()):
			return true
		return false

	# pPlot : CyPlot
	# returns AStarPlot if found, else ()
	def search(self, pPlot):
		pAPlot = self.makeTPlot(pPlot)
		if self.dList.has_key(pAPlot.getXY()):
			return self.dList[(pAPlot.getXY())]
		return ()

	# returns the number of items in the list
	def len(self):
		return len(self.dList)

	# looks for the element with the smallest f-costs and returns it as CyPlot
	def findMinFCost(self):
		fComp = self.maxCost
		for key, val in self.dList.items():
			lData = self.dList[key]
			if lData[self.IDX_FCOSTS] < fComp:
				fComp = lData[self.IDX_FCOSTS]
				retKey = key
		x = retKey[0]
		y = retKey[1]
		return CyMap().plot(x, y)
	
	# returns the first element in the dict as CyPlot and prepares to fetch the next
	def getFirst(self):
		self.lList = []
		self.iList = 0
		for key, val in self.dList.items():
			self.lList.append(key)
		return self.lList[0]
		
	# returns the next element in the dict as CyPlot. "getFirst" needs to be called before.
	def getNext(self):
		if self.iList < self.len():
			self.iList += 1
			return self.lList[self.iList]
		else:
			return ()

 
Update:
R i f E version:

- compatible with R i f E 1.20
- fixed a bug with imperial roads (now you can only use the imperial roads 'spell' after the imperial road event)
- fixed text bugs
- activated the ice mana flare event
- fixed a bug when casting the bet spell or arena battle spell on Great Colosseum and/or Great Circus on unowned plots​

Spoiler GIR03ImperialRoads (Part 2 / 4) :

Spoiler eventGIR03ImperialRoads_CvRandomEventInterface.py :

Code:
## eventGIR03ImperialRoads_CvRandomEventInterface.py
## MODULAR PYTHON FOR IMPERIAL ROADS MODULE
## by GIR
## Last Edited: 2011.01.19
##

from CvPythonExtensions import *
import GIR03ImperialRoads

# globals
IR = GIR03ImperialRoads.GIR03ImperialRoads()

def doViaAppiaTrigger_1(argsList):
	iHelp = 2
	IR.doGetHelpViaAppiaTrigger_1( argsList, iHelp )
def getHelpViaAppiaTrigger_1(argsList):
	iHelp = 1
	szHelp = IR.doGetHelpViaAppiaTrigger_1( argsList, iHelp )
	return szHelp

def getHelpViaAppiaTrigger2Yes(argsList):
	iHelp = 1
	szHelp = IR.CanDoGetHelpViaAppiaTrigger2Yes( argsList, iHelp )
	return szHelp
def doViaAppiaTrigger2Yes(argsList):
	iHelp = 2
	IR.CanDoGetHelpViaAppiaTrigger2Yes( argsList, iHelp )
def canDoViaAppiaTrigger2Yes(argsList):
	iHelp = 3
	bool = IR.CanDoGetHelpViaAppiaTrigger2Yes( argsList, iHelp )
	return bool

def doViaAppiaDelay(argsList):
	IR.doViaAppiaDelay( argsList )

def getHelpViaAppiaDelay1(argsList):
	szHelp = IR.getHelpViaAppiaDelay1( argsList )
	return szHelp

def canDoViaAppiaBuildRoadInfo(argsList):
	iHelp = 1
	bool = IR.CanDoHelpViaAppiaBuildRoadInfo( argsList, iHelp )
	return bool
def getHelpViaAppiaBuildRoadInfo(argsList):
	iHelp = 2
	szHelp = IR.CanDoHelpViaAppiaBuildRoadInfo( argsList, iHelp )
	return szHelp

def getHelpViaAppiaBuildRoad1(argsList):
	szHelp = IR.getHelpViaAppiaBuildRoad1( argsList )
	return szHelp

def canDoViaAppiaBuildRoad2(argsList):
	iHelp = 1
	bool = IR.CanDoHelpViaAppiaBuildRoad2( argsList, iHelp )
	return bool
def getHelpViaAppiaBuildRoad2(argsList):
	iHelp = 2
	szHelp = IR.CanDoHelpViaAppiaBuildRoad2( argsList, iHelp )
	return szHelp
def doViaAppiaBuildRoad2(argsList):
	iHelp = 3
	IR.CanDoHelpViaAppiaBuildRoad2( argsList, iHelp )

def canTriggerViaAppiaBuildRoadAI(argsList):
	iHelp = 1
	bool = IR.TriggerApplyViaAppiaBuildRoadAI( argsList, iHelp )
	return bool
def applyViaAppiaBuildRoadAI(argsList):
	iHelp = 2
	IR.TriggerApplyViaAppiaBuildRoadAI( argsList, iHelp )

Spoiler GIR03ImperialRoads_CvEventManager.py :

Code:
## GIR03ImperialRoads_CvEventManager.py
## MODULAR PYTHON FOR IMPERIAL ROADS MODULE
## by GIR
## Last Edited: 2011.01.19
##

from CvPythonExtensions import *
import SdToolKitAdvanced
import GIR03ImperialRoads

# globals
sdObjectGetVal = SdToolKitAdvanced.sdObjectGetVal

def onGameStart(self, argsList):
	'Called at the start of the game'
	gc 					= CyGlobalContext()
	lList = []
	for i in range(gc.getMAX_PLAYERS()):
		lList.append(-1)
	### "lZE_ViaAppia": -1 = notTriggered, 1 = Search, 0 = Triggered, ? = ?lpath ###
	scriptDictViaAppia 	= {
							"sZE_ViaAppia":				str("notTriggered"),
							"lZE_ViaAppia":				lList,
							"lZE_ViaAppiaCounter":		lList,
							"lZE_tempViaAppia":			[],
							"lZE_tlViaAppia":			[]
							}
	SdToolKitAdvanced.sdObjectInit("GIR03ImperialRoads", gc.getGame(), scriptDictViaAppia)

def onBeginGameTurn(self, argsList):
	'Called at the beginning of the end of each turn'
	gc = CyGlobalContext()
	if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "sZE_ViaAppia") != str("notTriggered"):
		GIR03ImperialRoads.GIR03ImperialRoads().onBeginGameTurnViaAppia()

def onCityBuilt(self, argsList):
	'City Built'
	gc 		= CyGlobalContext()
	pCity 	= argsList[0]
	iPlayer = pCity.getOwner()
	if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer] == -1:
		GIR03ImperialRoads.GIR03ImperialRoads().triggerViaAppiaSystem( iPlayer )

def onCityAcquiredAndKept(self, argsList):
	'City Acquired and Kept'
	gc 				= CyGlobalContext()
	iOwner, pCity 	= argsList
	iPlayer 		= pCity.getOwner()
	if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer] == -1:
		GIR03ImperialRoads.GIR03ImperialRoads().triggerViaAppiaSystem( iPlayer )

def onUnitPillage(self, argsList):
	'Unit pillages a plot'
	pUnit, iImprovement, iRoute, iOwner = argsList
	gc 		= CyGlobalContext()
	pPlot 	= CyMap().plot(pUnit.getX(), pUnit.getY())
	if iRoute == gc.getInfoTypeForString("ROUTE_ROMANROAD"):
		pPlot.setRouteType(gc.getInfoTypeForString("ROUTE_ROAD"))

def onTechAcquired(self, argsList):
	'Tech Acquired'
	iTechType, iTeam, iPlayer, bAnnounce = argsList
	# Note that iPlayer may be NULL (-1) and not a refer to a player object
	if iPlayer != -1:
		gc = CyGlobalContext()
		if iPlayer != gc.getORC_PLAYER() and iPlayer != gc.getANIMAL_PLAYER() and iPlayer != gc.getDEMON_PLAYER():
			if gc.getGame().getElapsedGameTurns() >= 1:
				if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer] == -1:
					GIR03ImperialRoads.GIR03ImperialRoads().triggerViaAppiaTechReq( argsList )

Spoiler spellGIR03ImperialRoads_CvSpellInterface.py :

Code:
## spellGIR03ImperialRoads_CvSpellInterface.py
## MODULAR PYTHON FOR IMPERIAL ROADS MODULE
## by GIR
## Last Edited: 2011.01.19
##

from CvPythonExtensions import *
import GIR03ImperialRoads

# globals
IR = GIR03ImperialRoads.GIR03ImperialRoads()

def reqViaAppiaUWI(caster):
	iHelp = 1
	bool = IR.reqAndSpellViaAppiaUWI( caster, iHelp )
	return bool
def spellViaAppiaUWI(caster):
	iHelp = 2
	IR.reqAndSpellViaAppiaUWI( caster, iHelp )

 
Is that a strict 20%, or are you open to argument/suggestions? I mean I'm installing your mod because I want those roads, so it'd be kind of a bummer if they didn't show up. Maybe instead, you might have multiple points where the roads have increasing probability of becoming available (the way some traits can be earned by minor leaders).

As a separate suggestion, it seems like some civs would be more inclined to have your roads (Bannor) than others (Lanum).
 
Is that a strict 20%, or are you open to argument/suggestions? I mean I'm installing your mod because I want those roads, so it'd be kind of a bummer if they didn't show up. Maybe instead, you might have multiple points where the roads have increasing probability of becoming available (the way some traits can be earned by minor leaders).

At the moment my two buildings and the imperial roads have a chance of 100% in each game (if you meet the requirements) so everyone can test them and find bugs and unbalanced stuff...

I think i will give the buildings a 20% chance - for the roads I'm not not sure (because I also very like them). Maybe they will stay at 100%.

As a separate suggestion, it seems like some civs would be more inclined to have your roads (Bannor) than others (Lanum).

I'm always open for ideas - what do u suggest?
I could think of cheaper and quicker build roads for Bannor, what else?



@EVERYONE:
what do you think about the mana flare event chance? is it too low? it is very rare that i see one within my borders or is it only me...

Spoiler GIR03ImperialRoads (Part 3 / 4) :

Spoiler GIR03ImperialRoads.py (PART 1 / 2) :

Code:
## GIR03ImperialRoads.py
## MODULAR PYTHON FOR IMPERIAL ROADS MODULE
## by GIR
## Last Edited: 2011.01.19
##

from CvPythonExtensions import *
import PyHelpers
import SdToolKitAdvanced
import AStarTools

# globals
gc = CyGlobalContext()
AStar = AStarTools.AStar()
sdObjectSetVal = SdToolKitAdvanced.sdObjectSetVal
sdObjectGetVal = SdToolKitAdvanced.sdObjectGetVal
localText = CyTranslator()

class GIR03ImperialRoads:

	### "lZE_ViaAppia": -1 = notTriggered, 1 = Search, 0 = Triggered, ? = ?lpath ###

	def getl_iTechReqViaAppia( self ):
		l_sTechReqViaAppia = [ "EXPLORATION", "MASONRY" ]
		l_iTechReqViaAppia = [ gc.getInfoTypeForString( "TECH_" + sTechReqViaAppia ) for sTechReqViaAppia in l_sTechReqViaAppia ]
		return l_iTechReqViaAppia

	def triggerViaAppiaTechReq( self, argsList ):
		iTechType, iTeam, iPlayer, bAnnounce = argsList
		l_iTechReqViaAppia = self.getl_iTechReqViaAppia()
		if iTechType in l_iTechReqViaAppia:
			self.triggerViaAppiaSystem( iPlayer )

	def triggerViaAppiaSystem( self, iPlayer ):
		l_iTechs = self.getl_iTechReqViaAppia()
		if self.isHasTechReqAND( iPlayer, l_iTechs ) == True:
			pPlayer 	= gc.getPlayer(iPlayer)
			l_pyCity 	= []
			iZahler 	= 0
			imaxCities 	= 10
			iWachter 	= 0
			for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList():
				l_pyCity.append(pyCity)
				iZahler += 1
				if iZahler == imaxCities:
					iWachter = 1
					break

			if iWachter == 0:
				iLange 	= len(l_pyCity)
				if iLange >= 3:
					pCCity 	= pPlayer.getCapitalCity()
					pCPlot 	= CyMap().plot(pCCity.getX(), pCCity.getY())
					if CyMap().getArea(pCPlot.getArea()).getCitiesPerPlayer(iPlayer) >=3:
						iWachter = 1
			if iWachter == 0:
				if iLange >= 5:
					for i in range(iLange):
						ppCity 	= l_pyCity[i].GetCy()
						ppPlot 	= CyMap().plot(ppCity.getX(), ppCity.getY())
						if CyMap().getArea(ppPlot.getArea()).getCitiesPerPlayer(iPlayer) >=2:
							iWachter = 1
							break
			if iWachter == 1:
				if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "sZE_ViaAppia") == str("notTriggered"):
					sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "sZE_ViaAppia", str("Triggered"))
				temp_lZE_ViaAppia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")
				temp_lZE_ViaAppia[iPlayer] = 0		# ### 0 = Triggered
				sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia", temp_lZE_ViaAppia)
				iEvent 		= gc.getInfoTypeForString("EVENTTRIGGER_VIA_APPIA_TRIGGER")
				triggerData = gc.getPlayer(iPlayer).initTriggeredData(iEvent, -1, -1, -1, -1, iPlayer, -1, -1, -1, -1, -1)
				
	def onBeginGameTurnViaAppia( self ):		### "lZE_ViaAppia": -1 = notTriggered, 1 = Search, 0 = Triggered, ? = ?lpath ###
		l_lZE_ViaAppiaCounter 	= sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")
		iLangeCounter 			= len( l_lZE_ViaAppiaCounter )
		for i in range(iLangeCounter):
			if l_lZE_ViaAppiaCounter[i] >= 1:
				iPlayer = i
				temp_lZE_ViaAppiaCounter = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")
				temp_lZE_ViaAppiaCounter[i] = temp_lZE_ViaAppiaCounter[i] - 1
				sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter", temp_lZE_ViaAppiaCounter)
				i_ViaAppiaCounter_iPlayer = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")[iPlayer]
				
				if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[i] == 1:			# ### Search
					if i_ViaAppiaCounter_iPlayer > 0:
						self.printSearchStones( iPlayer, i_ViaAppiaCounter_iPlayer )
					elif i_ViaAppiaCounter_iPlayer == 0:
						iEvent = gc.getInfoTypeForString("EVENTTRIGGER_VIA_APPIA_DELAY")
						triggerData = gc.getPlayer(iPlayer).initTriggeredData(iEvent, true, -1, -1, -1, iPlayer, -1, -1, -1, -1, -1)
						temp_lZE_ViaAppia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")
						temp_lZE_ViaAppia[i] = 0
						sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia", temp_lZE_ViaAppia)
				elif sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[i] != 1:		# ### Imperial Road in progress or waiting
					iDelay = self.getiDeley()					# ### 2,3,4,8 <-- Achtung - CanDoHelpViaAppiaBuildRoad2 iImmobile Timer
					if i_ViaAppiaCounter_iPlayer > 0:
						self.printImperialRoadProject( iPlayer, i_ViaAppiaCounter_iPlayer )
						iRest = i_ViaAppiaCounter_iPlayer % iDelay
					else:
						iRest = 0
					if iRest == 0:
						i_rtRomanRoad = gc.getInfoTypeForString("ROUTE_ROMANROAD")
						l_iPlotsXY = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer]
						l_iPlotsX = l_iPlotsXY[0]
						l_iPlotsY = l_iPlotsXY[1]

						for irun in range( len(l_iPlotsX) ):
							ipX = l_iPlotsX[irun]
							ipY = l_iPlotsY[irun]
							ppPlot = CyMap().plot(ipX,ipY)
							if ppPlot.getRouteType() != i_rtRomanRoad:
								ppPlot.setRouteType(i_rtRomanRoad)
								i_Color = gc.getInfoTypeForString("COLOR_LIGHT_GREY")
								sBuffer = gc.getRouteInfo(i_rtRomanRoad).getDescription()
								sText = localText.getText("TXT_KEY_S1",(sBuffer, ))
								### msg: %s1 ###
								zButton = gc.getRouteInfo(i_rtRomanRoad).getButton()
								#CyAudioGame().Play3DSound("AS2D_BUILD_WALLS",point.x,point.y,point.z)
								#CyAudioGame().Play2DSound("AS2D_BUILD_WALLS")
								CyInterface().addMessage(iPlayer,True,35,sText,"AS2D_BUILD_WALLS",0,zButton,ColorTypes(i_Color), ipX, ipY,True,True)
								### msg: %s1 ###
								break

						l_iPlotsX2 = []
						l_iPlotsY2 = []
						for irun in range( len(l_iPlotsX) ):
							ipX = l_iPlotsX[irun]
							ipY = l_iPlotsY[irun]
							ppPlot = CyMap().plot(ipX,ipY)
							if ppPlot.getRouteType() != i_rtRomanRoad:
								l_iPlotsX2.append( ipX )
								l_iPlotsY2.append( ipY )
						l_iPlotsXY = [ l_iPlotsX2, l_iPlotsY2 ]

						if len(l_iPlotsX2) >= 1:
							temp_lZE_ViaAppia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")
							temp_lZE_ViaAppia[iPlayer] = l_iPlotsXY
							sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia", temp_lZE_ViaAppia)

						elif len(l_iPlotsX2) == 0:
							temp_lZE_ViaAppia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")
							temp_lZE_ViaAppia[iPlayer] = 0
							sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia", temp_lZE_ViaAppia)
							temp_lZE_ViaAppiaCounter = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")
							temp_lZE_ViaAppiaCounter[iPlayer] = 0
							sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter", temp_lZE_ViaAppiaCounter)
						
					if i_ViaAppiaCounter_iPlayer == 0:
						temp_lZE_ViaAppia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")
						temp_lZE_ViaAppia[i] = 0
						sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia", temp_lZE_ViaAppia)

	def printSearchStones( self, iPlayer, iTurns ):
		szText 	= localText.getText("TXT_KEY_EVENT_VIA_APPIA_SEARCH_FOR_STONES_GAMETXT_1",(iTurns, ))
		i_Color = gc.getInfoTypeForString("COLOR_YELLOW")
		CyInterface().addMessage(iPlayer,True,30,szText,'',0,'',i_Color,-1,-1,True,True)
		### msg: [COLOR_YELLOW]Search for Stones in Progress: [COLOR_RED]%d1[COLOR_REVERT] [NUM1:Turn:Turns] left

	def printImperialRoadProject( self, iPlayer, iTurns ):
		szText 	= localText.getText("TXT_KEY_EVENT_VIA_APPIA_IMPERIAL_ROAD_PROJECT_GAMETXT_1",(iTurns, ))
		i_Color = gc.getInfoTypeForString("COLOR_YELLOW")
		CyInterface().addMessage(iPlayer,True,30,szText,'',0,'',i_Color,-1,-1,True,True)
		### msg: [COLOR_YELLOW]Imperial Road Project in Progress: [COLOR_RED]%d1[COLOR_REVERT] [NUM1:Turn:Turns] left

	def isHasTechReqAND( self, iPlayer, l_iTechs ):
		pPlayer = gc.getPlayer(iPlayer)
		if not pPlayer.isNone() and pPlayer.isAlive():
			iTeam 	= pPlayer.getTeam()
			pTeam 	= gc.getTeam(iTeam)
			iZahler = 0
			for i in range(len(l_iTechs)):
				iTech = l_iTechs[i]
				if pTeam.isHasTech(iTech) == True:
					iZahler += 1
			if iZahler == len(l_iTechs):
				return True
		return false

	def getEstEnd( self ):
		# ### GAMESPEED_QUICK = 480; GAMESPEED_NORMAL = 690; GAMESPEED_EPIC = 990; GAMESPEED_MARATHON = 1800
		base = 1000
		count = 4
		estiEnd = CyGame().getEstimateEndTurn()
		if ( estiEnd >= 1500 ):
			base = 1800
			count = 16
		elif ( estiEnd >= 750 ):
			base = 990
			count = 8
		elif ( estiEnd >= 500 ):
			base = 690
			count = 6
		elif ( estiEnd >= 330 ):
			base = 480
			count = 4
		elif ( estiEnd >= 10 ):
			base = 300
			count = 2
		argsListEst = base, count
		return argsListEst

	def getiDeley( self ):
		argsListEst = self.getEstEnd()
		count = argsListEst[1]					# ### 4,6,8,16
		iDelay = int(count/2)					# ### 2,3,4,8
		return iDelay

	def checkPlot( self, pLoopPlot ):
		if pLoopPlot.isNone() == False:
			if not pLoopPlot.isPeak():
				if not pLoopPlot.isWater():
					if not pLoopPlot.isCity():
						if pLoopPlot.getBonusType(-1) == -1:
							iWaechter = 0
							iImprovement = pLoopPlot.getImprovementType()
							if iImprovement != -1:
								if gc.getImprovementInfo(iImprovement).isPermanent() == False:
									if gc.getImprovementInfo(iImprovement).isUnique() == False:
										iWaechter = 1
							elif iImprovement == -1:
								iWaechter = 1
							if iWaechter == 1:
								iWaechter = 0
								iXLoop = pLoopPlot.getX()
								iYLoop = pLoopPlot.getY()
								pLoopPlot_nX = CyMap().plot(iXLoop-1, iYLoop)
								if pLoopPlot_nX.isNone() == False:
									pLoopPlot_pX = CyMap().plot(iXLoop+1, iYLoop)
									if pLoopPlot_pX.isNone() == False:
										return True
		return False

	def doGetHelpViaAppiaTrigger_1( self, argsList, iHelp ):
		if iHelp == 1:
			szHelp 			= localText.getText("TXT_KEY_EVENT_VIA_APPIA_TRIGGER_1_HELP_1", ())
			### msg: [ICON_BULLET]Imperial Roads can only connect a city with the government center on that continent.[NEWLINE][ICON_BULLET]Government centers are cities with Palace or Summerpalace or Winterpalace.[NEWLINE][ICON_BULLET]Imperial Roads can be build by Workers.[NEWLINE][ICON_BULLET]The worker has to be in the city you want to connect with your government center.[NEWLINE][ICON_BULLET]Imperial Roads adds +1[ICON_COMMERCE] on all plots.[NEWLINE][ICON_BULLET]Imperial Roads adds an additionally commerce bonus on plots with Cottage, Hamlet, Village, Town and Enclaves.[NEWLINE][ICON_BULLET]Units move quicker on Imperial Roads.[NEWLINE][ICON_BULLET]It costs a certain amount of money and time to complete a Imperial Road.[NEWLINE][ICON_BULLET]Costs and time depend on how many road segments have to be placed on the map.[NEWLINE][ICON_BULLET]Costs also depend on the movement costs of the plots on which the road will be placed. [COLOR_LIGHT_GREY](That means building an Imperial Road in a city that is already connectet with your government center via normal roads is much cheaper.)[COLOR_REVERT][NEWLINE][ICON_BULLET]Certain Civilizations have increased or reduced Imperial Road costs e.g. Bannor only pays 1/3 of the normal costs.[NEWLINE][ICON_BULLET]The amount of stone resources under your controle greatly affects the costs. [COLOR_LIGHT_GREY](0 stones = ten time the normal costs; 1 stone = normal cost; 2 stones = 1/2 costs; 3 stones = 1/3 costs...)[COLOR_REVERT][NEWLINE][ICON_BULLET]You can only build one Imperial Road project at any time. You have to wait until it's finished before beginning a new one.
			return szHelp
		elif iHelp == 2:
			kTriggeredData 	= argsList[1]
			iPlayer 		= int(kTriggeredData.ePlayer)
			iEvent 			= gc.getInfoTypeForString("EVENTTRIGGER_VIA_APPIA_TRIGGER_2")
			triggerData 	= gc.getPlayer(iPlayer).initTriggeredData(iEvent, -1, -1, -1, -1, iPlayer, -1, -1, -1, -1, -1)

	def CanDoGetHelpViaAppiaTrigger2Yes( self, argsList, iHelp ):
		kTriggeredData 	= argsList[1]
		iPlayer 		= int(kTriggeredData.ePlayer)
		pPlayer 		= gc.getPlayer(iPlayer)
		i_btStone 		= gc.getInfoTypeForString("BONUS_STONE")
		argsListEst 	= self.getEstEnd()
		iCount 			= int( argsListEst[1] + 4 )
		iGoldBase 		= int( argsListEst[0] / 2 )
		iNumStones 		= pPlayer.getNumAvailableBonuses(i_btStone)
		iGold 			= iGoldBase
		iGoldAtHand 	= pPlayer.getGold()
		if iNumStones == 0:
			if iGoldAtHand < iGoldBase:
				iGold 	= iGoldAtHand

		if iHelp == 1:
			sBonus 		= gc.getBonusInfo(i_btStone).getDescription()
			szHelp 		= localText.getText("TXT_KEY_EVENT_VIA_APPIA_TRIGGER_2_YES_HELP_1", (iGold, sBonus, iCount))
			### msg: [ICON_BULLET]Subtract [COLOR_YELLOW]%d1[COLOR_REVERT][ICON_GOLD] from your treasury.[NEWLINE][ICON_BULLET]Chance to receive [COLOR_HIGHLIGHT_TEXT]%s2[COLOR_REVERT] within [COLOR_YELLOW]%d3[COLOR_REVERT] turns inside your borders.
			if iGold > iGoldAtHand:
				szHelp 	= localText.getText("TXT_KEY_EVENT_VIA_APPIA_TRIGGER_2_YES_HELP_2", (iGold, sBonus, iCount))
				### msg: [ICON_BULLET][COLOR_RED]Unfortunately you don't have enough money to finance the search![NEWLINE][NEWLINE][ICON_BULLET]Subtract [COLOR_YELLOW]%d1[COLOR_RED][ICON_GOLD] from your treasury.[NEWLINE][ICON_BULLET]Chance to receive [COLOR_HIGHLIGHT_TEXT]%s2[COLOR_RED] within [COLOR_YELLOW]%d3[COLOR_RED] turns inside your borders.[COLOR_REVERT]
			return szHelp
		elif iHelp == 2:
			temp_lZE_ViaAppia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")
			temp_lZE_ViaAppia[iPlayer] = 1		# ### 1 = search
			sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia", temp_lZE_ViaAppia)
			temp_lZE_ViaAppiaCounter = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")
			temp_lZE_ViaAppiaCounter[iPlayer] = iCount
			sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter", temp_lZE_ViaAppiaCounter)
			pPlayer.changeGold(-iGold)
			szText 	= localText.getText("TXT_KEY_EVENT_VIA_APPIA_TRIGGER_2_YES_GAMETXT_1",(iGold, ))
			i_Color = gc.getInfoTypeForString("COLOR_RED")
			CyInterface().addMessage(iPlayer,True,15,szText,'',0,'',i_Color,-1,-1,True,True)
			### msg: [COLOR_REVERT]You financed a search for stones. [COLOR_YELLOW]%d1[COLOR_REVERT][ICON_GOLD][COLOR_RED] from your treasury removed.[COLOR_REVERT] ###
			self.printSearchStones( iPlayer, iCount )
		elif iHelp == 3:
			if iGold <= iGoldAtHand:
				return True
			return False

	def doViaAppiaDelay( self, argsList ):
		kTriggeredData = argsList[0]
		iPlayer = kTriggeredData.ePlayer
		pPlayer = gc.getPlayer(iPlayer)
		pCity = pPlayer.getCapitalCity()
		iX = pCity.getX()
		iY = pCity.getY()
		i_btStone = gc.getInfoTypeForString("BONUS_STONE")
		l_Gewichtung = [	6,5,5,4,4,4,5,5,6,
							5,5,4,3,3,3,4,5,5,
							5,4,3,2,2,2,3,4,5,
							4,3,2,1,1,1,2,3,4,
							4,3,2,1,0,1,2,3,4,
							4,3,2,1,1,1,2,3,4,
							5,4,3,2,2,2,3,4,5,
							5,5,4,3,3,3,4,5,5,
							6,5,5,4,4,4,5,5,6
						]
					###369
					###258
					###147

		for irun in range(1):
			### Sammle Gewichtungsplots ###
			i_Gewichtung = -1
			l_iPlotsX1 = []
			l_iPlotsX2 = []
			l_iPlotsX3 = []
			l_iPlotsX4 = []
			l_iPlotsX5 = []
			l_iPlotsX6 = []
			l_iPlotsY1 = []
			l_iPlotsY2 = []
			l_iPlotsY3 = []
			l_iPlotsY4 = []
			l_iPlotsY5 = []
			l_iPlotsY6 = []

			for iXLoop in range(iX - 4, iX + 5, 1):
				for iYLoop in range(iY - 4, iY + 5, 1):
					i_Gewichtung += 1
					pLoopPlot = CyMap().plot(iXLoop, iYLoop)
					if pLoopPlot.isNone() == False:
						if pLoopPlot.getOwner() == iPlayer:
							if self.checkPlot( pLoopPlot ) == True:
								if ( l_Gewichtung[i_Gewichtung] == 1 ):
									l_iPlotsX1.append( iXLoop )
									l_iPlotsY1.append( iYLoop )
								elif ( l_Gewichtung[i_Gewichtung] == 2 ):
									l_iPlotsX2.append( iXLoop )
									l_iPlotsY2.append( iYLoop )
								elif ( l_Gewichtung[i_Gewichtung] == 3 ):
									l_iPlotsX3.append( iXLoop )
									l_iPlotsY3.append( iYLoop )
								elif ( l_Gewichtung[i_Gewichtung] == 4 ):
									l_iPlotsX4.append( iXLoop )
									l_iPlotsY4.append( iYLoop )
								elif ( l_Gewichtung[i_Gewichtung] == 5 ):
									l_iPlotsX5.append( iXLoop )
									l_iPlotsY5.append( iYLoop )
								elif ( l_Gewichtung[i_Gewichtung] == 6 ):
									l_iPlotsX6.append( iXLoop )
									l_iPlotsY6.append( iYLoop )
			if len(l_iPlotsX3) >= 1:
				l_iPlotsX = l_iPlotsX3
				l_iPlotsY = l_iPlotsY3
			elif len(l_iPlotsX4) >= 1:
				l_iPlotsX = l_iPlotsX4
				l_iPlotsY = l_iPlotsY4
			elif len(l_iPlotsX5) >= 1:
				l_iPlotsX = l_iPlotsX5
				l_iPlotsY = l_iPlotsY5
			elif len(l_iPlotsX6) >= 1:
				l_iPlotsX = l_iPlotsX6
				l_iPlotsY = l_iPlotsY6
			elif len(l_iPlotsX2) >= 1:
				l_iPlotsX = l_iPlotsX2
				l_iPlotsY = l_iPlotsY2
			elif len(l_iPlotsX1) >= 1:
				l_iPlotsX = l_iPlotsX1
				l_iPlotsY = l_iPlotsY1
			else:
				l_iPlotsX = []
				l_iPlotsY = []
				map = gc.getMap()
				for i in range(map.numPlots()):
					plot = map.plotByIndex(i)
					if plot.getOwner() == iPlayer:
						if self.checkPlot( plot ) == True:
							l_iPlotsX.append( plot.getX() )
							l_iPlotsY.append( plot.getY() )
							break
			if len(l_iPlotsX) >= 1:
				iRand = CyGame().getSorenRandNum(len(l_iPlotsX), "ViaAppia")
				iiX = l_iPlotsX[iRand]
				iiY = l_iPlotsY[iRand]
				pPlot = CyMap().plot( iiX, iiY )
				pPlot.setBonusType(i_btStone)
				addPlotCulture = int(pPlot.getCulture(iPlayer) * 0.25) + 25
				pPlot.changeCulture(iPlayer, addPlotCulture, true)
				CyInterface().addMessage(iPlayer,false,15,localText.getText("TXT_KEY_RESOURCE_DISCOVERED_1",(gc.getBonusInfo(i_btStone).getDescription(),pCity.getName())),'AS2D_DISCOVERBONUS',0,gc.getBonusInfo(i_btStone).getButton(),ColorTypes(gc.getInfoTypeForString("COLOR_PLAYER_WHITE_TEXT")), iiX, iiY,True,True)
				### msg: [COLOR_SELECTED_TEXT]You have discovered a source of [COLOR_HIGHLIGHT_TEXT]%s1 [COLOR_SELECTED_TEXT]near %s2![COLOR_REVERT] ###




 
The Hippus are all about getting around, so they'd probably be more likely. The Mechanos feel to me like their all about bending their environment to their will, so they'd be more likely. The Kuriotates would probably have the greatest need for the feature, given their centralized production. And the Scions probably still remember having the feature in their old empire. But none of those quite so much as the Bannor. If 20% was the baseline, I'd probably put the Bannor at 40% or 50% and the others at 30%.

I would say that any of the civs that either inherently adjust their terrain (Malakin, for example) or naturally pair with religions that do so (either elves, I think Illian terraforming is through the White Hand at this point) would be less likely (the Malakim have their own special roads, the elves get fast movement through forests). The Archos and Doviello seem, I don't know that primitive is the right word, but I don't think the roads would be high on their priority list. And when Valkrionn finishes the Bezeri, they obviously wouldn't use them at all.
 
The Hippus are all about getting around, so they'd probably be more likely. The Mechanos feel to me like their all about bending their environment to their will, so they'd be more likely. The Kuriotates would probably have the greatest need for the feature, given their centralized production. And the Scions probably still remember having the feature in their old empire. But none of those quite so much as the Bannor. If 20% was the baseline, I'd probably put the Bannor at 40% or 50% and the others at 30%.

I would say that any of the civs that either inherently adjust their terrain (Malakin, for example) or naturally pair with religions that do so (either elves, I think Illian terraforming is through the White Hand at this point) would be less likely (the Malakim have their own special roads, the elves get fast movement through forests). The Archos and Doviello seem, I don't know that primitive is the right word, but I don't think the roads would be high on their priority list. And when Valkrionn finishes the Bezeri, they obviously wouldn't use them at all.

I think i will give the Imperial Roads a 100% chance and change the build time and costs for certain civilizations. I will try to include this in one of the next updates.

Spoiler GIR03ImperialRoads (Part 4 / 4) :

Spoiler GIR03ImperialRoads.py (PART 2 / 2) :

Code:
	def getHelpViaAppiaDelay1( self, argsList ):
		szHelp = localText.getText("TXT_KEY_EVENT_VIA_APPIA_DELAY_1_HELP", ())
		### msg: [ICON_BULLET]The amount of stone resources under your controle greatly affects the costs of the Imperial Roads.[NEWLINE][NEWLINE][ICON_BULLET]0 stone resources = [COLOR_RED]ten times[COLOR_REVERT] the normal costs[NEWLINE][ICON_BULLET]1 stone resource = normal costs[NEWLINE][ICON_BULLET]2 stone resources = 1 / 2 costs[NEWLINE][ICON_BULLET]3 stone resources = 1 / 3 costs[NEWLINE][ICON_BULLET]4 stone resources = 1 / 4 costs[NEWLINE][ICON_BULLET]...[NEWLINE]
		return szHelp

	def reqAndSpellViaAppiaUWI(self, caster, iHelp ):
		iX = caster.getX()
		iY = caster.getY()
		iPlayer = caster.getOwner()
		if iHelp == 1:
			pPlot = CyMap().plot( iX, iY )
			if pPlot.isCity() == True:
				pCity = pPlot.getPlotCity()
				#i_btStone = gc.getInfoTypeForString("BONUS_STONE")
				pPlayer = gc.getPlayer(iPlayer)
				pCCity = pPlayer.getCapitalCity()
				#if pCCity.hasBonus(i_btStone) == True:
				if pCity.getID() != pCCity.getID():
					lZE_ViaAppia_iPlayer = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer]
					if lZE_ViaAppia_iPlayer == 0 or lZE_ViaAppia_iPlayer == 1: 		### waiting or search
						return True
			return False
		elif iHelp == 2:
			CyVariableSystem().setValueInt("iStackBet", 0) # ### prevents stack building
			CyVariableSystem().setValueInt("iHelpTxt", 0) # ### should increase performance with mouse over python help txt
			iUnitID = caster.getID()
			iEvent = gc.getInfoTypeForString("EVENTTRIGGER_VIA_APPIA_BUILD_ROAD")
			triggerData = gc.getPlayer(iPlayer).initTriggeredData(iEvent, true, -1, iX, iY, iPlayer, -1, -1, -1, iUnitID, -1)

	def CanDoHelpViaAppiaBuildRoadInfo( self, argsList, iHelp ):
		if iHelp == 1:
			return false
		elif iHelp == 2:
			szHelp 	= localText.getText("TXT_KEY_EVENT_VIA_APPIA_BUILD_ROAD_INFO_HELP_1", ())
			### msg: [ICON_BULLET]Imperial Roads can only connect a city with the government center on that continent.[NEWLINE][ICON_BULLET]Government centers are cities with Palace or Summerpalace or Winterpalace.[NEWLINE][ICON_BULLET]Imperial Roads can be build by Workers.[NEWLINE][ICON_BULLET]The worker has to be in the city you want to connect with your government center.[NEWLINE][ICON_BULLET]Imperial Roads adds +1[ICON_COMMERCE] on all plots.[NEWLINE][ICON_BULLET]Imperial Roads adds an additionally commerce bonus on plots with Cottage, Hamlet, Village, Town and Enclaves.[NEWLINE][ICON_BULLET]Units move quicker on Imperial Roads.[NEWLINE][ICON_BULLET]It costs a certain amount of money and time to complete a Imperial Road.[NEWLINE][ICON_BULLET]Costs and time depend on how many road segments have to be placed on the map.[NEWLINE][ICON_BULLET]Costs also depend on the movement costs of the plots on which the road will be placed. [COLOR_LIGHT_GREY](That means building an Imperial Road in a city that is already connectet with your government center via normal roads is much cheaper.)[COLOR_REVERT][NEWLINE][ICON_BULLET]Certain Civilizations have increased or reduced Imperial Road costs e.g. Bannor only pays 1/3 of the normal costs.[NEWLINE][ICON_BULLET]The amount of stone resources under your controle greatly affects the costs. [COLOR_LIGHT_GREY](0 stones = ten time the normal costs; 1 stone = normal cost; 2 stones = 1/2 costs; 3 stones = 1/3 costs...)[COLOR_REVERT][NEWLINE][ICON_BULLET]You can only build one Imperial Road project at any time. You have to wait until it's finished before beginning a new one.
			return szHelp

	def getHelpViaAppiaBuildRoad1( self, argsList ):
		szHelp = localText.getText("TXT_KEY_EVENT_VIA_APPIA_BUILD_ROAD_1_HELP", ())
		### msg: I do not waste my money on roads!
		if CyVariableSystem().getValueInt("iStackBet") == 1:
			szHelp = localText.getText("TXT_KEY_EVENT_VIA_APPIA_BUILD_ROAD_1_HELP_PROGRESS", ())
			### msg: [COLOR_RED]There is already an Improved Road Project in progress.[NEWLINE]  Please wait until this one is finished and then try again.[COLOR_REVERT]
		return szHelp

	def CanDoHelpViaAppiaBuildRoad2( self, argsList, iHelp ):		# ### iHelp 1 = canDo; iHelp 2 = getHelp; iHelp 3 = Do
		kTriggeredData = argsList[1]
		iPlayer = int(kTriggeredData.ePlayer)
		pPlayer = gc.getPlayer(iPlayer)
		if not pPlayer.isNone() and pPlayer.isAlive():
			iX = kTriggeredData.iPlotX
			iY = kTriggeredData.iPlotY
			pPlot = CyMap().plot(iX, iY)
			if pPlot.isCity() == True:
				pCity = pPlot.getPlotCity()
				pUnit = pPlayer.getUnit(kTriggeredData.iUnitId)
				argsListVia = self.setAndGetViaAppia( pPlot, iPlayer, iHelp, pUnit )
				if iHelp == 1:
					if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer] == 1:			# ### Search
						return False
					if argsListVia == -1:
						return False
					return argsListVia								# ### (siehe setAndGetViaAppia iHelp = 1: is True or False)

		if iHelp == 1:
			return False
		elif iHelp == 2:
			if argsListVia == -1:
				szHelp = localText.getText("TXT_KEY_EVENT_VIA_APPIA_BUILD_ROAD_2_HELP_2", (pCity.getName(), ))
				### msg: [ICON_BULLET][COLOR_RED]Unfortunately %s1 can't be connected with any of your Government Centers.[COLOR_REVERT]
			else:
				imodRoadCost, sBuffer, pCCityName, iImmobile, ilen_l_iPlotsX = argsListVia
				szHelp = localText.getText("TXT_KEY_EVENT_VIA_APPIA_BUILD_ROAD_2_HELP_1", (imodRoadCost, sBuffer, pCCityName, iImmobile))
				### msg: [ICON_BULLET]Requires a possible land only path to your Government Center on this continent.[NEWLINE][ICON_BULLET]Subtract %d1[ICON_GOLD] from your treasury.[NEWLINE][ICON_BULLET]Receive an [COLOR_HIGHLIGHT_TEXT]%s2[COLOR_REVERT] to %s3 in about %d4 turns. [COLOR_LIGHT_GREY](Worker will be immobile for this period of time.)[COLOR_REVERT]
				if ilen_l_iPlotsX == 0:
					szHelp = localText.getText("TXT_KEY_EVENT_VIA_APPIA_BUILD_ROAD_2_HELP_3", (pCity.getName(), pCCityName))
					### msg: [ICON_BULLET][COLOR_RED]%s1 is already connected with %s2 via Improved Roads.[COLOR_REVERT]
				if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer] == 1:			# ### Search
					iTurns = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")[iPlayer]
					szHelp = localText.getText("TXT_KEY_EVENT_VIA_APPIA_BUILD_ROAD_2_HELP_4", (iTurns, ))
					### msg: [ICON_BULLET][COLOR_RED]You have to wait until the search for stones is finished ([COLOR_YELLOW]%d1 [NUM1:Turn:Turns] left[COLOR_RED]).[COLOR_REVERT]
			return szHelp

	def getGovernmentCenter( self, pCasterPlot, iPlayer ):
		pPlayer = gc.getPlayer(iPlayer)
		lgcCity = []
		for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList():
			pCity = pyCity.GetCy()
			if pCity.isGovernmentCenter() == True:
				if pCity.getID() != pCasterPlot.getPlotCity().getID():
					lgcCity.append(pCity)
		if len(lgcCity) == 0:
			return -1
		elif len(lgcCity) == 1:
			return lgcCity
		elif len(lgcCity) >= 2:
			pCCity = pPlayer.getCapitalCity()
			i_btSummerP = gc.getInfoTypeForString("BUILDING_FORBIDDEN_PALACE")
			i_btWinterP = gc.getInfoTypeForString("BUILDING_WINTER_PALACE")
			lgcCity2 = []
			for i in range(3):
				for irun in range(len(lgcCity)):
					pCity = lgcCity[irun]
					if i == 0:
						if pCity.isCapital() == True:
							lgcCity2.append(pCity)
					elif i == 1:
						if pCity.getNumRealBuilding(i_btSummerP) >= 1:
							lgcCity2.append(pCity)
					elif i == 2:
						if pCity.getNumRealBuilding(i_btWinterP) >= 1:
							lgcCity2.append(pCity)
			for i in range(len(lgcCity)):		# ### the important thing here is that the first element = Capital, second = SummerP (if present) and the third = WinterP (if present)
				pCity = lgcCity[i]
				lgcCity2.append(pCity)
			return lgcCity2
		return -1

	def setAndGetViaAppia( self, pPlot, iPlayer, iHelp, pUnit ):
		lgcCity = self.getGovernmentCenter( pPlot, iPlayer )
		iWaechter = 0

		if iHelp == 2:	# ### this should increase performance; iHelp 2 = getHelp
			if CyVariableSystem().getValueInt("iHelpTxt") == 1:
				argsListVia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_tempViaAppia")
				if len(argsListVia) == 5:
					return argsListVia

		if lgcCity != -1:
			if len(lgcCity) >= 1:
				for i in range(len(lgcCity)):

				#	pCity = pPlot.getPlotCity()
				#	pCCity = lgcCity[i]
				#	if pCity.getID() != pCCity.getID():
				#		pCPlot = CyMap().plot(pCCity.getX(),pCCity.getY())
				#		if pPlot.getArea() == pCPlot.getArea():

					if iWaechter == 1:
						break
					pCPlot = CyMap().plot(lgcCity[i].getX(), lgcCity[i].getY())
					if CyMap().calculatePathDistance(pPlot, pCPlot) != -1:
						argsListEst = self.getEstEnd()
						count = argsListEst[1]		# ### 4,6,8,16
						pPlayer = gc.getPlayer(iPlayer)
						iX = pPlot.getX()
						iY = pPlot.getY()
						iUnit = gc.getInfoTypeForString("UNIT_SKELETON")
						pNewUnit = pPlayer.initUnit(iUnit, iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
						pNewUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_MOBILITY1"), True)
						pNewUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_MOBILITY2"), True)
						pNewUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_NAVIGATION1"), True)
						pNewUnit.setHasPromotion(gc.getInfoTypeForString("PROMOTION_GOLEM"), True)
						iPathMovementCost = AStar.generatePath(pNewUnit, pPlot, pCPlot, True)
						pNewUnit.kill(True, 0)
						if iPathMovementCost != -1:
							iWaechter = 1
							l_pathList = AStar.getPath()
							i_rtRomanRoad = gc.getInfoTypeForString("ROUTE_ROMANROAD")
							sBuffer = gc.getRouteInfo(i_rtRomanRoad).getDescription()
							irrMovCost = gc.getRouteInfo(i_rtRomanRoad).getMovementCost()
							iRoadCost = int( ( abs( iPathMovementCost - ( len(l_pathList) * irrMovCost ) ) * count ) / 5 )
							numStones = pPlayer.getNumAvailableBonuses(gc.getInfoTypeForString("BONUS_STONE"))
							if numStones == 0:
								numStones = 0.100	### 0 stones means ten times the cost --> int(iRoadCost / numStones )
							imodRoadCost = int(iRoadCost / numStones )
							if pPlayer.getCivilizationType() == gc.getInfoTypeForString("CIVILIZATION_BANNOR"):
								imodRoadCost = int(imodRoadCost/3) + 1
							elif pPlayer.getCivilizationType() == gc.getInfoTypeForString("CIVILIZATION_KURIOTATES"):
								imodRoadCost = int(imodRoadCost/2) + 1
							if pPlayer.getGold() >= imodRoadCost or iHelp == 2 or pUnit == -1:		# ### iHelp 2 = getHelp
								if iHelp == 3:														# ### iHelp 3 = Do
									if pUnit != -1:													# ### it is pUnit = -1 for the one time AI help only
										pPlayer.changeGold(-imodRoadCost)
									i_Color = gc.getInfoTypeForString("COLOR_LIGHT_GREY")
									sText = localText.getText("TXT_KEY_S1",(sBuffer, ))
									### msg: %s1 ###
									zButton = gc.getRouteInfo(i_rtRomanRoad).getButton()
									if pPlot.getRouteType() != i_rtRomanRoad:
										pPlot.setRouteType(i_rtRomanRoad)
										CyInterface().addMessage(iPlayer,True,35,str(""),'',1,zButton,ColorTypes(i_Color), iX, iY,True,True)
										### MESSAGE_TYPE_DISPLAY_ONLY
										CyInterface().addMessage(iPlayer,True,-1,sText,'',0,zButton,ColorTypes(i_Color), iX, iY,True,True)
										### msg: %s1 ### MESSAGE_TYPE_INFO (log only)
									for irun in range(len(l_pathList)):
										t_iPlotXY = l_pathList[irun]
										ipX = t_iPlotXY[0]
										ipY = t_iPlotXY[1]
										ppPlot = CyMap().plot(ipX,ipY)
										#if ppPlot.getRouteType() != i_rtRomanRoad:
										#	ppPlot.setRouteType(i_rtRomanRoad)
										#	CyInterface().addMessage(iPlayer,True,35,sText,'',1,zButton,ColorTypes(i_Color), ipX, ipY,True,True)
										#	### msg: %s1 ###
										#	break

								l_iPlotsX = []
								l_iPlotsY = []
								for irun in range(len(l_pathList)):
									t_iPlotXY = l_pathList[irun]
									ipX = t_iPlotXY[0]
									ipY = t_iPlotXY[1]
									ppPlot = CyMap().plot(ipX,ipY)
									if ppPlot.getRouteType() != i_rtRomanRoad:
										l_iPlotsX.append( ipX )
										l_iPlotsY.append( ipY )
								l_iPlotsXY = [ l_iPlotsX, l_iPlotsY ]

								if iHelp == 1:														# ## iHelp 1 = canDo
									if len(l_iPlotsX) >= 1:
										if CyVariableSystem().getValueInt("iStackBet") == 0:
											argsListVia = True
										else:
											argsListVia = False
									else:
										argsListVia = False
									return argsListVia
									
								if iHelp == 2 or iHelp == 3:
									iDelay = self.getiDeley()										# ### 2,3,4,8 
									iImmobile = ( len(l_iPlotsX) * iDelay )
									if iImmobile == 0:
										iImmobile = 1

								if iHelp == 2:														# ### iHelp 2 = getHelp
									ilen_l_iPlotsX = len(l_iPlotsX)
									pCCityName = pCPlot.getPlotCity().getName()
									argsListVia = imodRoadCost, sBuffer, pCCityName, iImmobile, ilen_l_iPlotsX
									if CyVariableSystem().getValueInt("iHelpTxt") == 0:				# ### this should increase performance
										sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_tempViaAppia", argsListVia)
										CyVariableSystem().setValueInt("iHelpTxt", 1)
									return argsListVia

								elif iHelp == 3:													# ### iHelp 3 = Do
									if pUnit != -1:													# ### it is pUnit = -1 for the one time AI help only
										CyVariableSystem().setValueInt("iStackBet", 1)
										CyVariableSystem().setValueInt("iHelpTxt", 0)
										pUnit.changeImmobileTimer( iImmobile )
										#pUnit.getGroup().pushMission(MissionTypes.MISSION_MULTI_DESELECT, pUnit.getX(), pUnit.getY(), 0, False, False, MissionAITypes.NO_MISSIONAI, pUnit.plot(), pUnit)
										pUnit.getGroup().pushMission(MissionTypes.MISSION_SKIP, pUnit.getX(), pUnit.getY(), 0, False, False, MissionAITypes.NO_MISSIONAI, pUnit.plot(), pUnit)
									if len(l_iPlotsX) >= 1:
										temp_lZE_ViaAppia = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")
										temp_lZE_ViaAppia[iPlayer] = l_iPlotsXY
										sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia", temp_lZE_ViaAppia)
										temp_lZE_ViaAppiaCounter = sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")
										temp_lZE_ViaAppiaCounter[iPlayer] = iImmobile
										sdObjectSetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter", temp_lZE_ViaAppiaCounter)
										self.printImperialRoadProject( iPlayer, iImmobile )
		argsListVia = -1
		return argsListVia

	def TriggerApplyViaAppiaBuildRoadAI( self, argsList, iHelp ):
		kTriggeredData = argsList[0]
		iPlayer = kTriggeredData.ePlayer
		pPlayer = gc.getPlayer(iPlayer)
		if iHelp == 1:
			if not pPlayer.isNone() and pPlayer.isAlive():
				if pPlayer.isHuman() == False:	# ### one time AI help
					if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppia")[iPlayer] == 0:
						#if pPlayer.getNumAvailableBonuses(gc.getInfoTypeForString("BONUS_STONE")) >= 1:
						return True
			return False
		elif iHelp == 2:
			lCity = []
			pCCity = pPlayer.getCapitalCity()
			for pyCity in PyHelpers.PyPlayer(iPlayer).getCityList():
				pCity = pyCity.GetCy()
				if pCity.getID() != pCCity.getID():
					pPlot = CyMap().plot(pCity.getX(),pCity.getY())
					pCPlot = CyMap().plot(pCCity.getX(),pCCity.getY())
					if pPlot.getArea() == pCPlot.getArea():
						if CyMap().calculatePathDistance(pPlot, pCPlot) != -1:
							lCity.append(pCity)
			iLaenge = len(lCity)
			if iLaenge >= 1:
				for irun in range(iLaenge):
					iRand = CyGame().getSorenRandNum( len(lCity), "Random pCity")
					pCity = lCity[iRand]
					lCity2 = []
					for i in range(len(lCity)):
						if lCity[i].getID() != pCity.getID():
							lCity2.append(lCity[i])
					lCity = lCity2
					pPlot = CyMap().plot(pCity.getX(),pCity.getY())
					self.setAndGetViaAppia( pPlot, iPlayer, 3, -1 )
					if sdObjectGetVal("GIR03ImperialRoads", gc.getGame(), "lZE_ViaAppiaCounter")[iPlayer] >= 1:
						break

 
Update: (will break save games)
Update for RifE 1.20:

The most important change in this version is maybe the addition of an old system I made a long time ago in my Petra mod component and Flavian Amphitheatre mod component:

-In this version the owner of the Great Circus Improvement will be able to conquer enemy unique buildings. After you conquer/acquire a city with an unique building in it you will get a pop-up and you can decide if you want to keep it or replace it with your default building. Flavor Note: This won't work if you have an own unique building for this building type. (This is a week effect because most of the unique buildings have a low chance to survive after conquest or can't be conquered at all. If you want to change the conquest probability than go in the building xml - I didn't change it)
-In addition to that the owner of the Great Circus can build unique mounted units of all of his vassals. After you built a default mounted unit you will get a pop-up and can choose between your default unit or all of the unique units of the same unit class of your vassals.
-The same system works for unique melee units and the Great Colosseum.
-Also if you own the Great Colosseum you can build unique buildings of your vassals when you build a default building of that building type.

For more info see pictures below:



And here is the rest of the update:

  • Elohim Unique Improvements bug fixes:
    • Fixed a bug with the Elohim Yggdrasil event when only forest and no kelp is available to upgrade (upgrades 2 forests to ancient forest)
    • Fixed a bug with the Elohim Yggdrasil event when only kelp and no forest is available to upgrade (upgrades 2 kelp to kelp forest)

    Mana Flare adds and fixes:
    • Added mana flare event for Creation mana (for more info see post 2)
    • Added mana flare event for Dimensional mana (for more info see post 2)
    • Added mana flare event for Force mana (for more info see post 2)
    • Added mana flare event for Refined mana (for more info see post 2)
    • Added/changed Earth/Law/Mind/Spirit mana flare effects: Now all the buildings provided by the mana flare have a certain duration not only one turn. The duration depends on game speed and if the cause of the flare was an event and to a certain amount on luck (rand number).
    • Added/changed Chaos mana flare effect: Terrain type of the mana plot will change temporary to a random polt: (grass, plains, desert, marsh, tundra, snow, burning sands, broken lands, field of perdition, shallows)
    • Added/changed Body mana flare effect: Haste promotion gained by mana flare will have a duration of 4 turns / added Avatars to the immune list / changed chances for promotions (for more info see post 2)
    • Added/changed Air mana flare effect: Naval units gain haste promotion with duration of 4 turns if cause of mana flare was an event
    • Added new "save" improvements for the Air mana flare. Your unit won't get blown away when standing on them. (Improvements: broken sepulcher, cage, castle, citadel, citadel of light, fort, goblin fort, guardian, ring of carcer, tower, hill gigant steanding, dwarven mine, dwarven settlement, dwarven hall, dwarven fortress, tower of eyes )
    • Added "Earth Boosom" effect to Earth mana flares (changes the plot type of the mana plot to hill if the cause of the flare is an event)
    • Fixed a bug with the promotion chance function for mana flares (a lot of the chances were 1% higher then postet in the second post)

    Imperial Roads adds and fixes:
    • Fixed a bug with the "Imperial Roads" spell (now the casting worker will skip the turn and wake up properly after the road is finished)
    • Bannor and Kuriotates can build Imperial Roads cheaper than other civilizations ( Bannor = 1/3; Kuriotates = 1/2 )
    • Updated mouse over help text for Imperial Road spell
    • You don't need stones in the city which you want to connect to your government center. The road is build from your capital to all the other cities anyway.
    • Added building sounds when a Imperial Road segment is placed on the map and removed the road spell casting effect and sound.
    • Highly increased the performance of the python mouse over help text on the Imperial Roads spell popup. (The path, costs and duration will be calculated only once and not every time you mouse over the button. My bad, sorry.)
    • Reworked Imperial Roads code and fixed a bug when you finish a road project but your worker is immobile for some more turns.
    • Added a on screen counter for the search for stones event (see picture bottom)
    • Added a on screen counter for an Imperial road project (see picture bottom)

    Great Colosseum and Great Circus adds and fixes:
    • Reworked the bet system and remove a bunch of unnecessary events related to the bet spell events. It's working like before so never mind...
    • Increased performance with the Circus and Colosseum spells.
    • Added an on screen counter for the Great Circus
    • Added an on screen counter for the Great Colosseum
    • Added the unique building on city acquired system for the Great Circus
    • Added the vassal unique building system for the Great Colosseum
    • Added the vassal unique mounted units system for the Great Circus
    • Added the vassal unique melee units system for the Great Colosseum

For more info see post2 and post3.​

Pictures:
 
So was playing Rife as Ljosofar, and i got the Imperial Roads event. but when i click the button to build the road, it just takes up the worker's time and doesn't build it. :(
The text above the scores says "Imperial Road Project: 20 turns" for like 10 turns. Here's the save from when i tried to build the road (in Hyll).
 

Attachments

  • AutoSave_Turn_0245.CivBeyondSwordSave
    364.6 KB · Views: 114
So was playing Rife as Ljosofar, and i got the Imperial Roads event. but when i click the button to build the road, it just takes up the worker's time and doesn't build it. :(
The text above the scores says "Imperial Road Project: 20 turns" for like 10 turns. Here's the save from when i tried to build the road (in Hyll).




i tried your save and even without using the imperial road spell i had this error msg after each turn (you should enable error msg in your game).

there is a bug in rife 1.20 with the blizzard stuff that interfere with some python code in the game. there is also another bug with the illians + hand prist terraforming (mouse over of some temp snow terrain gives me also a error msg).
my advise: don't play with the illians in a game untis this bugs are fixed.
 
Love this, but I found one small exploit. I started a game as the Elohim and was two squares away from the Pyre. I sent my scout over there and the scout got the angel promotion. The next turn (3 or 4, I forget), I sacrificed the scout and my 1/2 scout became an 8/9 fire elemental. This is definitely making the early game quite easy. Just wanted to mention it... Otherwise, it's great!
 
Love this, but I found one small exploit. I started a game as the Elohim and was two squares away from the Pyre. I sent my scout over there and the scout got the angel promotion. The next turn (3 or 4, I forget), I sacrificed the scout and my 1/2 scout became an 8/9 fire elemental. This is definitely making the early game quite easy. Just wanted to mention it... Otherwise, it's great!

yes, that's true, this is too unbalanced. i will make it so that in this case the str. of the fire element will be similar with the str. of the elohim unit sacrificed on the pyre (only the event unit).
so with the next patch you will get a 3/4 (or 4/5) fire element if you sacrifie your angle scout but the fire element lose the angle promotion and you cant get the flying promotion if you level up your scout or what ever unit discovers the pyre at first...
 
had all 3 projects running and all 3 stopped. there were some blizzards on the map though but i think it was because blight hit in and workercommands were reset
 
had all 3 projects running and all 3 stopped. there were some blizzards on the map though but i think it was because blight hit in and workercommands were reset
i dont know how blight works but it should not interfere with my code.
could you plz upload a save?
also did you turned python exceptions on? (if not plz do it so you can see if it's because of the blizzards)

thx
 
Top Bottom