changing unique power

gui13

Chieftain
Joined
Jul 17, 2010
Messages
2
In Rhye´s and fall of civilization, how can i change the unique power of a civilization?
 
Moderator Action: Thread moved.
Questions belong either into the main section of the creation forum or into the appropriate subsections of the mods forum ;).
But in the tutorial section only finished tutorials should go, no questions ;).


And welcome to CFC :).
 
It depends. Most UPs are coded in the \Assets\Python\UniquePowers.py but some others are done in C++ and would have to be coded in the SDK (Software Developer's Kit) and recompiled into a custom DLL file.

It won't be easy to change UPs if you don't know programming. Turning the Russian UP into a global effect ("Universal Winter") was my first ever programming project, by the way. :D I think I got it right on the fourth try, but I was learning Python by doing it at that point. I will have to do it all over again some day though, as I'm still not entirely satisfied with the results.

A good start would be to learn Python, then. It can be done in a matter of weeks if you really wanna. You could probably learn the basics in a matter of days.
 
Thanks Baldyr, i appreciate your help.
Sure, just holler if I can offer any actual help. Like point you to where you can learn this stuff.

What exactly are you proposing to achieve, by the way? It might be easier to do than you'd imagine...
 
Hey Baldyr, I just want a quick assessment of my UP idea for my Iroquois (ie how hard it would be).

Unique Power: The Power of the Warpath
Improvements can be built in forests, jungles.

How hard would that be to make? And is it overpowered?
 
Hey Baldyr, I just want a quick assessment of my UP idea for my Iroquois (ie how hard it would be).

Unique Power: The Power of the Warpath
Improvements can be built in forests, jungles.

How hard would that be to make? And is it overpowered?
Actually, I have no idea. Improvements are defined in the XML but how to change them for just one Civ...? You'd have to dig into this and figure it out, I guess...

By the way, do you mean that the improvements would be the same as if the terrain feature was cleared? Like building a Farm on a Grassland Jungle tile or on a Plains Forest tile? And that would give +1 Food to the forest/jungle?

I guess its an interesting idea, here is what can be done with map tiles with Python, at least:
http://civ4bug.sourceforge.net/PythonAPI/Classes/CyPlot.html

If you can't find what you need there, then it would pretty much be a C++ thing that would have to be done in the SDK. (Well, I don't see anything useful at least. Its the entries that start with "VOID" that can be used to manipulate CyPlot instances. The other ones just lets you get information about them.) But (almost) anything is possible if you know how to achieve it. :king:
 
It's possible to do in Python. It would be pretty complex, though... This feature is part of Fall from Heaven 2 and is much cleaner- FFH 2 adds a new array to CIV4CivilizationInfos.xml, and then does it all in the DLL.

However, to do it in Python, you'd need to in onBeginPlayerTurn, loop through all of a player's units, check the ones that are building something, and if they are, save both the unit's owner and the feature to the plot's script data.

Then, in onImprovementBuilt, you would need to check the previous feature, and if it's no longer on the plot, and if it's one of the features you want (Forest or Jungle), and if the player who had just built the improvement has unique power, you add back the feature.

This is not perfect. In addition to other possible issues, if a feature is destroyed between the beginning of a player's turn and the completion of the improvement (depending on what happens between the beginning of a player's turn and checks for build progress in the DLL), it won't register, but it's the best you can do in Python only.

EDIT: Plenty of things are possible in Python only, but it's often not necessarily a good idea to do it in Python only. Take Final Frontier as an example. That mod has no custom DLL (until FF+, of course), John Shafer did everything using Python. As a result, it's really slow and has some bugs, but is impressive nonetheless.
 
Yeah, Python is good for some thing and less so for other things. This is why Rhye did some UP in Python and some in C++.

Regarding FF - isn't there supposed to be like a Fort replacement (a space station or something) that has its own cultural boundaries independent from any nearby cities/planets/whatever? Because this is something I'd wanna do with Forts myself. And since you say it was all done with Python...
 
YeRegarding FF - isn't there supposed to be like a Fort replacement (a space station or something) that has its own cultural boundaries independent from any nearby cities/planets/whatever? Because this is something I'd wanna do with Forts myself. And since you say it was all done with Python...

There is, and yes, it's all done with Python (until Final Frontier Plus anyway).

The trouble is that the method requires you to either:

a. Have a Fort unit built when the Fort improvement is, so the updateStarbaseCulture() function knows who owns the Fort. This is how Final Frontier's Starbase works- it's a unit.

b. Alternatively, have a method of storing the Fort's builder (script data, obviously) and a way of claiming the fort from other players. This might be easier, but you'd have to decide- does an enemy unit moving onto the Fort tile claim it? Do units have a custom Python action button letting them seize a tile? Or do Forts have to be razed and then rebuilt by another player?
 
b. Alternatively, have a method of storing the Fort's builder (script data, obviously) and a way of claiming the fort from other players. This might be easier, but you'd have to decide- does an enemy unit moving onto the Fort tile claim it? Do units have a custom Python action button letting them seize a tile? Or do Forts have to be razed and then rebuilt by another player?
What exactly would be the problem with this setup, then? I would probably prefer it if Forts could be taken, I guess... At least when outside of any city's cultural influence.

AFAIK the problem is having Fort tiles, or any tiles for that matter, that aren't part of a city's cultural radius register as owned. Period. Can this be achieved with Python? Like a tile containing a Fort being part of a Civ's cultural borders (just that one tile, unconnected to any other owned tiles). And the Fort would still function as a city in regard for using it as a port/channel/airport, to claim resources and so on. Just like any fort inside cultural borders.

How exactly?
 
What exactly would be the problem with this setup, then? I would probably prefer it if Forts could be taken, I guess... At least when outside of any city's cultural influence.

AFAIK the problem is having Fort tiles, or any tiles for that matter, that aren't part of a city's cultural radius register as owned. Period. Can this be achieved with Python? Like a tile containing a Fort being part of a Civ's cultural borders (just that one tile, unconnected to any other owned tiles). And the Fort would still function as a city in regard for using it as a port/channel/airport, to claim resources and so on. Just like any fort inside cultural borders.

How exactly?

Yes, it can be done.

Here is the original Final Frontier starbase code. updateAllStarbases() is called by onBeginEndGameTurn(), and canBuildStarbase() is called by canBuild(). Everything else is either called by one of those or is a callback.

There is only one change- a bugfix by me that makes it work properly on flat maps when the starbase is at the edge of the map (otherwise, the culture would spill over).

Spoiler :
Code:
#############################################################################################
#		Starbase Stuff
#############################################################################################
	
	def onUnitBuildImprovement(self, argsList):
		'Unit begins enacting a Build (building an Improvement or Route)'
		pUnit, iBuild, bFinished = argsList
		
		iBuildStarbaseID = CvUtil.findInfoTypeNum(gc.getBuildInfo,gc.getNumBuildInfos(),'BUILD_STARBASE')
		
		# Starbase WAS built
		if (iBuild == iBuildStarbaseID):
			pUnit.setScriptData("BuildingStarbase")

	def onImprovementBuilt(self, argsList):
		'Improvement Built'
		iImprovement, iX, iY = argsList
		
		iImprovementStarbaseID = CvUtil.findInfoTypeNum(gc.getImprovementInfo,gc.getNumImprovementInfos(),'IMPROVEMENT_STARBASE')
		iUnitConstructShipID = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_CONSTRUCT_SHIP')
		
		# Starbase finished
		if (iImprovement == iImprovementStarbaseID):
			
			pPlot = CyMap().plot(iX, iY)
			pPlot.setImprovementType(-1)
			
			# Look for Construction Ship on this plot
			for iUnitLoop in range(pPlot.getNumUnits()):
				pUnit = pPlot.getUnit(iUnitLoop)
				
				if (pUnit.getScriptData() == "BuildingStarbase"):
					self.doMakeStarbase(pUnit.getOwner(), iX, iY)
					self.aiKillTimerData = [3, pUnit.getOwner(), pUnit.getID()]
#					pUnit.kill(true, -1)
	
	def doMakeStarbase(self, iPlayer, iX, iY):
		
		pPlayer = gc.getPlayer(iPlayer)
		pPlot = CyMap().plot(iX, iY)
		
		# Create Starbase Unit
		iUnitStarbaseID = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_STARBASE_I')
		pPlayer.initUnit(iUnitStarbaseID, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.NO_DIRECTION)
		
		self.updateStarbaseCulture(iPlayer, iX, iY)
		
	def updateStarbaseCulture(self, iPlayer, iX, iY):
		
		# Create culture around unit
		for iXLoop in range(iX-2, iX+3):
			for iYLoop in range(iY-2, iY+3):
				iActiveX = iXLoop
				iActiveY = iYLoop
				if CyMap().isWrapX():
					if (iActiveX < 0):
						iActiveX = CyMap().getGridWidth() + iActiveX
				if CyMap().isWrapY():
					if (iActiveY < 0):
						iActiveY = CyMap().getGridHeight() + iActiveY
				pLoopPlot = CyMap().plot(iActiveX, iActiveY)
#				printd("Setting Player %d as the owner of %d, %d" %(iPlayer, iXLoop, iYLoop))
				# Don't override culture that's already here
				if not pLoopPlot.isNone():
					if (pLoopPlot.getOwner() == -1):
						pLoopPlot.setOwnerNoUnitCheck(iPlayer)
		
	def updateAllStarbases(self):
		
		# Update Starbase culture
		iUnitStarbaseID = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_STARBASE_I')
		iUnitStarbaseIID = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_STARBASE_II')
		iUnitStarbaseIIID = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_STARBASE_III')
		iUnitMissileI = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_MISSILE_I')
		iUnitMissileII = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_MISSILE_II')
		iUnitMissileIII = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_MISSILE_III')
		
		# List made to preserve culture of units built first
		aaiStarbaseList = []
		
		for iPlayerLoop in range(gc.getMAX_CIV_PLAYERS()):
			pPlayer = gc.getPlayer(iPlayerLoop)
			pTeam = gc.getTeam(pPlayer.getTeam())
			pyPlayer = PyPlayer(iPlayerLoop)
			
			iUnitToCreate = -1
			aiPossibleUnitList = [iUnitMissileI, iUnitMissileII, iUnitMissileIII]
			
			for iUnitLoop in aiPossibleUnitList:
				
				pUnitInfo = gc.getUnitInfo(iUnitLoop)
				iNeededTech = pUnitInfo.getPrereqAndTech()
				
				if (pTeam.isHasTech(iNeededTech)):
					iUnitToCreate = iUnitLoop
			
			apUnitList = pyPlayer.getUnitList()
			for pUnitLoop in apUnitList:
				if (pUnitLoop.getUnitType() == iUnitStarbaseID or pUnitLoop.getUnitType() == iUnitStarbaseIID or pUnitLoop.getUnitType() == iUnitStarbaseIIID):
					aaiStarbaseList.append([pUnitLoop.getGameTurnCreated(), iPlayerLoop, pUnitLoop.getX(), pUnitLoop.getY()])
					
					# Need appropriate tech to create Missile
					if (iUnitToCreate != -1):
						# Need appropriate turn to create
						iTurnCreated = pUnitLoop.getGameTurnCreated()
						iCurrentTurn = CyGame().getGameTurn()
						
						if (iTurnCreated != iCurrentTurn):
							iTurnsSinceCreation = iCurrentTurn - iTurnCreated
							# Produce Missile every 15 turns
							if (iTurnsSinceCreation % 15 == 0):
								print "UnitID: %d, X: %d, Y: %d" %(iUnitToCreate, pUnitLoop.getX(), pUnitLoop.getY())
								pUnit = pPlayer.initUnit(iUnitToCreate, pUnitLoop.getX(), pUnitLoop.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.NO_DIRECTION)
								# Load Missile onto Starbase... the C++ doesn't like this but it can deal :)
								pUnit.setTransportUnit(pUnitLoop)
		
#		printd("\n\nXXX: There are %d Starbases on the map" %(len(aaiStarbaseList)))
#		printd(aaiStarbaseList)
			
		if (len(aaiStarbaseList) > 0):
			
			# Make order such that units built first get culture preference
			aaiStarbaseList.sort()
#			aaiStarbaseList.reverse()
			
			for iStarbaseLoop in range(len(aaiStarbaseList)):
				self.updateStarbaseCulture(aaiStarbaseList[iStarbaseLoop][1], aaiStarbaseList[iStarbaseLoop][2], aaiStarbaseList[iStarbaseLoop][3])
		
	def canBuildStarbase(self, pPlot, iOffset=0):
		
		# Starbase restriction
		iBuildStarbase = CvUtil.findInfoTypeNum(gc.getBuildInfo,gc.getNumBuildInfos(),'BUILD_STARBASE')
		
		# Can't build on a Solar System
		iFeatureIDSolarSystem = CvUtil.findInfoTypeNum(gc.getFeatureInfo,gc.getNumFeatureInfos(),'FEATURE_SOLAR_SYSTEM')
		if (pPlot.getFeatureType() == iFeatureIDSolarSystem):
			return 0
		
		# Can't build on top of another Starbase
		iUnitStarbaseI = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_STARBASE_I')
		iUnitStarbaseII = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_STARBASE_II')
		iUnitStarbaseIII = CvUtil.findInfoTypeNum(gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_STARBASE_III')
		
		iNumUnits = iOffset # Offset so that Interface can disable button
		
		# Loop through all units on the plot
		for iUnitLoop in range(pPlot.getNumUnits()):
			pUnit = pPlot.getUnit(iUnitLoop)
			
			# Can't build on top of another Starbase
			if (pUnit.getUnitType() == iUnitStarbaseI or pUnit.getUnitType() == iUnitStarbaseII or pUnit.getUnitType() == iUnitStarbaseIII):
				return 0
			
			# if there are any Construction Ships already building a Starbase then disallow more	
			if (pUnit.getBuildType() == iBuildStarbase):
				iNumUnits += 1
				if (iNumUnits > 1):	# Account for the one unit actually performing the mission
					return 0
		
		return 1

Several things are handled poorly, especially the onUnitBuildImprovement() code. It initializes a timer, and on the end of the timer (after the actual starbase unit is created and its culture is generated) the unit is killed. This probably wouldn't be necessary if you don't use a Fort unit- and in any case, should be done by writing the owner of the build unit to script data each turn, since it makes no allowances

You also probably won't need the code to create missiles on each starbase.
 
What exactly does CyPlot.setOwnerNoUnitCheck() achieve? Is the "unit check" perhaps to see whether or not foreign units are present and need to be relocated?
 
For forts, can't you use the jculture? It makes fort improvements spread cultural borders of the owner by 1 tile (with 50% strength iirc), meaning that you can extend the borders with forts, until they are taken or destroyed - I believe it's part SDK, so that the AI also builds forts in contested locations to steal tiles.

EDIT: this: http://forums.civfanatics.com/showthread.php?t=283686
 
For forts, can't you use the jculture? It makes fort improvements spread cultural borders of the owner by 1 tile (with 50% strength iirc), meaning that you can extend the borders with forts, until they are taken or destroyed - I believe it's part SDK, so that the AI also builds forts in contested locations to steal tiles.

EDIT: this: http://forums.civfanatics.com/showthread.php?t=283686

It's entirely DLL, and that's the point- Baldyr is looking for a Python-only solution (at least, I think).

Well, there actually is some Python, but it looks like it's mostly AI Auto Play and various other (unnecessary) stuff. Kailric and I used it for our wild west Colonization mod, Westward Ho, and when he created the Forts modcomp for Colonization there
 
What exactly does CyPlot.setOwnerNoUnitCheck() achieve? Is the "unit check" perhaps to see whether or not foreign units are present and need to be relocated?

I think that's what it does, but I'm not sure.

The setOwner() function in the DLL has three arguments that aren't available to the Python version, so setOwnerNoUnitCheck() simply sets one of those arguments to true.

For forts, can't you use the jculture? It makes fort improvements spread cultural borders of the owner by 1 tile (with 50% strength iirc), meaning that you can extend the borders with forts, until they are taken or destroyed - I believe it's part SDK, so that the AI also builds forts in contested locations to steal tiles.

EDIT: this: http://forums.civfanatics.com/showthread.php?t=283686

It's entirely DLL, and that's the point- Baldyr is looking for a Python-only solution (at least, I think).

Well, there actually is some Python, but it looks like it's mostly AI Auto Play and various other (unnecessary) stuff. Kailric and I used it for our wild west Colonization mod, Westward Ho, and when he created the Forts modcomp for Colonization there was no Python involved.
 
Hey Baldyr, I just want a quick assessment of my UP idea for my Iroquois (ie how hard it would be).

Unique Power: The Power of the Warpath
Improvements can be built in forests, jungles.

How hard would that be to make? And is it overpowered?

How about adding a worker UU to Iroquois and edit "Builds" (so, modify CIV4UnitInfos.xml and CIV4BuildInfos.xml)?
Of course, there might be some RFC specific issues with modding, and I am not sure if that works though.
 
That's a very interesting idea. Would it say:

Unique Unit: Mohawk Warrior (current unit)

or

Unique Unit: Mohawk Warrior, iWorker?
 
Back
Top Bottom